feat(keyboard): leader-sequence runtime in the keymap dispatcher (RIG-2709) - #616
Open
rigel-mintaka wants to merge 1 commit into
Open
Conversation
This was referenced Aug 25, 2026
|
Compass engineering docs preview: https://compass-ux-rig-2709-leader-r.compass-eng-docs.pages.dev Deployed from |
…-2709) Arm-and-complete "press G, then <key>" sequences inside the one `keydown` handler `installKeymap` already owns — no second listener, no module global. - Per-install `pending` leader state + a `disarm()` that clears the live timeout; leader set is `leaderPrefixes(DEFAULT_KEYMAP, platform)`, computed once at install (table-derived, never hard-coded). - Per-keydown order (§A3): normalize → editable-guard FIRST (modifier-less keys only) → completion (pure-modifier keys ignored, Escape disarms+consumes, else disarm then resolve the `"<leader> <chord>"` sequence rows; a dead sequence falls through and re-enters arming) → arming (leader prefix, no command modifier, not `event.repeat`; preventDefault+stopPropagation) → single-chord path (unchanged). - Tier resolution factored into a `resolve(matching, event)` closure so a completed sequence and a single chord run byte-identical (active group → scoped → global, scope gate intact). - `isEditableTarget` extended to `HTMLSelectElement` and `[role=combobox|listbox|menu]` so a bare leader key never steals native `<select>` typeahead or an ARIA widget's keys. - Uninstaller clears any live disarm timer (no leak against a torn-down closure on test teardown / HMR). - `LEADER_TIMEOUT_MS = 1000` (OQ1 ratified) exported for runtime + tests. Also folds the two deferred RIG-2707 review lows into `leaderPrefixes`'s unit coverage (first runtime caller): per-platform resolution of a `Mod` leader segment, and distinct-leader accumulation with same-leader dedup. Tests: dispatch.test.ts + keyboard-e2e.test.tsx (51 pass) cover arm/complete, timeout disarm, editable + `<select>` + ARIA-widget guards, dead-sequence fall-through, re-arm, Escape, lone-Shift-does-not-disarm, Mod+B-mid-sequence disarm-and-resolve, held-key no-arm, and uninstall-clears-timer; the two e2e cases drive `G S`/`G L` through real App wiring. keymap.test.ts 20 pass. Ledger-impact: none (decisions landed with the design PR #544; DL-248..252). RIG-2709
rigel-mintaka
force-pushed
the
compass-ux/rig-2709-leader-runtime
branch
from
August 25, 2026 18:25
c956910 to
761ad0f
Compare
rigel-mintaka
marked this pull request as ready for review
August 25, 2026 18:38
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR is part of a stack containing 4 PRs:
mainArm-and-complete "press G, then " sequences inside the one
keydownhandler
installKeymapalready owns — no second listener, no module global.pendingleader state + adisarm()that clears the livetimeout; leader set is
leaderPrefixes(DEFAULT_KEYMAP, platform), computedonce at install (table-derived, never hard-coded).
keys only) → completion (pure-modifier keys ignored, Escape disarms+consumes,
else disarm then resolve the
"<leader> <chord>"sequence rows; a deadsequence falls through and re-enters arming) → arming (leader prefix,
no command modifier, not
event.repeat; preventDefault+stopPropagation) →single-chord path (unchanged).
resolve(matching, event)closure so acompleted sequence and a single chord run byte-identical (active group →
scoped → global, scope gate intact).
isEditableTargetextended toHTMLSelectElementand[role=combobox|listbox|menu]so a bare leader key never steals native<select>typeahead or an ARIA widget's keys.closure on test teardown / HMR).
LEADER_TIMEOUT_MS = 1000(OQ1 ratified) exported for runtime + tests.Also folds the two deferred RIG-2707 review lows into
leaderPrefixes's unitcoverage (first runtime caller): per-platform resolution of a
Modleadersegment, and distinct-leader accumulation with same-leader dedup.
Tests: dispatch.test.ts + keyboard-e2e.test.tsx (51 pass) cover arm/complete,
timeout disarm, editable +
<select>+ ARIA-widget guards, dead-sequencefall-through, re-arm, Escape, lone-Shift-does-not-disarm, Mod+B-mid-sequence
disarm-and-resolve, held-key no-arm, and uninstall-clears-timer; the two e2e
cases drive
G S/G Lthrough real App wiring. keymap.test.ts 20 pass.Ledger-impact: none (decisions landed with the design PR #544; DL-248..252).
RIG-2709