Repository navigation
docs(studio): document timeline keyboard navigation - #3031
Conversation
e28b1b5 to
7b6247f
Compare
58898e2 to
204a84f
Compare
7b6247f to
479d62e
Compare
204a84f to
fc6a7b5
Compare
479d62e to
f86eb06
Compare
f43c86c to
be24c54
Compare
f86eb06 to
795b0c4
Compare
vanceingalls
left a comment
There was a problem hiding this comment.
R1 review at head 795b0c448.
Claims audited against code at #2715 head be24c5412:
| Doc claim | Code | Verdict |
|---|---|---|
| Tab into timeline; one roving target | TimelineTrackRow tabIndex={rovingTargetId===id?0:-1} |
Match |
| Left/Right = prev/next item in row | resolveTimelineNavigationTarget ArrowLeft/Right branches |
Match |
| Up/Down = nearest-time in adjacent row | nearestTarget() sort by Math.abs(time - target.time) |
Match |
| Home/End = start/end of row | boundaryRow.items.at(-1) ?? boundaryRow |
Match (Home→row, End→last item; conceptual "start/end" is fair) |
| Ctrl/Cmd + Home/End = first/last logical row | timelineBoundary branch returns boundaryRow directly (Miguel R2 fix) |
Match — correctly last row, not last item of last row |
| Page Up/Down = visible page, focus-anchored | viewportPageSize uses focusedRow as anchor |
Match |
| Enter/Space = expand/collapse track row | event.key === "Enter" / " " + expandable → onToggleRow |
Match |
| Context Menu / Shift+F10 = context menu | event.key === "ContextMenu" or F10+shift → openContextMenu |
Match |
| Off-viewport target scrolls + restores focus | resolveTimelineFocusFallback chain |
Match |
| Treegrid role, track level/expanded | TimelineLanes role="treegrid"; TimelineTrackRow aria-level/aria-expanded |
Match |
| Clips/keyframes/ease announce names, times, selection | TimelineClip aria-label+aria-pressed; TimelineClipDiamonds keyframe aria-label+aria-pressed; TimelineDiamondConnectors ease aria-label |
Match |
Non-blocking nit (follow-up): APG disclosure arrows shipped in #2715 R2 — on an expandable track row, ArrowRight expands and ArrowLeft collapses (useTimelineKeyboardActor lines guarding event.key === "ArrowRight/Left" + expandable). The docs only mention Enter/Space for that toggle. Both work; adding a sentence would help WAI-ARIA-familiar users. Won't block on docs-only PR.
No emojis. No stale aria-multiselectable references. Table matches switch-statement. Tab into the timeline correctly avoids the non-Tab-header-key anti-pattern Miguel called out.
— Review by Via
james-russo-rames-d-jusso
left a comment
There was a problem hiding this comment.
Reviewed at 795b0c448. Docs-only, 28 additions across docs/studio/shortcuts.mdx (new "Timeline navigation" section with a 7-row shortcut table) and docs/studio/timeline.mdx (5 prose paragraphs + a cross-link back to the shortcuts anchor). Verified every user-visible claim against the code shipped in #2715 at be24c5412 — each keybinding, ARIA semantic, and roving-focus statement traced to file:line.
Three concerns worth inline. All non-blocking; all about docs undershooting or overshooting the shipped code.
Verified end-to-end:
-
✅ Shortcut table keybindings match the actor:
- ArrowLeft/Right within a row →
timelineKeyboardNavigation.ts:274-277,281 - ArrowUp/Down → nearest-time item on the neighbor row (
:293) - Home / End (unmodified) → row boundary (
:270-272) - Ctrl+Home / Ctrl+End (or Cmd on Mac) → first / last logical row (
:271-272);event.ctrlKey || event.metaKeyat the actor (useTimelineKeyboardActor.ts:100) makes both modifiers universal - PageUp/Down → uses
viewportPageSize(focus-anchored,useTimelineKeyboardActor.ts:28-49) - Enter / Space on expandable row →
onToggleRow(useTimelineKeyboardActor.ts:107-116) - Context Menu / Shift+F10 → synthesized
contextmenuMouseEvent at target center (useTimelineKeyboardActor.ts:120-135)
- ArrowLeft/Right within a row →
-
✅
role="treegrid"is set —TimelineLanes.tsx:153. (Impl detail: it's on the innerTimelineLaneswrapper, not on theoverflow-x-auto/overflow-y-autoscroll container atTimeline.tsx:462. Reader-facing statement is still accurate; scroll behavior + AT semantics live on different elements by design.) -
✅
aria-level+aria-expanded—TimelineTrackRow.tsx:52-53(aria-levelunconditional,aria-expandedcorrectly gated onlogicalRow.expandable); property sub-rows also carryaria-levelat:71; disclosure caret carriesaria-expandedatLayerDisclosureRow.tsx:48. -
✅ Clips:
aria-labelwith time +aria-pressed—TimelineClip.tsx:102-103. -
✅ Keyframes:
aria-labelwith time +aria-pressed—TimelineClipDiamonds.tsx:346-347. -
✅ Off-screen focus reveal — the
#2714focus coordinator + pin frompinnedRowKeys/pinnedClipIdentitieskeeps the focused target mounted; scroll +focusElementin the useEffect. Doc's "mounts it, scrolls it into view, and then restores focus" reads accurately (though the actual order is pin → mount viavirtualRows→ scroll → focus; user-facing description is fine). -
✅ Anchor
/studio/shortcuts#timeline-navigation— Mint config indocs/docs.jsonhas no slug rules; default kebab-case-lowercase applies.## Timeline navigation→#timeline-navigation.mint broken-linksin the test plan will catch any regression.
Body-only nit:
timeline.mdx:58— "Studio mounts it, scrolls it into view, and then restores focus" actually runs "pin → mount via virtualized row set → scroll into view → focus" — the pin comes first, and it's what keeps the target mounted long enough for the scroll+focus to succeed. Not worth changing the doc — the ordering-of-verbs is user-facing correct — but if a future edit tightens this, "pins" (or "keeps mounted") is the invariant the reader should carry into the code.
Test plan (mint validate, mint broken-links, git diff --check) is well-scoped for docs. CI at HEAD is all-pass except Graphite / mergeability_check (in-progress, standard) and Mintlify Deployment (skipping — expected on this PR shape).
Ready from where I sit once the three inline concerns are considered — most impactful is the easing-selection-state overclaim on timeline.mdx:61, since fixing it is a one-word edit ("names and times" instead of "names, times, and selection state"). Leaving as COMMENTED.
795b0c4 to
c6d632f
Compare
be24c54 to
16d27c2
Compare
c6d632f to
1969a47
Compare
|
All docs review follow-ups are folded into exact head |
vanceingalls
left a comment
There was a problem hiding this comment.
R2 delta at 1969a47d8. Three doc changes vs my R1 stamp at 795b0c448, all closing Rames's R1 concerns and my own APG-arrow follow-up:
shortcuts.mdx+1 paragraph after the table: ArrowRight expands / ArrowLeft collapses an expandable track row; ArrowLeft from a keyframe property row returns to parent; otherwise arrows move within the row.timeline.mdx:56— Enter/Space sentence expanded to also cover Right-to-expand, Left-to-collapse, Left-to-parent.timeline.mdx:58— "one keyboard target" → "one logical timeline target", plus explicit note that native header controls remain separate Tab stops.timeline.mdx:60— clips/keyframes split from easing (easing loses "selection state").
All four re-verify against #2715 code:
useTimelineKeyboardActor.ts:97-105—kind === "row" && expandableshort-circuit for ArrowRight/Left →onToggleRow.timelineKeyboardNavigation.ts:274-276— ArrowLeft on collapsed level-2 row →parentId.TimelineTrackHeader.tsx—VisibilityButton, prev/next-keyframe chevrons, add/remove-keyframe: native<button>with notabIndexoverride, so header controls do stay in the Tab order alongside the roving logical target.TimelineDiamondConnectors.tsx:181-182— ease control hasaria-label(name + time) but noaria-pressed.
Required checks (HF ruleset 14211637, 8): regression SUCCESS; other 7 (Semantic PR title, Test: runtime contract, Typecheck, Build, Test, Render on windows-latest, Tests on windows-latest) NOT_RUN — expected for a docs-only PR on the stack tip. mergeStateStatus: UNSTABLE is just Graphite mergeability_check in progress. Base is the stack branch codex/studio-timeline-f-keyboard-controls-v2; retarget to main before land.
Docs match code, R1 gaps closed. No new findings.
— Review by Via
The base branch was changed.
1969a47 to
19070b5
Compare
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
vanceingalls
left a comment
There was a problem hiding this comment.
Delta re-verify at head 19070b52d (Family F consolidated tip on main).
Rebase context: After #2711 + #2712 squash-merged, Miguel rebased #3031 onto current main. PR now carries 4 commits:
feat(studio): expose timeline treegrid semantics— #2713 content (prior stamp15ef84ca1/415548272)feat(studio): coordinate logical timeline focus— #2714 content (prior stamp21b2c9149)feat(studio): add timeline keyboard controls— #2715 content (prior stamp16d27c28c)docs(studio): document timeline keyboard navigation— docs (prior stamp1969a47d8)
Content match: Consolidated diff (41 files, +1905/-647) is the union of the four already-stamped bodies — lanesIdPrefix / timelineLogicalRowCellId / rowgroup>row refactor / aria-colcount+colindex / expandable (#2713); logical timelineFocus.id model / tabIndex={-1} / appliedRef self-heal / resolveTimelineFocusFallback deletion / getRowTop scroll geometry / focus tests / O(1) focusElement via CSS.escape / dropped aria-multiselectable (#2714); Arrow/Home/End/Page bindings / APG disclosure ArrowRight-expand / Ctrl+End→last / Enter/Space toggle + native-click assertion / ContextMenu+Shift+F10 / dataset.timelineFocusId Tab-bail / rovingTargetId-gated tabIndex / viewportPageSize memo (#2715); shortcuts.mdx + timeline.mdx APG arrows + parent-jump + native-header Tab access + selection-vs-easing split (#3031 docs).
Review threads: All 3 doc threads from Rames D Jusso resolved by Miguel (easing selection-state phrasing, "logical timeline target" scoping, expand/collapse row-vs-item table split).
Required-checks state (ruleset 14211637):
- Build: IN_PROGRESS
- Render on windows-latest: IN_PROGRESS
- Semantic PR title: SUCCESS
- Test: not surfaced by name in this rollup (Producer: unit/integration tests IN_PROGRESS)
- Test: runtime contract: IN_PROGRESS
- Tests on windows-latest: IN_PROGRESS
- Typecheck: IN_PROGRESS
- regression: SUCCESS
mergeStateStatus: BLOCKED — CI still restarting per Miguel. Approve stands on the consolidated content match; land only after all 8 required checks turn SUCCESS.
Review by Via
james-russo-rames-d-jusso
left a comment
There was a problem hiding this comment.
Reviewed at 19070b52d — tip-only carve-out landing strategy.
Delta from my prior fully-approved cumulative tree (1969a47d8):
All 41 files in the current #3031 diff have byte-identical blob SHAs between 1969a47d8 and 19070b52d. Zero content changes; the rebase relocated the four remaining Family F commits (#2713-scope + #2714-scope + #2715-scope + docs) onto current main without touching the tree.
New commit stack sitting cleanly on top of main at 0f1333c80 (squash-merge of #2712):
fd520d3a feat(studio): expose timeline treegrid semantics(was #2713 @415548272)f2819fa6 feat(studio): coordinate logical timeline focus(was #2714 @21b2c9149)fccb4261 feat(studio): add timeline keyboard controls(was #2715 @16d27c28c)19070b52 docs(studio): document timeline keyboard navigation(was docs @1969a47d8)
Files that dropped out of the diff are all now-landed #2711/#2712 or External-change-stack scope (playerStore.ts, liveTime.ts, useSdkSession.ts, usePreviewPersistence.ts, externalFileReloadBus.ts, useStudioExternalFileChanges.ts, App.tsx, DesignPanelPromoteProvider.tsx, ExternalFileConflictBanner.tsx, scripts/ci/install-workspace-dependencies.sh, .github/workflows/ci.yml, …). Their state at 19070b52d = state at main; no drift.
Cumulative content is exactly what I signed off at 1969a47d8. LGTM from my side — safe to re-stamp this as the tip-only landing candidate.

What
Document timeline keyboard navigation, virtualized focus restoration, and screen-reader semantics in the existing Studio guides.
Why
The new interaction path should be discoverable where people already learn timeline editing and look up keyboard commands.
How
The timeline task guide explains the workflow and expected behavior. The shortcuts reference owns the exact command table so the two pages do not duplicate the same job.
This documentation PR targets #2715 and is the stack tip.
Test plan
npx mint validatenpx mint broken-links --check-redirectsgit diff --checkUnit tests added/updated (documentation-only change)
Manual testing performed
Documentation updated