diff --git a/src/components/insights/coach-panel/__tests__/history-rail.test.tsx b/src/components/insights/coach-panel/__tests__/history-rail.test.tsx index d1e8d0678..4f22bb61c 100644 --- a/src/components/insights/coach-panel/__tests__/history-rail.test.tsx +++ b/src/components/insights/coach-panel/__tests__/history-rail.test.tsx @@ -66,6 +66,21 @@ describe("", () => { expect(html).toContain("Conversations"); }); + it("renders the rail label as a real `

` heading (v1.4.33)", () => { + // The rail mounts inline on `lg+` desktop where no `SheetTitle` + // wrapper covers it. Without a real heading element the drawer + // lost its semantic outline above the message thread — fixed in + // v1.4.33 by promoting the rail label to `

`. + const client = makeClientWithConversations(samplePage); + const html = render( + {}} />, + client, + ); + expect(html).toMatch( + /]*data-slot="coach-history-rail-heading"[^>]*>[\s\S]*Conversations[\s\S]*<\/h3>/, + ); + }); + it("renders one row per conversation", () => { const client = makeClientWithConversations(samplePage); const html = render( diff --git a/src/components/insights/coach-panel/__tests__/sources-rail.test.tsx b/src/components/insights/coach-panel/__tests__/sources-rail.test.tsx index 84373b10f..3e4b974ff 100644 --- a/src/components/insights/coach-panel/__tests__/sources-rail.test.tsx +++ b/src/components/insights/coach-panel/__tests__/sources-rail.test.tsx @@ -17,6 +17,17 @@ describe("", () => { expect(html).toContain("What I can see"); }); + it("renders the rail label as a real `

` heading (v1.4.33)", () => { + // The rail mounts inline on `xl+` desktop where no `SheetTitle` + // wrapper covers it. Promoting the label to `

` restores the + // drawer's semantic outline so screen-reader users can navigate + // by heading. + const html = render(); + expect(html).toMatch( + /]*data-slot="coach-sources-rail-heading"[^>]*>[\s\S]*What I can see[\s\S]*<\/h3>/, + ); + }); + it("lists exactly five rows (BP, weight, pulse, mood, compliance)", () => { const html = render(); const rows = html.match(/data-slot="coach-sources-row"/g) ?? []; diff --git a/src/components/insights/coach-panel/history-rail.tsx b/src/components/insights/coach-panel/history-rail.tsx index c0442440e..96d1fa99a 100644 --- a/src/components/insights/coach-panel/history-rail.tsx +++ b/src/components/insights/coach-panel/history-rail.tsx @@ -69,15 +69,23 @@ export function HistoryRail({ data-slot="coach-history-rail" className={cn("flex h-full min-h-0 flex-col gap-2 p-3", className)} > -
+ {/* v1.4.33 — promote the rail label from a `` to a real + `

` so the drawer carries a semantic outline on desktop + where the rail is mounted inline (no `SheetTitle` wrapper). + The mobile rail-tray still wraps the rail inside its own + `SheetTitle`, so screen-reader users hear the section twice + when the tray is open — that's intentional Radix behaviour + (the rail still has to stand alone on desktop). */} +

+ {t("insights.coach.historyTitle")} +

{/* Window selector — every row below is filtered to the picked window when the next Coach message goes out. 36px touch