feat(ui): polish — design tokens, focus-visible, a11y, Dashboard component#237
Open
wreiske wants to merge 2 commits into
Open
feat(ui): polish — design tokens, focus-visible, a11y, Dashboard component#237wreiske wants to merge 2 commits into
wreiske wants to merge 2 commits into
Conversation
Phase 1 — Token foundation - Add BrandSpacing/BrandDensity/BrandMotion/BrandFocusRing/BrandElevation interfaces (src/brands/types.ts) - Emit new --mieweb-* CSS custom props for spacing (xs..2xl), density-scale, motion (fast/base/slow + 3 easings), focus-ring (width/offset/style), elevation (1..6 + inner) - Wire defaults into base.css :root + @theme so all 8 brands inherit automatically - BlueHive populated with full token values (src/brands/bluehive.{ts,css}) - Tailwind preset exposes shadow elevation-*, spacing brand-*, transition duration/timing, ring width/offset utilities - :focus-visible consumes brand focus-ring tokens - Compact density via [data-density=compact] (preferred) + legacy body.condensed alias - prefers-reduced-motion already honored Phase 2 — Component cleanup - Badge: hardcoded green/yellow/red → semantic success/warning/destructive scales (dark-mode aware) - HRISProviderSelector pending-sync alert: yellow-* → warning tokens + role=status - ProviderOverview skeleton: gray-200/gray-700 → bg-muted (theme-aware) - Global sweep: focus:ring → focus-visible:ring across all components (mouse focus no longer shows ring) - Table: <th scope=col> for screen-reader column header semantics Phase 3 — Dashboard - New <Dashboard> composable component (src/components/Dashboard/Dashboard.tsx) - Slots: Dashboard.Header / Title / Subtitle / Actions / Grid / Widget - Responsive 1 → 6 → 12 column grid (mobile / tablet / desktop) - Density + brand-spacing aware - Exported from src/index.ts - Removed stale .bak / .backup / .broken story files Phase 4 — Verification - New tests/visual/a11y.spec.ts with axe-core (WCAG 2.1 A+AA) - 14 core stories scanned, zero critical/serious violations - @axe-core/playwright added as devDependency Validation - pnpm typecheck PASS - pnpm lint PASS - pnpm test (vitest) 113/113 PASS - pnpm build (tsup ESM+CJS+DTS) PASS - pnpm test:visual: 20/20 baseline regressions PASS (within 5% tolerance) - pnpm test:visual: 14/14 a11y PASS
Deploying ui with
|
| Latest commit: |
b95d33c
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://c42975f2.ui-6d0.pages.dev |
| Branch Preview URL: | https://feat-ui-polish-phase1-4.ui-6d0.pages.dev |
There was a problem hiding this comment.
Pull request overview
This PR is a broad UI “polish sprint” that extends the design-token foundation (spacing/density/motion/focus-ring/elevation), standardizes :focus-visible usage across components, adds an axe-core Playwright accessibility suite, and introduces a new composable Dashboard component exported from the library.
Changes:
- Added brand token groups (spacing/density/motion/focus ring) + elevation ramp and exposed them via CSS variables and Tailwind preset utilities/safelist.
- Standardized focus styling across many components by moving rings to
focus-visible:*utilities and made a few semantic color/accessibility tweaks (e.g., warning status alert,th scope="col"). - Added axe-core Playwright tests and a new
Dashboardslot-based component.
Reviewed changes
Copilot reviewed 61 out of 62 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/visual/components.spec.ts | Minor formatting change to a story navigation call. |
| tests/visual/a11y.spec.ts | New Playwright/axe accessibility test suite targeting core stories. |
| src/tailwind-preset.ts | Added new token utilities to theme + extended Tailwind safelist. |
| src/styles/base.css | Added elevation/spacing/motion/focus-ring CSS variables + density selector + focus-visible outline tokenization. |
| src/index.ts | Exported new Dashboard component from the package entry point. |
| src/components/WebsiteInput/WebsiteInput.tsx | Switched ring styling to focus-visible:*. |
| src/components/Toast/Toast.tsx | Switched ring styling to focus-visible:*. |
| src/components/ThemeProvider/ThemeToggle.tsx | Switched ring styling to focus-visible:*. |
| src/components/Textarea/Textarea.tsx | Switched ring styling (incl. error state) to focus-visible:*. |
| src/components/Table/Table.tsx | Added scope="col" to table header cells for improved semantics. |
| src/components/StepIndicator/StepIndicator.tsx | Switched ring styling to focus-visible:*. |
| src/components/Sidebar/Sidebar.tsx | Switched ring styling to focus-visible:*. |
| src/components/SetupServiceModal/SetupServiceModal.tsx | Switched ring styling to focus-visible:*. |
| src/components/ServiceShippingSettings/ServiceShippingSettings.tsx | Switched ring styling to focus-visible:*. |
| src/components/ServiceGeneralSettings/ServiceGeneralSettings.tsx | Switched ring styling to focus-visible:*. |
| src/components/ServiceBadge/ServiceBadge.tsx | Switched ring styling to focus-visible:*. |
| src/components/Select/Select.tsx | Switched ring styling (incl. error state + searchable input) to focus-visible:*. |
| src/components/SchedulePicker/SchedulePicker.tsx | Switched ring styling to focus-visible:*. |
| src/components/RejectionModal/RejectionModal.tsx | Switched ring styling to focus-visible:*. |
| src/components/RecurringServiceCard/RecurringServiceCard.tsx | Switched ring styling to focus-visible:*. |
| src/components/ProviderSelector/ProviderSelector.tsx | Switched ring styling to focus-visible:*. |
| src/components/ProviderSearchFilters/ProviderSearchFilters.tsx | Switched ring styling to focus-visible:*. |
| src/components/ProviderOverview/ProviderOverview.tsx | Updated skeleton colors to semantic bg-muted. |
| src/components/ProviderDetailHeader/ProviderDetailHeader.tsx | Switched ring styling to focus-visible:*. |
| src/components/PhoneInput/PhoneInput.tsx | Switched ring styling to focus-visible:*. |
| src/components/PaymentMethod/PaymentMethod.tsx | Switched ring styling to focus-visible:*. |
| src/components/PatientHeader/PatientHeader.tsx | Switched ring styling to focus-visible:*. |
| src/components/OrderList/OrderList.tsx | Switched ring styling to focus-visible:*. |
| src/components/OrderConfirmationWizard/OrderConfirmationWizard.tsx | Switched ring styling to focus-visible:*. |
| src/components/Messaging/MessageThread.tsx | Switched ring styling to focus-visible:*. |
| src/components/Messaging/MessageList.tsx | Switched ring styling to focus-visible:*. |
| src/components/Messaging/MessageComposer.tsx | Switched ring styling to focus-visible:*. |
| src/components/Messaging/MessageBubble.tsx | Switched ring styling to focus-visible:*. |
| src/components/Messaging/ConversationHeader.tsx | Switched ring styling to focus-visible:*. |
| src/components/Messaging/AttachmentPicker.tsx | Switched ring styling to focus-visible:*. |
| src/components/LanguageSelector/LanguageSelector.tsx | Switched ring styling to focus-visible:*. |
| src/components/InviteUserModal/InviteUserModal.tsx | Switched ring styling to focus-visible:*. |
| src/components/Input/Input.tsx | Switched ring styling (incl. error state) to focus-visible:*. |
| src/components/HRISProviderSelector/HRISProviderSelector.tsx | Converted pending-sync alert to semantic warning tokens + added role="status" + focus-visible ring updates. |
| src/components/EmployerServiceModal/EmployerServiceModal.tsx | Switched ring styling to focus-visible:*. |
| src/components/DateRangePicker/DateRangePicker.tsx | Switched ring styling to focus-visible:*. |
| src/components/DateInput/DateInput.tsx | Switched ring styling (incl. error state) to focus-visible:*. |
| src/components/Dashboard/index.ts | New Dashboard barrel export. |
| src/components/Dashboard/Dashboard.tsx | New composable Dashboard component with slot API and responsive grid/widget spans. |
| src/components/Dashboard/Dashboard.stories.tsx.broken | Removed broken backup story file. |
| src/components/Dashboard/Dashboard.stories.tsx.bak | Removed backup story file. |
| src/components/Dashboard/Dashboard.stories.tsx.backup | Removed backup story file. |
| src/components/CountryCodeDropdown/CountryCodeDropdown.tsx | Switched ring styling to focus-visible:*. |
| src/components/CountBadge/CountBadge.tsx | Switched ring styling to focus-visible:*. |
| src/components/BookingDialog/BookingDialog.tsx | Switched ring styling to focus-visible:*. |
| src/components/Badge/Badge.tsx | Switched badge palettes from literal colors to semantic success/warning/destructive tokens. |
| src/components/AuthDialog/AuthDialog.tsx | Switched ring styling to focus-visible:*. |
| src/components/AppHeader/AppHeader.tsx | Switched ring styling to focus-visible:*. |
| src/components/AI/MCPToolCall.tsx | Switched ring styling to focus-visible:*. |
| src/components/AI/AIChatModal.tsx | Switched ring styling to focus-visible:*. |
| src/components/Address/Address.tsx | Switched ring styling to focus-visible:*. |
| src/brands/types.ts | Extended brand token types + defaults; updated CSS/Tailwind theme generation to emit new token variables. |
| src/brands/bluehive.ts | Populated BlueHive brand config with new token groups (spacing/density/motion/focus ring/elevation). |
| src/brands/bluehive.css | Added new token CSS variables and focus-ring styling to the BlueHive standalone CSS. |
| pnpm-lock.yaml | Added @axe-core/playwright (and updated axe-core snapshot). |
| package.json | Added @axe-core/playwright dev dependency. |
| .storybook/preview.tsx | Applied data-density globally and injected brand token CSS variables (spacing/motion/focus/elevation) into Storybook. |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- a11y.spec: throw on Storybook error/no-preview state (mirror components.spec); fix 6 wrong story IDs (Badge/Card/Progress/Avatar/Tabs/Toast/Alert) so failures surface - tailwind-preset: safelist Dashboard responsive grid (col-span-full, sm:col-span-*, lg:col-span-*, lg:grid-cols-12, md:p-brand-xl, sm:gap-brand-lg) and focus-visible ring utilities (ring-2, ring-offset-2, ring-primary, ring-destructive, ring-success, ring-success/20, ring-destructive/20, border-transparent) - BrandDensity.default now drives the initial --mieweb-density-scale; added [data-density='comfortable'] reset selector so brands defaulting to compact can be flipped back at runtime - BrandFocusRing.color now emits --mieweb-focus-ring-color mapped to a semantic token (ring/primary/destructive); consumed by base.css, bluehive.css, and the Storybook preview :focus-visible outline Validation: tsc, eslint, prettier, vitest (113/113), build-storybook, playwright (20 visual + 14 a11y = 34/34) all green.
Member
Author
|
Addressed all 4 Copilot review comments in
Validation: typecheck, eslint, prettier, vitest (113/113), |
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
A focused polish sprint covering the four phases of the original UI polish plan: design-token foundation, semantic color cleanup, focus-visible standardization, accessibility instrumentation, and a new composable
Dashboardcomponent. Existing visual baselines remain valid (all 20 snapshot tests pass within tolerance), so this is a non-breaking visual upgrade that ships new capability (better dark mode, density support, motion tokens, brand-driven focus rings) without disturbing pixel-level appearance of existing components.What's in it
Phase 1 — Design token foundation
BrandConfigwith optionalspacing,density,motion,focusRinggroups + numberedelevation 1..6 + inner(src/brands/types.ts)--mieweb-*CSS custom properties emitted into:rootviasrc/styles/base.cssso all 8 brands inherit defaults automatically — individual brands can opt-in to overridebluehivebrand fully populated as the reference (src/brands/bluehive.{ts,css})src/tailwind-preset.ts) exposes new utilities:shadow-elevation-1..6,spacing brand-xs..2xl(density-multiplied),transition duration fast/base/slow,transition timing standard/emphasized/decelerate,ring-width-focus,ring-offset-width-focus@themeblock re-exports the same tokens[data-density="compact"]with legacybody.condensedalias for the existing 11.5k-line condensed sheet:focus-visiblenow consumes--mieweb-focus-ring-*so brands can configure focus appearanceprefers-reduced-motionalready honored in base CSSPhase 2 — Component cleanup
green-*/yellow-*/red-*palettes → semanticsuccess/warning/destructivescales (full light + dark mode coverage)warningsemantic tokens, addedrole="status"gray-200 dark:bg-gray-700→bg-muted(theme-aware)focus:ring*→focus-visible:ring*across all 54 affected component files — keyboard-only focus indication, no ring on mouse clickscope="col"on<th>for screen-reader column semantics (already hadaria-sort)Phase 3 — Dashboard
<Dashboard>component (src/components/Dashboard/Dashboard.tsx) with slot API:Dashboard.Header / .Title / .Subtitle / .ActionsDashboard.Grid— responsive 1-col (mobile) → 6-col (sm) → 12-col (lg) CSS gridDashboard.Widget colSpan={1..12} smColSpan={1..6}gap-brand-md/lgdensity-aware spacingsrc/index.ts*.bak / *.backup / *.brokenfilesPhase 4 — Accessibility verification
@axe-core/playwright(dev)tests/visual/a11y.spec.ts— runs axe against WCAG 2.1 A+AA tags on 14 core stories (Button, Input, Select, Checkbox, Switch, Badge, Card, Alert, Progress, Avatar, Breadcrumb, Tabs, Toast)Validation
pnpm typecheckpnpm lintpnpm test(vitest)pnpm build(tsup)pnpm test:visualregressionpnpm test:visuala11yBefore/after screenshots — yes, we have visual regression testing
The repository uses Playwright visual regression (
tests/visual/components.spec.ts) with 20 baseline PNGs intests/visual/components.spec.ts-snapshots/. Those baselines are the "before" — they were generated againstmainprior to this work. Whenpnpm test:visualruns in this PR, Playwright pixel-compares against those baselines:*-actual.png/*-diff.pngartifacts inplaywright-report/for reviewplaywright-report/index.htmlTo see "after" visual changes for the dark-mode + density paths (which the existing snapshots don't cover), follow-up work would parameterize the spec across viewports + light/dark + density (see Follow-ups).
Design decisions worth a review note
BrandDensity.default. A future<MieWebUIProvider density="compact">could swap densities at runtime. Out of scope here.--mieweb-ring(matches existing brand).focusRing.colorfield onBrandConfiglets brands override.Dashboardwidget content — left as openchildrenAPI rather than constraining to specific slot types, so apps can drop inCard, charts, custom widgets.base.css. Each brand can override later as needed. This avoids churning 7 files for no immediate visual change.Follow-ups (not blocking)
mieweb,ccme,enterprise-health,ozwell,waggleline,webchart,defaulttests/visual/components.spec.tsacross mobile/tablet/desktop viewports + light/dark themesSelectcombobox variant,DateInput/DateRangePicker, and replace<div role="checkbox">inCheckrIntegration.tsxwith real<Checkbox>Dashboard.stories.tsx(2273 lines) using the new<Dashboard>slot APIDashboardWidgetintoDashboard/folderFiles changed: 62
focus-visiblesweepDashboard.tsx,a11y.spec.ts