Skip to content

a11y(2.1.1): ZoomSvg — add keyboard pan/zoom controls so the workflow family tree is operable without a mouse#3530

Open
rosanusi wants to merge 2 commits into
mainfrom
wcag/2.1.1-zoom-svg-pan-zoom-keyboard
Open

a11y(2.1.1): ZoomSvg — add keyboard pan/zoom controls so the workflow family tree is operable without a mouse#3530
rosanusi wants to merge 2 commits into
mainfrom
wcag/2.1.1-zoom-svg-pan-zoom-keyboard

Conversation

@rosanusi

Copy link
Copy Markdown

Description & motivation 💭

ZoomSvg is the pan/zoom container that hosts the workflow family tree. Pan was bound to mouse drag only; zoom was bound to the mouse wheel only. The sole keyboard-reachable control was the Center reset button. Keyboard users could not reposition or zoom the tree — a real barrier when the tree has multiple generations or wide sibling sets and nodes fall off-viewport.

This PR adds three things:

  1. panBy / zoomBy helpers — shared viewport-mutation functions, reusable by both mouse and keyboard paths.
  2. Button cluster — Pan Up / Down / Left / Right and Zoom In / Out buttons alongside the existing Center button, each gated by the existing pannable / zoomable props. Zoom buttons become disabled at the maxZoomIn / maxZoomOut clamp boundary.
  3. Container keyboard shortcutstabindex="0" container with on:keydown; arrow keys pan and +/- zoom only when the container is focused (scoped to the element, never global).
  4. plus / minus icons — added to the icon system (src/lib/holocene/icon/svg/), registered in paths.ts.

Mouse drag, wheel zoom, and the existing Center button are all unchanged.

Closes SC 2.1.1, 2.5.1, and 2.5.7 — one fix resolves all three:

SC Defect Closed?
2.1.1 Keyboard (A) No keyboard alternative for drag-to-pan / wheel-to-zoom ✅ Tab-reachable buttons + container arrow-key shortcuts
2.5.1 Pointer Gestures (A) Drag-to-pan and wheel-to-zoom have no single-pointer alternative ✅ Pan/Zoom buttons are single-tap controls
2.5.7 Dragging Movements (AA) Pan requires a drag gesture, no single-pointer alternative ✅ Same buttons close 2.5.7

Files changed (4):

  • src/lib/holocene/zoom-svg.svelte — all logic and template changes
  • src/lib/holocene/icon/svg/plus.svelte — new icon
  • src/lib/holocene/icon/svg/minus.svelte — new icon
  • src/lib/holocene/icon/paths.ts — registers plus and minus

cloud-ui inherits the fix via the @temporalio/ui tarball repack.

Closes matrix defect (d) recorded at audit-output/vpat-matrix.md:119.

Screenshots (if applicable) 📸

New button cluster appears at top-right of the ZoomSvg container alongside the existing Center button: Pan Up ↑, Pan Down ↓, Pan Left ←, Pan Right →, Zoom In +, Zoom Out −, Center ⊙.

Design Considerations 🎨

Uses the existing Button variant="secondary" size="sm" pattern matching the Center button. No new design tokens. Button order in the cluster: pan directions first, zoom second, center last.

Testing 🧪

How was this tested 👻

  • Manual testing

Steps for others to test: 🚶🏽‍♂️🚶🏽‍♀️

  1. Open a workflow with multiple child workflows in its family tree (/namespaces/{ns}/workflows/{wf}/{run}/relationships).
  2. Tab into the ZoomSvg container. Confirm it is reachable and announced as Zoomable workflow graph…, group.
  3. Tab through the controls cluster. Confirm Pan Up, Pan Down, Pan Left, Pan Right, Zoom In, Zoom Out, Center are each focus stops in that order.
  4. Activate each Pan button with Enter and Space. Confirm the viewport moves ~10% in the expected direction.
  5. Activate Zoom In repeatedly until the button becomes disabled. Confirm the boundary clamp is respected.
  6. Activate Zoom Out repeatedly until disabled. Same check at maxZoomOut.
  7. Focus the outer container <div> itself. Press Arrow keys — confirm the viewport pans. Press + / - — confirm zoom. Confirm these shortcuts only fire when the container is focused (Tab away and press arrow keys; should have no effect on the graph).
  8. Regression: mouse drag still pans, wheel still zooms, Center still resets.
  9. Screen reader (VoiceOver): confirm container announcement includes the aria-label keyboard description; confirm each button announces as Pan up, button etc.
  10. axe-core on the relationships page: zero new violations.

Checklists

Draft Checklist

  • Visual review of button cluster placement in the UI
  • VoiceOver smoke test on container and each button
  • Cross-browser: Firefox + Safari (wheel-zoom and arrow-key pan)

Merge Checklist

  • All pan directions and zoom levels tested with keyboard
  • disabled state at clamp boundaries verified
  • Mouse regression confirmed
  • axe-core: zero new violations

Issue(s) closed

Closes finding #10 from audit-output/issues/2.1.1-keyboard-audit.md.
Closes matrix defect (d) at audit-output/vpat-matrix.md:119.
Also closes 2.5.1 and 2.5.7 angles per audit-output/issues/2.5.1-pointer-gestures-verification.md §1.4.

Docs

Any docs updates needed?

No doc changes needed.

A11y-Audit-Ref: 2.1.1-zoom-svg-pan-zoom-keyboard

…2.5.1, 2.5.7)

Pan was mouse-drag only; zoom was wheel only — no keyboard or single-pointer
alternative. Adds panBy/zoomBy helpers, a tab-reachable button cluster (Pan
Up/Down/Left/Right, Zoom In/Out, Center), and arrow-key/+/- shortcuts on
the focused container. Mouse paths are unchanged. Also adds plus/minus icons.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 10, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
holocene Ready Ready Preview, Comment Jun 11, 2026 3:43pm

Request Review

@github-actions github-actions Bot added a11y Accessibility audit PR a11y:bucket-3 Bucket 3: engineer required a11y:sc-2.1.1 labels Jun 10, 2026
@temporal-cicd

temporal-cicd Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor
Warnings
⚠️

📊 Strict Mode: 4 errors in 1 file (0.4% of 902 total)

src/lib/holocene/zoom-svg.svelte (4)
  • L15:6: Variable 'svg' implicitly has type 'any' in some locations where its type cannot be determined.
  • L55:17: Variable 'svg' implicitly has an 'any' type.
  • L88:59: Variable 'svg' implicitly has an 'any' type.
  • L89:60: Variable 'svg' implicitly has an 'any' type.

Generated by 🚫 dangerJS against 58da27a

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@rosanusi rosanusi marked this pull request as ready for review June 11, 2026 15:52
@rosanusi rosanusi requested a review from a team as a code owner June 11, 2026 15:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a11y:bucket-3 Bucket 3: engineer required a11y:sc-2.1.1 a11y Accessibility audit PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant