ChemPal Documentation - v0.0.13-beta.5
    Preparing search index...

    Function useHotkeys

    • Installs a single global keydown listener on document that dispatches to the supplied handler map based on the application's hotkey config.

      The hook is intentionally generic: it has no knowledge of the concrete actions. Callers pass a handlers map keyed by the id field from config.json, and the hook takes care of:

      • Skipping events originating from inputs / textareas / contentEditable hosts
      • Matching modifier combos strictly (so ctrl+s won't fire on ctrl+shift+s)
      • Calling preventDefault + stopPropagation when a binding fires
      • Awaiting async handlers and logging any errors

      Parameters

      Returns void

      useHotkeys(
      { showHotkeyHelp: () => setHelpOpen(true) },
      { onTriggered: (cfg) => cfg.flash && flashStatusText(cfg.flash) },
      );
      export function useHotkeys(handlers: HotkeyHandlers, options: UseHotkeysOptions = {}): void {
      const compiled = useMemo(() => compile(hotkeysConfig as HotkeyConfig[]), []);
      const { onTriggered } = options;

      useEffect(() => {
      const onKeyDown = (event: KeyboardEvent) => {
      if (isEditableTarget(event)) return;

      for (const { config, binding } of compiled) {
      if (!matches(event, binding)) continue;
      const handler = handlers[config.id];
      if (!handler) continue;

      event.preventDefault();
      event.stopPropagation();

      try {
      const result = handler();
      if (result instanceof Promise) {
      result.catch((error) => {
      console.error(`Hotkey handler "${config.id}" failed`, { error });
      });
      }
      onTriggered?.(config);
      } catch (error) {
      console.error(`Hotkey handler "${config.id}" threw`, { error });
      }
      return;
      }
      };

      document.addEventListener("keydown", onKeyDown);
      return () => document.removeEventListener("keydown", onKeyDown);
      }, [compiled, handlers, onTriggered]);
      }