// React port of ../../help.ts: the `?` overlay renders the command registry // (commands.ts) directly — the same list that dispatches the keys — so a // binding can never be documented as one thing and do another. import { useEffect, useState } from "react"; import { createPortal } from "react-dom"; import { CommandSet, defineCommands, keyCaps } from "../../commands.js"; import { groupedCommands } from "./model.js"; export function HelpOverlay() { const [open, setOpen] = useState(false); useEffect(() => { const helpKeys = new CommandSet(defineCommands({ "help.toggle": () => setOpen((o) => !o) })); const overlayKeys = new CommandSet(defineCommands({ "help.close": () => setOpen(false) })); const onKeydown = (e: KeyboardEvent) => { if (open && overlayKeys.handle(e)) return; helpKeys.handle(e); }; window.addEventListener("keydown", onKeydown); return () => window.removeEventListener("keydown", onKeydown); }, [open]); if (!open) return null; const close = () => setOpen(false); return createPortal(
{ if (e.target === e.currentTarget) close(); }} >

Keyboard shortcuts

{groupedCommands().map((group) => (

{group.title}

{group.items.map((cmd) => (
{keyCaps(cmd.keys[0]).map((cap, i) => ( {cap} ))}
{cmd.label}
))}
))}
, document.body, ); }