) => void;
}
@@ -79,71 +77,77 @@ interface CompoundedComponent extends React.FC
{
const ImageInternal: CompoundedComponent = props => {
const {
- src: imgSrc,
- alt,
- onPreviewClose: onInitialPreviewClose,
+ // Misc
prefixCls = 'rc-image',
previewPrefixCls = `${prefixCls}-preview`,
- placeholder,
- fallback,
+
+ // Style
+ rootClassName,
+ className,
+ style,
+
+ classNames = {},
+ styles = {},
+
width,
height,
- style,
+
+ // Image
+ src: imgSrc,
+ alt,
+ placeholder,
+ fallback,
+
+ // Preview
preview = true,
- className,
+
+ // Events
onClick,
onError,
- wrapperClassName,
- wrapperStyle,
- rootClassName,
...otherProps
} = props;
- const isCustomPlaceholder = placeholder && placeholder !== true;
+ const groupContext = useContext(PreviewGroupContext);
+
+ // ========================== Preview ===========================
+ const canPreview = !!preview;
+
const {
src: previewSrc,
- visible: previewVisible = undefined,
- onVisibleChange: onPreviewVisibleChange = onInitialPreviewClose,
- getContainer: getPreviewContainer = undefined,
- mask: previewMask,
- maskClassName,
- classNames: imageClassNames,
- styles,
- movable,
- icons,
- scaleStep,
- minScale,
- maxScale,
- imageRender,
- toolbarRender,
- ...dialogProps
- }: ImagePreviewType = typeof preview === 'object' ? preview : {};
- const src = previewSrc ?? imgSrc;
- const [isShowPreview, setShowPreview] = useMergedState(!!previewVisible, {
- value: previewVisible,
- onChange: onPreviewVisibleChange,
- });
- const [getImgRef, srcAndOnload, status] = useStatus({
- src: imgSrc,
- isCustomPlaceholder,
- fallback,
+ open: previewOpen = undefined,
+ onOpenChange: onPreviewOpenChange,
+ cover,
+ classNames: previewClassNames = {},
+ styles: previewStyles = {},
+ ...restProps
+ }: PreviewConfig = preview && typeof preview === 'object' ? preview : {};
+
+ // ============================ Open ============================
+ const [isShowPreview, setShowPreview] = useMergedState(!!previewOpen, {
+ value: previewOpen,
});
- const [mousePosition, setMousePosition] = useState(null);
- const groupContext = useContext(PreviewGroupContext);
+ const [mousePosition, setMousePosition] = useState(null);
- const canPreview = !!preview;
+ const triggerPreviewOpen = (nextOpen: boolean) => {
+ setShowPreview(nextOpen);
+ onPreviewOpenChange?.(nextOpen);
+ };
const onPreviewClose = () => {
- setShowPreview(false);
- setMousePosition(null);
+ triggerPreviewOpen(false);
};
- const wrapperClass = cn(prefixCls, wrapperClassName, rootClassName, {
- [`${prefixCls}-error`]: status === 'error',
+ // ========================= ImageProps =========================
+ const isCustomPlaceholder = placeholder && placeholder !== true;
+
+ const src = previewSrc ?? imgSrc;
+ const [getImgRef, srcAndOnload, status] = useStatus({
+ src: imgSrc,
+ isCustomPlaceholder,
+ fallback,
});
- // ========================= ImageProps =========================
const imgCommonProps = useMemo(
() => {
const obj: ImageElementProps = {};
@@ -171,7 +175,10 @@ const ImageInternal: CompoundedComponent = props => {
// ========================== Preview ===========================
const onPreview: React.MouseEventHandler = e => {
- const { left, top } = getOffset(e.target as HTMLDivElement);
+ const rect = (e.target as HTMLDivElement).getBoundingClientRect();
+ const left = rect.x + rect.width / 2;
+ const top = rect.y + rect.height / 2;
+
if (groupContext) {
groupContext.onPreview(imageId, src, left, top);
} else {
@@ -179,7 +186,7 @@ const ImageInternal: CompoundedComponent = props => {
x: left,
y: top,
});
- setShowPreview(true);
+ triggerPreviewOpen(true);
}
onClick?.(e);
@@ -190,25 +197,29 @@ const ImageInternal: CompoundedComponent = props => {
<>
![]()
= props => {
)}
{/* Preview Click Mask */}
- {previewMask && canPreview && (
+ {cover !== false && canPreview && (
- {previewMask}
+ {cover}
)}
{!groupContext && canPreview && (
= props => {
alt={alt}
imageInfo={{ width, height }}
fallback={fallback}
- getContainer={getPreviewContainer}
- icons={icons}
- movable={movable}
- scaleStep={scaleStep}
- minScale={minScale}
- maxScale={maxScale}
- rootClassName={rootClassName}
- imageRender={imageRender}
imgCommonProps={imgCommonProps}
- toolbarRender={toolbarRender}
- classNames={imageClassNames}
- styles={styles}
- {...dialogProps}
+ classNames={previewClassNames}
+ styles={previewStyles}
+ rootClassName={rootClassName}
+ {...restProps}
/>
)}
>
diff --git a/src/Operations.tsx b/src/Operations.tsx
deleted file mode 100644
index ce6aa2c5..00000000
--- a/src/Operations.tsx
+++ /dev/null
@@ -1,297 +0,0 @@
-import Portal from '@rc-component/portal';
-import classnames from 'classnames';
-import CSSMotion from '@rc-component/motion';
-import KeyCode from '@rc-component/util/lib/KeyCode';
-import * as React from 'react';
-import { useContext } from 'react';
-import type { ImgInfo, SemanticName } from './Image';
-import type { PreviewProps, ToolbarRenderInfoType } from './Preview';
-import { PreviewGroupContext } from './context';
-import type { TransformType } from './hooks/useImageTransform';
-import classNames from 'classnames';
-
-type OperationType =
- | 'prev'
- | 'next'
- | 'flipY'
- | 'flipX'
- | 'rotateLeft'
- | 'rotateRight'
- | 'zoomOut'
- | 'zoomIn';
-
-interface RenderOperationParams {
- icon: React.ReactNode;
- type: OperationType;
- disabled?: boolean;
- onClick: (e: React.MouseEvent) => void;
-}
-
-interface OperationsProps
- extends Pick<
- PreviewProps,
- | 'visible'
- | 'maskTransitionName'
- | 'getContainer'
- | 'prefixCls'
- | 'rootClassName'
- | 'icons'
- | 'countRender'
- | 'closeIcon'
- | 'onClose'
- > {
- showSwitch: boolean;
- showProgress: boolean;
- current: number;
- transform: TransformType;
- count: number;
- scale: number;
- minScale: number;
- maxScale: number;
- onActive: (offset: number) => void;
- onZoomIn: () => void;
- onZoomOut: () => void;
- onRotateRight: () => void;
- onRotateLeft: () => void;
- onFlipX: () => void;
- onFlipY: () => void;
- onReset: () => void;
- toolbarRender: (
- originalNode: React.ReactElement,
- info: ToolbarRenderInfoType | Omit,
- ) => React.ReactNode;
- zIndex?: number;
- image?: ImgInfo;
- classNames?: Partial>;
- styles?: Partial>;
-}
-
-const Operations: React.FC = props => {
- const {
- visible,
- maskTransitionName,
- getContainer,
- prefixCls,
- rootClassName,
- icons,
- countRender,
- showSwitch,
- showProgress,
- current,
- transform,
- count,
- scale,
- minScale,
- maxScale,
- closeIcon,
- onActive,
- onClose,
- onZoomIn,
- onZoomOut,
- onRotateRight,
- onRotateLeft,
- onFlipX,
- onFlipY,
- onReset,
- toolbarRender,
- zIndex,
- image,
- classNames: imageClassNames,
- styles,
- } = props;
- const groupContext = useContext(PreviewGroupContext);
- const { rotateLeft, rotateRight, zoomIn, zoomOut, close, left, right, flipX, flipY } = icons;
- const toolClassName = `${prefixCls}-operations-operation`;
-
- React.useEffect(() => {
- const onKeyDown = (e: KeyboardEvent) => {
- if (e.keyCode === KeyCode.ESC) {
- onClose();
- }
- };
-
- if (visible) {
- window.addEventListener('keydown', onKeyDown);
- }
-
- return () => {
- window.removeEventListener('keydown', onKeyDown);
- };
- }, [visible]);
-
- const handleActive = (e: React.MouseEvent, offset: number) => {
- e.preventDefault();
- e.stopPropagation();
-
- onActive(offset);
- };
-
- const renderOperation = React.useCallback(
- ({ type, disabled, onClick, icon }: RenderOperationParams) => {
- return (
-
- {icon}
-
- );
- },
- [toolClassName, prefixCls],
- );
-
- const switchPrevNode = showSwitch
- ? renderOperation({
- icon: left,
- onClick: e => handleActive(e, -1),
- type: 'prev',
- disabled: current === 0,
- })
- : undefined;
-
- const switchNextNode = showSwitch
- ? renderOperation({
- icon: right,
- onClick: e => handleActive(e, 1),
- type: 'next',
- disabled: current === count - 1,
- })
- : undefined;
-
- const flipYNode = renderOperation({
- icon: flipY,
- onClick: onFlipY,
- type: 'flipY',
- });
-
- const flipXNode = renderOperation({
- icon: flipX,
- onClick: onFlipX,
- type: 'flipX',
- });
-
- const rotateLeftNode = renderOperation({
- icon: rotateLeft,
- onClick: onRotateLeft,
- type: 'rotateLeft',
- });
-
- const rotateRightNode = renderOperation({
- icon: rotateRight,
- onClick: onRotateRight,
- type: 'rotateRight',
- });
-
- const zoomOutNode = renderOperation({
- icon: zoomOut,
- onClick: onZoomOut,
- type: 'zoomOut',
- disabled: scale <= minScale,
- });
-
- const zoomInNode = renderOperation({
- icon: zoomIn,
- onClick: onZoomIn,
- type: 'zoomIn',
- disabled: scale === maxScale,
- });
-
- const toolbarNode = (
-
- {flipYNode}
- {flipXNode}
- {rotateLeftNode}
- {rotateRightNode}
- {zoomOutNode}
- {zoomInNode}
-
- );
-
- return (
-
- {({ className, style }) => (
-
-
- {closeIcon === null ? null : (
-
- )}
-
- {showSwitch && (
- <>
-
handleActive(e, -1)}
- >
- {left}
-
-
handleActive(e, 1)}
- >
- {right}
-
- >
- )}
-
-
- {showProgress && (
-
- {countRender ? countRender(current + 1, count) : `${current + 1} / ${count}`}
-
- )}
-
- {toolbarRender
- ? toolbarRender(toolbarNode, {
- icons: {
- prevIcon: switchPrevNode,
- nextIcon: switchNextNode,
- flipYIcon: flipYNode,
- flipXIcon: flipXNode,
- rotateLeftIcon: rotateLeftNode,
- rotateRightIcon: rotateRightNode,
- zoomOutIcon: zoomOutNode,
- zoomInIcon: zoomInNode,
- },
- actions: {
- onActive,
- onFlipY,
- onFlipX,
- onRotateLeft,
- onRotateRight,
- onZoomOut,
- onZoomIn,
- onReset,
- onClose,
- },
- transform,
- ...(groupContext ? { current, total: count } : {}),
- image,
- })
- : toolbarNode}
-
-
-
- )}
-
- );
-};
-
-export default Operations;
diff --git a/src/Preview.tsx b/src/Preview.tsx
deleted file mode 100644
index 284c13c6..00000000
--- a/src/Preview.tsx
+++ /dev/null
@@ -1,362 +0,0 @@
-import type { DialogProps as IDialogPropTypes } from '@rc-component/dialog';
-import Dialog from '@rc-component/dialog';
-import KeyCode from '@rc-component/util/lib/KeyCode';
-import classnames from 'classnames';
-import React, { useContext, useEffect, useRef, useState } from 'react';
-import type { ImgInfo, SemanticName } from './Image';
-import Operations from './Operations';
-import { PreviewGroupContext } from './context';
-import type { TransformAction, TransformType } from './hooks/useImageTransform';
-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';
-
-export type ToolbarRenderInfoType = {
- icons: {
- prevIcon?: React.ReactNode;
- nextIcon?: React.ReactNode;
- flipYIcon: React.ReactNode;
- flipXIcon: React.ReactNode;
- rotateLeftIcon: React.ReactNode;
- rotateRightIcon: React.ReactNode;
- zoomOutIcon: React.ReactNode;
- zoomInIcon: React.ReactNode;
- };
- actions: {
- onActive?: (offset: number) => void;
- onFlipY: () => void;
- onFlipX: () => void;
- onRotateLeft: () => void;
- onRotateRight: () => void;
- onZoomOut: () => void;
- onZoomIn: () => void;
- onClose: () => void;
- onReset: () => void;
- };
- transform: TransformType;
- current: number;
- total: number;
- image: ImgInfo;
-};
-
-export interface PreviewProps extends Omit {
- imgCommonProps?: React.ImgHTMLAttributes;
- src?: string;
- alt?: string;
- imageInfo?: {
- width: number | string;
- height: number | string;
- };
- fallback?: string;
- movable?: boolean;
- rootClassName?: string;
- icons?: {
- rotateLeft?: React.ReactNode;
- rotateRight?: React.ReactNode;
- zoomIn?: React.ReactNode;
- zoomOut?: React.ReactNode;
- close?: React.ReactNode;
- left?: React.ReactNode;
- right?: React.ReactNode;
- flipX?: React.ReactNode;
- flipY?: React.ReactNode;
- };
- current?: number;
- count?: number;
- closeIcon?: React.ReactNode;
- countRender?: (current: number, total: number) => React.ReactNode;
- scaleStep?: number;
- minScale?: number;
- maxScale?: number;
- imageRender?: (
- originalNode: React.ReactElement,
- info: { transform: TransformType; current?: number; image?: ImgInfo },
- ) => React.ReactNode;
- onClose?: () => void;
- onTransform?: (info: { transform: TransformType; action: TransformAction }) => void;
- toolbarRender?: (
- originalNode: React.ReactElement,
- info: ToolbarRenderInfoType,
- ) => React.ReactNode;
- onChange?: (current, prev) => void;
- classNames?: Partial>;
- styles?: Partial> & {
- /** Temporarily used in PurePanel, not used externally by antd */
- wrapper?: React.CSSProperties;
- };
-}
-
-interface PreviewImageProps extends React.ImgHTMLAttributes {
- fallback?: string;
- imgRef: React.MutableRefObject;
-}
-
-const PreviewImage: React.FC = ({ fallback, src, imgRef, ...props }) => {
- const [getImgRef, srcAndOnload] = useStatus({
- src,
- fallback,
- });
-
- return (
-
{
- imgRef.current = ref;
- getImgRef(ref);
- }}
- {...props}
- {...srcAndOnload}
- />
- );
-};
-
-const Preview: React.FC = props => {
- const {
- prefixCls,
- src,
- alt,
- imageInfo,
- fallback,
- movable = true,
- onClose,
- visible,
- icons = {},
- rootClassName,
- closeIcon,
- getContainer,
- current = 0,
- count = 1,
- countRender,
- scaleStep = 0.5,
- minScale = 1,
- maxScale = 50,
- transitionName = 'zoom',
- maskTransitionName = 'fade',
- imageRender,
- imgCommonProps,
- toolbarRender,
- onTransform,
- onChange,
- classNames: imageClassNames,
- styles,
- ...restProps
- } = props;
-
- const imgRef = useRef();
- const groupContext = useContext(PreviewGroupContext);
- const showLeftOrRightSwitches = groupContext && count > 1;
- const showOperationsProgress = groupContext && count >= 1;
- const [enableTransition, setEnableTransition] = useState(true);
- const { transform, resetTransform, updateTransform, dispatchZoomChange } = useImageTransform(
- imgRef,
- minScale,
- maxScale,
- onTransform,
- );
- const { isMoving, onMouseDown, onWheel } = useMouseEvent(
- imgRef,
- movable,
- visible,
- scaleStep,
- transform,
- updateTransform,
- dispatchZoomChange,
- );
- const { isTouching, onTouchStart, onTouchMove, onTouchEnd } = useTouchEvent(
- imgRef,
- movable,
- visible,
- minScale,
- transform,
- updateTransform,
- dispatchZoomChange,
- );
- const { rotate, scale } = transform;
-
- const wrapClassName = classnames({
- [`${prefixCls}-moving`]: isMoving,
- });
-
- useEffect(() => {
- if (!enableTransition) {
- setEnableTransition(true);
- }
- }, [enableTransition]);
-
- const onAfterClose = () => {
- resetTransform('close');
- };
-
- 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: number) => {
- const position = current + offset;
-
- if (!Number.isInteger(position) || position < 0 || position > count - 1) {
- return;
- }
-
- setEnableTransition(false);
- resetTransform(offset < 0 ? 'prev' : 'next');
- onChange?.(position, current);
- };
-
- const onKeyDown = (event: KeyboardEvent) => {
- if (!visible || !showLeftOrRightSwitches) return;
-
- if (event.keyCode === KeyCode.LEFT) {
- onActive(-1);
- } else if (event.keyCode === KeyCode.RIGHT) {
- onActive(1);
- }
- };
-
- const onDoubleClick = (event: React.MouseEvent) => {
- if (visible) {
- if (scale !== 1) {
- updateTransform({ x: 0, y: 0, scale: 1 }, 'doubleClick');
- } else {
- dispatchZoomChange(
- BASE_SCALE_RATIO + scaleStep,
- 'doubleClick',
- event.clientX,
- event.clientY,
- );
- }
- }
- };
-
- useEffect(() => {
- window.addEventListener('keydown', onKeyDown, false);
-
- return () => {
- window.removeEventListener('keydown', onKeyDown);
- };
- }, [visible, showLeftOrRightSwitches, current]);
-
- const imgNode = (
-
- );
-
- const image = {
- url: src,
- alt,
- ...imageInfo,
- };
-
- return (
- <>
-
-
- >
- );
-};
-
-export default Preview;
diff --git a/src/Preview/CloseBtn.tsx b/src/Preview/CloseBtn.tsx
new file mode 100644
index 00000000..aacd6cc6
--- /dev/null
+++ b/src/Preview/CloseBtn.tsx
@@ -0,0 +1,17 @@
+import * as React from 'react';
+
+export interface CloseBtnProps {
+ prefixCls: string;
+ icon?: React.ReactNode;
+ onClick: React.MouseEventHandler;
+}
+
+export default function CloseBtn(props: CloseBtnProps) {
+ const { prefixCls, icon, onClick } = props;
+
+ return (
+
+ );
+}
diff --git a/src/Preview/Footer.tsx b/src/Preview/Footer.tsx
new file mode 100644
index 00000000..f93e66d5
--- /dev/null
+++ b/src/Preview/Footer.tsx
@@ -0,0 +1,212 @@
+import classnames from 'classnames';
+import * as React from 'react';
+import type { Actions, PreviewProps } from '.';
+import type { ImgInfo } from '../Image';
+import type { TransformType } from '../hooks/useImageTransform';
+
+export type FooterSemanticName = 'footer' | 'actions';
+
+type OperationType =
+ | 'prev'
+ | 'next'
+ | 'flipY'
+ | 'flipX'
+ | 'rotateLeft'
+ | 'rotateRight'
+ | 'zoomOut'
+ | 'zoomIn';
+
+interface RenderOperationParams {
+ icon: React.ReactNode;
+ type: OperationType;
+ disabled?: boolean;
+ onClick: (e: React.MouseEvent) => void;
+}
+
+export interface FooterProps extends Actions {
+ prefixCls: string;
+ showProgress: boolean;
+ countRender?: PreviewProps['countRender'];
+ actionsRender?: PreviewProps['actionsRender'];
+ current: number;
+ count: number;
+ showSwitch: boolean;
+ icons: PreviewProps['icons'];
+ scale: number;
+ minScale: number;
+ maxScale: number;
+ image: ImgInfo;
+ transform: TransformType;
+
+ // Style
+ classNames: Partial>;
+ styles: Partial>;
+}
+
+export default function Footer(props: FooterProps) {
+ // 修改解构,添加缺失的属性,并提供默认值
+ const {
+ prefixCls,
+ showProgress,
+ current,
+ count,
+ showSwitch,
+
+ // Style
+ classNames,
+ styles,
+
+ // render
+ icons,
+ image,
+ transform,
+ countRender,
+ actionsRender,
+
+ // Scale
+ scale,
+ minScale,
+ maxScale,
+
+ // Actions
+ onActive,
+ onFlipY,
+ onFlipX,
+ onRotateLeft,
+ onRotateRight,
+ onZoomOut,
+ onZoomIn,
+ onClose,
+ onReset,
+ } = props;
+
+ const { left, right, prev, next, flipY, flipX, rotateLeft, rotateRight, zoomOut, zoomIn } = icons;
+
+ // ========================== Render ==========================
+ // >>>>> Progress
+ const progressNode = showProgress && (
+
+ {countRender ? countRender(current + 1, count) : `${current + 1} / ${count}`}
+
+ );
+
+ // >>>>> Actions
+ const actionCls = `${prefixCls}-actions-action`;
+
+ const renderOperation = ({ type, disabled, onClick, icon }: RenderOperationParams) => {
+ return (
+
+ {icon}
+
+ );
+ };
+
+ const switchPrevNode = showSwitch
+ ? renderOperation({
+ icon: prev ?? left,
+ onClick: () => onActive(-1),
+ type: 'prev',
+ disabled: current === 0,
+ })
+ : undefined;
+
+ const switchNextNode = showSwitch
+ ? renderOperation({
+ icon: next ?? right,
+ onClick: () => onActive(1),
+ type: 'next',
+ disabled: current === count - 1,
+ })
+ : undefined;
+
+ const flipYNode = renderOperation({
+ icon: flipY,
+ onClick: onFlipY,
+ type: 'flipY',
+ });
+
+ const flipXNode = renderOperation({
+ icon: flipX,
+ onClick: onFlipX,
+ type: 'flipX',
+ });
+
+ const rotateLeftNode = renderOperation({
+ icon: rotateLeft,
+ onClick: onRotateLeft,
+ type: 'rotateLeft',
+ });
+
+ const rotateRightNode = renderOperation({
+ icon: rotateRight,
+ onClick: onRotateRight,
+ type: 'rotateRight',
+ });
+
+ const zoomOutNode = renderOperation({
+ icon: zoomOut,
+ onClick: onZoomOut,
+ type: 'zoomOut',
+ disabled: scale <= minScale,
+ });
+
+ const zoomInNode = renderOperation({
+ icon: zoomIn,
+ onClick: onZoomIn,
+ type: 'zoomIn',
+ disabled: scale === maxScale,
+ });
+
+ const actionsNode = (
+
+ {flipYNode}
+ {flipXNode}
+ {rotateLeftNode}
+ {rotateRightNode}
+ {zoomOutNode}
+ {zoomInNode}
+
+ );
+
+ // >>>>> Render
+ return (
+
+ {progressNode}
+ {actionsRender
+ ? actionsRender(actionsNode, {
+ icons: {
+ prevIcon: switchPrevNode,
+ nextIcon: switchNextNode,
+ flipYIcon: flipYNode,
+ flipXIcon: flipXNode,
+ rotateLeftIcon: rotateLeftNode,
+ rotateRightIcon: rotateRightNode,
+ zoomOutIcon: zoomOutNode,
+ zoomInIcon: zoomInNode,
+ },
+ actions: {
+ onActive,
+ onFlipY,
+ onFlipX,
+ onRotateLeft,
+ onRotateRight,
+ onZoomOut,
+ onZoomIn,
+ onReset,
+ onClose,
+ },
+ transform,
+ current,
+ total: count,
+ image,
+ })
+ : actionsNode}
+
+ );
+}
diff --git a/src/Preview/PrevNext.tsx b/src/Preview/PrevNext.tsx
new file mode 100644
index 00000000..adaad514
--- /dev/null
+++ b/src/Preview/PrevNext.tsx
@@ -0,0 +1,44 @@
+import classNames from 'classnames';
+import * as React from 'react';
+import type { OperationIcons } from '.';
+
+export interface PrevNextProps {
+ prefixCls: string;
+ onActive: (offset: number) => void;
+ current: number;
+ count: number;
+ icons: OperationIcons;
+}
+
+export default function PrevNext(props: PrevNextProps) {
+ const {
+ prefixCls,
+ onActive,
+ current,
+ count,
+ icons: { left, right, prev, next },
+ } = props;
+
+ const switchCls = `${prefixCls}-switch`;
+
+ return (
+ <>
+ onActive(-1)}
+ >
+ {prev ?? left}
+
+ onActive(1)}
+ >
+ {next ?? right}
+
+ >
+ );
+}
diff --git a/src/Preview/index.tsx b/src/Preview/index.tsx
new file mode 100644
index 00000000..dd86ed5a
--- /dev/null
+++ b/src/Preview/index.tsx
@@ -0,0 +1,482 @@
+import CSSMotion from '@rc-component/motion';
+import Portal, { type PortalProps } from '@rc-component/portal';
+import { useEvent } from '@rc-component/util';
+import KeyCode from '@rc-component/util/lib/KeyCode';
+import classnames from 'classnames';
+import React, { useContext, useEffect, useRef, useState } from 'react';
+import type { ImgInfo } from '../Image';
+import { PreviewGroupContext } from '../context';
+import type { TransformAction, TransformType } from '../hooks/useImageTransform';
+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, { type FooterSemanticName } from './Footer';
+import PrevNext from './PrevNext';
+
+// Note: if you want to add `action`,
+// pls contact @zombieJ or @thinkasany first.
+export type InternalPreviewSemanticName = 'root' | 'mask' | 'body' | FooterSemanticName;
+
+export interface OperationIcons {
+ rotateLeft?: React.ReactNode;
+ rotateRight?: React.ReactNode;
+ zoomIn?: React.ReactNode;
+ zoomOut?: React.ReactNode;
+ close?: React.ReactNode;
+ prev?: React.ReactNode;
+ next?: React.ReactNode;
+ /** @deprecated Please use `prev` instead */
+ left?: React.ReactNode;
+ /** @deprecated Please use `next` instead */
+ right?: React.ReactNode;
+ flipX?: React.ReactNode;
+ flipY?: React.ReactNode;
+}
+
+export interface Actions {
+ onActive: (offset: number) => void;
+ onFlipY: () => void;
+ onFlipX: () => void;
+ onRotateLeft: () => void;
+ onRotateRight: () => void;
+ onZoomOut: () => void;
+ onZoomIn: () => void;
+ onClose: () => void;
+ onReset: () => void;
+}
+
+export type ToolbarRenderInfoType = {
+ icons: {
+ prevIcon?: React.ReactNode;
+ nextIcon?: React.ReactNode;
+ flipYIcon: React.ReactNode;
+ flipXIcon: React.ReactNode;
+ rotateLeftIcon: React.ReactNode;
+ rotateRightIcon: React.ReactNode;
+ zoomOutIcon: React.ReactNode;
+ zoomInIcon: React.ReactNode;
+ };
+ actions: Actions;
+ transform: TransformType;
+ current: number;
+ total: number;
+ image: ImgInfo;
+};
+
+export interface InternalPreviewConfig {
+ // Semantic
+ classNames?: Partial>;
+ styles?: Partial>;
+
+ // Image
+ src?: string;
+ alt?: string;
+
+ // Scale
+ scaleStep?: number;
+ minScale?: number;
+ maxScale?: number;
+
+ // Display
+ motionName?: string;
+ open?: boolean;
+ getContainer?: PortalProps['getContainer'];
+ zIndex?: number;
+
+ // Operation
+ movable?: boolean;
+ icons?: OperationIcons;
+ closeIcon?: React.ReactNode;
+
+ onTransform?: (info: { transform: TransformType; action: TransformAction }) => void;
+
+ // Render
+ countRender?: (current: number, total: number) => React.ReactNode;
+ imageRender?: (
+ originalNode: React.ReactElement,
+ info: { transform: TransformType; current?: number; image: ImgInfo },
+ ) => React.ReactNode;
+ actionsRender?: (
+ originalNode: React.ReactElement,
+ info: ToolbarRenderInfoType,
+ ) => React.ReactNode;
+}
+
+export interface PreviewProps extends InternalPreviewConfig {
+ // Misc
+ prefixCls: string;
+ rootClassName?: string;
+
+ // Origin image Info
+ imageInfo?: {
+ width: number | string;
+ height: number | string;
+ };
+ fallback?: string;
+
+ // Preview image
+ imgCommonProps?: React.ImgHTMLAttributes;
+ width?: string | number;
+ height?: string | number;
+
+ // Pagination
+ current?: number;
+ count?: number;
+ onChange?: (current: number, prev: number) => void;
+
+ // Events
+ onClose?: () => void;
+
+ // Display
+ mousePosition: null | { x: number; y: number };
+}
+
+interface PreviewImageProps extends React.ImgHTMLAttributes {
+ fallback?: string;
+ imgRef: React.MutableRefObject;
+}
+
+const PreviewImage: React.FC = ({ fallback, src, imgRef, ...props }) => {
+ const [getImgRef, srcAndOnload] = useStatus({
+ src,
+ fallback,
+ });
+
+ return (
+
{
+ imgRef.current = ref;
+ getImgRef(ref);
+ }}
+ {...props}
+ {...srcAndOnload}
+ />
+ );
+};
+
+const Preview: React.FC = props => {
+ const {
+ prefixCls,
+ rootClassName,
+ src,
+ alt,
+ imageInfo,
+ fallback,
+ movable = true,
+ onClose,
+ open,
+ 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,
+ } = props;
+
+ const imgRef = useRef();
+ 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: React.MouseEvent) => {
+ 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 = (
+
+ );
+
+ 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: number) => {
+ 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: KeyboardEvent) => {
+ if (open) {
+ const { keyCode } = event;
+
+ if (keyCode === KeyCode.ESC) {
+ onClose?.();
+ }
+
+ 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: boolean) => {
+ if (!nextVisible) {
+ setLockScroll(false);
+ }
+ };
+
+ // ========================== Render ==========================
+ const bodyStyle: React.CSSProperties = {
+ ...styles.body,
+ };
+ if (mousePosition) {
+ bodyStyle.transformOrigin = `${mousePosition.x}px ${mousePosition.y}px`;
+ }
+
+ return (
+
+
+ {({ className: motionClassName, style: motionStyle }) => {
+ const mergedStyle = {
+ ...styles.root,
+ ...motionStyle,
+ };
+
+ if (zIndex) {
+ mergedStyle.zIndex = zIndex;
+ }
+
+ return (
+
+ {/* Mask */}
+
+
+ {/* Body */}
+
+ {/* Preview Image */}
+ {imageRender
+ ? imageRender(imgNode, {
+ transform,
+ image,
+ ...(groupContext ? { current } : {}),
+ })
+ : imgNode}
+
+
+ {/* Close Button */}
+ {closeIcon !== false && closeIcon !== null && (
+
+ )}
+
+ {/* Switch prev or next */}
+ {showLeftOrRightSwitches && (
+
+ )}
+
+ {/* Footer */}
+
+
+ );
+ }}
+
+
+ );
+};
+
+export default Preview;
diff --git a/src/PreviewGroup.tsx b/src/PreviewGroup.tsx
index 5fc0bc90..546dbe81 100644
--- a/src/PreviewGroup.tsx
+++ b/src/PreviewGroup.tsx
@@ -1,34 +1,22 @@
import useMergedState from '@rc-component/util/lib/hooks/useMergedState';
import * as React from 'react';
import { useState } from 'react';
-import type { ImgInfo, ImagePreviewType } from './Image';
-import type { PreviewProps, ToolbarRenderInfoType } from './Preview';
+import type { ImgInfo } from './Image';
+import type { InternalPreviewConfig, PreviewProps } from './Preview';
import Preview from './Preview';
import { PreviewGroupContext } from './context';
import type { TransformType } from './hooks/useImageTransform';
import usePreviewItems from './hooks/usePreviewItems';
import type { ImageElementProps, OnGroupPreview } from './interface';
-export interface PreviewGroupPreview
- extends Omit<
- ImagePreviewType,
- 'mask' | 'maskClassName' | 'onVisibleChange' | 'toolbarRender' | 'imageRender'
- > {
- /**
- * If Preview the show img index
- * @default 0
- */
+export interface GroupPreviewConfig extends InternalPreviewConfig {
current?: number;
- countRender?: (current: number, total: number) => React.ReactNode;
- toolbarRender?: (
- originalNode: React.ReactElement,
- info: ToolbarRenderInfoType,
- ) => React.ReactNode;
+ // Similar to InternalPreviewConfig but has additional current
imageRender?: (
originalNode: React.ReactElement,
info: { transform: TransformType; current: number; image: ImgInfo },
) => React.ReactNode;
- onVisibleChange?: (value: boolean, prevValue: boolean, current: number) => void;
+ onOpenChange?: (value: boolean, info: { current: number }) => void;
onChange?: (current: number, prevCurrent: number) => void;
}
@@ -37,7 +25,7 @@ export interface GroupConsumerProps {
icons?: PreviewProps['icons'];
items?: (string | ImageElementProps)[];
fallback?: string;
- preview?: boolean | PreviewGroupPreview;
+ preview?: boolean | GroupPreviewConfig;
children?: React.ReactNode;
}
@@ -50,21 +38,12 @@ const Group: React.FC = ({
fallback,
}) => {
const {
- visible: previewVisible,
- onVisibleChange,
- getContainer,
+ open: previewOpen,
+ onOpenChange,
current: currentIndex,
- movable,
- minScale,
- maxScale,
- countRender,
- closeIcon,
onChange,
- onTransform,
- toolbarRender,
- imageRender,
- ...dialogProps
- } = typeof preview === 'object' ? preview : ({} as PreviewGroupPreview);
+ ...restProps
+ } = preview && typeof preview === 'object' ? preview : ({} as GroupPreviewConfig);
// ========================== Items ===========================
const [mergedItems, register, fromItems] = usePreviewItems(items);
@@ -80,10 +59,10 @@ const Group: React.FC = ({
// >>> Image
const { src, ...imgCommonProps } = mergedItems[current]?.data || {};
// >>> Visible
- const [isShowPreview, setShowPreview] = useMergedState(!!previewVisible, {
- value: previewVisible,
- onChange: (val, prevVal) => {
- onVisibleChange?.(val, prevVal, current);
+ const [isShowPreview, setShowPreview] = useMergedState(!!previewOpen, {
+ value: previewOpen,
+ onChange: val => {
+ onOpenChange?.(val, { current });
},
});
@@ -118,7 +97,7 @@ const Group: React.FC = ({
}, [isShowPreview]);
// ========================== Events ==========================
- const onInternalChange: PreviewGroupPreview['onChange'] = (next, prev) => {
+ const onInternalChange: GroupPreviewConfig['onChange'] = (next, prev) => {
setCurrent(next);
onChange?.(next, prev);
@@ -141,27 +120,18 @@ const Group: React.FC = ({
{children}
);
diff --git a/src/hooks/useMouseEvent.ts b/src/hooks/useMouseEvent.ts
index 7a2f6278..b9ce378c 100644
--- a/src/hooks/useMouseEvent.ts
+++ b/src/hooks/useMouseEvent.ts
@@ -12,7 +12,7 @@ import type {
export default function useMouseEvent(
imgRef: React.MutableRefObject,
movable: boolean,
- visible: boolean,
+ open: boolean,
scaleStep: number,
transform: TransformType,
updateTransform: UpdateTransformFunc,
@@ -43,7 +43,7 @@ export default function useMouseEvent(
};
const onMouseMove = (event: MouseEvent) => {
- if (visible && isMoving) {
+ if (open && isMoving) {
updateTransform(
{
x: event.pageX - startPositionInfo.current.diffX,
@@ -55,7 +55,7 @@ export default function useMouseEvent(
};
const onMouseUp = () => {
- if (visible && isMoving) {
+ if (open && isMoving) {
setMoving(false);
/** No need to restore the position when the picture is not moved, So as not to interfere with the click */
@@ -83,7 +83,7 @@ export default function useMouseEvent(
};
const onWheel = (event: React.WheelEvent) => {
- if (!visible || event.deltaY == 0) return;
+ if (!open || event.deltaY == 0) return;
// Scale ratio depends on the deltaY size
const scaleRatio = Math.abs(event.deltaY / 100);
// Limit the maximum scale ratio
@@ -122,7 +122,7 @@ export default function useMouseEvent(
// /* istanbul ignore next */
window.top?.removeEventListener('mousemove', onMouseMove);
};
- }, [visible, isMoving, x, y, rotate, movable]);
+ }, [open, isMoving, x, y, rotate, movable]);
return {
isMoving,
diff --git a/src/hooks/useTouchEvent.ts b/src/hooks/useTouchEvent.ts
index 8d17a45b..fd83cbce 100644
--- a/src/hooks/useTouchEvent.ts
+++ b/src/hooks/useTouchEvent.ts
@@ -47,7 +47,7 @@ function getCenter(oldPoint1: Point, oldPoint2: Point, newPoint1: Point, newPoin
export default function useTouchEvent(
imgRef: React.MutableRefObject,
movable: boolean,
- visible: boolean,
+ open: boolean,
minScale: number,
transform: TransformType,
updateTransform: UpdateTransformFunc,
@@ -131,7 +131,7 @@ export default function useTouchEvent(
};
const onTouchEnd = () => {
- if (!visible) return;
+ if (!open) return;
if (isTouching) {
setIsTouching(false);
@@ -167,7 +167,7 @@ export default function useTouchEvent(
e.preventDefault();
};
- if (visible && movable) {
+ if (open && movable) {
window.addEventListener('touchmove', preventDefault, {
passive: false,
});
@@ -175,7 +175,7 @@ export default function useTouchEvent(
return () => {
window.removeEventListener('touchmove', preventDefault);
};
- }, [visible, movable]);
+ }, [open, movable]);
return {
isTouching,
diff --git a/src/util.ts b/src/util.ts
index 8a407809..9f44fef2 100644
--- a/src/util.ts
+++ b/src/util.ts
@@ -8,24 +8,6 @@ export function isImageValid(src: string) {
}
// ============================= Legacy =============================
-// TODO: Remove this. It's copy directly from legacy `rc-util` package
-export function getOffset(node: HTMLElement) {
- const box = node.getBoundingClientRect();
- const docElem = document.documentElement;
-
- // < ie8 不支持 win.pageXOffset, 则使用 docElem.scrollLeft
- return {
- left:
- box.left +
- (window.pageXOffset || docElem.scrollLeft) -
- (docElem.clientLeft || document.body.clientLeft || 0),
- top:
- box.top +
- (window.pageYOffset || docElem.scrollTop) -
- (docElem.clientTop || document.body.clientTop || 0),
- };
-}
-
export function getClientSize() {
const width = document.documentElement.clientWidth;
const height = window.innerHeight || document.documentElement.clientHeight;
diff --git a/tests/__snapshots__/basic.test.tsx.snap b/tests/__snapshots__/basic.test.tsx.snap
index 2c4974d0..591e3248 100644
--- a/tests/__snapshots__/basic.test.tsx.snap
+++ b/tests/__snapshots__/basic.test.tsx.snap
@@ -10,5 +10,8 @@ exports[`Basic snapshot 1`] = `
src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
width="200"
/>
+
`;
diff --git a/tests/__snapshots__/controlled.test.tsx.snap b/tests/__snapshots__/controlled.test.tsx.snap
deleted file mode 100644
index 4fec6b2a..00000000
--- a/tests/__snapshots__/controlled.test.tsx.snap
+++ /dev/null
@@ -1,37 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Controlled With previewVisible 1`] = `
-
-
-
-
-
-

-
-
-
-
-
-
-`;
diff --git a/tests/__snapshots__/preview.test.tsx.snap b/tests/__snapshots__/preview.test.tsx.snap
deleted file mode 100644
index 8bf3fbea..00000000
--- a/tests/__snapshots__/preview.test.tsx.snap
+++ /dev/null
@@ -1,106 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Preview add rootClassName should be correct 1`] = `
-
-

-
-`;
-
-exports[`Preview add rootClassName should be correct when open preview 1`] = `
-[
-
-
-

-
-
,
-
-
-
-
-
-
-
-
-
-

-
-
-
-
-
-
-
-
-
,
-
-
-
-
,
-]
-`;
diff --git a/tests/__snapshots__/previewGroup.test.tsx.snap b/tests/__snapshots__/previewGroup.test.tsx.snap
deleted file mode 100644
index 17a37815..00000000
--- a/tests/__snapshots__/previewGroup.test.tsx.snap
+++ /dev/null
@@ -1,37 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`PreviewGroup With Controlled 1`] = `
-
-
-
-
-
-

-
-
-
-
-
-
-`;
diff --git a/tests/basic.test.tsx b/tests/basic.test.tsx
index a58d5e7a..72705815 100644
--- a/tests/basic.test.tsx
+++ b/tests/basic.test.tsx
@@ -58,18 +58,22 @@ describe('Basic', () => {
expect(img).toHaveStyle({ objectFit: 'cover' });
});
- it('wrapperClassName and wrapperStyle should work on image wrapper element', () => {
+ it('classNames.root and styles.root should work on image wrapper element', () => {
const { container } = render(
,
);
- const wrapperElement = container.querySelector('img').parentElement;
- expect(wrapperElement).toHaveClass('wrapper');
+ const wrapperElement = container.firstChild;
+ expect(wrapperElement).toHaveClass('bamboo');
expect(wrapperElement).toHaveStyle({ objectFit: 'cover' });
});
@@ -81,20 +85,20 @@ describe('Basic', () => {
style={{
display: 'none',
}}
- preview={{ mask: 'Click to Preview' }}
+ preview={{ cover: 'Click to Preview' }}
/>,
);
- const maskElement = container.querySelector('.rc-image-mask');
+ const maskElement = container.querySelector('.rc-image-cover');
expect(maskElement).toHaveStyle({ display: 'none' });
});
- it('preview zIndex should pass into operations', () => {
+ it('preview zIndex should pass', () => {
const { baseElement } = render(
,
);
- const operationsElement = baseElement.querySelector('.rc-image-preview-operations-wrapper');
- expect(operationsElement).toHaveStyle({ zIndex: 10000 });
+ const operationsElement = baseElement.querySelector('.rc-image-preview');
+ expect(operationsElement).toHaveStyle({ zIndex: 9999 });
});
});
diff --git a/tests/controlled.test.tsx b/tests/controlled.test.tsx
index 03b9ea81..ee243e29 100644
--- a/tests/controlled.test.tsx
+++ b/tests/controlled.test.tsx
@@ -1,6 +1,6 @@
import { act, fireEvent, render } from '@testing-library/react';
-import Image from '../src';
import React from 'react';
+import Image from '../src';
describe('Controlled', () => {
beforeEach(() => {
@@ -14,7 +14,7 @@ describe('Controlled', () => {
const { rerender } = render(
,
);
@@ -23,7 +23,7 @@ describe('Controlled', () => {
rerender(
,
);
@@ -31,7 +31,7 @@ describe('Controlled', () => {
jest.runAllTimers();
});
- expect(document.querySelector('.rc-image-preview')).toMatchSnapshot();
+ expect(document.querySelector('.rc-image-preview')).toBeFalsy();
});
it('controlled current in group', () => {
@@ -57,33 +57,4 @@ describe('Controlled', () => {
expect(document.querySelector('.rc-image-preview-img')).toHaveAttribute('src', 'src3');
});
-
- // it('controlled visible and current with items in group', () => {
- // const { rerender } = render(
- //
- //
- // ,
- // );
-
- // expect(document.querySelector('.rc-image-preview')).toBeTruthy();
-
- // fireEvent.click(document.querySelector('.rc-image-preview-switch-right'));
- // expect(document.querySelector('.rc-image-preview-img')).toHaveAttribute('src', 'src2');
-
- // fireEvent.click(document.querySelector('.rc-image-preview-operations-operation-close'));
-
- // rerender(
- //
- //
- //
- //
- // ,
- // );
-
- // act(() => {
- // jest.runAllTimers();
- // });
-
- // expect(document.querySelector('.rc-image-preview-img')).toHaveAttribute('src', 'src3');
- // });
});
diff --git a/tests/preview.test.tsx b/tests/preview.test.tsx
index f0ec73ac..608b28af 100644
--- a/tests/preview.test.tsx
+++ b/tests/preview.test.tsx
@@ -5,8 +5,8 @@ import RotateLeftOutlined from '@ant-design/icons/RotateLeftOutlined';
import RotateRightOutlined from '@ant-design/icons/RotateRightOutlined';
import ZoomInOutlined from '@ant-design/icons/ZoomInOutlined';
import ZoomOutOutlined from '@ant-design/icons/ZoomOutOutlined';
-import { act, createEvent, fireEvent, render } from '@testing-library/react';
import { spyElementPrototypes } from '@rc-component/util/lib/test/domHook';
+import { act, createEvent, fireEvent, render } from '@testing-library/react';
import React from 'react';
jest.mock('../src/Preview', () => {
@@ -64,33 +64,35 @@ describe('Preview', () => {
,
);
+ // Click Image
fireEvent.click(container.querySelector('.rc-image'));
+ expect(onPreviewCloseMock).toHaveBeenCalledWith(true);
+
act(() => {
jest.runAllTimers();
});
-
expect(document.querySelector('.rc-image-preview')).toBeTruthy();
- // With mask close
- expect(onPreviewCloseMock).toBeCalledWith(true, false);
- fireEvent.click(document.querySelector('.rc-image-preview-wrap'));
+ // Click Mask
+ onPreviewCloseMock.mockReset();
+ fireEvent.click(document.querySelector('.rc-image-preview-mask'));
+ expect(onPreviewCloseMock).toHaveBeenCalledWith(false);
- // With btn close
+ // Click Image again
fireEvent.click(container.querySelector('.rc-image'));
act(() => {
jest.runAllTimers();
});
- fireEvent.click(document.querySelector('.rc-image-preview-operations-operation'));
-
- expect(onPreviewCloseMock).toBeCalledWith(false, true);
-
- onPreviewCloseMock.mockRestore();
+ // Click Close Button
+ onPreviewCloseMock.mockReset();
+ fireEvent.click(document.querySelector('.rc-image-preview-close'));
+ expect(onPreviewCloseMock).toHaveBeenCalledWith(false);
});
it('Unmount', () => {
@@ -118,7 +120,7 @@ describe('Preview', () => {
jest.runAllTimers();
});
- fireEvent.click(document.querySelectorAll('.rc-image-preview-operations-operation')[3]);
+ fireEvent.click(document.querySelectorAll('.rc-image-preview-actions-action')[3]);
act(() => {
jest.runAllTimers();
});
@@ -126,7 +128,7 @@ describe('Preview', () => {
transform: 'translate3d(0px, 0px, 0) scale3d(1, 1, 1) rotate(90deg)',
});
- fireEvent.click(document.querySelectorAll('.rc-image-preview-operations-operation')[2]);
+ fireEvent.click(document.querySelectorAll('.rc-image-preview-actions-action')[2]);
act(() => {
jest.runAllTimers();
});
@@ -145,7 +147,7 @@ describe('Preview', () => {
jest.runAllTimers();
});
- fireEvent.click(document.querySelectorAll('.rc-image-preview-operations-operation')[1]);
+ fireEvent.click(document.querySelectorAll('.rc-image-preview-actions-action')[1]);
act(() => {
jest.runAllTimers();
});
@@ -153,7 +155,7 @@ describe('Preview', () => {
transform: 'translate3d(0px, 0px, 0) scale3d(-1, 1, 1) rotate(0deg)',
});
- fireEvent.click(document.querySelectorAll('.rc-image-preview-operations-operation')[0]);
+ fireEvent.click(document.querySelectorAll('.rc-image-preview-actions-action')[0]);
act(() => {
jest.runAllTimers();
});
@@ -161,7 +163,7 @@ describe('Preview', () => {
transform: 'translate3d(0px, 0px, 0) scale3d(-1, -1, 1) rotate(0deg)',
});
- fireEvent.click(document.querySelectorAll('.rc-image-preview-operations-operation')[1]);
+ fireEvent.click(document.querySelectorAll('.rc-image-preview-actions-action')[1]);
act(() => {
jest.runAllTimers();
});
@@ -169,7 +171,7 @@ describe('Preview', () => {
transform: 'translate3d(0px, 0px, 0) scale3d(1, -1, 1) rotate(0deg)',
});
- fireEvent.click(document.querySelectorAll('.rc-image-preview-operations-operation')[0]);
+ fireEvent.click(document.querySelectorAll('.rc-image-preview-actions-action')[0]);
act(() => {
jest.runAllTimers();
});
@@ -188,7 +190,7 @@ describe('Preview', () => {
jest.runAllTimers();
});
- fireEvent.click(document.querySelectorAll('.rc-image-preview-operations-operation')[5]);
+ fireEvent.click(document.querySelectorAll('.rc-image-preview-actions-action')[5]);
act(() => {
jest.runAllTimers();
});
@@ -196,7 +198,7 @@ describe('Preview', () => {
transform: 'translate3d(-256px, -192px, 0) scale3d(1.5, 1.5, 1) rotate(0deg)',
});
- fireEvent.click(document.querySelectorAll('.rc-image-preview-operations-operation')[4]);
+ fireEvent.click(document.querySelectorAll('.rc-image-preview-actions-action')[4]);
act(() => {
jest.runAllTimers();
});
@@ -204,7 +206,7 @@ describe('Preview', () => {
transform: 'translate3d(0px, 0px, 0) scale3d(1, 1, 1) rotate(0deg)',
});
- fireEvent.click(document.querySelectorAll('.rc-image-preview-operations-operation')[5]);
+ fireEvent.click(document.querySelectorAll('.rc-image-preview-actions-action')[5]);
act(() => {
jest.runAllTimers();
});
@@ -212,7 +214,7 @@ describe('Preview', () => {
transform: 'translate3d(-256px, -192px, 0) scale3d(1.5, 1.5, 1) rotate(0deg)',
});
- fireEvent.click(document.querySelectorAll('.rc-image-preview-operations-operation')[4]);
+ fireEvent.click(document.querySelectorAll('.rc-image-preview-actions-action')[4]);
act(() => {
jest.runAllTimers();
});
@@ -269,7 +271,7 @@ describe('Preview', () => {
jest.runAllTimers();
});
- fireEvent.click(document.querySelectorAll('.rc-image-preview-operations-operation')[4]);
+ fireEvent.click(document.querySelectorAll('.rc-image-preview-actions-action')[4]);
act(() => {
jest.runAllTimers();
});
@@ -277,7 +279,7 @@ describe('Preview', () => {
transform: 'translate3d(0px, 0px, 0) scale3d(1, 1, 1) rotate(0deg)',
});
- fireEvent.click(document.querySelectorAll('.rc-image-preview-operations-operation')[5]);
+ fireEvent.click(document.querySelectorAll('.rc-image-preview-actions-action')[5]);
act(() => {
jest.runAllTimers();
});
@@ -285,7 +287,7 @@ describe('Preview', () => {
transform: 'translate3d(-512px, -384px, 0) scale3d(2, 2, 1) rotate(0deg)',
});
- fireEvent.click(document.querySelectorAll('.rc-image-preview-operations-operation')[4]);
+ fireEvent.click(document.querySelectorAll('.rc-image-preview-actions-action')[4]);
act(() => {
jest.runAllTimers();
});
@@ -325,7 +327,7 @@ describe('Preview', () => {
jest.runAllTimers();
});
- fireEvent.click(document.querySelectorAll('.rc-image-preview-operations-operation')[5]);
+ fireEvent.click(document.querySelectorAll('.rc-image-preview-actions-action')[5]);
act(() => {
jest.runAllTimers();
});
@@ -571,7 +573,7 @@ describe('Preview', () => {
jest.restoreAllMocks();
});
- it('PreviewGroup', () => {
+ it('PreviewGroup render', () => {
const { container } = render(
{
jest.runAllTimers();
});
- fireEvent.click(document.querySelectorAll('.anticon')[1]);
- act(() => {
- jest.runAllTimers();
- });
-
- fireEvent.click(document.querySelector('.rc-image-preview-wrap'));
-
- fireEvent.click(container.querySelectorAll('.rc-image')[1]);
- act(() => {
- jest.runAllTimers();
- });
-
- fireEvent.click(document.querySelectorAll('.anticon')[0]);
- act(() => {
- jest.runAllTimers();
- });
-
- fireEvent.click(document.querySelector('.rc-image-preview-wrap'));
+ expect(document.querySelectorAll('.rc-image-preview-actions-action')).toHaveLength(6);
});
it('preview placeholder', () => {
@@ -625,14 +610,16 @@ describe('Preview', () => {
,
);
- expect(document.querySelector('.rc-image-mask').textContent).toEqual('Bamboo Is Light');
- expect(document.querySelector('.rc-image-mask')).toHaveClass('bamboo');
+ expect(document.querySelector('.rc-image-cover').textContent).toEqual('Bamboo Is Light');
+ expect(document.querySelector('.rc-image-cover')).toHaveClass('bamboo');
});
it('previewSrc', () => {
@@ -660,9 +647,8 @@ describe('Preview', () => {
,
@@ -670,38 +656,33 @@ describe('Preview', () => {
expect(global._previewProps).toEqual(
expect.objectContaining({
- transitionName: 'abc',
- maskTransitionName: 'def',
+ motionName: 'abc',
}),
);
- expect(container.querySelector('.rc-image-close')).toBeFalsy();
+ expect(document.querySelector('.rc-image-preview-close')).toBeFalsy();
});
it('Customize Group preview props', () => {
const src = 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png';
render(
-
+
,
);
expect(global._previewProps).toEqual(
expect.objectContaining({
- transitionName: 'abc',
- maskTransitionName: 'def',
+ motionName: 'abc',
}),
);
});
it('add rootClassName should be correct', () => {
const src = 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png';
- const { container, asFragment } = render();
+ const { container } = render();
- expect(container.querySelectorAll('.custom-className')).toHaveLength(1);
- expect(asFragment().firstChild).toMatchSnapshot();
+ expect(container.querySelector('.rc-image.custom-className')).toBeTruthy();
});
it('add rootClassName should be correct when open preview', () => {
@@ -716,22 +697,19 @@ describe('Preview', () => {
'src',
src,
);
- expect(document.querySelector('.rc-image-preview-root.custom-className')).toBeFalsy();
+ expect(document.querySelector('.rc-image-preview.custom-className')).toBeFalsy();
fireEvent.click(container.querySelector('.rc-image'));
act(() => {
jest.runAllTimers();
});
- expect(
- document.querySelector('.rc-image-preview-root.custom-className .rc-image-preview'),
- ).toBeTruthy();
- expect(document.querySelector('.rc-image-preview-root.custom-className')).toBeTruthy();
- expect(
- document.querySelector('.rc-image-preview-root.custom-className .rc-image-preview-img'),
- ).toHaveAttribute('src', previewSrc);
-
- expect(Array.from(document.body.children)).toMatchSnapshot();
+ expect(document.querySelector('.rc-image-preview.custom-className')).toBeTruthy();
+ expect(document.querySelector('.rc-image-preview.custom-className img')).toHaveAttribute(
+ 'src',
+ previewSrc,
+ );
+ expect(document.querySelectorAll('.custom-className')).toHaveLength(2);
});
it('if async src set should be correct', () => {
@@ -757,10 +735,10 @@ describe('Preview', () => {
jest.runAllTimers();
});
- expect(document.querySelector('.rc-image-preview-img')).toHaveAttribute('src', src);
+ expect(document.querySelector('.rc-image-preview img')).toHaveAttribute('src', src);
- expect(document.querySelector('.rc-image-preview-switch-left')).toHaveClass(
- 'rc-image-preview-switch-left-disabled',
+ expect(document.querySelector('.rc-image-preview-switch-prev')).toHaveClass(
+ 'rc-image-preview-switch-disabled',
);
});
@@ -783,7 +761,7 @@ describe('Preview', () => {
);
});
- describe('toolbarRender', () => {
+ describe('actionsRender', () => {
it('single', () => {
const printImage = jest.fn();
const { container } = render(
@@ -793,7 +771,7 @@ describe('Preview', () => {
width={200}
height={200}
preview={{
- toolbarRender: (_, { icons, image, actions }) => {
+ actionsRender: (_, { icons, image, actions }) => {
printImage(image);
return (
<>
@@ -883,9 +861,9 @@ describe('Preview', () => {
},
]}
preview={{
- visible: true,
+ open: true,
current: 1,
- toolbarRender: (_, { icons, actions }) => {
+ actionsRender: (_, { icons, actions }) => {
return (
<>
{icons.prevIcon}
@@ -905,10 +883,9 @@ describe('Preview', () => {
);
// Origin Node
- fireEvent.click(document.querySelector('.rc-image-preview-operations-operation-prev'));
+ fireEvent.click(document.querySelector('.rc-image-preview-actions-action-prev'));
expect(onChange).toHaveBeenCalledWith(0, 1);
-
- fireEvent.click(document.querySelector('.rc-image-preview-operations-operation-next'));
+ fireEvent.click(document.querySelector('.rc-image-preview-actions-action-next'));
expect(onChange).toHaveBeenCalledWith(2, 1);
// Customize
@@ -937,7 +914,7 @@ describe('Preview', () => {
expect(document.querySelector('.rc-image-preview')).toBeTruthy();
- fireEvent.click(document.querySelector('.rc-image-preview-operations-operation-flipY'));
+ fireEvent.click(document.querySelector('.rc-image-preview-actions-action-flipY'));
act(() => {
jest.runAllTimers();
});
@@ -981,12 +958,12 @@ describe('Preview', () => {
});
it('should be closed when press esc after click portal', () => {
- const onVisibleChange = jest.fn();
+ const onOpenChange = jest.fn();
const { container } = render(
,
);
@@ -998,16 +975,16 @@ describe('Preview', () => {
expect(document.querySelector('.rc-image-preview')).toBeTruthy();
- expect(onVisibleChange).toBeCalledWith(true, false);
+ expect(onOpenChange).toHaveBeenCalledWith(true);
- fireEvent.click(document.querySelector('.rc-image-preview-operations'));
+ fireEvent.click(document.querySelector('.rc-image-preview-actions'));
fireEvent.keyDown(window, { key: 'Escape', keyCode: 27 });
- expect(onVisibleChange).toBeCalledWith(false, true);
- expect(onVisibleChange).toBeCalledTimes(2);
+ expect(onOpenChange).toHaveBeenCalledWith(false);
+ expect(onOpenChange).toHaveBeenCalledTimes(2);
- onVisibleChange.mockRestore();
+ onOpenChange.mockRestore();
});
it('not modify preview image size', () => {
@@ -1017,7 +994,7 @@ describe('Preview', () => {
width={20}
height={20}
preview={{
- visible: true,
+ open: true,
}}
/>,
);
@@ -1026,17 +1003,19 @@ describe('Preview', () => {
jest.runAllTimers();
});
- const previewImg = document.querySelector('.rc-image-preview-img-wrapper img');
+ const previewImg = document.querySelector('.rc-image-preview img');
expect(previewImg).not.toHaveAttribute('width');
expect(previewImg).not.toHaveAttribute('height');
});
it('support classnames and styles', () => {
const customClassnames = {
+ cover: 'custom-cover',
mask: 'custom-mask',
actions: 'custom-actions',
root: 'custom-root',
};
const customStyles = {
+ cover: { color: 'red' },
mask: { color: 'red' },
actions: { backgroundColor: 'blue' },
root: { border: '1px solid green' },
@@ -1047,19 +1026,23 @@ describe('Preview', () => {
preview={{
styles: customStyles,
classNames: customClassnames,
- mask: 'Bamboo Is Light',
+ cover: 'Bamboo Is Light',
zIndex: 9999,
- visible: true,
+ open: true,
}}
/>,
);
- const mask = document.querySelector('.rc-image-mask');
- const actions = baseElement.querySelector('.rc-image-preview-operations');
+
+ const cover = document.querySelector('.rc-image-cover');
+ const mask = document.querySelector('.rc-image-preview-mask');
+ const actions = baseElement.querySelector('.rc-image-preview-actions');
+ expect(cover).toHaveClass(customClassnames.cover);
+ expect(cover).toHaveStyle(customStyles.cover);
expect(mask).toHaveClass(customClassnames.mask);
expect(mask).toHaveStyle(customStyles.mask);
expect(actions).toHaveClass(customClassnames.actions);
expect(actions).toHaveStyle(customStyles.actions);
- expect(baseElement.querySelector('.rc-image-preview-root')).toHaveClass(customClassnames.root);
+ expect(baseElement.querySelector('.rc-image-preview')).toHaveClass(customClassnames.root);
expect(baseElement.querySelector('.rc-image-preview')).toHaveStyle(customStyles.root);
});
});
diff --git a/tests/previewGroup.test.tsx b/tests/previewGroup.test.tsx
index ad38e78e..f904ec40 100644
--- a/tests/previewGroup.test.tsx
+++ b/tests/previewGroup.test.tsx
@@ -1,5 +1,5 @@
-import { act, fireEvent, render } from '@testing-library/react';
import KeyCode from '@rc-component/util/lib/KeyCode';
+import { act, fireEvent, render } from '@testing-library/react';
import React from 'react';
import Image from '../src';
@@ -14,9 +14,9 @@ describe('PreviewGroup', () => {
it('onChange should be called', () => {
const onChange = jest.fn();
- const onVisibleChange = jest.fn();
+ const onOpenChange = jest.fn();
const { container } = render(
-
+
@@ -29,15 +29,15 @@ describe('PreviewGroup', () => {
jest.runAllTimers();
});
expect(onChange).not.toHaveBeenCalled();
- expect(onVisibleChange).toBeCalledWith(true, false, 0);
+ expect(onOpenChange).toBeCalledWith(true, { current: 0 });
- fireEvent.click(document.querySelector('.rc-image-preview-switch-right'));
+ fireEvent.click(document.querySelector('.rc-image-preview-switch-next'));
act(() => {
jest.runAllTimers();
});
expect(onChange).toHaveBeenCalledWith(1, 0);
- fireEvent.click(document.querySelector('.rc-image-preview-switch-right'));
+ fireEvent.click(document.querySelector('.rc-image-preview-switch-next'));
act(() => {
jest.runAllTimers();
});
@@ -145,42 +145,52 @@ describe('PreviewGroup', () => {
jest.runAllTimers();
});
- expect(document.querySelector('.rc-image-preview-switch-left-disabled')).toBeTruthy();
+ expect(
+ document.querySelector('.rc-image-preview-switch-prev.rc-image-preview-switch-disabled'),
+ ).toBeTruthy();
expect(document.querySelector(previewProgressElementPath).textContent).toEqual('1 / 2');
- fireEvent.click(document.querySelector('.rc-image-preview-switch-right'));
+ fireEvent.click(document.querySelector('.rc-image-preview-switch-next'));
act(() => {
jest.runAllTimers();
});
- expect(document.querySelector('.rc-image-preview-switch-right-disabled')).toBeTruthy();
+ expect(
+ document.querySelector('.rc-image-preview-switch-next.rc-image-preview-switch-disabled'),
+ ).toBeTruthy();
expect(document.querySelector(previewProgressElementPath).textContent).toEqual('2 / 2');
- fireEvent.click(document.querySelector('.rc-image-preview-switch-left'));
+ fireEvent.click(document.querySelector('.rc-image-preview-switch-prev'));
act(() => {
jest.runAllTimers();
});
- expect(document.querySelector('.rc-image-preview-switch-left-disabled')).toBeTruthy();
+ expect(
+ document.querySelector('.rc-image-preview-switch-prev.rc-image-preview-switch-disabled'),
+ ).toBeTruthy();
fireEvent.keyDown(window, { keyCode: KeyCode.RIGHT });
act(() => {
jest.runAllTimers();
});
- expect(document.querySelector('.rc-image-preview-switch-right-disabled')).toBeTruthy();
+ expect(
+ document.querySelector('.rc-image-preview-switch-next.rc-image-preview-switch-disabled'),
+ ).toBeTruthy();
fireEvent.keyDown(window, { keyCode: KeyCode.LEFT });
act(() => {
jest.runAllTimers();
});
- expect(document.querySelector('.rc-image-preview-switch-left-disabled')).toBeTruthy();
+ expect(
+ document.querySelector('.rc-image-preview-switch-prev.rc-image-preview-switch-disabled'),
+ ).toBeTruthy();
});
it('With Controlled', () => {
const { rerender } = render(
-
+
,
);
@@ -188,7 +198,7 @@ describe('PreviewGroup', () => {
expect(document.querySelector('.rc-image-preview')).toBeTruthy();
rerender(
-
+
,
);
@@ -196,12 +206,12 @@ describe('PreviewGroup', () => {
jest.runAllTimers();
});
- expect(document.querySelector('.rc-image-preview')).toMatchSnapshot();
+ expect(document.querySelector('.rc-image-preview')).toBeFalsy();
});
it('should show error img', () => {
render(
-
+
,
);
@@ -221,7 +231,7 @@ describe('PreviewGroup', () => {
jest.runAllTimers();
});
- fireEvent.click(document.querySelectorAll('.rc-image-preview-operations-operation')[3]);
+ fireEvent.click(document.querySelectorAll('.rc-image-preview-actions-action')[3]);
act(() => {
jest.runAllTimers();
});
@@ -230,7 +240,7 @@ describe('PreviewGroup', () => {
transform: 'translate3d(0px, 0px, 0) scale3d(1, 1, 1) rotate(90deg)',
});
- fireEvent.click(document.querySelector('.rc-image-preview-switch-right'));
+ fireEvent.click(document.querySelector('.rc-image-preview-switch-next'));
act(() => {
jest.runAllTimers();
});
@@ -258,7 +268,7 @@ describe('PreviewGroup', () => {
'no-referrer',
);
- fireEvent.click(document.querySelector('.rc-image-preview-switch-right'));
+ fireEvent.click(document.querySelector('.rc-image-preview-switch-next'));
act(() => {
jest.runAllTimers();
});
@@ -284,10 +294,10 @@ describe('PreviewGroup', () => {
});
expect(document.querySelector('.rc-image-preview-img')).toHaveAttribute('src', 'src1');
- fireEvent.click(document.querySelector('.rc-image-preview-switch-right'));
+ fireEvent.click(document.querySelector('.rc-image-preview-switch-next'));
expect(document.querySelector('.rc-image-preview-img')).toHaveAttribute('src', 'src2');
- fireEvent.click(document.querySelector('.rc-image-preview-switch-right'));
+ fireEvent.click(document.querySelector('.rc-image-preview-switch-next'));
expect(document.querySelector('.rc-image-preview-img')).toHaveAttribute('src', 'src3');
});
@@ -318,17 +328,17 @@ describe('PreviewGroup', () => {
});
expect(document.querySelector('.rc-image-preview-img')).toHaveAttribute('src', 'src1');
- fireEvent.click(document.querySelector('.rc-image-preview-switch-right'));
+ fireEvent.click(document.querySelector('.rc-image-preview-switch-next'));
expect(document.querySelector('.rc-image-preview-img')).toHaveAttribute('src', 'src2');
- fireEvent.click(document.querySelector('.rc-image-preview-switch-right'));
+ fireEvent.click(document.querySelector('.rc-image-preview-switch-next'));
expect(document.querySelector('.rc-image-preview-img')).toHaveAttribute('src', 'src3');
});
it('should keep order', async () => {
const Demo = ({ firstUrl }: { firstUrl: string }) => {
return (
-
+
@@ -339,24 +349,24 @@ describe('PreviewGroup', () => {
// Open preview
expect(document.querySelector('.rc-image-preview-progress').textContent).toEqual('1 / 2');
- expect(
- document.querySelector('.rc-image-preview-img-wrapper img')!.src,
- ).toEqual('http://first/img.png');
+ expect(document.querySelector('.rc-image-preview img')!.src).toEqual(
+ 'http://first/img.png',
+ );
// Modify URL should keep order
rerender();
expect(document.querySelector('.rc-image-preview-progress').textContent).toEqual('1 / 2');
- expect(
- document.querySelector('.rc-image-preview-img-wrapper img')!.src,
- ).toEqual('http://second/img.png');
+ expect(document.querySelector('.rc-image-preview img')!.src).toEqual(
+ 'http://second/img.png',
+ );
});
it('onTransform should be triggered when switch', () => {
const onTransform = jest.fn();
render(
{
]}
/>,
);
- fireEvent.click(document.querySelector('.rc-image-preview-operations-operation-flipY'));
+ fireEvent.click(document.querySelector('.rc-image-preview-actions-action-flipY'));
act(() => {
jest.runAllTimers();
});
@@ -386,7 +396,7 @@ describe('PreviewGroup', () => {
},
action: 'flipY',
});
- fireEvent.click(document.querySelector('.rc-image-preview-switch-right'));
+ fireEvent.click(document.querySelector('.rc-image-preview-switch-next'));
act(() => {
jest.runAllTimers();
});