Registry letting the canvas expose actions to the App-level command
palette without lifting its internal state (drawer visibility, save
handler) into App. GraphCanvas registers on mount and unregisters on
unmount.
has() is not "is the editor open?": the registration hooks sit above
GraphCanvas's if (!policy) early return (hook order must not vary across
renders), so a canvas mounted with policy={null} — App's state whenever
nothing is selected — still registers. Commands that require a real graph
pair has() with CommandContext.editorOpen (see commands.ts).
This registry is intentionally not reactive: register/its returned
cleanup are side-effectful mutations of a plain Map ref, and invoke/
has are live reads of that ref — none of them trigger a re-render, and
none of them need to. has(id) reflects whatever is registered at the
moment some other render calls it (e.g. CommandPalette re-evaluating
when() on every keystroke, or App re-rendering for any of its own
reasons); nothing here re-renders App or the palette just because a
registration changed. An earlier version bumped a useState counter on
every register/unregister specifically to force such a re-render, but
paired with a memoized context value (needed to stop the registration
effect in useRegisterEditorAction from re-firing on every provider
render — see git history) that counter became a state update with no
observer: the memoized value and children are both referentially
stable, so React bails out of re-rendering anything below the Provider
on a bump. It was dead weight, not a bug fix, so it's gone.
Registry letting the canvas expose actions to the App-level command palette without lifting its internal state (drawer visibility, save handler) into App. GraphCanvas registers on mount and unregisters on unmount.
has()is not "is the editor open?": the registration hooks sit above GraphCanvas'sif (!policy)early return (hook order must not vary across renders), so a canvas mounted withpolicy={null}— App's state whenever nothing is selected — still registers. Commands that require a real graph pairhas()withCommandContext.editorOpen(see commands.ts).This registry is intentionally not reactive:
register/its returned cleanup are side-effectful mutations of a plainMapref, andinvoke/hasare live reads of that ref — none of them trigger a re-render, and none of them need to.has(id)reflects whatever is registered at the moment some other render calls it (e.g. CommandPalette re-evaluatingwhen()on every keystroke, or App re-rendering for any of its own reasons); nothing here re-renders App or the palette just because a registration changed. An earlier version bumped auseStatecounter on every register/unregister specifically to force such a re-render, but paired with a memoized context value (needed to stop the registration effect inuseRegisterEditorActionfrom re-firing on every provider render — see git history) that counter became a state update with no observer: the memoized value andchildrenare both referentially stable, so React bails out of re-rendering anything below the Provider on a bump. It was dead weight, not a bug fix, so it's gone.