From f223ca89791f38377cd96c75d1725bdd36d49f5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sat, 18 Jul 2026 03:19:43 +0200 Subject: [PATCH] fix(a11y): explicit accessibilityLayer, tile headings, stronger focus ring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Health-chart and mood-chart now pass accessibilityLayer explicitly on their ComposedChart root — Recharts 3 already defaults it on, but pinning it here documents the choice and survives a future default flip on the two busiest chart surfaces in the app. TileHeader's titleAs="h2" was previously read as a single-owner exception; the docstring undersold it — sibling h2 tiles in one grid nest correctly under the page h1 same as a lone owning block. Wires it through the dashboard's recent-workouts tile and the insights vitals grid (both the loaded SparklineDeltaTile card and the two provisional/ building states), so a rotor user gets one heading per tile instead of landing on the page's single h1 and nothing else. The coach composer's focus ring rode ring-primary/15 — likely under the 3:1 non-text-contrast floor next to its /50 border. Raises it to /50, matching the family of "wrapper focus-within ring, outline-none inner control" the standard already uses elsewhere at full strength. --- src/components/charts/health-chart.tsx | 1 + src/components/charts/mood-chart.tsx | 1 + src/components/dashboard/recent-workouts-tile.tsx | 1 + src/components/insights/coach-panel/coach-input.tsx | 2 +- src/components/insights/derived/sparkline-delta-tile.tsx | 1 + src/components/insights/derived/vitals-dashboard.tsx | 8 +++++++- src/components/insights/tile-header.tsx | 8 +++++--- 7 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/components/charts/health-chart.tsx b/src/components/charts/health-chart.tsx index 774f30e5e..66e0a22b7 100644 --- a/src/components/charts/health-chart.tsx +++ b/src/components/charts/health-chart.tsx @@ -1825,6 +1825,7 @@ export function HealthChart({ {/* v1.4.25 W3 — the mood chart's YAxis is pinned to five mood-score ticks ([1,2,3,4,5]), which Recharts diff --git a/src/components/dashboard/recent-workouts-tile.tsx b/src/components/dashboard/recent-workouts-tile.tsx index 7fcf86efc..2eee9a39d 100644 --- a/src/components/dashboard/recent-workouts-tile.tsx +++ b/src/components/dashboard/recent-workouts-tile.tsx @@ -84,6 +84,7 @@ export function RecentWorkoutsTile() { icon={Activity} size="sm" title={t("dashboard.recentWorkouts.title")} + titleAs="h2" right={ - +

diff --git a/src/components/insights/tile-header.tsx b/src/components/insights/tile-header.tsx index 3ceb76aad..a5fdf21f8 100644 --- a/src/components/insights/tile-header.tsx +++ b/src/components/insights/tile-header.tsx @@ -54,9 +54,11 @@ interface TileHeaderProps { /** * Render the title as a real heading element (e.g. `"h2"`) instead of the * default presentational `CardTitle` div, keeping the identical CardTitle - * styling. Use only where the tile owns the ONLY heading on its subpage - * branch (the recovery blocks) so the `h1 → h2` outline stays nested with no - * skipped level. Default (unset) keeps every other tile a plain CardTitle. + * styling. Use on tiles that sit directly under the page's `h1` — a single + * owning block (the recovery blocks) or a grid of sibling tiles (dashboard + * tiles, insights overview grids) both nest correctly as `h1 → h2, h2, …`; + * just don't nest a `titleAs="h2"` tile inside another heading's own + * subsection. Default (unset) keeps every other tile a plain CardTitle. */ titleAs?: "h2"; }