Skip to content

Commit

Permalink
feat: display preview-src after loading
Browse files Browse the repository at this point in the history
  • Loading branch information
wangcch committed Dec 30, 2020
1 parent d230eac commit 837b4a2
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 9 deletions.
9 changes: 5 additions & 4 deletions src/Image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ interface CompoundedComponent<P> extends React.FC<P> {
PreviewGroup: typeof PreviewGroup;
}

type ImageStatus = 'normal' | 'error' | 'loading';
export type ImageStatus = 'normal' | 'error' | 'loading';

const ImageInternal: CompoundedComponent<ImageProps> = ({
src: imgSrc,
Expand Down Expand Up @@ -77,6 +77,7 @@ const ImageInternal: CompoundedComponent<ImageProps> = ({
mask: previewMask,
}: ImagePreviewType = typeof preview === 'object' ? preview : {};
const src = previewSrc ?? imgSrc;
const thumbnail = previewSrc ? imgSrc : undefined;
const isControlled = previewVisible !== undefined;
const [isShowPreview, setShowPreview] = useMergedState(!!previewVisible, {
value: previewVisible,
Expand Down Expand Up @@ -153,14 +154,13 @@ const ImageInternal: CompoundedComponent<ImageProps> = ({
return () => {};
}

const unRegister = registerImage(currentId, src);

const unRegister = registerImage(currentId, src, thumbnail);
if (!canPreview) {
unRegister();
}

return unRegister;
}, [src, canPreview]);
}, [thumbnail, src, canPreview]);

const wrapperClass = cn(prefixCls, wrapperClassName, {
[`${prefixCls}-error`]: isError,
Expand Down Expand Up @@ -228,6 +228,7 @@ const ImageInternal: CompoundedComponent<ImageProps> = ({
onClose={onPreviewClose}
mousePosition={mousePosition}
src={mergedSrc}
thumbnail={thumbnail}
alt={alt}
getContainer={getPreviewContainer}
/>
Expand Down
73 changes: 70 additions & 3 deletions src/Preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,16 @@ import { warning } from 'rc-util/lib/warning';
import useFrameSetState from './hooks/useFrameSetState';
import getFixScaleEleTransPosition from './getFixScaleEleTransPosition';
import { context } from './PreviewGroup';
import { ImageStatus } from './Image';

const { useState, useEffect } = React;

interface PreviewProps extends Omit<IDialogPropTypes, 'onClose'> {
onClose?: (e: React.SyntheticEvent<Element>) => void;
src?: string;
alt?: string;
/** thumbnail src value */
thumbnail?: string;
}

const initialPosition = {
Expand All @@ -29,7 +32,16 @@ const initialPosition = {
};

const Preview: React.FC<PreviewProps> = props => {
const { prefixCls, src, alt, onClose, afterClose, visible, ...restProps } = props;
const {
prefixCls,
src,
alt,
thumbnail: originalThumbnail,
onClose,
afterClose,
visible,
...restProps
} = props;
const [scale, setScale] = useState(1);
const [rotate, setRotate] = useState(0);
const [position, setPosition] = useFrameSetState<{
Expand All @@ -48,12 +60,38 @@ const Preview: React.FC<PreviewProps> = props => {
deltaX: 0,
deltaY: 0,
});
const {
previewUrls,
thumbnailUrls,
current,
isPreviewGroup,
setCurrent,
setThumbnailUrls,
} = React.useContext(context);

const thumbnail = isPreviewGroup ? thumbnailUrls.get(current)?.url : originalThumbnail;
const containThumbnail = !!thumbnail;
const initCurThumbnailLoadState =
containThumbnail && (isPreviewGroup ? thumbnailUrls?.get(current)?.done : false);
const [fakeImgStatus, setFakeImgStatus] = React.useState<ImageStatus>(
containThumbnail && !initCurThumbnailLoadState ? 'loading' : 'normal',
);

const combinationSrc = (() => {
if (fakeImgStatus === 'loading') {
return thumbnail;
}
if (isPreviewGroup) {
return previewUrls.get(current);
}

return src;
})();

const [isMoving, setMoving] = React.useState(false);
const { previewUrls, current, isPreviewGroup, setCurrent } = React.useContext(context);
const previewGroupCount = previewUrls.size;
const previewUrlsKeys = Array.from(previewUrls.keys());
const currentPreviewIndex = previewUrlsKeys.indexOf(current);
const combinationSrc = isPreviewGroup ? previewUrls.get(current) : src;
const showLeftOrRightSwitches = isPreviewGroup && previewGroupCount > 1;
const [lastWheelZoomDirection, setLastWheelZoomDirection] = React.useState({ wheelDirection: 0 });

Expand Down Expand Up @@ -184,6 +222,20 @@ const Preview: React.FC<PreviewProps> = props => {
setLastWheelZoomDirection({ wheelDirection });
};

const onFakeLoad: React.ReactEventHandler<HTMLImageElement> = () => {
setFakeImgStatus('normal');

if (isPreviewGroup && containThumbnail) {
setThumbnailUrls(oldThumbnailUrls => {
const url = oldThumbnailUrls.get(current)?.url;
return new Map(oldThumbnailUrls).set(current, { url, done: true });
});
}
};
const onFakeError: React.ReactEventHandler<HTMLImageElement> = () => {
setFakeImgStatus('error');
};

useEffect(() => {
const { wheelDirection } = lastWheelZoomDirection;
if (wheelDirection > 0) {
Expand Down Expand Up @@ -227,6 +279,12 @@ const Preview: React.FC<PreviewProps> = props => {
};
}, [visible, isMoving]);

useEffect(() => {
if (isPreviewGroup && thumbnail && !initCurThumbnailLoadState) {
setFakeImgStatus('loading');
}
}, [initCurThumbnailLoadState, thumbnail, isPreviewGroup]);

return (
<Dialog
{...restProps}
Expand Down Expand Up @@ -269,6 +327,15 @@ const Preview: React.FC<PreviewProps> = props => {
transform: `scale3d(${scale}, ${scale}, 1) rotate(${rotate}deg)`,
}}
/>
{containThumbnail && (
<img
className={`${prefixCls}-faker-img`}
src={src}
onLoad={onFakeLoad}
onError={onFakeError}
style={{ display: 'none' }}
/>
)}
</div>
{showLeftOrRightSwitches && (
<div
Expand Down
18 changes: 16 additions & 2 deletions src/PreviewGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ export interface GroupConsumerValue extends GroupConsumerProps {
isPreviewGroup?: boolean;
previewUrls: Map<number, string>;
setPreviewUrls: React.Dispatch<React.SetStateAction<Map<number, string>>>;
thumbnailUrls?: Map<number, { url: string; done: boolean }>;
setThumbnailUrls?: React.Dispatch<React.SetStateAction<Map<number, { url: string; done: boolean }>>>;
current: number;
setCurrent: React.Dispatch<React.SetStateAction<number>>;
setShowPreview: React.Dispatch<React.SetStateAction<boolean>>;
setMousePosition: React.Dispatch<React.SetStateAction<null | { x: number; y: number }>>;
registerImage: (id: number, url: string) => () => void;
registerImage: (id: number, url: string, thumbnail?: string) => () => void;
}

/* istanbul ignore next */
Expand All @@ -35,15 +37,24 @@ const Group: React.FC<GroupConsumerProps> = ({
children,
}) => {
const [previewUrls, setPreviewUrls] = useState<Map<number, string>>(new Map());
const [thumbnailUrls, setThumbnailUrls] = useState<Map<number, { url: string; done: boolean }>>(
new Map(),
);
const [current, setCurrent] = useState<number>();
const [isShowPreview, setShowPreview] = useState(false);
const [mousePosition, setMousePosition] = useState<null | { x: number; y: number }>(null);

const registerImage = (id: number, url: string) => {
const registerImage = (id: number, url: string, thumbnail?: string) => {
setPreviewUrls(oldPreviewUrls => {
return new Map(oldPreviewUrls).set(id, url);
});

if (thumbnail) {
setThumbnailUrls(oldThumbnailUrls => {
return new Map(oldThumbnailUrls).set(id, { url: thumbnail, done: false });
});
}

return () => {
setPreviewUrls(oldPreviewUrls => {
const clonePreviewUrls = new Map(oldPreviewUrls);
Expand All @@ -65,6 +76,8 @@ const Group: React.FC<GroupConsumerProps> = ({
isPreviewGroup: true,
previewUrls,
setPreviewUrls,
thumbnailUrls,
setThumbnailUrls,
current,
setCurrent,
setShowPreview,
Expand All @@ -80,6 +93,7 @@ const Group: React.FC<GroupConsumerProps> = ({
onClose={onPreviewClose}
mousePosition={mousePosition}
src={previewUrls.get(current)}
thumbnail={thumbnailUrls.get(current)?.url}
/>
</Provider>
);
Expand Down
8 changes: 8 additions & 0 deletions tests/preview.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,14 @@ describe('Preview', () => {
});

expect(wrapper.find('.rc-image-preview').get(0)).toBeTruthy();
expect(wrapper.find('.rc-image-preview-img').prop('src')).toBe(src);
expect(wrapper.find('.rc-image-preview-faker-img').prop('src')).toBe(previewSrc);

act(() => {
wrapper.find('.rc-image-preview-faker-img').simulate('load');
jest.runAllTimers();
wrapper.update();
});
expect(wrapper.find('.rc-image-preview-img').prop('src')).toBe(previewSrc);
});
});

0 comments on commit 837b4a2

Please sign in to comment.