Spaces:
Sleeping
Sleeping
| "use client"; | |
| import { | |
| createContext, | |
| ReactNode, | |
| useCallback, | |
| useContext, | |
| useRef, | |
| useState, | |
| } from "react"; | |
| import { PARAM_HELP, ParamKey } from "./paramHelpContent"; | |
| import ParamHelpModal from "./ParamHelpModal"; | |
| type Ctx = { | |
| open: (key: ParamKey, returnFocusTo?: HTMLElement | null) => void; | |
| close: () => void; | |
| current: ParamKey | null; | |
| }; | |
| const ParamHelpCtx = createContext<Ctx | null>(null); | |
| export function useParamHelp(): Ctx { | |
| const ctx = useContext(ParamHelpCtx); | |
| if (!ctx) { | |
| throw new Error( | |
| "useParamHelp(): ParamHelpProvider missing — wrap the page once near the root.", | |
| ); | |
| } | |
| return ctx; | |
| } | |
| export default function ParamHelpProvider({ children }: { children: ReactNode }) { | |
| const [current, setCurrent] = useState<ParamKey | null>(null); | |
| const returnRef = useRef<HTMLElement | null>(null); | |
| const open = useCallback( | |
| (key: ParamKey, returnFocusTo: HTMLElement | null = null) => { | |
| returnRef.current = returnFocusTo; | |
| setCurrent(key); | |
| }, | |
| [], | |
| ); | |
| const close = useCallback(() => { | |
| setCurrent(null); | |
| const target = returnRef.current; | |
| if (target) { | |
| // Defer focus to the next tick so the modal has unmounted. | |
| setTimeout(() => { | |
| try { | |
| target.focus(); | |
| } catch { | |
| /* ignore */ | |
| } | |
| }, 0); | |
| } | |
| }, []); | |
| return ( | |
| <ParamHelpCtx.Provider value={{ open, close, current }}> | |
| {children} | |
| {current && ( | |
| <ParamHelpModal entry={PARAM_HELP[current]} onClose={close} /> | |
| )} | |
| </ParamHelpCtx.Provider> | |
| ); | |
| } | |