Skip to content

feat(web): jump event form focus with a Mod+E field-jump sequence - #2734

Merged
tyler-dane merged 4 commits into
mainfrom
claude/event-form-keyboard-shortcuts-b97b5e
Aug 10, 2026
Merged

feat(web): jump event form focus with a Mod+E field-jump sequence#2734
tyler-dane merged 4 commits into
mainfrom
claude/event-form-keyboard-shortcuts-b97b5e

Conversation

@tyler-dane

Copy link
Copy Markdown
Contributor

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-level e-then-letter sequence (EDIT_SEQUENCE_FIELDS), so both mechanisms share one mental model. Also adds location as 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 bare e and not bailing on editable targets (the whole point is firing while a form field has focus). It imports the grid hook's EDIT_SEQUENCE_FIELDS map as the single source of truth for letter-to-field mapping rather than duplicating it. An earlier draft carried an unused EVENT_FORM_FIELD_JUMP_SHORTCUTS const with no consumer and a duplicated test-dispatch helper; both were removed during a /simplify pass.

Automated validation

Verified in a real browser preview (bun run dev:web, anon "Start Now" session, no backend needed):

  • Opened an event form, focused Title, dispatched Mod+E then l → focus moved to Location, both the leader and follow keydown had defaultPrevented: true.
  • From inside the TipTap description editor, Mod+E then t → focus moved back to Title.
  • A bare l with no leader → not intercepted (defaultPrevented: false), confirming normal typing is untouched.
  • Shortcuts help overlay renders all 7 new "Jump to ..." rows under Edit, each showing a grouped ⌘E chip followed by the field's letter chip.

Independent review

Ran a fresh, diff-first feature-dev:code-reviewer pass 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's useEditSequenceShortcut both attach document-level capture-phase keydown listeners without stopImmediatePropagation, 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 bare e as 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

bun run type-check
./node_modules/.bin/biome check packages/web/src/common/utils/form/form.util.ts packages/web/src/common/utils/form/form.util.test.ts packages/web/src/views/Forms/EventForm/EventForm.tsx packages/web/src/views/Forms/EventForm/EventForm.test.tsx packages/web/src/views/Forms/hooks/useEventFormFieldJumpShortcuts.ts packages/web/src/shortcuts/useEditSequenceShortcut.ts packages/web/src/shortcuts/useEditSequenceShortcut.test.tsx packages/web/src/shortcuts/shortcuts.registry.ts packages/web/src/shortcuts/shortcuts.registry.test.ts packages/web/src/grid/shortcuts/useGridEventFormFieldSequences.ts
cd packages/web && TZ=Etc/UTC NODE_ENV=test PORT=3000 bun test ./src/views/Forms/EventForm/EventForm.test.tsx ./src/common/utils/form/form.util.test.ts ./src/shortcuts/useEditSequenceShortcut.test.tsx ./src/shortcuts/shortcuts.registry.test.ts

74/74 tests passing, type-check clean, lint clean.

🤖 Generated with Claude Code

tyler-dane and others added 4 commits August 10, 2026 10:18
…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>
@tyler-dane
tyler-dane merged commit 3e3e126 into main Aug 10, 2026
20 checks passed
@tyler-dane
tyler-dane deleted the claude/event-form-keyboard-shortcuts-b97b5e branch August 10, 2026 17:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant