From d5b8fbe40806fc982102e827e485da9e8ba6e9f9 Mon Sep 17 00:00:00 2001 From: Pas <74743263+Pasithea0@users.noreply.github.com> Date: Mon, 29 Sep 2025 15:56:48 -0600 Subject: [PATCH] Feat: close any modal with esc --- src/components/overlays/OverlayDisplay.tsx | 2 +- src/hooks/useGlobalKeyboardEvents.ts | 38 ++++++++++++++++++++++ src/setup/App.tsx | 2 ++ 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 src/hooks/useGlobalKeyboardEvents.ts diff --git a/src/components/overlays/OverlayDisplay.tsx b/src/components/overlays/OverlayDisplay.tsx index 9143094d..e7232b3a 100644 --- a/src/components/overlays/OverlayDisplay.tsx +++ b/src/components/overlays/OverlayDisplay.tsx @@ -140,7 +140,7 @@ export function OverlayPortal(props: { clickOutsideDeactivates: true, fallbackFocus: () => document.body, returnFocusOnDeactivate: true, - escapeDeactivates: true, + escapeDeactivates: false, // Let our keyboard handler manage escape preventScroll: true, // Disable the problematic check that causes the matches.call error checkCanFocusTrap: () => Promise.resolve(), diff --git a/src/hooks/useGlobalKeyboardEvents.ts b/src/hooks/useGlobalKeyboardEvents.ts new file mode 100644 index 00000000..a917aeda --- /dev/null +++ b/src/hooks/useGlobalKeyboardEvents.ts @@ -0,0 +1,38 @@ +import { useEffect } from "react"; + +import { useOverlayStack } from "@/stores/interface/overlayStack"; + +/** + * Global keyboard event handler that works across the entire application. + * Handles Escape key to close modals and other global shortcuts. + */ +export function useGlobalKeyboardEvents() { + const { getTopModal, hideModal } = useOverlayStack(); + + useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + // Don't handle keyboard events if user is typing in an input + if ( + event.target && + (event.target as HTMLInputElement).nodeName === "INPUT" + ) { + return; + } + + // Handle Escape key to close modals + if (event.key === "Escape") { + const topModal = getTopModal(); + if (topModal) { + hideModal(topModal); + } + } + }; + + // Add event listener to document for global coverage + document.addEventListener("keydown", handleKeyDown); + + return () => { + document.removeEventListener("keydown", handleKeyDown); + }; + }, [getTopModal, hideModal]); +} diff --git a/src/setup/App.tsx b/src/setup/App.tsx index e026b533..3917d548 100644 --- a/src/setup/App.tsx +++ b/src/setup/App.tsx @@ -12,6 +12,7 @@ import { import { convertLegacyUrl, isLegacyUrl } from "@/backend/metadata/getmeta"; import { generateQuickSearchMediaUrl } from "@/backend/metadata/tmdb"; import { NotificationModal } from "@/components/overlays/notificationsModal"; +import { useGlobalKeyboardEvents } from "@/hooks/useGlobalKeyboardEvents"; import { useOnlineListener } from "@/hooks/usePing"; import { AboutPage } from "@/pages/About"; import { AdminPage } from "@/pages/admin/AdminPage"; @@ -100,6 +101,7 @@ export const maintenanceTime = "March 31th 11:00 PM - 5:00 AM EST"; function App() { useHistoryListener(); useOnlineListener(); + useGlobalKeyboardEvents(); const maintenance = false; // Shows maintance page const [showDowntime, setShowDowntime] = useState(maintenance);