/**
* The global keyboard map (weave-workspace §11 P4).
*
* > Global keys: `⌘K` search, `⌘1/2/3` focus column, `/` filter tree, `g` fit
* > graph, `?` help, `Esc` clear selection. Vim-ish `j/k` in the tree.
* > *Exit: the whole workspace is drivable without a mouse.*
*
* One pure function, {@link shellKey}, maps an **event descriptor** and a
* **context** to an action or to `null`. Nothing here listens, nothing here
* calls `preventDefault`, and nothing here knows what a `KeyboardEvent` is —
* {@link KeyDescriptor} is five booleans and a string. `keys.ts` does the
* subscribing and `Shell.tsx` does the dispatching, which is what makes the
* whole keymap coverable without a DOM (§10).
*
* ## `null` means "the browser keeps it", and it is the important case
*
* This is `treeKey`'s `handled: false` contract, promoted to the document.
* The stakes are higher here: `treeKey` sits on one column, while this
* handler sees **every** keystroke in the workspace. A global handler that
* swallows Tab traps keyboard users; one that swallows ⌘R breaks reload; one
* that fires `g` while a user is typing "graph" into the filter box makes
* text entry impossible. So the default is `null` and every claim is narrow:
*
* | | Claimed when |
* | --- | --- |
* | `⌘K` / `Ctrl K` | always — a modifier shortcut is unambiguous even mid-word |
* | `⌘1` `⌘2` `⌘3` | always |
* | `Esc` | an overlay is open, or something is selected. Never otherwise |
* | `/` `g` `?` `t` | **only** when focus is not in a text field and no overlay is open |
*
* `j` / `k` are not here at all: they are tree-scoped, so they live in
* `tree.model.ts`'s `normalizeTreeKey` where the tree's own handler applies
* them — a global `j` would move the tree selection while the user is looking
* at the graph.
*
* ## While an overlay is open, the global map is one key wide
*
* The palette contains a text input and its own listbox navigation, and the
* help sheet is a trap the user must be able to leave. Anything beyond
* `Escape` reaching the document from inside a modal is a bug — most sharply
* `⌘K`, which would otherwise re-open the palette on top of itself.
*/
import { COLUMNS, type ColumnId, type OverlayId } from "./shell.model";
// --- the event, without the DOM ---------------------------------------------------
/**
* A keystroke, reduced to what a decision needs.
*
* `typing` rather than a target element: whether focus sits in a text field
* is the only property of the target this map cares about, and passing the
* element would drag `HTMLElement` into a module the root `tsconfig.json`
* project compiles.
*/
export interface KeyDescriptor {
/** `KeyboardEvent.key` — `"k"`, `"Escape"`, `"/"`, `"?"`. */
readonly key: string;
readonly ctrl: boolean;
readonly meta: boolean;
readonly shift: boolean;
readonly alt: boolean;
/** Focus is in an ``, `