feat(ui-kit-system): segment group with animated indicator, switch motion (#572 part 2) - #575
feat(ui-kit-system): segment group with animated indicator, switch motion (#572 part 2)#575omridevk wants to merge 1 commit into
Conversation
…tion Adds a SegmentGroup primitive built on Ark's segment group. Its selected indicator is a real layout animation: zag publishes the selected item's rect as --left/--top/--width/--height and reads --transition-duration and --transition-timing-function back out, so the indicator slides between segments the same way the tabs indicator does. Under prefers-reduced-motion the duration collapses and the indicator snaps. The switch thumb moved with `translate`, which trans-btn never listed among its transitioned properties, so the thumb jumped. It now transitions `translate` and snaps under reduced motion. Refs #572 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 47 minutes Limit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?Wait for the limit to reset, then comment An organization admin can change what happens after included review limits in Billing. How do review limits work?CodeRabbit enforces per-developer PR review limits within each organization. For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
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 |
Part 2 of the widget-settings lane (#572), scoped to
packages/ui-kit-system. Independent of part 1.SegmentGroup
New primitive built on Ark's segment group, following the package's existing conventions (module-level class constants,
splitProps(props, ['class']),Object.assign({}, Ark, {...})so every unstyled Ark part still passes through).The selected indicator is a real layout animation, not a re-render. zag publishes the selected item's rect as
--left/--top/--width/--heightand reads--transition-durationand--transition-timing-functionback out (@zag-js/radio-group/dist/radio-group.connect.mjs:198-210) — the same mechanism family as the tabs indicator. The indicator slides at 200ms onvar(--chat-ease-expo), andmotion-reduce:[--transition-duration:0.01ms]collapses it to a snap.Root defaults
orientationtohorizontal; zag's own default is vertical, which is wrong for a segmented control. Vertical is still available and styled.One primitive, not two
The spec calls for both a SegmentGroup and a RadioGroup. They are the same component. Ark's
SegmentGroupandRadioGroupare both backed by the@zag-js/radio-groupmachine — same anatomy, same radio semantics, same WAI-ARIA radio keyboard support, sameIndicatorpart;SegmentGroup.RootProvidereven takes aUseRadioGroupReturn. A second file would have differed only in its class strings.The scheme tiles the spec describes are a radio-semantics group with custom item rendering:
SegmentGroup.Itemtakes arbitrary children, and the indicator auto-sizes to whichever item is selected, so tiles get the sliding selection for free.SegmentGroup.ItemControl(the radio dot) passes through unstyled on purpose — styling it would fight the segmented look, and a tile consumer wants its own mark.Switch thumb
The dispatch was to add thumb motion only if it did not already animate. It looked like it did (
translate-x-0.5totranslate-x-3.5undertrans-btn). It did not.UnoCSS wind4 compiles
translate-x-*to thetranslateproperty (computed:translate: 14px,transform: none), andtrans-btntransitionstransform, background-color, border-color, color.translateis not in that list, so the thumb jumped while the track colour faded underneath it. The thumb now transitionstranslateat 140ms onvar(--chat-ease-expo), withmotion-reduce:[transition-property:background-color]killing the travel while keeping the colour change.Before/after frames sampled 50ms after the click: previously the thumb was already hard against the right edge; now it is genuinely mid-travel.
Tests and stories
Five browser tests (
test/segment-group.browser.test.tsx, real Chromium): radiogroup role and accessible name, click selection, arrow-key selection with focus, disabled segment, and the indicator staying withheld until something is selected. Native role locators, web-first assertions, no test-ids, no polling, no CSS-value assertions — the visual and motion claims are carried by driven-flow screenshots instead.Four stories:
Default,Scheme(the auto/light/dark scheme axis with icons),Vertical,Disabled.Notes
rounded-chat-surface-sm(4px) rather than the spec's 3px inner radius.--chat-radius-chip(3px) is defined inui-kit-chat's token sheet, notui-kit-system's, and no existingui-kit-systemcomponent references it — using it here would make the base package depend on a downstream stylesheet and silently collapse to 0 wherever onlyui-kit-system/tokens.cssis loaded. Worth adding a 3px surface token if the mockup needs the tighter inner corner.min-h-8(32px), consistent withSelect.Item.Observations, not addressed here
trans-*shortcut inpackages/uno-preset/src/motion.tscarries amotion-reducevariant, unlike everyanim-*shortcut. Every consumer oftrans-btn,trans-lift,trans-pop-inkeeps sliding underprefers-reduced-motion. Fixed locally on the switch thumb; the systemic fix belongs in the preset.trans-btntransitionstransformwhile wind4 emitstranslate, so any other component pairingtrans-btnwith atranslate-*utility is also silently not animating. Worth a sweep.apps/storybook/.storybook/storybook.csshas a global@media (prefers-reduced-motion: reduce) { * { transition-duration: 0.01ms !important } }. Any reduced-motion evidence captured in Storybook snaps whether or not the component asks to, so the screenshots above neutralize that rule before sampling.Refs #572
🤖 Generated with Claude Code