Make the canvas keyboard-reachable + trap focus in dialogs (#84)
The arrow-key nudge handler existed but only ever acted on a POINTER selection, and nothing could select without a mouse — so the feature was unusable by exactly the keyboard users it's for. This is the scoped first slice: give the canvas a keyboard path in, and fix the Modal focus trap that every destructive confirmation goes through. Canvas: - The <svg> gets role="application" + an aria-label describing the controls, and a <title> naming the garden — a screen reader now announces an interactive canvas rather than an empty graphic. - Each object <g> is a focusable role="button" with an aria-label (name + kind) and aria-pressed reflecting selection. Enter/Space selects it — the step that was missing — which makes the existing arrow-key nudge reachable. - A :focus-visible CSS rule draws a dashed accent ring on keyboard focus (and NOT on a mouse click, which is the point of :focus-visible). CSS rather than React state because onFocus on an SVG <g> is unreliable, and a CSS rule cleanly overrides the shape's inline stroke. Modal (blast radius: DeleteGarden/ClearBed/DeletePlant/DeleteSeedLot/Share): - Tab is trapped inside the dialog and wraps at the ends, instead of walking out into the page behind the backdrop. - On close, focus returns to the element that opened the dialog rather than landing on <body>. Verified live against the built binary with real keyboard input: Tab focuses an object (SVG <g tabindex> genuinely takes focus), Enter flips aria-pressed false→true, the focus-visible dash renders (computed stroke-dasharray "5px, 4px"), the dialog traps focus through 5 Tabs, and Escape closes it and restores focus to the opener. Follow-ups noted, not done here: object dimensions in the aria-label (needs the garden's unit context this component doesn't hold), roving-tabindex between plops inside a focused bed, and the EditorRail tablist semantics. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01H3zbym8Doka2d7D48maSgZ
This commit is contained in:
@@ -28,6 +28,19 @@
|
||||
font-family: var(--font-sans);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
/* Keyboard focus on a canvas object (#84). :focus-visible shows the ring for
|
||||
keyboard focus but not a mouse click; the dashed accent ring distinguishes
|
||||
"focused" from the solid ring that marks "selected". A CSS rule overrides
|
||||
the shape's inline stroke presentation attributes. */
|
||||
.object-shape {
|
||||
outline: none;
|
||||
}
|
||||
.object-shape:focus-visible :is(rect, ellipse) {
|
||||
stroke: var(--color-accent-strong);
|
||||
stroke-width: 2;
|
||||
stroke-dasharray: 5 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* Dark theme: override the same tokens so utilities recolor automatically. */
|
||||
|
||||
Reference in New Issue
Block a user