feat(a11y): screen-reader summaries, accessible modal primitive, reduced motion, colour-safe health status - #1011
Merged
llinsss merged 1 commit intoAug 28, 2026
Conversation
…, colour-safe health status - a11yChartSummary: spoken summaries + list equivalents + semantic headings for charts and the vet map, kept in sync with the active filter (closes DogStark#979) - AccessibleModal / useAccessibleModal: one accessible dialog primitive with focus move + restore, Android back handling, and nested-modal stacking (closes DogStark#980) - motion: useReducedMotion hook + pure helpers that drop movement while keeping state changes across transitions, charts, and gestures (closes DogStark#981) - theme/healthStatus: high-contrast, colour-blind-safe status tokens with text and icon cues, WCAG AA verified in light and dark themes (closes DogStark#982) - docs/ACCESSIBILITY.md and focused unit tests for each module
|
@ushpraise Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
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.
Summary
Adds four small, independently-tested accessibility building blocks and moves the app toward using them. Each module is a pure, unit-testable core with a thin React wrapper, so the behaviour is characterised by tests before any screen is migrated.
Closes #979
Closes #980
Closes #981
Closes #982
#979 — Screen-reader summaries for charts and maps
src/utils/a11yChartSummary.tsgives visual-only data a non-visual equivalent (WCAG 1.1.1 / 1.3.1):buildChartSummary— one-line spoken summary (count, latest value, trend, min–max range) for a chart region'saccessibilityLabel.buildChartDataTable— orderedstring[], one focusable row per plotted point, so a series can be read point by point.buildMapSummary/buildClinicListSummary— summary + nearest-first list equivalent forVetMapScreen's pins, synchronised with the active filter and offline state. No coordinates or phone numbers are placed in the spoken strings.sectionHeading— heading text for use withaccessibilityRole="header".#980 — Standardised modal focus and back-button behaviour
src/hooks/useAccessibleModal.ts+src/components/AccessibleModal.tsx— one accessible dialog primitive:returnFocusRef) on close;onRequestClose;modalStackso that with nested modals only the top-most instance reacts to back / receives focus;accessibilityViewIsModalcontainer and a header-role title.The stacking logic lives in pure
modalStackhelpers and is covered by nested-modal tests.#981 — Respect reduced motion
src/utils/motion.ts:useReducedMotion()— live OS "Reduce Motion" preference, defaults tofalse, updates onreduceMotionChanged, cleans up its listener, and degrades gracefully if the preference can't be read.motionDuration,resolveTransition(navigation),allowDecorativeAnimation(looping / parallax / gesture-driven),chartDrawProgress(chart jumps to its final frame).AccessibleModalalready consumes it (animationType="none"under reduced motion).#982 — High-contrast, colour-blind-safe health statuses
src/theme/healthStatus.ts— severity and trend tokens that never rely on hue alone (WCAG 1.4.1). Every token carries a textlabel, anicon, and a distinctshape;describeHealthStatus()produces the spoken/label string. Foreground colours use an Okabe–Ito-derived palette and are verified in tests to clear WCAG AA (4.5:1) against every light and dark surface token.Tests
Focused unit tests added for all four modules (characterisation-first), following existing repo patterns (
jest.mock('react-native'),renderHook):src/utils/__tests__/a11yChartSummary.test.ts— summaries, list equivalents, empty/offline/malformed-input paths, no-PII assertions.src/utils/__tests__/motion.test.ts— reduced-motion policy + hook default / live-update / unmount / unsupported-preference paths.src/hooks/__tests__/useAccessibleModal.test.ts— focus move + restore, Android back routing, nested-modal stacking, unmount cleanup.src/theme/__tests__/healthStatus.test.ts— redundant cues, distinct shapes, WCAG AA contrast in light and dark themes.Pure-function output was verified locally via
node --experimental-strip-types; the full Jest run requiresnpm install(nonode_modulesin this environment).Notes
docs/ACCESSIBILITY.md. Migrating each existing chart/modal/animation onto these helpers is intended as follow-up so this PR stays reviewable.