feat(web): keyboard shortcut registry + useShortcut hook #1018

Closed
opened 2026-05-09 18:18:25 +00:00 by claude-desktop · 1 comment
Collaborator

As a developer wiring keyboard behaviour,
I want a single typed registry of every keyboard shortcut + a useShortcut hook that consumes it,
so that the upcoming <ShortcutOverlay> (#nav-v2-8) and runtime hooks read the same source-of-truth and never drift.

Resolves the "drift between docs and behaviour" risk called out during spec review.

Acceptance criteria

Registry

  • apps/web/src/lib/shortcuts.ts exports interface ShortcutDef { keys: string[]; label: string; scope: ShortcutScope; description?: string }.
  • SHORTCUTS: ShortcutDef[] constant lists every shortcut in the app, grouped by scope (global, board, agents, flows, …).
  • Initial scopes seeded: global (?, g h, g b, g a, g w, g f, [, Esc), board (h j k l, a, r, /).

Hook

  • useShortcut(scope: ShortcutScope, handler: (def: ShortcutDef, e: KeyboardEvent) => void) subscribes for the page lifetime.
  • Shift+/ matches ?. AZERTY chord alias g h matches the same overlay.
  • Inputs / textareas / [contenteditable] are excluded from key matching unless the shortcut is explicitly scoped to inputs.
  • Chord support (g b) with 1 s timeout; chord state visible (no UI yet, but a useChordState returns the buffered prefix).

Refactor

  • apps/web/src/components/board/use-board-keymap.ts rewritten to consume the registry instead of inlining key strings.
  • No behavioural change in the board page (existing tests still pass).

Tests

  • Unit tests cover: scope filter, modifier keys, input-element exclusion, chord timeout, AZERTY alias.

Out of scope

  • Building the overlay UI (#nav-v2-8).
  • Adding go-to-route navigation handlers (g b etc.) — registry only declares the shortcuts; runtime wiring lands with the sidebar (#nav-v2-5).

References

  • Spec: docs/specs/nav-consolidation.md § Global keyboard shortcut overlay.
  • Existing keymap to fold in: apps/web/src/components/board/use-board-keymap.ts.
**As a** developer wiring keyboard behaviour, **I want** a single typed registry of every keyboard shortcut + a `useShortcut` hook that consumes it, **so that** the upcoming `<ShortcutOverlay>` (#nav-v2-8) and runtime hooks read the same source-of-truth and never drift. Resolves the "drift between docs and behaviour" risk called out during spec review. ## Acceptance criteria ### Registry - [ ] `apps/web/src/lib/shortcuts.ts` exports `interface ShortcutDef { keys: string[]; label: string; scope: ShortcutScope; description?: string }`. - [ ] `SHORTCUTS: ShortcutDef[]` constant lists every shortcut in the app, grouped by scope (`global`, `board`, `agents`, `flows`, …). - [ ] Initial scopes seeded: `global` (`?`, `g h`, `g b`, `g a`, `g w`, `g f`, `[`, `Esc`), `board` (`h j k l`, `a`, `r`, `/`). ### Hook - [ ] `useShortcut(scope: ShortcutScope, handler: (def: ShortcutDef, e: KeyboardEvent) => void)` subscribes for the page lifetime. - [ ] `Shift+/` matches `?`. AZERTY chord alias `g h` matches the same overlay. - [ ] Inputs / textareas / `[contenteditable]` are excluded from key matching unless the shortcut is explicitly scoped to inputs. - [ ] Chord support (`g b`) with 1 s timeout; chord state visible (no UI yet, but a `useChordState` returns the buffered prefix). ### Refactor - [ ] `apps/web/src/components/board/use-board-keymap.ts` rewritten to consume the registry instead of inlining key strings. - [ ] No behavioural change in the board page (existing tests still pass). ### Tests - [ ] Unit tests cover: scope filter, modifier keys, input-element exclusion, chord timeout, AZERTY alias. ## Out of scope - Building the overlay UI (#nav-v2-8). - Adding go-to-route navigation handlers (`g b` etc.) — registry only declares the shortcuts; runtime wiring lands with the sidebar (#nav-v2-5). ## References - Spec: `docs/specs/nav-consolidation.md` § Global keyboard shortcut overlay. - Existing keymap to fold in: `apps/web/src/components/board/use-board-keymap.ts`.
claude-desktop added this to the nav-v2 milestone 2026-05-09 18:18:25 +00:00
Collaborator

🧹 janitor: this ticket has been idle-assigned since 2026-05-09T20:59:58.000Z. Re-dispatching.

🧹 janitor: this ticket has been idle-assigned since 2026-05-09T20:59:58.000Z. Re-dispatching.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/claude-hooks#1018
No description provided.