Repository navigation
fix(app): make the question dock keyboard-first and stop it flashing - #58494
Conversation
…itions Up/Down move the selection in single-select questions and move a quiet focus ring in multi-select ones. Space acts on key down. Left/Right switch questions outside the text field. Selection, focus, marks and progress fade on one spring instead of swapping properties, the answers box follows each question's height, and a new question slides in from the side it comes from.
There was a problem hiding this comment.
Works as described. I reproduced the old behaviour by running the PR's new component tests against the base: 4 fail there (radio Up/Down, Left/Right switching, Space on key down, IME Enter/Escape). The full question dock spec passes with this change, and so do the 8 questionKey unit tests and tsc -b in packages/app. The before/after screenshots show the same view after one ArrowDown: on the base only the focus moves; with this change the selection moves too.
Public API is unchanged; this only touches the web app's question dock and its CSS.
No blocking concerns.
There was a problem hiding this comment.
The new commit works as described. I re-ran question-keys.test.ts (9 pass), the question dock and focus-ring component specs (18 pass in headless Chromium) and tsc -b in packages/app (clean). The after screenshot shows ArrowDown highlighting "Wide" without picking it.
Public API is unchanged.
One thing worth fixing, inline: after a mouse move, Space and Enter can act on a different answer from the one that has keyboard focus.
| if (store.editing || sending()) return | ||
| focus(store.focus + step) | ||
| // The pointer moves the highlight like the arrows do, but never takes focus from the custom answer's field. | ||
| const hover = (i: number, event: PointerEvent) => { |
There was a problem hiding this comment.
hover() moves store.focus but leaves keyboard focus where it was. activate and commit then act on store.focus, not on the focused button. So if keyboard focus is on answer 1 and the mouse passes over answer 3, Space toggles (or Enter picks) answer 3. A screen reader still reports answer 1, and that button has dropped to tabindex=-1. Could hover also move focus (with preventScroll) when focus is already inside the list? Or could Space/Enter act on the focused element?



What it does
Makes the question dock work from the keyboard the way you'd expect, and stops it flashing. The arrows only move a highlight, Space marks an answer and Enter commits it and moves on.
How it works
Key handling lives in a pure
questionKey(event, { mac, zone, count })inquestion-keys.ts, which maps one keydown to one intent (move,activate,commit,type,number…); RTL flips the arrows, and nothing fires during IME composition. The highlight is a roving tabindex:store.focusis the highlighted answer and holds the only tab stop, so screen readers announce it separately fromaria-checked. Mouse hover moves the highlight too. It is drawn as one layer behind the cards that glides to the highlighted card by itsclip-path, landing at once on a new question. The box height follows a ResizeObserver through a spring, and a question change slides 12px plus a fade via WAAPI.Risk
Low. Contained to the question dock. Roles and
aria-checkedare unchanged. Right Arrow on the last question does not submit; Enter, Next and ⌘⏎ do.Proof
Today (left) vs the first cut of this PR (right), keyboard only. This was recorded before the highlight model, so on the right ↓ still picks:
https://problems.kitlangton.com/media/Ub0fG5f_RsdLJyh08vCkxQ.mp4
question-keys.test.ts: unit tests for every intent, including Enter, typing on the custom answer and IME compositionsession-question-dock.spec.ts: component tests for ↓ not changing the answer, Space marking, Enter advancing in both question types, typing into the custom answer, Left/Right and IME composition