Repository navigation
feat(ui): design-system facelift — control scale, contrast in 6 themes, a11y fixes, Figma relink - #639
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedToo many files! This PR contains 162 files, which is 62 over the limit of 100. To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch. Upgrade to a paid plan to raise the limit. This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry. ⚙️ Run configuration
⛔ Files ignored due to path filters (1)
📒 Files selected for processing (162)
You can disable this status message by setting the
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Storybook A11y Report
Light
By group
New violations (314)
Resolved violations (605)
Dark
By group
|
Adds section F (Carousel and Steps contrast + control sizing) to the facelift backlog and a work log of the Figma-side changes: re-aliased and new variables, remote-to-local variable rebinding, rebuilt Carousel controls on Action Icon, Steps 24/32/40 scale, measured contrast in all six theme modes, and the code checklist to run after the token export. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- table.figma.ts now targets the new static Table set (3938:1793) on the consolidated Figma Table page; the old Table page was removed. - data-table.figma.ts: the Figma assembly is now named DataTable. - carousel.figma.ts: map the size=full variant (typo fixed in Figma). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
axe flagged aria-prohibited-attr on every skeleton shape: aria-label is not allowed on a generic <div>. The root and standalone shapes are now role="status" (named live region); shapes inside <Skeleton> are aria-hidden so a group announces once; a consumer-hidden shape keeps aria-busy + aria-hidden without status semantics (PriceBlock and AvailabilityStatus contract unchanged). Skeleton v1.0.2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Without a target page the prev/next trigger rendered as an <a> with no href, which has no role, so Zag's aria-label was prohibited (axe aria-prohibited-attr, also on DataTable pagination). It now renders an aria-disabled <button type="button">. Pagination v1.0.1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Without an id prop the Label rendered htmlFor={undefined} while Zag
fell back to its own number-input:<uid>:input id, leaving the field
without an accessible name (axe label, critical). Fall back to a
generated id so label and input always match. FormNumericInput v1.1.1.
The NumericInput Playground story also names its input when the
visible label is toggled off.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Akros Orders demo squeezed the shipping / pickup-point column at 1440 px: under table-layout auto the enum filter selects reserve a min-width from their longest option label (264-304 px against declared 150-170 px), the table grew to 1836 px and the shipping column slid under the pinned actions. - FieldSelect skips the width reservation under tableLayout="fixed" (where content cannot reflow a column) and fills the cell instead. - Under fixed layout the built-in actions column is sized to its widest rendered actions cell instead of collapsing to 0 px. - The Orders demo opts into tableLayout="fixed". DataTable v1.2.2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
storybook, @storybook/react, addon-a11y, addon-themes 10.6.0 -> 10.6.1; @storybook/test-runner 0.24.4 -> 0.26.0; storybook-react-rsbuild and storybook-addon-rslib 3.4.2 -> 3.6.0. `storybook automigrate` reports no migrations; dev server and static build verified. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Records the Tabs, TreeView, Badge, placeholder, fg/secondary (Dark) and neo-dark bg-light changes made in Figma for the audit / Notion items, measured contrast in all six modes, the open input-hover decision, and the post-export check. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Format: CSS variables Exported themes: 6 themes (light, dark, neo, neo-dark, business, akros) Base branch: master
Regenerated tokens/figma/variables.css and brand-overrides.css with merge-figma-themes.mjs from the cherry-picked export. Verified against figma-facelift-log-2026-10.md: all Carousel/Steps/Tabs/TreeView/Badge re-aliases, the 4 new carousel size tokens, fg/secondary + fg/placeholder per mode and the neo-dark bg-light/primary scale are present. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Code side of the Carousel facelift (Figma 2026-10-08, tokens exported): - Previous / Next / Autoplay render ActionIcon (facelift B9) sized from the carousel size: sm 24, md 32, lg/full 40 px. - Carousel.Indicator is a 24 px target (was 16 px, below WCAG 2.2 target size) with an 8 px dot child; children still replace the dot. - Autoplay keeps the opaque control surface over the slide image. Carousel v1.1.0 (molecule and the template that composes it). axe: 0 violations across the 13 Carousel stories. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
All logged re-aliases and per-mode values are present in the export. axe on real stories cleared Tabs/TreeView/Badge/Input/Carousel in all six brand/mode combinations; three remaining Steps solid-variant issues are fixed in Figma (new color/steps/title/fg/solid/current) and wait for the next export. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Format: CSS variables Exported themes: 6 themes (light, dark, neo, neo-dark, business, akros) Base branch: master
Adds color/steps/title/fg/solid/current, moves the solid complete trigger to fill/surface and lightens neo-dark fg-accent/primary (primary/400). Verified against figma-facelift-log-2026-10.md round 2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The solid variant puts the current trigger on the primary tint, where the accent title was accent-on-accent (neo-light 3.95, neo-dark 2.65). It now uses the new --color-steps-title-fg-solid-current (fg/primary, 6.42-18.54 across modes). Steps v1.0.2; axe color-contrast clean on all Steps stories' component markup in all six brand/mode combinations. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Zag renders the step list as role="tablist" but the items as div[aria-current], which a tablist may not own (aria-required-children, critical — facelift C5). Items are now role="presentation" and the step state moves to the tab as aria-current="step"; separators are aria-hidden. Steps.Progress gets a default accessible name (aria-progressbar-name). The Validation story labels its inputs. Steps v1.0.3. axe: 0 non-contrast violations across 13 Steps stories. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Zag hides off-screen slides with aria-hidden only, so links or buttons on them stayed in the tab order (facelift C5, axe aria-hidden-focus). Hidden slides are now inert; verified the flag follows navigation. - New aria-label prop names the carousel region, so several carousels on a page are distinguishable (axe landmark-unique); multi-carousel stories are labelled. Carousel v1.2.0. axe: 0 non-contrast violations across 13 stories. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
StatusText rendered a bare <div>, so form errors appearing after validation were never announced (facelift C4). status="error" now renders role="alert"; warning/success render role="status"; plain helper text stays silent and is read through aria-describedby. A caller-supplied role still wins. Checked the stories the Playwright specs query by role: no duplicate alert/status roles appear. StatusText v1.0.1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Validation text sat next to Select, Switch, Slider, RadioGroup and PhoneInput but was never associated with the focusable control, so screen readers did not read it on focus (facelift C4). - New internal useDescribedBy / useRegisterDescription: a compound StatusText part registers its id while mounted, and the control renders aria-describedby only then (never a dangling id). A caller's own aria-describedby is joined, not replaced. - Select: trigger. RadioGroup: radiogroup root. PhoneInput: input. - Switch: hidden input. Slider: each thumb (role="slider"). Select v1.1.2, Switch v1.0.1, Slider v1.0.2, RadioGroup v1.0.1, PhoneInput v1.0.2. Browser check: 17 links, 0 broken references; axe has no new violations across 54 stories. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011Mx4mNZrqt5ZWysuyyKcE1
b2b72f2 to
44280de
Compare
The country trigger is Zag's role="combobox", which takes no name from its content, and its aria-labelledby points at a Select label that PhoneInput never renders. Every PhoneInput story failed axe button-name (critical, 18 nodes / 13 stories). It now defaults to aria-label "Country: <selected country>", skipped when the caller passes aria-label or aria-labelledby. PhoneInput v1.0.3. axe: 0 non-contrast violations across 13 stories (the warning StatusText contrast left is C1, a Figma status-color fix). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011Mx4mNZrqt5ZWysuyyKcE1
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011PeAJJVgQ7SbBZu4zGN2X3
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011PeAJJVgQ7SbBZu4zGN2X3
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011PeAJJVgQ7SbBZu4zGN2X3
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011PeAJJVgQ7SbBZu4zGN2X3
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011PeAJJVgQ7SbBZu4zGN2X3
Contrast fixes from the facelift audit: button hover/pressed states, VerticalNavigation, QuantityField, DatePicker, header, pagination, product-card, radio-card and select foregrounds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011PeAJJVgQ7SbBZu4zGN2X3
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011PeAJJVgQ7SbBZu4zGN2X3
…le name Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011PeAJJVgQ7SbBZu4zGN2X3
Icon, Carousel, FormInput, FormTextarea, Slider, Tabs and the ProductCard template, per the libs/ui rule to use type over interface. No API change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011PeAJJVgQ7SbBZu4zGN2X3
The Figma export bakes accent-light, item-bg-current, indicator-fg-hover and group-bg-secondary into fixed colours because Figma has no color-mix. Their formulas now load after the Figma layer, so overriding the accent, secondary, surface or foreground token recolours the whole component. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011PeAJJVgQ7SbBZu4zGN2X3
While reviewing the pagination component in Storybook, I noticed that the button background bleeds out behind the rounded corners. Do we want to address this in this PR? @depthark
|
Master's dependency upgrade, cart components and the a11y fixes it made in parallel overlapped this branch: - Same fix on both sides, master's version kept: NumericInput template labels, Steps progress name, DataTable sr-only column headers (master's translations.selectionLabel / reorderLabel), Accordion <h3> heading. - Combined: PhoneInput country trigger (master's naming logic), Steps aria-current from Zag plus this branch's aria-controls guard, FormNumericInput ids plus the generated-id fallback, StatusText described-by linking on master's renamed import. - Kept this branch: Skeleton role="status" naming, Carousel ActionIcon triggers, DataTable fixed-layout column widths. - package.json and pnpm-lock.yaml follow master; its upgrade covers this branch's Storybook bumps. - Changelog: this branch's entries renumbered on top of master's versions; NumericInput v1.1.2 and Accordion v1.0.2 entries dropped as duplicates of master's fixes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011PeAJJVgQ7SbBZu4zGN2X3
LineItem and TotalsSummary linked to their deleted feature branch; CascadeSelect, Command, DatePicker, Tour and Hotkeys still used the old NMIT-WR repo. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011PeAJJVgQ7SbBZu4zGN2X3
…hanges Both differ from master only in prop types, so their versions were left at master's after the merge; the version gate needs a bump. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011PeAJJVgQ7SbBZu4zGN2X3
Select, PhoneInput and RadioGroup stored one message id and cleared it when any message unmounted, so a hint plus a conditional error linked only one, and removing the error unlinked the hint. The described-by helper now keeps a list of mounted ids and removes only the departing one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011PeAJJVgQ7SbBZu4zGN2X3
A fragment was wrapped in one <li>, nesting its <li> children and merging its links into a single entry. Fragments are flattened before wrapping. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011PeAJJVgQ7SbBZu4zGN2X3
PriceBlock and AvailabilityStatus gaps alias their spacing reference tokens again (spacing-price-block-related/compact, spacing-availability-status-compact); pending gaps back to 4 / 8 px. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011PeAJJVgQ7SbBZu4zGN2X3
|
🎉 This PR is included in version 0.56.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |

Summary
Design-system facelift and accessibility pass for
@techsio/ui-kit, done in Figma and code together. There is one feature per commit; the full log is inlibs/ui/docs/figma-facelift-log-2026-10.md.Figma (source of truth) → 4 token exports merged
xsmatchessm, and small field text is 16 px everywhere.border/control,bg/control-checked,border/control-selectedandborder/danger|success|warningtokens for control boundaries and validation (≥ 3 : 1, C3).fg/on-selected, plusfg/on-secondary|tertiary|warning|danger|tintfor text on fills.Code
label).aria-controls.h-form-control-*on Button, Select, Combobox, CascadeSelect and Tabs.ProductCard.Name as,NumericInputTemplate aria-label,Slider aria-label[], DataTabletranslations.selectColumnLabel/reorderColumnLabel, DataTable fixed-layout widths.@componentVersion, the skillcomponent_versionand the changelog (enforced by the skill-sync gate).Testing
color-contrastsweep in six brand/mode combinations runs after each export.tscclean;pnpm validate:tokenspasses; Biome per file adds no new errors.🤖 Generated with Claude Code
https://claude.ai/code/session_011PeAJJVgQ7SbBZu4zGN2X3