diff --git a/src/components/FullscreenButton.tsx b/src/components/FullscreenButton.tsx deleted file mode 100644 index 96a1a053..00000000 --- a/src/components/FullscreenButton.tsx +++ /dev/null @@ -1,69 +0,0 @@ -'use client'; - -import { useEffect, useCallback, RefObject } from 'react'; -import { MdFullscreen, MdFullscreenExit } from 'react-icons/md'; -import { clsx } from 'clsx/lite'; -import { useAppState } from '@/state/AppState'; -import LoaderButton from './primitives/LoaderButton'; - -export default function FullscreenButton({ - className, - imageRef, -}: { - className?: string; - imageRef: RefObject; -}) { - const { isFullscreen, setIsFullscreen, isCommandKOpen } = useAppState(); - - // Toggle fullscreen mode - const toggleFullscreen = useCallback(async () => { - if (!document.fullscreenElement) { - if (isCommandKOpen) return; - await imageRef.current?.requestFullscreen(); - setIsFullscreen?.(true); - } else { - await document.exitFullscreen(); - setIsFullscreen?.(false); - } - }, [imageRef, setIsFullscreen, isCommandKOpen]); - - // Toggle fullscreen on 'f' key press - const handleKeyDown = useCallback((event: KeyboardEvent) => { - if (event.key === 'f' || event.key === 'F') { - toggleFullscreen(); - } - }, [toggleFullscreen]); - - // Handle fullscreen change (e.g, switching tabs in fullscreen mode) - const handleFullscreenChange = useCallback(() => { - if (!document.fullscreenElement) { - setIsFullscreen?.(false); - } - }, [setIsFullscreen]); - - useEffect(() => { - document.addEventListener('keydown', handleKeyDown); - document.addEventListener('fullscreenchange', handleFullscreenChange); - - return () => { - document.removeEventListener('keydown', handleKeyDown); - document.removeEventListener('fullscreenchange', handleFullscreenChange); - }; - }, [handleKeyDown, handleFullscreenChange]); - - return ( - - : } - spinnerColor="light-gray" - styleAs="link" - onClick={toggleFullscreen} - /> - ); -} diff --git a/src/components/image/useImageZoomControls.ts b/src/components/image/useImageZoomControls.ts index 324c639c..f4e9b80f 100644 --- a/src/components/image/useImageZoomControls.ts +++ b/src/components/image/useImageZoomControls.ts @@ -1,12 +1,19 @@ -import { RefObject, useEffect, useRef } from 'react'; +import { useAppState } from '@/state/AppState'; +import { RefObject, useCallback, useEffect, useRef } from 'react'; import Viewer from 'viewerjs'; +const EVENT_SHOWN = 'shown'; +const EVENT_HIDDEN = 'hidden'; +const EVENT_KEYDOWN = 'keydown'; + export default function useImageZoomControls( imageRef: RefObject, isEnabled?: boolean, ) { const viewerRef = useRef(null); + const { isCommandKOpen, setShouldRespondToKeyboardCommands } = useAppState(); + useEffect(() => { if (imageRef.current && isEnabled) { viewerRef.current = new Viewer(imageRef.current, { @@ -26,4 +33,41 @@ export default function useImageZoomControls( }; } }, [imageRef, isEnabled]); + + // On shown, disable keyboard commands + const onShown = useCallback(() => + setShouldRespondToKeyboardCommands?.(false), + [setShouldRespondToKeyboardCommands]); + useEffect(() => { + const imageRefCurrent = imageRef.current; + imageRefCurrent?.addEventListener(EVENT_SHOWN, onShown); + return () => { + imageRefCurrent?.removeEventListener(EVENT_SHOWN, onShown); + }; + }, [imageRef, onShown]); + + // On hide, reenable keyboard commands + const onHide = useCallback(() => + setShouldRespondToKeyboardCommands?.(true), + [setShouldRespondToKeyboardCommands]); + useEffect(() => { + const imageRefCurrent = imageRef.current; + imageRefCurrent?.addEventListener(EVENT_HIDDEN, onHide); + return () => { + imageRefCurrent?.removeEventListener(EVENT_HIDDEN, onHide); + }; + }, [imageRef, onHide]); + + // On 'F' keydown, toggle fullscreen + const handleKeyDown = useCallback((e: KeyboardEvent) => { + if (!isCommandKOpen && e.key.toUpperCase() === 'F') { + viewerRef.current?.show(); + } + }, [isCommandKOpen]); + useEffect(() => { + document.addEventListener(EVENT_KEYDOWN, handleKeyDown); + return () => { + document.removeEventListener(EVENT_KEYDOWN, handleKeyDown); + }; + }, [handleKeyDown]); } diff --git a/src/state/AppState.ts b/src/state/AppState.ts index 9dcde3ca..69975e9e 100644 --- a/src/state/AppState.ts +++ b/src/state/AppState.ts @@ -39,9 +39,6 @@ export interface AppStateContext { setShouldDebugImageFallbacks?: Dispatch> shouldShowBaselineGrid?: boolean setShouldShowBaselineGrid?: Dispatch> - // FULLSCREEN - isFullscreen?: boolean - setIsFullscreen?: Dispatch> } export const AppStateContext = createContext({}); diff --git a/src/state/AppStateProvider.tsx b/src/state/AppStateProvider.tsx index 0f04d631..e8619fec 100644 --- a/src/state/AppStateProvider.tsx +++ b/src/state/AppStateProvider.tsx @@ -52,9 +52,6 @@ export default function AppStateProvider({ useState(false); const [shouldShowBaselineGrid, setShouldShowBaselineGrid] = useState(false); - // FULLSCREEN - const [isFullscreen, setIsFullscreen] = - useState(false); const invalidateSwr = useCallback(() => setSwrTimestamp(Date.now()), []); @@ -125,9 +122,6 @@ export default function AppStateProvider({ setShouldDebugImageFallbacks, shouldShowBaselineGrid, setShouldShowBaselineGrid, - // FULLSCREEN - isFullscreen, - setIsFullscreen, }} > {children}