feat(web): jump event form focus with a Mod+E field-jump sequence - #2734
Merged
Conversation
…form Lets a user editing the event form jump focus directly to a field (title/location/description/start/end/recurrence/calendar) instead of tabbing through everything. Also adds location to the existing grid e-then-letter focus sequence, which previously had no entry for it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…cut map dispatchModShiftKey copy-pasted dispatchModKey for one extra field; give dispatchModKey a shift option instead. EVENT_FORM_FIELD_JUMP_SHORTCUTS duplicated the same mapping already expressed by the 7 useAppShortcut calls with no other consumer. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Mod+Shift+R (hard reload), Mod+Shift+C (inspect element), and Mod+Shift+I (DevTools on Windows/Linux) are browser-chrome shortcuts that fire before page JS sees the keydown, so preventDefault can't suppress them - Mod+Shift+R in particular could reload the page and discard an unsaved draft. Remap recurrence/calendar/title to X/K/H, which aren't bound by any browser, and add a test covering a jump fired from inside the TipTap description editor. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Mod+Shift+letter direct chords kept colliding with real, unblockable browser-chrome shortcuts across Chrome/Firefox/Edge/Safari (hard reload, DevTools, inspect element, and even Edge's global "paste-address-bar-and-go" on the location letter), forcing non-mnemonic substitute letters. Replace with Mod+E arming a short window, then a bare t/l/d/s/e/r/c - the exact same letters and field mapping as the existing grid e-then-letter sequence, so every mnemonic is exact and there are zero browser conflicts (bare letters after a leader aren't browser shortcuts). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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.
Summary
Lets a user editing the event form jump focus directly to a field instead of Tabbing through everything: press Mod+E to arm a short window, then a bare letter (
t/l/d/s/e/r/c) jumps to title/location/description/start/end/recurrence/calendar. Works from anywhere in the form, including inside the TipTap description editor. Uses the exact same letters as the pre-existing grid-levele-then-letter sequence (EDIT_SEQUENCE_FIELDS), so both mechanisms share one mental model. Also addslocationas a jumpable field to that grid sequence, which previously had no entry (no id existed on the location input).Direct
Mod+Shift+<letter>chords were tried first and abandoned: individual letters kept colliding with real, unblockable browser-chrome shortcuts across Chrome/Firefox/Edge/Safari (hard reload, DevTools, inspect element, and Edge's global "paste address bar and go" landing on the location letter). A leader-sequence design eliminates that whole class of risk — bare letters typed after a leader keydown are never browser shortcuts, so every mnemonic stays exact.Simplicity
The new hook (
useEventFormFieldJumpShortcuts.ts) is a direct port of the existing grid sequence's arm/disarm/keyup-suppression state machine, differing only in arming on Mod+E instead of bareeand not bailing on editable targets (the whole point is firing while a form field has focus). It imports the grid hook'sEDIT_SEQUENCE_FIELDSmap as the single source of truth for letter-to-field mapping rather than duplicating it. An earlier draft carried an unusedEVENT_FORM_FIELD_JUMP_SHORTCUTSconst with no consumer and a duplicated test-dispatch helper; both were removed during a/simplifypass.Automated validation
Verified in a real browser preview (
bun run dev:web, anon "Start Now" session, no backend needed):l→ focus moved to Location, both the leader and follow keydown haddefaultPrevented: true.t→ focus moved back to Title.lwith no leader → not intercepted (defaultPrevented: false), confirming normal typing is untouched.Independent review
Ran a fresh, diff-first
feature-dev:code-reviewerpass against the final 4-commit diff with no context from the implementation session. Result: no blocking or major (≥80 confidence) findings. One minor observation (~65% confidence, explicitly non-blocking): the new hook and the grid'suseEditSequenceShortcutboth attachdocument-level capture-phase keydown listeners withoutstopImmediatePropagation, so if focus is on a non-editable form control (e.g. a button) when the Mod+E-then-e("end") sequence fires, the grid hook could also interpret the bareeas its own leader and arm for 600ms — narrow, non-crashing, no fix applied.An earlier review pass on the (now-superseded) direct-chord version caught: a duplicated test-dispatch helper, an unused shortcut-map const, and — the reason for the full mechanism swap — Mod+Shift+R/C/I colliding with browser reload/DevTools, and Mod+Shift+L colliding with Edge's global paste-and-go. All resolved by moving to the leader-sequence design.
Test plan
74/74 tests passing, type-check clean, lint clean.
🤖 Generated with Claude Code