Skip to content

fix(frontend): overlay/focus/motion a11y, sign-in & registry recovery, DS hardening#1036

Merged
BigSimmo merged 8 commits into
mainfrom
claude/frontend-review-improve-123366
Jul 21, 2026
Merged

fix(frontend): overlay/focus/motion a11y, sign-in & registry recovery, DS hardening#1036
BigSimmo merged 8 commits into
mainfrom
claude/frontend-review-improve-123366

Conversation

@BigSimmo

@BigSimmo BigSimmo commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Summary

Targeted convergence & hardening of the (already mature) frontend, from a fresh adversarially-verified audit — no redesign, no god-component refactor. 31 findings audited (1 High, rest Medium/Low, no Critical); the High + confirmed Mediums + clear low-risk wins are fixed here (17 findings), the rest documented as follow-ups.

Accessibility

  • ui/sheet.tsx — module-level open-stack so only the top-most Sheet handles Escape/Tab (fixes stacked Evidence→lightbox/table double-close + focus escape), with a ref-counted body-scroll lock. (ARCH-01 High, ARCH-02; WCAG 2.1.2/2.4.3)
  • scroll-padding-bottom on #main-content so keyboard focus never lands under the fixed composer dock. (A11Y-FOCUS-01; WCAG 2.4.11)
  • New resolveScrollBehavior() gates ~13 scripted smooth-scrolls on the reduced-motion preference (the in-app toggle was silently broken for scrolling). (ANIM-01; WCAG 2.3.3)
  • IconButton primitive with a TS-required accessible label; adopted in InlineNotice + image lightbox. Live regions on the answer skeleton and lightbox loading/failure. (TCD-06, A11Y-LIVE-02/03)

State / feedback / forms

  • Settings sign-in now surfaces auth.notice (the "check your email" confirmation) and OAuth errors via the shared InlineNotice. (STATE-01)
  • Registry errors get a real Retry (hook refetch + button) across the record loader and services/forms homes, instead of a reload-only dead end. (STATE-02)
  • Email-field autofill/inputMode/aria-invalid+aria-describedby on Settings & account-setup; 100vh→100dvh in the global error boundary. (FV-01/FV-02, RESP-03)

Design system

  • --shadow-rail-active token replaces 4 hand-inlined active-rail shadows; the design-system-contract literal-shadow baseline is tightened 6→1. (DSD-05/01/06)

Tests & docs

  • 5 new *.dom.test.tsx (stacked Sheet, reduced-motion scroll, IconButton label contract, ModeHomeStatusNotice retry, registry error-recovery); docs/testing.md component-test patterns + contribution checklist; docs/design-system.md new-API entries.

Verification

npm run typecheck ✓ · npm run lint ✓ · full unit+jsdom suite npm run test — 344 files / 3077 passed / 1 skipped / 0 failed ✓ · check:design-system-contract ✓ (at the tightened baseline) · check:type-scale/check:icon-scale ✓ · format:check ✓. The Chromium verify:ui gate runs here in CI.

Clinical-governance preflight

N/A — pure UI/frontend work. No changes to ingestion, answer generation, search/ranking, source rendering, document access, privacy, or clinical output. (One clinical-adjacent finding — FV-03, patient-profile numeric bounds — was deliberately deferred as governance-gated.)

Notes

  • Rebased onto current origin/main; a pre-existing unrelated ACL migration that was parked on the branch base was excluded.
  • Deferred (documented): the viewport/chrome-height token (RESP-01/DSD-04), enhancement burndown (DSD-02/03), god-component render tests (TCD-01…05), and FV-03/FV-04.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added “Try again” retry actions for forms, services, and record loading errors.
    • Introduced a standardized accessible icon-only button pattern and migrated key controls to it.
  • Accessibility
    • Improved loading/error announcements (status/alert roles) and corrected icon-button labeling.
    • Enhanced form error association for sign-in email input.
    • Scrolling animations now consistently respect reduced-motion preferences.
  • Visual Updates
    • Updated “rail active” shadows/elevation tokens, including forced-colors handling.
    • Refined mobile scroll padding for the bottom composer area and error screen centering.
  • Documentation & Tests
    • Expanded design-system contract + UI testing guidance, with added reduced-motion, sheet stacking, icon button, and retry test coverage.

…, DS hardening

Targeted convergence & hardening from a fresh audit of the (already mature)
frontend — no redesign, no god-component refactor. All batches verified:
typecheck, lint, full unit+jsdom suite (2986 passed / 1 skipped), and the
design-system contract at a tightened literal-shadow baseline.

- ui/sheet.tsx: module-level open-stack so only the top-most Sheet handles
  Escape/Tab (fixes stacked Evidence->lightbox/table double-close + focus
  escape), with a ref-counted body-scroll lock (ARCH-01/02; WCAG 2.1.2/2.4.3).
- scroll-padding-bottom on #main-content so keyboard focus never lands under the
  fixed composer dock (A11Y-FOCUS-01; WCAG 2.4.11).
- new resolveScrollBehavior() gates ~14 scripted smooth-scrolls on the
  reduced-motion preference (ANIM-01; WCAG 2.3.3).
- ui-primitives: IconButton primitive with a required accessible label; adopted
  in InlineNotice + image lightbox. Live regions on answer skeleton / lightbox
  loading+failure (A11Y-LIVE-02/03).
- settings-dialog: surface auth notice + OAuth errors via the shared InlineNotice
  (STATE-01); email-field autofill/inputmode/aria (FV-01/02).
- registry hooks: refetch + Retry affordance across the record loader and the
  services/forms homes (STATE-02); 100vh->100dvh in global-error (RESP-03).
- --shadow-rail-active token replaces 4 inlined active-rail shadows; contract
  literal-shadow baseline tightened 6->1 (DSD-05/01/06).
- Regression tests (sheet, scroll-behavior, icon-button, mode-home-status-notice,
  registry-retry) + docs (component-test patterns, contribution checklist, APIs).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@supabase

supabase Bot commented Jul 21, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project sjrfecxgysukkwxsowpy because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: b9723053-b562-4a23-8289-3d05e6f661fe

📥 Commits

Reviewing files that changed from the base of the PR and between eb79f44 and 0ebdf27.

📒 Files selected for processing (2)
  • scripts/check-maintainability-budgets.mjs
  • src/components/ClinicalDashboard.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/ClinicalDashboard.tsx

📝 Walkthrough

Walkthrough

The PR centralizes reduced-motion scrolling, adds accessible UI primitives and status semantics, introduces retryable registry errors, coordinates stacked sheets, standardizes active-rail styling, and documents related design-system and testing contracts.

Changes

UI behavior and accessibility contracts

Layer / File(s) Summary
Reduced-motion scrolling and mobile layout
src/lib/scroll-behavior.ts, src/components/ClinicalDashboard.tsx, src/components/DocumentViewer.tsx, tests/*, docs/*
Scripted scrolling respects reduced-motion preferences, mobile scroll padding accounts for the composer reserve, and related tests and documentation are added.
Design tokens and viewport styling
src/app/globals.css, src/components/clinical-dashboard/favourites-*.tsx, src/components/clinical-dashboard/medication-prescribing-workspace.tsx, src/app/global-error.tsx, scripts/*, docs/design-system.md
Active rows use the --shadow-rail-active token, forced colors disable it, contract baselines and tooling notes are updated, and the global error layout uses 100dvh.
Accessible controls and feedback
src/components/ui-primitives.tsx, src/components/clinical-dashboard/*, tests/icon-button.dom.test.tsx, docs/design-system.md, docs/testing.md
IconButton standardizes labeled icon controls, loading and failure states expose status roles, authentication feedback is associated with inputs, and jsdom UI testing guidance is documented.
Registry retry actions
src/lib/use-registry-records.ts, src/components/*registry*, src/components/mode-home-template.tsx, tests/*retry*
Registry hooks expose refetch, error states render “Try again” actions, and navigation links remain available.
Stacked sheet coordination
src/components/ui/sheet.tsx, tests/sheet.dom.test.tsx
Open sheets share body scroll locking, only the top sheet handles keyboard events, and overflow is restored after the final sheet closes.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested labels: codex

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main frontend hardening changes around a11y, sign-in/registry recovery, and design-system updates.
Description check ✅ Passed The description covers the main template sections and provides substantive summary, verification, governance, and notes details.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/frontend-review-improve-123366

Comment @coderabbitai help to get the list of available commands.

BigSimmo and others added 2 commits July 21, 2026 10:30
The resolveScrollBehavior() swap lengthened a scrollTo call past the print
width; apply the wrap so format:check passes. No behavior change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/ui/sheet.tsx (1)

214-231: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Keep focus inside the remaining top Sheet.

Line 217 pops a lower Sheet, but Lines 218-231 still restore its prior focus target. If a lower Sheet closes while an upper Sheet remains open, this moves focus behind the active modal. Restore focus only when the closing Sheet was topmost; add a regression test for this out-of-order close.

Proposed fix
     return () => {
       window.cancelAnimationFrame(focusFrame);
       window.removeEventListener("keydown", onKeyDown);
+      const wasTopmost = isTopmostSheet(sheetId);
       popSheet(sheetId);
+      if (!wasTopmost) return;
       const restoreTarget = explicitReturnElement ?? previousActiveElement;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/ui/sheet.tsx` around lines 214 - 231, Update the cleanup logic
around popSheet in the Sheet component to restore focus only when the closing
sheet was topmost; when another Sheet remains active, leave focus within that
remaining top Sheet. Add a regression test covering out-of-order closure of a
lower Sheet while an upper Sheet is still open, verifying focus is not moved
behind the active modal.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/testing.md`:
- Line 65: Update the verification checklist in docs/testing.md to include npm
run verify:pr-local before handoff and npm run ensure before browser work.
Preserve the existing order requiring npm run verify:cheap first, npm run
verify:ui for UI/routing/styling changes, and the manual dark-mode and
forced-colors spot check.

In `@tests/clinical-dashboard-merge-artifacts.test.ts`:
- Around line 145-147: Add a second assertion in the clinical dashboard artifact
test alongside the existing clinicalDashboardSource check, targeting the
non-answer mobile class combination with sm:mb-0 and the same mobile composer
reserve scroll-padding utility. Keep the existing sm:mb-24 assertion unchanged.

---

Outside diff comments:
In `@src/components/ui/sheet.tsx`:
- Around line 214-231: Update the cleanup logic around popSheet in the Sheet
component to restore focus only when the closing sheet was topmost; when another
Sheet remains active, leave focus within that remaining top Sheet. Add a
regression test covering out-of-order closure of a lower Sheet while an upper
Sheet is still open, verifying focus is not moved behind the active modal.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 413bfde7-d86a-49bc-875e-0e0799f444cc

📥 Commits

Reviewing files that changed from the base of the PR and between 366eff9 and 9a70926.

📒 Files selected for processing (30)
  • docs/design-system.md
  • docs/testing.md
  • scripts/check-type-scale.mjs
  • scripts/design-system-contract-baseline.json
  • src/app/global-error.tsx
  • src/app/globals.css
  • src/components/ClinicalDashboard.tsx
  • src/components/DocumentViewer.tsx
  • src/components/clinical-dashboard/account-setup-dialog.tsx
  • src/components/clinical-dashboard/answer-status.tsx
  • src/components/clinical-dashboard/favourites-command-library-page.tsx
  • src/components/clinical-dashboard/favourites-library-nav.tsx
  • src/components/clinical-dashboard/image-lightbox.tsx
  • src/components/clinical-dashboard/medication-prescribing-workspace.tsx
  • src/components/clinical-dashboard/settings-dialog.tsx
  • src/components/forms/forms-home-page.tsx
  • src/components/mode-home-template.tsx
  • src/components/registry-record-loader.tsx
  • src/components/services/services-home-page.tsx
  • src/components/ui-primitives.tsx
  • src/components/ui/sheet.tsx
  • src/lib/scroll-behavior.ts
  • src/lib/use-registry-records.ts
  • tests/clinical-dashboard-merge-artifacts.test.ts
  • tests/favourites-demo-boundary.test.ts
  • tests/icon-button.dom.test.tsx
  • tests/mode-home-status-notice.dom.test.tsx
  • tests/registry-retry.dom.test.tsx
  • tests/scroll-behavior.dom.test.tsx
  • tests/sheet.dom.test.tsx

Comment thread docs/testing.md Outdated
Comment thread tests/clinical-dashboard-merge-artifacts.test.ts
@github-actions

Copy link
Copy Markdown

CI triage

CI failed on this PR. Automated classification of the 2 failed job(s):

  • Static PR checksneeds investigation: inspect the failing step and uploaded diagnostics; rerun only after classifying the cause.
  • PR requiredneeds investigation: inspect the failing step and uploaded diagnostics; rerun only after classifying the cause.

Compared with main CI run #4223 (success).

Classification is evidence routing, not permission to ignore a failure. Exact quarantined Playwright identities remain governed by the flake ledger.

BigSimmo and others added 5 commits July 21, 2026 10:41
- check:maintainability-budgets was red: the reduced-motion helper import
  (resolveScrollBehavior) grew ClinicalDashboard.tsx 4272->4274 and
  DocumentViewer.tsx 1733->1734 (import + one prettier-wrapped call).
  Ratchet the no-growth budgets by the exact +2/+1; no monolith complexity
  added, and #1034 is separately decomposing ClinicalDashboard downward.
- docs/testing.md: document verify:pr-local (before handoff) and
  npm run ensure (before browser work) in the Verify checklist.
- clinical-dashboard-merge-artifacts.test.ts: also assert the non-answer
  (sm:mb-0) branch carries the scroll-padding-bottom utility.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013f523gDfoBXPYT4H9vXRkE
…23366' into claude/frontend-review-improve-123366
…w-improve-123366

# Conflicts:
#	scripts/check-maintainability-budgets.mjs
@BigSimmo
BigSimmo merged commit 4ac43aa into main Jul 21, 2026
18 checks passed
@BigSimmo
BigSimmo deleted the claude/frontend-review-improve-123366 branch July 21, 2026 04:20
BigSimmo added a commit that referenced this pull request Jul 21, 2026
…sions (#1048)

* test(a11y): lock in reduced-motion scroll + focus-not-obscured regressions

Guard the two accessibility fixes shipped in #1036 against regression:

- ANIM-01 (WCAG 2.3.3): a live Chromium test intercepts the behaviour argument
  every scripted scrollTo/scrollIntoView receives, then triggers a known scroll
  ("New chat"). Reduced motion must produce instant "auto" jumps; no-preference
  must animate ("smooth") — verifying resolveScrollBehavior() is threaded through
  the call sites, not just unit-tested in isolation.
- A11Y-FOCUS-01 (WCAG 2.4.11): a deterministic source pin asserts #main-content
  reserves scroll-padding-bottom in both mobile dock branches (plus the answer
  scroll-padding-top). The reservation only renders in app states impractical to
  reach reliably in a browser test, so it is pinned at source — the repo's
  established pattern for phone scroll-geometry invariants.

Verified: typecheck, lint, format:check, full unit+jsdom suite (348 files /
3108 passed / 0 failed), and both targeted tests green against the local server.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* test(a11y): scope scroll-padding guard to #main-content and require both dock branches

Address the review findings on the A11Y-FOCUS-01 source pin:
- Bind every assertion to the extracted `<main id="main-content">` opening tag
  instead of counting source-wide occurrences, so a reservation class that drifts
  onto a child or a non-scrolling wrapper now fails the guard (a `>` inside a
  className comment means the tag is read up to its line-final `>`).
- Require the *paired* `pb` + `scroll-padding-bottom` reservation in both dock
  branches (>=2), so one branch losing its content padding no longer passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LRZ1EyBZW1ADXrZvMxEEsC

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants