Files
2026-05-27 23:29:53 +01:00

3.0 KiB

OpenSpec Change: enterprise-react-hotkeys

  • Change ID: enterprise-react-hotkeys
  • Package: @suaveplan/react-hotkeys
  • Category: react
  • Target path: react/ui/react-hotkeys
  • Status: PROPOSED
  • Date: 2026-04-24
  • Reference spec: /mnt/s/web/suaveplan/enterprise/react-hotkeys.md

Summary

Deliver @suaveplan/react-hotkeys on genesis from scratch at enterprise quality. Keyboard-shortcut primitives: useHotkey, useHotkeys, HotkeyScope, HotkeyCheatSheet, combo parser/matcher/formatter. Genesis replaces the module-level mutable registry with a useSyncExternalStore-backed store, adds sequence combos (e.g. g g), platform-aware mod key, conflict detection, prevent-in-input guard, and full Storybook + Playwright coverage.


Current-state audit (genesis)

Package does not exist on genesis — fresh build.


Available workspace deps on genesis

Package Role
@suaveplan/error (workspace:^) HotkeyError
@suaveplan/react-translate (workspace:^) i18n for cheat-sheet chrome strings
zod (catalog:forms) Hotkey binding schemas

External: tslib catalog:build. React 18 peer.


Preserved public API surface

HotkeyCheatSheet      — renders all registered entries with descriptions
HotkeyScope           — provider routing events to active scope
useHotkey(combo, handler, options?)
useHotkeys(bindings: HotkeyBinding[], options?)
useHotkeyRegistry(): HotkeyRegistryEntry[]

parseCombo(raw: string): HotkeyCombo
matchesCombo(event: KeyboardEvent, combo: HotkeyCombo): boolean
formatCombo(combo: HotkeyCombo): string

// Types
HotkeyBinding, HotkeyCombo, HotkeyOptions, HotkeyRegistryEntry, RegistryEntry

New additions for genesis

  1. useSyncExternalStore-backed registry — cheat-sheet re-renders on mount/unmount without parent re-render.
  2. Sequence combos — g g, ctrl+k ctrl+p parsed as HotkeyCombo[] array; matched against a keydown sequence buffer.
  3. Platform-aware mod key — mod expands to cmd on macOS, ctrl on Windows/Linux.
  4. Conflict detection — useHotkeys warns (via @suaveplan/error HotkeyError) when two bindings share the same scope + combo.
  5. prevent-in-input guard — options.preventDefault skips when target is INPUT, TEXTAREA, [contenteditable].
  6. Stories — HotkeyCheatSheet default + live-update, HotkeyScope scoped-routing, useHotkey playground.

File layout

react/ui/react-hotkeys/
  package.json
  tsconfig.json
  vitest.config.ts
  src/
    index.ts
    hooks/
      use-hotkey/ (ts + types + md + test + stories + index)
      use-hotkeys/ (ts + types + md + test + index)
      use-hotkey-registry/ (ts + md + test + index)
    components/
      hotkey-scope/ (tsx + types + md + test + stories + index)
      hotkey-cheat-sheet/ (tsx + types + md + test + stories + index)
    store/
      hotkey-store/ (ts + md + test + index)
    types/
      hotkey.types.ts
    utils/
      combo-parser/ (ts + md + test + index)
  e2e/
    hotkeys.spec.ts