[P3] Live Dive profile inspector needs a mouse hover; keyboard and touch users have no way to use it #120

Open
opened 2026-10-31 19:47:41 +00:00 by pedro · 0 comments
Owner

Priority: P3
Type: bug
Source: full codebase review requested 2026-10-31 (independently reproduced against 2cac7cf)

Location: src/App.tsx:2215-2234, src/App.tsx:2309-2314, src/style.css:470-474

Problem and evidence

The live "Dive profile" panel draws an <svg role="img">. Its depth/time inspector (profileHover) is set only in onPointerMove and cleared in onPointerLeave. Nothing in the panel can take focus, and there is no range input or key handler. The readout says "Hover over the profile to inspect depth and time." The other scrubbable charts all pair the chart with a type="range" input: DiveSummary.tsx:210, DiveImport.tsx:516, DiveReplayComparison.tsx:610 and ProfilePlanner.tsx:277/834. Keyboard and screen-reader users therefore cannot inspect past depth and time on the live chart. On touch, the .profile svg rule does not set touch-action: none (unlike the replay scrubber at style.css:1872). A drag gets taken over by browser scrolling, which cancels the pointer and fires pointerleave. A stationary tap fires pointerdown, pointerup and then pointerleave with no pointermove. In both cases the readout never shows a value, or resets right away.

I traced this through the code; I did not run a browser. At src/App.tsx:2215-2234 the svg has only the onPointerMove and onPointerLeave handlers, with no tabIndex, onKeyDown, onPointerDown or pointer capture. setProfileHover is called only there (App.tsx:168, 1024). The readout text at App.tsx:2313 refers only to hovering. A grep for type="range" shows that every other profile chart has a slider and the live Dive profile panel has none. style.css:470-474 sets no touch-action on .profile svg, while style.css:1061 and 1872 set touch-action: none on other scrubbers. Under standard Pointer Events behaviour, touch has no hover, a tap produces no pointermove, and a scroll gesture produces pointercancel followed by pointerleave. So the readout cannot persist on touch.

Suggested correction

Add a "Profile time" range input under the live chart (min 0, max dive.minutes, a small step) that drives profileHover. Give it aria-valuetext with the formatted time and depth, matching the DiveSummary and planner sliders. Add onPointerDown with setPointerCapture, and set touch-action: none (or pan-y) on the svg, so a tap or drag selects a time on touch. Consider not clearing the selection on pointerleave for touch pointers. Reword the readout to something like "Drag on the profile or use the slider to inspect depth and time."

Acceptance criteria

With a dive in progress or paused, a keyboard user can Tab to a Profile time slider in the Dive profile panel and change it with the arrow keys. The readout and the dashed marker then update to the chosen time and depth, and the slider announces both through aria-valuetext. On a touch emulation (Playwright hasTouch), tapping the chart leaves the readout showing a time and depth instead of the hover prompt. Regression test: render the live panel, focus the slider, press ArrowRight, and assert the readout text changes from the default prompt to a "m:ss · Depth" string. pnpm verify passes.

Scope: maintenance of the educational simulator. Preserve historical R1 acceptance and operational-validation limits.

Priority: P3 Type: bug Source: full codebase review requested 2026-10-31 (independently reproduced against `2cac7cf`) Location: `src/App.tsx:2215-2234`, `src/App.tsx:2309-2314`, `src/style.css:470-474` Problem and evidence The live "Dive profile" panel draws an `<svg role="img">`. Its depth/time inspector (`profileHover`) is set only in `onPointerMove` and cleared in `onPointerLeave`. Nothing in the panel can take focus, and there is no range input or key handler. The readout says "Hover over the profile to inspect depth and time." The other scrubbable charts all pair the chart with a `type="range"` input: DiveSummary.tsx:210, DiveImport.tsx:516, DiveReplayComparison.tsx:610 and ProfilePlanner.tsx:277/834. Keyboard and screen-reader users therefore cannot inspect past depth and time on the live chart. On touch, the `.profile svg` rule does not set `touch-action: none` (unlike the replay scrubber at style.css:1872). A drag gets taken over by browser scrolling, which cancels the pointer and fires pointerleave. A stationary tap fires pointerdown, pointerup and then pointerleave with no pointermove. In both cases the readout never shows a value, or resets right away. I traced this through the code; I did not run a browser. At src/App.tsx:2215-2234 the svg has only the onPointerMove and onPointerLeave handlers, with no tabIndex, onKeyDown, onPointerDown or pointer capture. `setProfileHover` is called only there (App.tsx:168, 1024). The readout text at App.tsx:2313 refers only to hovering. A grep for `type="range"` shows that every other profile chart has a slider and the live Dive profile panel has none. style.css:470-474 sets no touch-action on `.profile svg`, while style.css:1061 and 1872 set `touch-action: none` on other scrubbers. Under standard Pointer Events behaviour, touch has no hover, a tap produces no pointermove, and a scroll gesture produces pointercancel followed by pointerleave. So the readout cannot persist on touch. Suggested correction Add a "Profile time" range input under the live chart (min 0, max dive.minutes, a small step) that drives `profileHover`. Give it aria-valuetext with the formatted time and depth, matching the DiveSummary and planner sliders. Add `onPointerDown` with `setPointerCapture`, and set `touch-action: none` (or pan-y) on the svg, so a tap or drag selects a time on touch. Consider not clearing the selection on pointerleave for touch pointers. Reword the readout to something like "Drag on the profile or use the slider to inspect depth and time." Acceptance criteria With a dive in progress or paused, a keyboard user can Tab to a Profile time slider in the Dive profile panel and change it with the arrow keys. The readout and the dashed marker then update to the chosen time and depth, and the slider announces both through aria-valuetext. On a touch emulation (Playwright hasTouch), tapping the chart leaves the readout showing a time and depth instead of the hover prompt. Regression test: render the live panel, focus the slider, press ArrowRight, and assert the readout text changes from the default prompt to a "m:ss · Depth" string. pnpm verify passes. Scope: maintenance of the educational simulator. Preserve historical R1 acceptance and operational-validation limits.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: pedro/DiveSim#120
No description provided.