From 0db18f1e949deb5eaf2d8701edcbf8008b8f9cca Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 8 Mar 2025 16:37:27 +0200 Subject: [PATCH] web/modal: allow non-dismissable modals --- web/src/ui/modal/Modal.tsx | 20 +++++++++++--------- web/src/ui/modal/contexts.ts | 1 + web/src/vite-env.d.ts | 1 + 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/web/src/ui/modal/Modal.tsx b/web/src/ui/modal/Modal.tsx index 1188cd1..ff5fc9d 100644 --- a/web/src/ui/modal/Modal.tsx +++ b/web/src/ui/modal/Modal.tsx @@ -29,7 +29,7 @@ const ModalWrapper = ({ children, ContextType, historyStateKey }: ModalWrapperPr return newState }, null) const onClickWrapper = useCallback((evt?: React.MouseEvent) => { - if (evt && evt.target !== evt.currentTarget) { + if (evt && (evt.target !== evt.currentTarget || state?.noDismiss)) { return } evt?.stopPropagation() @@ -37,9 +37,9 @@ const ModalWrapper = ({ children, ContextType, historyStateKey }: ModalWrapperPr if (history.state?.[historyStateKey]) { history.back() } - }, [historyStateKey]) + }, [historyStateKey, state]) const onKeyWrapper = (evt: React.KeyboardEvent) => { - if (evt.key === "Escape") { + if (evt.key === "Escape" && !state?.noDismiss) { setState(null) if (history.state?.[historyStateKey]) { history.back() @@ -55,12 +55,17 @@ const ModalWrapper = ({ children, ContextType, historyStateKey }: ModalWrapperPr }, [historyStateKey]) const wrapperRef = useRef(null) useLayoutEffect(() => { + window.closeModal = onClickWrapper + if (historyStateKey === "nestable_modal") { + window.openNestableModal = openModal + } else { + window.openModal = openModal + } if (wrapperRef.current && (!document.activeElement || !wrapperRef.current.contains(document.activeElement))) { wrapperRef.current.focus() } - }, [state]) + }, [state, onClickWrapper, historyStateKey, openModal]) useEffect(() => { - window.closeModal = onClickWrapper const listener = (evt: PopStateEvent) => { if (!evt.state?.[historyStateKey]) { setState(null) @@ -68,7 +73,7 @@ const ModalWrapper = ({ children, ContextType, historyStateKey }: ModalWrapperPr } window.addEventListener("popstate", listener) return () => window.removeEventListener("popstate", listener) - }, [historyStateKey, onClickWrapper]) + }, [historyStateKey]) let modal: JSX.Element | null = null if (state) { let content = @@ -97,9 +102,6 @@ const ModalWrapper = ({ children, ContextType, historyStateKey }: ModalWrapperPr modal = content } } - if (historyStateKey === "nestable_modal") { - window.openNestableModal = openModal - } return {children} {modal} diff --git a/web/src/ui/modal/contexts.ts b/web/src/ui/modal/contexts.ts index 083a039..03e3013 100644 --- a/web/src/ui/modal/contexts.ts +++ b/web/src/ui/modal/contexts.ts @@ -33,6 +33,7 @@ export interface ModalState { innerBoxClass?: string onClose?: () => void captureInput?: boolean + noDismiss?: boolean } export type openModal = (state: ModalState) => void diff --git a/web/src/vite-env.d.ts b/web/src/vite-env.d.ts index 19f446a..7b6f3e6 100644 --- a/web/src/vite-env.d.ts +++ b/web/src/vite-env.d.ts @@ -17,6 +17,7 @@ declare global { gcSettings: GCSettings hackyOpenEventContextMenu?: string closeModal: () => void + openModal: openModal openNestableModal: openModal gomuksAndroid?: true }