canvas/docs/plan-keyboard-gesture-integration.md
2026-03-11 18:42:08 -07:00

2.7 KiB

Keyboard Integration as Shared Input, Not as Gesture

Decision

Keyboard is not a GestureType.

v2 treats pointer gestures and keyboard events as parallel input streams that share:

  • one context stack
  • one resolver
  • one action dispatcher
  • one provider-owned keyboard listener per active canvas

Runtime Shape

  • Pointer stays gesture-native:
    • tap
    • double-tap
    • triple-tap
    • long-press
    • drag
    • pinch
    • scroll
  • Keyboard uses a separate event shape:
    • kind: 'key'
    • phase: 'down' | 'up'
    • key
    • code
    • repeat
  • Shared runtime event union:
    • PointerGestureEvent
    • KeyInputEvent
    • InputEvent
  • Held keyboard state is explicit:
    • heldKeys.byKey
    • heldKeys.byCode
  • Pointer events carry a held-key snapshot so bindings like Space+drag are modeled as pointer gestures with keyboard context.

Resolver Rules

  • Pointer patterns still match pointer gesture types.
  • Keyboard patterns match phase, key, and/or code.
  • key score: +64
  • code score: +64
  • held-key positive score: +16
  • held-key negative score: +8
  • If both key and code are present, both must match.

Ownership

  • InputProvider is the single keyboard owner for the active canvas.
  • The last canvas root to receive pointer interaction or focus becomes keyboard-active.
  • Keyboard routing is suppressed when:
    • target is input
    • target is textarea
    • target is contentEditable
    • IME composition is active
  • Held keys clear on blur and visibilitychange.

Default Behavior

  • / opens command line
  • Cmd/Ctrl+F opens search
  • Cmd/Ctrl+C/X/V/D route through shared input actions
  • Cmd/Ctrl+Z, Cmd/Ctrl+Shift+Z, Cmd/Ctrl+Y route through shared input actions
  • Delete / Backspace delete current selection
  • Escape precedence:
    1. cancel active interaction
    2. exit keyboard manipulate mode
    3. clear search / selection / close palette
  • keyboardInteractionMode is explicit:
    • 'navigate'
    • 'manipulate'
  • Navigate mode:
    • arrows move focus
    • Enter selects and enters manipulate mode
    • Space activates focused node
    • Tab cycles focus
  • Manipulate mode:
    • arrows nudge selection by 10
    • Shift+Arrow nudges by 50
    • Escape returns to navigate mode

Cutoff

  • Remove keyboard ownership from:
    • packages/canvas/src/commands/keyboard.ts
    • packages/canvas/src/hooks/useCanvasHistory.ts
    • packages/canvas/src/hooks/useArrowKeyNavigation.ts
  • Keep those exports as compatibility shims only if needed for callers during the repo migration.

Verification

  • resolver tests for key/code/held-key matching
  • runtime tests for Space+drag, Escape, copy/paste, undo/redo, and active-canvas ownership
  • behavior tests for navigate vs manipulate mode