Refine zoom viewer behavior
This commit is contained in:
parent
33a430dcfd
commit
23eb87edd9
@ -6,7 +6,7 @@ import { RiCollapseDiagonalLine, RiExpandDiagonalLine } from 'react-icons/ri';
|
||||
|
||||
export type ZoomControlsRef = {
|
||||
open: () => void
|
||||
zoom: (zoomLevel?: number) => void
|
||||
zoomTo: (zoomLevel?: number) => void
|
||||
}
|
||||
|
||||
export default function ZoomControls({
|
||||
@ -22,28 +22,33 @@ export default function ZoomControls({
|
||||
}) {
|
||||
const refContainer = useRef<HTMLDivElement>(null);
|
||||
|
||||
const { open, zoom, zoomLevel, isShown } = useImageZoomControls(
|
||||
const {
|
||||
open,
|
||||
reset,
|
||||
zoomTo,
|
||||
zoomLevel,
|
||||
viewerContainerRef,
|
||||
} = useImageZoomControls(
|
||||
refContainer,
|
||||
isEnabled,
|
||||
shouldZoomOnFKeydown,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (ref) { ref.current = { open, zoom }; }
|
||||
}, [ref, open, zoom]);
|
||||
if (ref) { ref.current = { open, zoomTo }; }
|
||||
}, [ref, open, zoomTo]);
|
||||
|
||||
const shouldZoomTo2x = zoomLevel < 2;
|
||||
const shouldZoomTo2x = zoomLevel !== 2;
|
||||
|
||||
const button =
|
||||
<button
|
||||
className={clsx(
|
||||
isShown ? 'inline-flex' : 'hidden',
|
||||
'fixed top-[20px] right-[70px] z-[100000]',
|
||||
'fixed top-[20px] right-[70px]',
|
||||
'size-10 items-center justify-center',
|
||||
'rounded-full border-none',
|
||||
'text-white bg-black/50 hover:bg-black/85',
|
||||
)}
|
||||
onClick={() => zoom(shouldZoomTo2x ? 2 : 1)}
|
||||
onClick={() => shouldZoomTo2x ? zoomTo(2) : reset()}
|
||||
>
|
||||
{shouldZoomTo2x
|
||||
? <RiCollapseDiagonalLine className="shrink-0" size={20} />
|
||||
@ -56,9 +61,9 @@ export default function ZoomControls({
|
||||
className={clsx('h-full', isEnabled && 'cursor-zoom-in')}
|
||||
>
|
||||
{children}
|
||||
{typeof window !== 'undefined'
|
||||
? createPortal(button, document.body)
|
||||
: button}
|
||||
{viewerContainerRef.current
|
||||
? createPortal(button, viewerContainerRef.current)
|
||||
: null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -11,10 +11,12 @@ export default function useImageZoomControls(
|
||||
) {
|
||||
const viewerRef = useRef<Viewer | null>(null);
|
||||
|
||||
const viewerContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const { setShouldRespondToKeyboardCommands } = useAppState();
|
||||
|
||||
const [isShown, setIsShown] = useState(false);
|
||||
const [zoomLevel, setZoomLevel] = useState(1);
|
||||
|
||||
const [colorLight, setColorLight] = useState<string>();
|
||||
|
||||
useMetaThemeColor({ colorLight });
|
||||
@ -27,10 +29,15 @@ export default function useImageZoomControls(
|
||||
viewerRef.current?.hide();
|
||||
}, [viewerRef]);
|
||||
|
||||
const zoom = useCallback((zoomLevel = 1) => {
|
||||
const zoomTo = useCallback((zoomLevel = 1) => {
|
||||
viewerRef.current?.zoomTo(zoomLevel);
|
||||
}, [viewerRef]);
|
||||
|
||||
const reset = useCallback(() => {
|
||||
setZoomLevel(1);
|
||||
viewerRef.current?.reset();
|
||||
}, [viewerRef]);
|
||||
|
||||
// On 'F' keydown, toggle fullscreen
|
||||
const handleKeyDown = useCallback(() => {
|
||||
if (shouldExpandOnFKeydown) {
|
||||
@ -41,8 +48,6 @@ export default function useImageZoomControls(
|
||||
|
||||
useEffect(() => {
|
||||
if (imageRef.current && isEnabled) {
|
||||
const closeButton = document
|
||||
.getElementsByClassName('viewer-close')[0] as HTMLElement;
|
||||
viewerRef.current = new Viewer(imageRef.current, {
|
||||
navbar: false,
|
||||
title: false,
|
||||
@ -51,6 +56,10 @@ export default function useImageZoomControls(
|
||||
reset: 2,
|
||||
zoomOut: 3,
|
||||
},
|
||||
ready: ({ target }) => {
|
||||
viewerContainerRef.current =
|
||||
(target as any).viewer.viewer as HTMLDivElement;
|
||||
},
|
||||
url: (image: HTMLImageElement) => {
|
||||
image.loading = 'eager';
|
||||
return image.src;
|
||||
@ -58,13 +67,10 @@ export default function useImageZoomControls(
|
||||
show: () => {
|
||||
setShouldRespondToKeyboardCommands?.(false);
|
||||
setColorLight('#000');
|
||||
setIsShown(true);
|
||||
if (closeButton) { closeButton.style.display = 'none'; }
|
||||
},
|
||||
hide: () => {
|
||||
setTimeout(() => {
|
||||
setColorLight(undefined);
|
||||
setIsShown(false);
|
||||
}, 300);
|
||||
},
|
||||
hidden: () => {
|
||||
@ -73,15 +79,6 @@ export default function useImageZoomControls(
|
||||
zoom: ({ detail: { ratio } }) => {
|
||||
setZoomLevel(ratio);
|
||||
},
|
||||
view: () => {
|
||||
const container = document
|
||||
.getElementsByClassName('viewer-container')[0];
|
||||
if (container) {
|
||||
const closeButton = document
|
||||
.getElementsByClassName('viewer-close')[0] as HTMLElement;
|
||||
if (closeButton) { closeButton.style.display = 'inline-flex'; }
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return () => {
|
||||
@ -92,15 +89,16 @@ export default function useImageZoomControls(
|
||||
}, [
|
||||
imageRef,
|
||||
isEnabled,
|
||||
zoom,
|
||||
zoomTo,
|
||||
setShouldRespondToKeyboardCommands,
|
||||
]);
|
||||
|
||||
return {
|
||||
open,
|
||||
close,
|
||||
zoom,
|
||||
reset,
|
||||
zoomTo,
|
||||
zoomLevel,
|
||||
isShown,
|
||||
viewerContainerRef,
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user