Skip to content

fix(timeline): let the keyboard activate a lane pill, not just the pointer - #547

Open
EtienneLescot wants to merge 1 commit into
mainfrom
claude/pill-keyboard-activation
Open

fix(timeline): let the keyboard activate a lane pill, not just the pointer#547
EtienneLescot wants to merge 1 commit into
mainfrom
claude/pill-keyboard-activation

Conversation

@EtienneLescot

@EtienneLescot EtienneLescot commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Summary

Every timeline lane pill renders with role="button" and tabIndex={0} — reachable by Tab, announced as activatable — and nothing answered. The only selection path was onPointerDown; V4Timeline.tsx had no onKeyDown at all (grep -c onKeyDown on main returns 0).

The consequence is not a missing keystroke, it is that focus led nowhere. Delete, copy/paste and the inspector all act on tl.selection, so a keyboard user could tab to a zoom, speed, trim, annotation or full-camera pill and then do nothing with any of them.

  • Enter and Space select the focused pill; Shift adds to the selection, matching shift-click.
  • Every other key is left alone. The editor binds single letters (Z, T, D…) on window, and swallowing them here would disable the shortcuts while a pill has focus.
  • e.nativeEvent.stopPropagation(), not just the synthetic one: the shell's handler listens on window, above React's root container, and Space is bound to play/pause there. Stopping only the synthetic event would select the pill and toggle playback in one keystroke.

Selection is now one named callback (selectPill) that both doors call, instead of tl.selectRegion inlined in the pointer path. That is what stops the two drifting apart again, and it is the single line a new pill kind has to touch.

Related issue

Raised by CodeRabbit on #543 and deliberately left out of that PR: the bug predates it, and the fix changes keyboard behaviour for every lane kind rather than the two #543 adds.

Interaction with #543: both touch renderOnePill, so whichever lands second rebases over the other. If this lands first, #543's rebase needs selectPill to map its two audio lanes onto the document kind "audio" — one line, in the one place selection now lives.

Type of change

  • Bug fix
  • Enhancement

Release impact

  • Patch

Desktop impact

  • Not platform-specific

Screenshots / video

None — no visual change. The pill already had focus styling; what changes is that pressing Enter or Space on a focused one now does something.

Testing

  • npm run test2220 passed, 5 skipped, 0 failed (186 files)
  • npx tsc --noEmit and npx tsc -p tsconfig.test.json --noEmit — clean
  • npm run lint (Biome) — clean (15 pre-existing warnings in untouched files)

Five tests in V4Timeline.geometry.test.tsx: Enter selects, Space selects, Shift makes it additive, an ignored key does not select, and the window listener sees the ignored key but not Enter or Space.

Verified as a real regression test: removing the handler fails four of the five. The fifth (other keys are left alone) passes either way by construction — it guards against over-capture rather than proving the feature.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added keyboard support for timeline lane-pill selection using Enter and Space.
    • Supports Shift-assisted additive selection for keyboard users.
    • Prevents selection keys from triggering unrelated playback or global shortcuts.
  • Tests

    • Added coverage for keyboard selection, additive selection, and shortcut isolation.

…inter

Every lane pill renders with `role="button"` and `tabIndex={0}`, so it is reachable
by Tab and announced as activatable. Nothing answered: the only selection path was
`onPointerDown`, and the file had no `onKeyDown` at all.

The consequence is not that a keystroke was missing — it is that focus led nowhere.
Delete, copy/paste and the inspector all act on `tl.selection`, so a keyboard user
could reach a zoom, speed, trim, annotation or full-camera pill and then do nothing
with any of them.

Enter and Space now select, and Shift+Enter adds to the selection, matching
shift-click. Every other key is left alone: the editor binds single letters (Z, T,
D…) on window, and swallowing them here would disable the shortcuts while a pill has
focus.

`e.nativeEvent.stopPropagation()`, not just the synthetic one. The shell's shortcut
handler listens on WINDOW, above React's root container, and Space is bound to
play/pause there — stopping only the synthetic event would select the pill and toggle
playback in the same keystroke. A test pins that, and pins that an ignored key still
reaches the window listener.

Selection is now one named callback (`selectPill`) that both doors call, rather than
`tl.selectRegion` inlined in the pointer path. That is what stops the two drifting
again, and it is the single line a new pill kind has to touch.
@coderabbitai

coderabbitai Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1eb7ae8e-b2b6-4d76-aaf9-3d58e422d394

📥 Commits

Reviewing files that changed from the base of the PR and between dcb1864 and 4fc5aea.

📒 Files selected for processing (2)
  • src/components/ai-edition/v4/V4Timeline.geometry.test.tsx
  • src/components/ai-edition/v4/V4Timeline.tsx

Included review availability: Your plan provides up to 8 included reviews per hour; 6 remain after this review.


📝 Walkthrough

Walkthrough

Lane-pill selection now uses a shared callback for pointer and keyboard input. Enter and Space activate pills, support Shift-based additive selection, and do not trigger window-level playback handling. Tests cover activation, ignored keys, and propagation.

Changes

Lane-pill selection

Layer / File(s) Summary
Shared selection logic
src/components/ai-edition/v4/V4Timeline.tsx
Pointer selection uses the reusable selectPill callback. Pill-drag dependencies include the callback.
Keyboard activation and validation
src/components/ai-edition/v4/V4Timeline.tsx, src/components/ai-edition/v4/V4Timeline.geometry.test.tsx
Enter and Space select pills, prevent default behavior, stop propagation to the window-level playback handler, and preserve unrelated shortcut propagation. Tests cover these behaviors.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to 4fc5a

Focused timeline pills can now be selected with Enter or Space without also triggering playback, while existing pointer selection remains unchanged; no actionable merge-blocking risk remains after normal checks and review.

Suggested reviewers: arhxam

Sequence Diagram(s)

sequenceDiagram
  participant KeyboardUser
  participant LanePill
  participant V4Timeline
  participant WindowPlaybackHandler
  KeyboardUser->>LanePill: Press Enter or Space
  LanePill->>V4Timeline: preventDefault and stopPropagation
  V4Timeline->>V4Timeline: Call selectPill with optional Shift selection
  V4Timeline--xWindowPlaybackHandler: Do not trigger playback
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the primary change: enabling keyboard activation for timeline lane pills.
Description check ✅ Passed The description includes all required sections, explains the keyboard behavior and implementation, identifies the related issue, documents release and platform impact, and provides detailed testing re…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description includes all required sections, explains the keyboard behavior and implementation, identifies the related issue, documents release and platform impact, and provides detailed testing results. The related issue reference does not use the template's preferred "Refs #543" syntax, but the information is present.

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/pill-keyboard-activation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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