hub-client: UI/UX modernization Phase 2 — keyboard and assistive-tech support - #609
Merged
Merged
Conversation
Contributor
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
shikokuchuo
force-pushed
the
hub-client-uiux-phase2
branch
3 times, most recently
from
August 26, 2026 14:43
3173121 to
ef3ebba
Compare
…tics
File tree (FileSidebar) is now an APG treeview: role=tree/treeitem/group
with aria-level/aria-expanded/aria-selected, roving tabindex (one tab
stop for the whole tree), ArrowUp/Down/Home/End navigation, ArrowRight/
Left expand/collapse/parent, type-ahead with repeat-key cycling, Enter/
Space activation, and Shift+F10/Menu-key context menu anchored to the
row so focus returns to it. Search results become a listbox with the
same navigation; ArrowDown from the search input moves into the results
and Escape clears back to the input. Row kebab buttons leave the tab
order (tabIndex=-1) — the keyboard path is Shift+F10 on the row.
- Outline chevrons gain aria-expanded and per-symbol accessible names
('Collapse Introduction'); outline rows/chevrons get the token focus
ring, replacing a bare outline:none (lint exception burned down).
- Sidebar section headers get aria-controls wired to role=region
content panels with aria-labelledby, plus a focus-visible ring.
- Focus rings: token --focus-ring on tree rows, search results, folder
headers, section headers (inset offset so scroll containers don't
clip them); file-row kebab now also appears on row focus-within.
- Menu: focus return on close is synchronous again, but happens BEFORE
the closing state updates commit — a dialog opened from a menu item
now captures the trigger (not the doomed menu item) as its restore
target during render, so Escape from the dialog returns focus to the
trigger. Fixes the pre-existing projects-home-dialogs failure.
- DevHarness sidebar route is stateful (tracks selection, records the
last action in an offscreen testid) and gains a search fixture, so
keyboard specs can assert activation; e2e/sidebar-keyboard.visual
.spec.ts covers all of the above (15 specs).
- baseline-screens now screenshots the surface's container element for
component routes instead of the full page: a sidebar-wide change
measured 0.86% of full-page pixels, silently under the 1% tolerance.
Baselines regenerated locally (gitignored); the sidebar baseline now
includes the search box, matching real chrome.
Phase 2 of the UI/UX modernization plan.
- Burn down the lint:css outline:none exceptions to zero: the rule is now enforced repo-wide. Every suppressed outline gains the token --focus-ring on :focus-visible (NewFileDialog, ProjectSelector, ProjectSetSetup, ReplayDrawer, debug page); .qh-input gains the ring (border-color-only focus was too subtle); the rename input and the two ProjectSelector halo shadows standardize on the one token ring. - Forced colors (Windows High Contrast): .qh-icon-btn, .qh-dialog, .qh-tooltip, and the toasts get system-color borders (ButtonBorder/ CanvasText) so they keep visible boundaries when the platform strips backgrounds and shadows. The replay waveform scrubber rings the waveform on keyboard focus. Covered by e2e/forced-colors.visual.spec .ts (Playwright forcedColors emulation). - New e2e/gallery-states-a11y.visual.spec.ts scans the open menu and visible tooltip with axe-core in both themes, strict zero-tolerance for serious/critical (scoped via .include so the page's baselined contrast issues don't leak in). This is the Phase 2 extension of the axe coverage to every gallery surface. - That scan caught a real one: menu shortcut hints used --text-muted, 3.6:1 on the dark menu background (WCAG 1.4.3 fail). New semantic token --menu-hint-text: --text-muted in light (5.2:1), --text-secondary in dark (5.6:1). - Replay waveform slider gains aria-label='Replay position'. Phase 2 of the UI/UX modernization plan.
…cript - src/utils/keyboardShortcuts.ts: the single source of truth for keyboard interactions (global handlers + the tree/listbox/menu/dialog patterns), rendered by the new Keyboard Shortcuts section in the sidebar's About tab. AboutTab.test.tsx pins the reference to render every group and entry so docs can't drift from the registry. - hub-client/screen-reader-smoke.md: the manual VoiceOver pass (header, file tree, outline, dialogs, notifications) and the Windows High Contrast pass, alongside the automated forced-colors spec that references it. Phase 2 of the UI/UX modernization plan.
… focus chain src/strings.ts is the single source of truth for app-chrome copy (header, file tree, outline, sections, notifications, dialogs, tabs, view toggle, replay), with the copy conventions recorded in the module header: Unicode … (never three dots), sentence case, … only on menu items that open dialogs, one verb per concept. Migrated the chrome components; ProjectsHome/ProjectSelector/ProjectSetSetup keep local strings (noted in the module). Copy fixes from the audit: 'Upload asset' → 'Add asset' (matches the dialog it opens), 'Open in New Tab'/'Copy Link'/'Browse Files' → sentence case, 'Share Project' → 'Share project', 'Loading...' and friends → '…'. Test assertions updated to match. Two focus-chain fixes this surfaced: - Menu now handles Enter/Space explicitly (preventDefault + click the focused item). The browser's default activation click is dispatched after the keydown handler — with the synchronous focus return it landed on the re-focused trigger and re-opened the menu. - ModalDialog's focus restore defers past the commit via a microtask and skips while the dialog is still connected: StrictMode's mount-time double-effect was running the unmount cleanup while the dialog stayed mounted, stealing focus from the autoFocus child to the restore target. The menu→dialog→trigger focus chain now works end to end (projects-home-dialogs spec green). Baselines regenerated (gitignored, local-only): dialog-share (title now sentence case) and dialog-new-file (the focused filename input shows the new .qh-input focus ring — the intended WCAG 2.4.7 change). Phase 2 of the UI/UX modernization plan.
The shortcuts reference used global --text-primary/--bg-input tokens, but the About tab lives in the editor-token scope where those resolve differently — the kbd chips rendered dark-on-dark in dark mode. The section now uses the same editor-scoped tokens as the rest of AboutTab (kbd chips match the sidebar search input styling). The About tab had no dev-harness route, so no visual or axe coverage caught this. Added the #/dev/about-tab route (sidebar width, in the editor chrome scope) and registered it in baseline-screens and baseline-a11y. The axe scan also surfaced a pre-existing issue: .section-label's --editor-text-muted is 4.24:1 on the dark sidebar (WCAG 1.4.3 needs 4.5:1). The new group titles use --editor-text-dim instead; the shared label pattern is baselined as-is, with the token fix deferred to the Phase 5 visual gate.
shikokuchuo
force-pushed
the
hub-client-uiux-phase2
branch
from
August 26, 2026 17:13
ef3ebba to
07b041d
Compare
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.
Stacked on #607. Review and merge that PR first.
What this PR does
Phase 2 of the hub-client UI/UX modernization: full keyboard access and assistive-technology support.
src/strings.ts.Bug fixes
Testing
recreate-all-snapshotsworkflow run on this branch adds the new baselines as a bot commit.