mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 13:52:20 +00:00
fix(a11y): explicit accessibilityLayer, tile headings, stronger focus ring
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.
This commit is contained in:
1 parent
3a45fcc3bd
commit
f223ca8979
7 files changed
+17
-5
No files matched your search
@@ -1825,6 +1825,7 @@ export function HealthChart({
|
||||
<ComposedChart
|
||||
data={chartDataWithCompare ?? chartData}
|
||||
margin={{ top: 10, right: 8, bottom: 8, left: 8 }}
|
||||
accessibilityLayer
|
||||
>
|
||||
<CartesianGrid
|
||||
strokeDasharray="3 3"
|
||||
|
||||
@@ -733,6 +733,7 @@ export function MoodChart({
|
||||
<ComposedChart
|
||||
data={chartDataWithCompare ?? chartData}
|
||||
margin={{ top: 10, right: 8, bottom: 8, left: 8 }}
|
||||
accessibilityLayer
|
||||
>
|
||||
{/* v1.4.25 W3 — the mood chart's YAxis is pinned to
|
||||
five mood-score ticks ([1,2,3,4,5]), which Recharts
|
||||
|
||||
@@ -84,6 +84,7 @@ export function RecentWorkoutsTile() {
|
||||
icon={Activity}
|
||||
size="sm"
|
||||
title={t("dashboard.recentWorkouts.title")}
|
||||
titleAs="h2"
|
||||
right={
|
||||
<Link
|
||||
href="/insights/workouts"
|
||||
|
||||
@@ -646,7 +646,7 @@ export function CoachInput({
|
||||
className={cn(
|
||||
"border-border/60 bg-muted/40 group rounded-2xl border",
|
||||
"shadow-sm transition-colors",
|
||||
"focus-within:border-primary/50 focus-within:ring-primary/15 focus-within:bg-background focus-within:ring-2",
|
||||
"focus-within:border-primary/50 focus-within:ring-primary/50 focus-within:bg-background focus-within:ring-2",
|
||||
// Both surfaces share ONE baseline row: the drawer flanks the
|
||||
// textarea with mic (left) + send (right); the page leads with a
|
||||
// `+` actions menu, then the textarea, then mic + send. `items-end`
|
||||
|
||||
@@ -146,6 +146,7 @@ export function SparklineDeltaTile({
|
||||
<TileHeader
|
||||
icon={Icon}
|
||||
title={label}
|
||||
titleAs="h2"
|
||||
className="min-w-0"
|
||||
titleClassName="min-w-0 truncate whitespace-nowrap"
|
||||
right={
|
||||
|
||||
@@ -262,7 +262,12 @@ function BaselineTile({
|
||||
data-state="provisional"
|
||||
className="bg-card border-border flex h-full w-full min-w-0 flex-col gap-3 rounded-xl border p-4 md:p-6"
|
||||
>
|
||||
<TileHeader icon={Icon} title={label} titleClassName="truncate" />
|
||||
<TileHeader
|
||||
icon={Icon}
|
||||
title={label}
|
||||
titleAs="h2"
|
||||
titleClassName="truncate"
|
||||
/>
|
||||
<p
|
||||
className="text-muted-foreground text-sm"
|
||||
data-slot="vitals-tile-building"
|
||||
@@ -457,6 +462,7 @@ function HrvBalanceTile({ read, isLoading }: TileProps) {
|
||||
<TileHeader
|
||||
icon={HeartPulse}
|
||||
title={t("measurements.typeHeartRateVariability")}
|
||||
titleAs="h2"
|
||||
titleClassName="truncate"
|
||||
/>
|
||||
<p className="text-muted-foreground text-sm">
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user