Files
video-gen/video-gen-admin/node_modules/@rc-component/image/es/Preview/index.js
T
2026-05-25 17:08:18 +08:00

363 lines
9.9 KiB
JavaScript

function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
import CSSMotion from '@rc-component/motion';
import Portal from '@rc-component/portal';
import { useEvent } from '@rc-component/util';
import { useLockFocus } from "@rc-component/util/es/Dom/focus";
import useLayoutEffect from "@rc-component/util/es/hooks/useLayoutEffect";
import KeyCode from "@rc-component/util/es/KeyCode";
import { clsx } from 'clsx';
import React, { useContext, useEffect, useRef, useState } from 'react';
import { PreviewGroupContext } from "../context";
import useImageTransform from "../hooks/useImageTransform";
import useMouseEvent from "../hooks/useMouseEvent";
import useStatus from "../hooks/useStatus";
import useTouchEvent from "../hooks/useTouchEvent";
import { BASE_SCALE_RATIO } from "../previewConfig";
import CloseBtn from "./CloseBtn";
import Footer from "./Footer";
import PrevNext from "./PrevNext";
// Note: if you want to add `action`,
// pls contact @zombieJ or @thinkasany first.
const PreviewImage = ({
fallback,
src,
imgRef,
...props
}) => {
const [getImgRef, srcAndOnload] = useStatus({
src,
fallback
});
return /*#__PURE__*/React.createElement("img", _extends({
ref: ref => {
imgRef.current = ref;
getImgRef(ref);
}
}, props, srcAndOnload));
};
const Preview = props => {
const {
prefixCls,
rootClassName,
src,
alt,
imageInfo,
fallback,
movable = true,
onClose,
open,
afterOpenChange,
maskClosable = true,
icons = {},
closeIcon,
getContainer,
current = 0,
count = 1,
countRender,
scaleStep = 0.5,
minScale = 1,
maxScale = 50,
motionName = 'fade',
imageRender,
imgCommonProps,
actionsRender,
onTransform,
onChange,
classNames = {},
styles = {},
mousePosition,
zIndex,
focusTrap = true
} = props;
const imgRef = useRef();
const wrapperRef = useRef(null);
const triggerRef = useRef(null);
const groupContext = useContext(PreviewGroupContext);
const showLeftOrRightSwitches = groupContext && count > 1;
const showOperationsProgress = groupContext && count >= 1;
// ======================== Transform =========================
const [enableTransition, setEnableTransition] = useState(true);
const {
transform,
resetTransform,
updateTransform,
dispatchZoomChange
} = useImageTransform(imgRef, minScale, maxScale, onTransform);
const {
isMoving,
onMouseDown,
onWheel
} = useMouseEvent(imgRef, movable, open, scaleStep, transform, updateTransform, dispatchZoomChange);
const {
isTouching,
onTouchStart,
onTouchMove,
onTouchEnd
} = useTouchEvent(imgRef, movable, open, minScale, transform, updateTransform, dispatchZoomChange);
const {
rotate,
scale
} = transform;
useEffect(() => {
if (!enableTransition) {
setEnableTransition(true);
}
}, [enableTransition]);
useEffect(() => {
if (!open) {
resetTransform('close');
}
}, [open]);
// ========================== Image ===========================
const onDoubleClick = event => {
if (open) {
if (scale !== 1) {
updateTransform({
x: 0,
y: 0,
scale: 1
}, 'doubleClick');
} else {
dispatchZoomChange(BASE_SCALE_RATIO + scaleStep, 'doubleClick', event.clientX, event.clientY);
}
}
};
const imgNode = /*#__PURE__*/React.createElement(PreviewImage, _extends({}, imgCommonProps, {
width: props.width,
height: props.height,
imgRef: imgRef,
className: `${prefixCls}-img`,
alt: alt,
style: {
transform: `translate3d(${transform.x}px, ${transform.y}px, 0) scale3d(${transform.flipX ? '-' : ''}${scale}, ${transform.flipY ? '-' : ''}${scale}, 1) rotate(${rotate}deg)`,
transitionDuration: (!enableTransition || isTouching) && '0s'
},
fallback: fallback,
src: src,
onWheel: onWheel,
onMouseDown: onMouseDown,
onDoubleClick: onDoubleClick,
onTouchStart: onTouchStart,
onTouchMove: onTouchMove,
onTouchEnd: onTouchEnd,
onTouchCancel: onTouchEnd
}));
const image = {
url: src,
alt,
...imageInfo
};
// ======================== Operation =========================
// >>>>> Actions
const onZoomIn = () => {
dispatchZoomChange(BASE_SCALE_RATIO + scaleStep, 'zoomIn');
};
const onZoomOut = () => {
dispatchZoomChange(BASE_SCALE_RATIO / (BASE_SCALE_RATIO + scaleStep), 'zoomOut');
};
const onRotateRight = () => {
updateTransform({
rotate: rotate + 90
}, 'rotateRight');
};
const onRotateLeft = () => {
updateTransform({
rotate: rotate - 90
}, 'rotateLeft');
};
const onFlipX = () => {
updateTransform({
flipX: !transform.flipX
}, 'flipX');
};
const onFlipY = () => {
updateTransform({
flipY: !transform.flipY
}, 'flipY');
};
const onReset = () => {
resetTransform('reset');
};
const onActive = offset => {
const nextCurrent = current + offset;
if (nextCurrent >= 0 && nextCurrent <= count - 1) {
setEnableTransition(false);
resetTransform(offset < 0 ? 'prev' : 'next');
onChange?.(nextCurrent, current);
}
};
// >>>>> Effect: Keyboard
const onKeyDown = useEvent(event => {
if (open) {
const {
keyCode
} = event;
if (showLeftOrRightSwitches) {
if (keyCode === KeyCode.LEFT) {
onActive(-1);
} else if (keyCode === KeyCode.RIGHT) {
onActive(1);
}
}
}
});
useEffect(() => {
if (open) {
window.addEventListener('keydown', onKeyDown);
return () => {
window.removeEventListener('keydown', onKeyDown);
};
}
}, [open]);
// ======================= Lock Scroll ========================
const [lockScroll, setLockScroll] = useState(false);
React.useEffect(() => {
if (open) {
setLockScroll(true);
}
}, [open]);
const onVisibleChanged = nextVisible => {
if (!nextVisible) {
setLockScroll(false);
// Restore focus to the trigger element after leave animation
triggerRef.current?.focus?.();
triggerRef.current = null;
}
afterOpenChange?.(nextVisible);
};
// ========================== Portal ==========================
const [portalRender, setPortalRender] = useState(false);
useLayoutEffect(() => {
if (open) {
setPortalRender(true);
}
}, [open]);
const onEsc = ({
top
}) => {
if (top) {
onClose?.();
}
};
// =========================== Focus ============================
useLayoutEffect(() => {
if (open) {
triggerRef.current = document.activeElement;
}
}, [open]);
useLockFocus(focusTrap && open && portalRender, () => wrapperRef.current);
// ========================== Render ==========================
const bodyStyle = {
...styles.body
};
if (mousePosition) {
bodyStyle.transformOrigin = `${mousePosition.x}px ${mousePosition.y}px`;
}
return /*#__PURE__*/React.createElement(Portal, {
open: portalRender && open,
autoDestroy: false,
getContainer: getContainer,
autoLock: lockScroll,
onEsc: onEsc
}, /*#__PURE__*/React.createElement(CSSMotion, {
motionName: motionName,
visible: portalRender && open,
motionAppear: true,
motionEnter: true,
motionLeave: true,
onVisibleChanged: onVisibleChanged
}, ({
className: motionClassName,
style: motionStyle
}) => {
const mergedStyle = {
...styles.root,
...motionStyle
};
if (zIndex) {
mergedStyle.zIndex = zIndex;
}
return /*#__PURE__*/React.createElement("div", {
ref: wrapperRef,
className: clsx(prefixCls, rootClassName, classNames.root, motionClassName, {
[`${prefixCls}-movable`]: movable,
[`${prefixCls}-moving`]: isMoving
}),
style: mergedStyle,
role: "dialog",
"aria-modal": "true",
"aria-label": alt,
tabIndex: -1
}, /*#__PURE__*/React.createElement("div", {
className: clsx(`${prefixCls}-mask`, classNames.mask),
style: styles.mask,
onClick: maskClosable ? onClose : undefined
}), /*#__PURE__*/React.createElement("div", {
className: clsx(`${prefixCls}-body`, classNames.body),
style: bodyStyle
}, imageRender ? imageRender(imgNode, {
transform,
image,
...(groupContext ? {
current
} : {})
}) : imgNode), closeIcon !== false && closeIcon !== null && /*#__PURE__*/React.createElement(CloseBtn, {
prefixCls: prefixCls,
icon: closeIcon === true ? icons.close : closeIcon || icons.close,
onClick: onClose,
className: classNames.close,
style: styles.close
}), showLeftOrRightSwitches && /*#__PURE__*/React.createElement(PrevNext, {
prefixCls: prefixCls,
current: current,
count: count,
icons: icons,
onActive: onActive
}), /*#__PURE__*/React.createElement(Footer, {
prefixCls: prefixCls,
showProgress: showOperationsProgress,
current: current,
count: count,
showSwitch: showLeftOrRightSwitches
// Style
,
classNames: classNames,
styles: styles
// Render
,
image: image,
transform: transform,
icons: icons,
countRender: countRender,
actionsRender: actionsRender
// Scale
,
scale: scale,
minScale: minScale,
maxScale: maxScale
// Actions
,
onActive: onActive,
onFlipY: onFlipY,
onFlipX: onFlipX,
onRotateLeft: onRotateLeft,
onRotateRight: onRotateRight,
onZoomOut: onZoomOut,
onZoomIn: onZoomIn,
onClose: onClose,
onReset: onReset
}));
}));
};
export default Preview;