1
This commit is contained in:
+8
@@ -0,0 +1,8 @@
|
||||
import * as React from 'react';
|
||||
export interface WatermarkContextProps {
|
||||
add: (ele: HTMLElement) => void;
|
||||
remove: (ele: HTMLElement) => void;
|
||||
}
|
||||
declare const WatermarkContext: React.Context<WatermarkContextProps>;
|
||||
export declare function usePanelRef(panelSelector?: string): (ele: HTMLElement | null) => void;
|
||||
export default WatermarkContext;
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
"use strict";
|
||||
|
||||
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
exports.usePanelRef = usePanelRef;
|
||||
var React = _interopRequireWildcard(require("react"));
|
||||
var _util = require("@rc-component/util");
|
||||
function voidFunc() {}
|
||||
const WatermarkContext = /*#__PURE__*/React.createContext({
|
||||
add: voidFunc,
|
||||
remove: voidFunc
|
||||
});
|
||||
function usePanelRef(panelSelector) {
|
||||
const watermark = React.useContext(WatermarkContext);
|
||||
const panelEleRef = React.useRef(null);
|
||||
const panelRef = (0, _util.useEvent)(ele => {
|
||||
if (ele) {
|
||||
const innerContentEle = panelSelector ? ele.querySelector(panelSelector) : ele;
|
||||
if (innerContentEle) {
|
||||
watermark.add(innerContentEle);
|
||||
panelEleRef.current = innerContentEle;
|
||||
}
|
||||
} else {
|
||||
watermark.remove(panelEleRef.current);
|
||||
}
|
||||
});
|
||||
return panelRef;
|
||||
}
|
||||
var _default = exports.default = WatermarkContext;
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
import React from 'react';
|
||||
export interface WatermarkProps {
|
||||
zIndex?: number;
|
||||
rotate?: number;
|
||||
width?: number;
|
||||
height?: number;
|
||||
image?: string;
|
||||
content?: string | string[];
|
||||
font?: {
|
||||
color?: CanvasFillStrokeStyles['fillStyle'];
|
||||
fontSize?: number | string;
|
||||
fontWeight?: 'normal' | 'lighter' | 'bold' | 'bolder' | number;
|
||||
fontStyle?: 'none' | 'normal' | 'italic' | 'oblique';
|
||||
fontFamily?: string;
|
||||
textAlign?: CanvasTextAlign;
|
||||
};
|
||||
style?: React.CSSProperties;
|
||||
className?: string;
|
||||
rootClassName?: string;
|
||||
gap?: [number, number];
|
||||
offset?: [number, number];
|
||||
children?: React.ReactNode;
|
||||
inherit?: boolean;
|
||||
/**
|
||||
* @since 6.0.0
|
||||
*/
|
||||
onRemove?: () => void;
|
||||
}
|
||||
declare const Watermark: React.FC<WatermarkProps>;
|
||||
export default Watermark;
|
||||
+239
@@ -0,0 +1,239 @@
|
||||
"use strict";
|
||||
"use client";
|
||||
|
||||
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
|
||||
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
||||
var _react = _interopRequireWildcard(require("react"));
|
||||
var _mutateObserver = require("@rc-component/mutate-observer");
|
||||
var _util = require("@rc-component/util");
|
||||
var _clsx = require("clsx");
|
||||
var _toList = _interopRequireDefault(require("../_util/toList"));
|
||||
var _context = require("../config-provider/context");
|
||||
var _internal = require("../theme/internal");
|
||||
var _context2 = _interopRequireDefault(require("./context"));
|
||||
var _useClips = _interopRequireWildcard(require("./useClips"));
|
||||
var _useRafDebounce = _interopRequireDefault(require("./useRafDebounce"));
|
||||
var _useSingletonCache = _interopRequireDefault(require("./useSingletonCache"));
|
||||
var _useWatermark = _interopRequireDefault(require("./useWatermark"));
|
||||
var _utils = require("./utils");
|
||||
/**
|
||||
* Only return `next` when size changed.
|
||||
* This is only used for elements compare, not a shallow equal!
|
||||
*/
|
||||
function getSizeDiff(prev, next) {
|
||||
return prev.size === next.size ? prev : next;
|
||||
}
|
||||
const DEFAULT_GAP_X = 100;
|
||||
const DEFAULT_GAP_Y = 100;
|
||||
const fixedStyle = {
|
||||
position: 'relative',
|
||||
overflow: 'hidden'
|
||||
};
|
||||
const Watermark = props => {
|
||||
const {
|
||||
/**
|
||||
* The antd content layer zIndex is basically below 10
|
||||
* https://github.com/ant-design/ant-design/blob/6192403b2ce517c017f9e58a32d58774921c10cd/components/style/themes/default.less#L335
|
||||
*/
|
||||
zIndex = 9,
|
||||
rotate = -22,
|
||||
width,
|
||||
height,
|
||||
image,
|
||||
content,
|
||||
font = {},
|
||||
style,
|
||||
className,
|
||||
rootClassName,
|
||||
gap = [DEFAULT_GAP_X, DEFAULT_GAP_Y],
|
||||
offset,
|
||||
children,
|
||||
inherit = true,
|
||||
onRemove
|
||||
} = props;
|
||||
const {
|
||||
className: contextClassName,
|
||||
style: contextStyle
|
||||
} = (0, _context.useComponentConfig)('watermark');
|
||||
const mergedStyle = {
|
||||
...fixedStyle,
|
||||
...contextStyle,
|
||||
...style
|
||||
};
|
||||
const [, token] = (0, _internal.useToken)();
|
||||
const {
|
||||
color = token.colorFill,
|
||||
fontSize = token.fontSizeLG,
|
||||
fontWeight = 'normal',
|
||||
fontStyle = 'normal',
|
||||
fontFamily = 'sans-serif',
|
||||
textAlign = 'center'
|
||||
} = font;
|
||||
const [gapX = DEFAULT_GAP_X, gapY = DEFAULT_GAP_Y] = gap;
|
||||
const gapXCenter = gapX / 2;
|
||||
const gapYCenter = gapY / 2;
|
||||
const offsetLeft = offset?.[0] ?? gapXCenter;
|
||||
const offsetTop = offset?.[1] ?? gapYCenter;
|
||||
const markStyle = _react.default.useMemo(() => {
|
||||
const mergedMarkStyle = {
|
||||
zIndex,
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
top: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
pointerEvents: 'none',
|
||||
backgroundRepeat: 'repeat'
|
||||
};
|
||||
/** Calculate the style of the offset */
|
||||
let positionLeft = offsetLeft - gapXCenter;
|
||||
let positionTop = offsetTop - gapYCenter;
|
||||
if (positionLeft > 0) {
|
||||
mergedMarkStyle.left = `${positionLeft}px`;
|
||||
mergedMarkStyle.width = `calc(100% - ${positionLeft}px)`;
|
||||
positionLeft = 0;
|
||||
}
|
||||
if (positionTop > 0) {
|
||||
mergedMarkStyle.top = `${positionTop}px`;
|
||||
mergedMarkStyle.height = `calc(100% - ${positionTop}px)`;
|
||||
positionTop = 0;
|
||||
}
|
||||
mergedMarkStyle.backgroundPosition = `${positionLeft}px ${positionTop}px`;
|
||||
return mergedMarkStyle;
|
||||
}, [zIndex, offsetLeft, gapXCenter, offsetTop, gapYCenter]);
|
||||
const [container, setContainer] = _react.default.useState();
|
||||
// Used for nest case like Modal, Drawer
|
||||
const [subElements, setSubElements] = _react.default.useState(() => new Set());
|
||||
// Nest elements should also support watermark
|
||||
const targetElements = _react.default.useMemo(() => {
|
||||
const list = container ? [container] : [];
|
||||
return [].concat(list, (0, _toConsumableArray2.default)(Array.from(subElements)));
|
||||
}, [container, subElements]);
|
||||
// ============================ Content =============================
|
||||
/**
|
||||
* Get the width and height of the watermark. The default values are as follows
|
||||
* Image: [120, 64]; Content: It's calculated by content;
|
||||
*/
|
||||
const getMarkSize = ctx => {
|
||||
let defaultWidth = 120;
|
||||
let defaultHeight = 64;
|
||||
if (!image && ctx.measureText) {
|
||||
ctx.font = `${Number(fontSize)}px ${fontFamily}`;
|
||||
const contents = (0, _toList.default)(content);
|
||||
const sizes = contents.map(item => {
|
||||
const metrics = ctx.measureText(item);
|
||||
return [metrics.width, metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent];
|
||||
});
|
||||
defaultWidth = Math.ceil(Math.max.apply(Math, (0, _toConsumableArray2.default)(sizes.map(size => size[0]))));
|
||||
defaultHeight = Math.ceil(Math.max.apply(Math, (0, _toConsumableArray2.default)(sizes.map(size => size[1])))) * contents.length + (contents.length - 1) * _useClips.FontGap;
|
||||
}
|
||||
return [width ?? defaultWidth, height ?? defaultHeight];
|
||||
};
|
||||
const getClips = (0, _useClips.default)();
|
||||
const getClipsCache = (0, _useSingletonCache.default)();
|
||||
const [watermarkInfo, setWatermarkInfo] = _react.default.useState(null);
|
||||
// Generate new Watermark content
|
||||
const renderWatermark = () => {
|
||||
const canvas = document.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (ctx) {
|
||||
const ratio = (0, _utils.getPixelRatio)();
|
||||
const [markWidth, markHeight] = getMarkSize(ctx);
|
||||
const drawCanvas = drawContent => {
|
||||
const params = [drawContent || '', rotate, ratio, markWidth, markHeight, {
|
||||
color,
|
||||
fontSize,
|
||||
fontStyle,
|
||||
fontWeight,
|
||||
fontFamily,
|
||||
textAlign
|
||||
}, gapX, gapY];
|
||||
const [nextClips, clipWidth] = getClipsCache(params, () => getClips.apply(void 0, params));
|
||||
setWatermarkInfo([nextClips, clipWidth]);
|
||||
};
|
||||
if (image) {
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
drawCanvas(img);
|
||||
};
|
||||
img.onerror = () => {
|
||||
drawCanvas(content);
|
||||
};
|
||||
img.crossOrigin = 'anonymous';
|
||||
img.referrerPolicy = 'no-referrer';
|
||||
img.src = image;
|
||||
} else {
|
||||
drawCanvas(content);
|
||||
}
|
||||
}
|
||||
};
|
||||
const syncWatermark = (0, _useRafDebounce.default)(renderWatermark);
|
||||
// ============================= Effect =============================
|
||||
// Append watermark to the container
|
||||
const [appendWatermark, removeWatermark, isWatermarkEle] = (0, _useWatermark.default)(markStyle, onRemove);
|
||||
(0, _react.useEffect)(() => {
|
||||
if (watermarkInfo) {
|
||||
targetElements.forEach(holder => {
|
||||
appendWatermark(watermarkInfo[0], watermarkInfo[1], holder);
|
||||
});
|
||||
}
|
||||
}, [watermarkInfo, targetElements]);
|
||||
// ============================ Observe =============================
|
||||
const onMutate = (0, _util.useEvent)(mutations => {
|
||||
mutations.forEach(mutation => {
|
||||
if ((0, _utils.reRendering)(mutation, isWatermarkEle)) {
|
||||
syncWatermark();
|
||||
} else if (mutation.target === container && mutation.attributeName === 'style') {
|
||||
// We've only force container not modify.
|
||||
// Not consider nest case.
|
||||
const keyStyles = Object.keys(fixedStyle);
|
||||
for (let i = 0; i < keyStyles.length; i += 1) {
|
||||
const key = keyStyles[i];
|
||||
const oriValue = mergedStyle[key];
|
||||
const currentValue = container.style[key];
|
||||
if (oriValue && oriValue !== currentValue) {
|
||||
container.style[key] = oriValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
(0, _mutateObserver.useMutateObserver)(targetElements, onMutate);
|
||||
(0, _react.useEffect)(syncWatermark, [rotate, zIndex, width, height, image, content, color, fontSize, fontWeight, fontStyle, fontFamily, textAlign, gapX, gapY, offsetLeft, offsetTop]);
|
||||
// ============================ Context =============================
|
||||
const watermarkContext = _react.default.useMemo(() => ({
|
||||
add: ele => {
|
||||
setSubElements(prev => {
|
||||
const clone = new Set(prev);
|
||||
clone.add(ele);
|
||||
return getSizeDiff(prev, clone);
|
||||
});
|
||||
},
|
||||
remove: ele => {
|
||||
removeWatermark(ele);
|
||||
setSubElements(prev => {
|
||||
const clone = new Set(prev);
|
||||
clone.delete(ele);
|
||||
return getSizeDiff(prev, clone);
|
||||
});
|
||||
}
|
||||
}), []);
|
||||
// ============================= Render =============================
|
||||
const childNode = inherit ? (/*#__PURE__*/_react.default.createElement(_context2.default.Provider, {
|
||||
value: watermarkContext
|
||||
}, children)) : children;
|
||||
return /*#__PURE__*/_react.default.createElement("div", {
|
||||
ref: setContainer,
|
||||
className: (0, _clsx.clsx)(className, contextClassName, rootClassName),
|
||||
style: mergedStyle
|
||||
}, childNode);
|
||||
};
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
Watermark.displayName = 'Watermark';
|
||||
}
|
||||
var _default = exports.default = Watermark;
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
import type { WatermarkProps } from '.';
|
||||
export declare const FontGap = 3;
|
||||
/**
|
||||
* Get the clips of text content.
|
||||
* This is a lazy hook function since SSR no need this
|
||||
*/
|
||||
declare const useClips: () => (content: NonNullable<WatermarkProps["content"]> | HTMLImageElement, rotate: number, ratio: number, width: number, height: number, font: Required<NonNullable<WatermarkProps["font"]>>, gapX: number, gapY: number) => [dataURL: string, finalWidth: number, finalHeight: number];
|
||||
export default useClips;
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
"use strict";
|
||||
|
||||
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = exports.FontGap = void 0;
|
||||
var _react = _interopRequireDefault(require("react"));
|
||||
var _toList = _interopRequireDefault(require("../_util/toList"));
|
||||
const FontGap = exports.FontGap = 3;
|
||||
const prepareCanvas = (width, height, ratio = 1) => {
|
||||
const canvas = document.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
const realWidth = width * ratio;
|
||||
const realHeight = height * ratio;
|
||||
canvas.setAttribute('width', `${realWidth}px`);
|
||||
canvas.setAttribute('height', `${realHeight}px`);
|
||||
ctx.save();
|
||||
return [ctx, canvas, realWidth, realHeight];
|
||||
};
|
||||
// Get boundary of rotated text
|
||||
const getRotatePos = (x, y, angle) => {
|
||||
const targetX = x * Math.cos(angle) - y * Math.sin(angle);
|
||||
const targetY = x * Math.sin(angle) + y * Math.cos(angle);
|
||||
return [targetX, targetY];
|
||||
};
|
||||
/**
|
||||
* Get the clips of text content.
|
||||
* This is a lazy hook function since SSR no need this
|
||||
*/
|
||||
const useClips = () => {
|
||||
// Get single clips
|
||||
const getClips = (content, rotate, ratio, width, height, font, gapX, gapY) => {
|
||||
// ================= Text / Image =================
|
||||
const [ctx, canvas, contentWidth, contentHeight] = prepareCanvas(width, height, ratio);
|
||||
if (content instanceof HTMLImageElement) {
|
||||
// Image
|
||||
ctx.drawImage(content, 0, 0, contentWidth, contentHeight);
|
||||
} else {
|
||||
// Text
|
||||
const {
|
||||
color,
|
||||
fontSize,
|
||||
fontStyle,
|
||||
fontWeight,
|
||||
fontFamily,
|
||||
textAlign
|
||||
} = font;
|
||||
const mergedFontSize = Number(fontSize) * ratio;
|
||||
ctx.font = `${fontStyle} normal ${fontWeight} ${mergedFontSize}px/${height}px ${fontFamily}`;
|
||||
ctx.fillStyle = color;
|
||||
ctx.textAlign = textAlign;
|
||||
ctx.textBaseline = 'top';
|
||||
const contents = (0, _toList.default)(content);
|
||||
contents?.forEach((item, index) => {
|
||||
ctx.fillText(item ?? '', contentWidth / 2, index * (mergedFontSize + FontGap * ratio));
|
||||
});
|
||||
}
|
||||
// ==================== Rotate ====================
|
||||
const angle = Math.PI / 180 * Number(rotate);
|
||||
const maxSize = Math.max(width, height);
|
||||
const [rCtx, rCanvas, realMaxSize] = prepareCanvas(maxSize, maxSize, ratio);
|
||||
// Copy from `ctx` and rotate
|
||||
rCtx.translate(realMaxSize / 2, realMaxSize / 2);
|
||||
rCtx.rotate(angle);
|
||||
if (contentWidth > 0 && contentHeight > 0) {
|
||||
rCtx.drawImage(canvas, -contentWidth / 2, -contentHeight / 2);
|
||||
}
|
||||
let left = 0;
|
||||
let right = 0;
|
||||
let top = 0;
|
||||
let bottom = 0;
|
||||
const halfWidth = contentWidth / 2;
|
||||
const halfHeight = contentHeight / 2;
|
||||
const points = [[0 - halfWidth, 0 - halfHeight], [0 + halfWidth, 0 - halfHeight], [0 + halfWidth, 0 + halfHeight], [0 - halfWidth, 0 + halfHeight]];
|
||||
points.forEach(([x, y]) => {
|
||||
const [targetX, targetY] = getRotatePos(x, y, angle);
|
||||
left = Math.min(left, targetX);
|
||||
right = Math.max(right, targetX);
|
||||
top = Math.min(top, targetY);
|
||||
bottom = Math.max(bottom, targetY);
|
||||
});
|
||||
const cutLeft = left + realMaxSize / 2;
|
||||
const cutTop = top + realMaxSize / 2;
|
||||
const cutWidth = right - left;
|
||||
const cutHeight = bottom - top;
|
||||
// ================ Fill Alternate ================
|
||||
const realGapX = gapX * ratio;
|
||||
const realGapY = gapY * ratio;
|
||||
const filledWidth = (cutWidth + realGapX) * 2;
|
||||
const filledHeight = cutHeight + realGapY;
|
||||
const [fCtx, fCanvas] = prepareCanvas(filledWidth, filledHeight);
|
||||
const drawImg = (targetX = 0, targetY = 0) => {
|
||||
fCtx.drawImage(rCanvas, cutLeft, cutTop, cutWidth, cutHeight, targetX, targetY, cutWidth, cutHeight);
|
||||
};
|
||||
drawImg();
|
||||
drawImg(cutWidth + realGapX, -cutHeight / 2 - realGapY / 2);
|
||||
drawImg(cutWidth + realGapX, +cutHeight / 2 + realGapY / 2);
|
||||
return [fCanvas.toDataURL(), filledWidth / ratio, filledHeight / ratio];
|
||||
};
|
||||
return _react.default.useCallback(getClips, []);
|
||||
};
|
||||
var _default = exports.default = useClips;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Callback will only execute last one for each raf
|
||||
*/
|
||||
export default function useRafDebounce(callback: VoidFunction): () => void;
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
"use strict";
|
||||
|
||||
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = useRafDebounce;
|
||||
var _react = _interopRequireDefault(require("react"));
|
||||
var _util = require("@rc-component/util");
|
||||
var _raf = _interopRequireDefault(require("@rc-component/util/lib/raf"));
|
||||
/**
|
||||
* Callback will only execute last one for each raf
|
||||
*/
|
||||
function useRafDebounce(callback) {
|
||||
const executeRef = _react.default.useRef(false);
|
||||
const rafRef = _react.default.useRef(null);
|
||||
const wrapperCallback = (0, _util.useEvent)(callback);
|
||||
return () => {
|
||||
if (executeRef.current) {
|
||||
return;
|
||||
}
|
||||
executeRef.current = true;
|
||||
wrapperCallback();
|
||||
rafRef.current = (0, _raf.default)(() => {
|
||||
executeRef.current = false;
|
||||
});
|
||||
};
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
export type GetCache<T, R> = (cacheKeys: T, callback: () => R) => R;
|
||||
/**
|
||||
* Singleton cache will only take latest `cacheParams` as key
|
||||
* and return the result for callback matching.
|
||||
*/
|
||||
export default function useSingletonCache<T extends any[], R>(): GetCache<T, R>;
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
"use strict";
|
||||
|
||||
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
||||
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = useSingletonCache;
|
||||
var React = _interopRequireWildcard(require("react"));
|
||||
var _isEqual = _interopRequireDefault(require("@rc-component/util/lib/isEqual"));
|
||||
/**
|
||||
* Singleton cache will only take latest `cacheParams` as key
|
||||
* and return the result for callback matching.
|
||||
*/
|
||||
function useSingletonCache() {
|
||||
const cacheRef = React.useRef([null, null]);
|
||||
const getCache = (cacheKeys, callback) => {
|
||||
const filteredKeys = cacheKeys.map(item => item instanceof HTMLElement || Number.isNaN(item) ? '' : item);
|
||||
if (!(0, _isEqual.default)(cacheRef.current[0], filteredKeys)) {
|
||||
cacheRef.current = [filteredKeys, callback()];
|
||||
}
|
||||
return cacheRef.current[1];
|
||||
};
|
||||
return getCache;
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
import * as React from 'react';
|
||||
/**
|
||||
* Base size of the canvas, 1 for parallel layout and 2 for alternate layout
|
||||
* Only alternate layout is currently supported
|
||||
*/
|
||||
export declare const BaseSize = 2;
|
||||
export declare const FontGap = 3;
|
||||
export type AppendWatermark = (base64Url: string, markWidth: number, container: HTMLElement) => void;
|
||||
declare function useWatermark(markStyle: React.CSSProperties, onRemove?: () => void): [
|
||||
appendWatermark: AppendWatermark,
|
||||
removeWatermark: (container: HTMLElement) => void,
|
||||
isWatermarkEle: (ele: Node, index?: number) => boolean
|
||||
];
|
||||
export default useWatermark;
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
"use strict";
|
||||
|
||||
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = exports.FontGap = exports.BaseSize = void 0;
|
||||
var React = _interopRequireWildcard(require("react"));
|
||||
var _util = require("@rc-component/util");
|
||||
var _utils = require("./utils");
|
||||
/**
|
||||
* Base size of the canvas, 1 for parallel layout and 2 for alternate layout
|
||||
* Only alternate layout is currently supported
|
||||
*/
|
||||
const BaseSize = exports.BaseSize = 2;
|
||||
const FontGap = exports.FontGap = 3;
|
||||
// Prevent external hidden elements from adding accent styles
|
||||
const emphasizedStyle = {
|
||||
visibility: 'visible !important'
|
||||
};
|
||||
const noop = () => {};
|
||||
function useWatermark(markStyle, onRemove) {
|
||||
const watermarkMapRef = React.useRef(new Map());
|
||||
const onRemoveEvent = (0, _util.useEvent)(onRemove ?? noop);
|
||||
const appendWatermark = (base64Url, markWidth, container) => {
|
||||
if (container) {
|
||||
const exist = watermarkMapRef.current.get(container);
|
||||
if (!exist) {
|
||||
const newWatermarkEle = document.createElement('div');
|
||||
watermarkMapRef.current.set(container, newWatermarkEle);
|
||||
}
|
||||
const watermarkEle = watermarkMapRef.current.get(container);
|
||||
watermarkEle.setAttribute('style', (0, _utils.getStyleStr)({
|
||||
...markStyle,
|
||||
backgroundImage: `url('${base64Url}')`,
|
||||
backgroundSize: `${Math.floor(markWidth)}px`,
|
||||
...emphasizedStyle
|
||||
}));
|
||||
// Prevents using the browser `Hide Element` to hide watermarks
|
||||
watermarkEle.removeAttribute('class');
|
||||
watermarkEle.removeAttribute('hidden');
|
||||
if (watermarkEle.parentElement !== container) {
|
||||
if (exist && onRemove) {
|
||||
onRemoveEvent();
|
||||
}
|
||||
container.append(watermarkEle);
|
||||
}
|
||||
}
|
||||
return watermarkMapRef.current.get(container);
|
||||
};
|
||||
const removeWatermark = container => {
|
||||
const watermarkEle = watermarkMapRef.current.get(container);
|
||||
if (watermarkEle && container) {
|
||||
container.removeChild(watermarkEle);
|
||||
}
|
||||
watermarkMapRef.current.delete(container);
|
||||
};
|
||||
const isWatermarkEle = ele => Array.from(watermarkMapRef.current.values()).includes(ele);
|
||||
return [appendWatermark, removeWatermark, isWatermarkEle];
|
||||
}
|
||||
var _default = exports.default = useWatermark;
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
/** converting camel-cased strings to be lowercase and link it with Separator */
|
||||
export declare function toLowercaseSeparator(key: string): string;
|
||||
export declare function getStyleStr(style: React.CSSProperties): string;
|
||||
/** Returns the ratio of the device's physical pixel resolution to the css pixel resolution */
|
||||
export declare function getPixelRatio(): number;
|
||||
/** Whether to re-render the watermark */
|
||||
export declare const reRendering: (mutation: MutationRecord, isWatermarkEle: (ele: Node, index?: number) => boolean) => boolean;
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.getPixelRatio = getPixelRatio;
|
||||
exports.getStyleStr = getStyleStr;
|
||||
exports.reRendering = void 0;
|
||||
exports.toLowercaseSeparator = toLowercaseSeparator;
|
||||
/** converting camel-cased strings to be lowercase and link it with Separator */
|
||||
function toLowercaseSeparator(key) {
|
||||
return key.replace(/([A-Z])/g, '-$1').toLowerCase();
|
||||
}
|
||||
function getStyleStr(style) {
|
||||
return Object.keys(style).map(key => `${toLowercaseSeparator(key)}: ${style[key]};`).join(' ');
|
||||
}
|
||||
/** Returns the ratio of the device's physical pixel resolution to the css pixel resolution */
|
||||
function getPixelRatio() {
|
||||
return window.devicePixelRatio || 1;
|
||||
}
|
||||
/** Whether to re-render the watermark */
|
||||
const reRendering = (mutation, isWatermarkEle) => {
|
||||
let flag = false;
|
||||
// Whether to delete the watermark node
|
||||
if (mutation.removedNodes.length) {
|
||||
flag = Array.from(mutation.removedNodes).some(isWatermarkEle);
|
||||
}
|
||||
// Whether the watermark dom property value has been modified
|
||||
if (mutation.type === 'attributes' && isWatermarkEle(mutation.target)) {
|
||||
flag = true;
|
||||
}
|
||||
return flag;
|
||||
};
|
||||
exports.reRendering = reRendering;
|
||||
Reference in New Issue
Block a user