371 lines
12 KiB
JavaScript
371 lines
12 KiB
JavaScript
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.default = void 0;
|
|
var _motion = _interopRequireDefault(require("@rc-component/motion"));
|
|
var _portal = _interopRequireDefault(require("@rc-component/portal"));
|
|
var _util = require("@rc-component/util");
|
|
var _focus = require("@rc-component/util/lib/Dom/focus");
|
|
var _useLayoutEffect = _interopRequireDefault(require("@rc-component/util/lib/hooks/useLayoutEffect"));
|
|
var _KeyCode = _interopRequireDefault(require("@rc-component/util/lib/KeyCode"));
|
|
var _clsx = require("clsx");
|
|
var _react = _interopRequireWildcard(require("react"));
|
|
var _context = require("../context");
|
|
var _useImageTransform = _interopRequireDefault(require("../hooks/useImageTransform"));
|
|
var _useMouseEvent = _interopRequireDefault(require("../hooks/useMouseEvent"));
|
|
var _useStatus = _interopRequireDefault(require("../hooks/useStatus"));
|
|
var _useTouchEvent = _interopRequireDefault(require("../hooks/useTouchEvent"));
|
|
var _previewConfig = require("../previewConfig");
|
|
var _CloseBtn = _interopRequireDefault(require("./CloseBtn"));
|
|
var _Footer = _interopRequireDefault(require("./Footer"));
|
|
var _PrevNext = _interopRequireDefault(require("./PrevNext"));
|
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
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); }
|
|
// Note: if you want to add `action`,
|
|
// pls contact @zombieJ or @thinkasany first.
|
|
|
|
const PreviewImage = ({
|
|
fallback,
|
|
src,
|
|
imgRef,
|
|
...props
|
|
}) => {
|
|
const [getImgRef, srcAndOnload] = (0, _useStatus.default)({
|
|
src,
|
|
fallback
|
|
});
|
|
return /*#__PURE__*/_react.default.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 = (0, _react.useRef)();
|
|
const wrapperRef = (0, _react.useRef)(null);
|
|
const triggerRef = (0, _react.useRef)(null);
|
|
const groupContext = (0, _react.useContext)(_context.PreviewGroupContext);
|
|
const showLeftOrRightSwitches = groupContext && count > 1;
|
|
const showOperationsProgress = groupContext && count >= 1;
|
|
|
|
// ======================== Transform =========================
|
|
const [enableTransition, setEnableTransition] = (0, _react.useState)(true);
|
|
const {
|
|
transform,
|
|
resetTransform,
|
|
updateTransform,
|
|
dispatchZoomChange
|
|
} = (0, _useImageTransform.default)(imgRef, minScale, maxScale, onTransform);
|
|
const {
|
|
isMoving,
|
|
onMouseDown,
|
|
onWheel
|
|
} = (0, _useMouseEvent.default)(imgRef, movable, open, scaleStep, transform, updateTransform, dispatchZoomChange);
|
|
const {
|
|
isTouching,
|
|
onTouchStart,
|
|
onTouchMove,
|
|
onTouchEnd
|
|
} = (0, _useTouchEvent.default)(imgRef, movable, open, minScale, transform, updateTransform, dispatchZoomChange);
|
|
const {
|
|
rotate,
|
|
scale
|
|
} = transform;
|
|
(0, _react.useEffect)(() => {
|
|
if (!enableTransition) {
|
|
setEnableTransition(true);
|
|
}
|
|
}, [enableTransition]);
|
|
(0, _react.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(_previewConfig.BASE_SCALE_RATIO + scaleStep, 'doubleClick', event.clientX, event.clientY);
|
|
}
|
|
}
|
|
};
|
|
const imgNode = /*#__PURE__*/_react.default.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(_previewConfig.BASE_SCALE_RATIO + scaleStep, 'zoomIn');
|
|
};
|
|
const onZoomOut = () => {
|
|
dispatchZoomChange(_previewConfig.BASE_SCALE_RATIO / (_previewConfig.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 = (0, _util.useEvent)(event => {
|
|
if (open) {
|
|
const {
|
|
keyCode
|
|
} = event;
|
|
if (showLeftOrRightSwitches) {
|
|
if (keyCode === _KeyCode.default.LEFT) {
|
|
onActive(-1);
|
|
} else if (keyCode === _KeyCode.default.RIGHT) {
|
|
onActive(1);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
(0, _react.useEffect)(() => {
|
|
if (open) {
|
|
window.addEventListener('keydown', onKeyDown);
|
|
return () => {
|
|
window.removeEventListener('keydown', onKeyDown);
|
|
};
|
|
}
|
|
}, [open]);
|
|
|
|
// ======================= Lock Scroll ========================
|
|
const [lockScroll, setLockScroll] = (0, _react.useState)(false);
|
|
_react.default.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] = (0, _react.useState)(false);
|
|
(0, _useLayoutEffect.default)(() => {
|
|
if (open) {
|
|
setPortalRender(true);
|
|
}
|
|
}, [open]);
|
|
const onEsc = ({
|
|
top
|
|
}) => {
|
|
if (top) {
|
|
onClose?.();
|
|
}
|
|
};
|
|
|
|
// =========================== Focus ============================
|
|
(0, _useLayoutEffect.default)(() => {
|
|
if (open) {
|
|
triggerRef.current = document.activeElement;
|
|
}
|
|
}, [open]);
|
|
(0, _focus.useLockFocus)(focusTrap && open && portalRender, () => wrapperRef.current);
|
|
|
|
// ========================== Render ==========================
|
|
const bodyStyle = {
|
|
...styles.body
|
|
};
|
|
if (mousePosition) {
|
|
bodyStyle.transformOrigin = `${mousePosition.x}px ${mousePosition.y}px`;
|
|
}
|
|
return /*#__PURE__*/_react.default.createElement(_portal.default, {
|
|
open: portalRender && open,
|
|
autoDestroy: false,
|
|
getContainer: getContainer,
|
|
autoLock: lockScroll,
|
|
onEsc: onEsc
|
|
}, /*#__PURE__*/_react.default.createElement(_motion.default, {
|
|
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.default.createElement("div", {
|
|
ref: wrapperRef,
|
|
className: (0, _clsx.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.default.createElement("div", {
|
|
className: (0, _clsx.clsx)(`${prefixCls}-mask`, classNames.mask),
|
|
style: styles.mask,
|
|
onClick: maskClosable ? onClose : undefined
|
|
}), /*#__PURE__*/_react.default.createElement("div", {
|
|
className: (0, _clsx.clsx)(`${prefixCls}-body`, classNames.body),
|
|
style: bodyStyle
|
|
}, imageRender ? imageRender(imgNode, {
|
|
transform,
|
|
image,
|
|
...(groupContext ? {
|
|
current
|
|
} : {})
|
|
}) : imgNode), closeIcon !== false && closeIcon !== null && /*#__PURE__*/_react.default.createElement(_CloseBtn.default, {
|
|
prefixCls: prefixCls,
|
|
icon: closeIcon === true ? icons.close : closeIcon || icons.close,
|
|
onClick: onClose,
|
|
className: classNames.close,
|
|
style: styles.close
|
|
}), showLeftOrRightSwitches && /*#__PURE__*/_react.default.createElement(_PrevNext.default, {
|
|
prefixCls: prefixCls,
|
|
current: current,
|
|
count: count,
|
|
icons: icons,
|
|
onActive: onActive
|
|
}), /*#__PURE__*/_react.default.createElement(_Footer.default, {
|
|
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
|
|
}));
|
|
}));
|
|
};
|
|
var _default = exports.default = Preview; |