File size: 1,582 Bytes
0fff343
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
"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>
  );
}