Repository navigation
refactor!: rebuild the component library on Base UI + Tailwind v4 for UI3 - #1
Merged
Merged
Conversation
Adopt pnpm catalogs, replace eslint with oxlint/oxfmt via vite-plus, build packages with vp pack, and upgrade storybook to v10.
Port the platform Tailwind v4 theme into @thinkbuff/figma-theme, replace UnoCSS utilities and variant groups with Tailwind classes, inline SVG icons, and ship @thinkbuff/figma-react/styles.css with @source. BREAKING CHANGE: @thinkbuff/figma-theme/unocss is removed; consumers use Tailwind v4 and import @thinkbuff/figma-react/styles.css.
Drop all @radix-ui dependencies and the radix catalog now that every component runs on Base UI, widen the react peer range to ^18.2.0 || ^19, and document the breaking API changes in the changelog.
Replace figma-kit with the Design file as the reference for token values and component appearance, and record the resulting architecture: layers, token pipeline and naming, usage rules, directory conventions, extension points and release policy. Add ADRs for runtime variable names, the normalized token source and flat component directories. Drop the figma-kit based UI3 migration notes; component audits now stay local.
Add `pnpm tokens:import <dir>`, which normalizes the Figma "Export modes" DTCG files into packages/theme/tokens/ (eight color modes, sizing, typography). Color maps and generated CSS now derive from that JSON instead of hand-copied values; elevation and repo-only extensions are hand-maintained JSON. All semantic Design file colors except the fullscreen, desktop, code and inspect families are published (490 per mode, up from 268). `:root` now resolves Figma light: the FigJam block also claimed it and won the cascade, so unthemed pages rendered FigJam colors. The shared/mode-invariant split is gone, so `BaseThemeCSSVariables` is removed and every mode map is complete.
Generate a block per mode: the editor-type class (`figjam`, `devmode`, `slides`) combines with the runtime `figma-light`/`figma-dark` class, so FigJam dark, Dev Mode and Slides resolve their own colors and elevation, including in nested containers. Standalone `figjam.css`, `devmode.css` and `slides.css` entries resolve their editor's light mode at `:root` again. Drop the legacy `xs/sm/md/lg` type scale in favour of the Design file styles (`text-figma-body-medium`, `text-figma-body-large`), and order elevation shadow layers as in the Design file. Storybook gains all eight themes; visual tests add FigJam dark baselines. Existing baselines are pixel-identical.
The pixelmatch threshold of 0.2 let light-gray color changes and sub-pixel text shifts pass, so baselines drifted from the rendered UI (e.g. the badge restyle and the 0.5% body letter spacing never reached them). Use threshold 0 and re-record the 267 baselines that no longer matched; the strict suite is deterministic across consecutive runs.
- Collapse variant+color into a single variant prop matching the Design Button component set: primary, secondary, destructive, secondary-destructive, inverse, success, figjam, link, link-danger, ghost. - Secondary is now the outlined bordertranslucent treatment; ghost uses the transparent-secondary tokens; filled variants get the selected focus outline plus the white inset focus ring from the Design file. - Replace fullWidth with size="wide" and add a 24px leading icon slot. - Remove the warning variant and dead btn-* classes; migrate stories and overlay consumers to the new API. - Register the new Button utilities in the theme utility contract.
- ActionIcon gains variant="secondary" (persistent bordertranslucent stroke per the Button icon set) and drops activeAppearance — the expanded state now always follows the dialog-toggle spec (bg-selected, bg-selected-secondary hover, no icon tint). - Toggle replaces stroke with variant: "highlighted" (default), "default" (icon-swap, no pressed fill per Button icon toggle), and "secondary" (Dialog Toggle w/ Stroke; pressed drops the stroke). - Hover/active fills switch to the Design file's transparent tokens (bghovertransparent, bgtransparentsecondary/hover); pressed hovers use bg-selected-secondary. - Add border-figma-bordertranslucent to the theme utility contract.
New Core component for the UI3 `Button icon split` set: an `ActionIconSplit` root (gap-px container, size small 41x24 / large 49x32, disabled propagated via context) with `Button` and `Chevron` subparts. Halves carry the spec's per-side corner radius; hover/active fills use the transparent tokens, focus draws the 1px selected stroke on the focused half, and `aria-expanded` follows the dialog-toggle fill so the chevron half can trigger menus via `render`.
- Row highlight uses bg-menu-selected (fixes the wrong #50297a deep purple in FigJam dark) - ItemBadge uses bg-toolbar + text-onbrand per the spec's Badge small/Variant=Menu - ItemCheck renders the spec's plain 16px check icon instead of a filled selected-strong chip - Disabled rows unify on text-menu-disabled / icon-menu-disabled - New ItemSwitch on DropdownMenu and ContextMenu for the spec's Menu row/Toggle: a menuitemcheckbox row with a leading Switch cell; clicking toggles without closing the menu
- Select.Trigger: single border-selected focus/open ring (drops the double outline), texthighlight block on the open value, new stroke prop for the borderless Stroke=False variant, flush 24px icon-lead cell and the spec's 24px bg-secondary well on size=large - ValueField.NumericSelect: chevron segment uses bg-selected + border-selected while open - VariableChip: 16px tall per spec; disabled uses border-disabled - New VariableCell for the spec's Variable Cell row - New bg-figma-texthighlight utility; Input gains a VariableChip composition story for the Variable state
Slider: - new `modified` prop renders the spec's Stroke (Modified) thumb (bg-default knob, icon-onbrand ring, elevation-300) - hue/opacity thumbs embed the spec's 12px _Chit 24 square (a small Swatch) instead of a 6px disc - disabled thumb uses bg-disabled (was bg-disabled-secondary); track and gradient-chit rings use the bordertranslucent token; stepper ticks use icon-tertiary / icon Swatch: - new `type="opacity"` (left half solid, right half ~24% alpha) and `shape="circle"` (16px round chit, no ring) per the _Chit 24 spec - inset ring binds to the bordertranslucent token
The handle spec embeds _Chit 24/Variant=Circle (a 12px round chit), not a square one. Swatch's shape="circle" now honors `size` so the thumb chit renders as 12px.
The thumb's 4px border shrinks its flex content box to 8px, so the 12px chit was flex-shrunk to 8x12 — an ellipse. `shrink-0` restores the spec's round chit inside the ring.
The handle embeds a 12px _Chit 24 instance, but that component is a 24px cell whose visible circle is only 16px — so the dot inside the 16px thumb is 8px, not a 12px solid circle. Render a plain 8px dot.
Avatar: - initials fills bind to the multiplayer* / textonmultiplayer* tokens via new semantic utilities (were hardcoded light-theme hexes — dark themes rendered the wrong colors) - colors renamed to spec names (magenta->pink, slate->grey); new overflow-unread / overflow-read colors for "+N" avatars; new `disabled` prop (bg-tertiary + text); square at size="small" uses r=2 (rounded-figma-sm) Badge: - `size="small"` (14px) removed — no spec counterpart; `size="large"` added (16px, 13px text — "Badge large") - new `variant="alt"` for the "Badge small alt" subtle-fill family - new colors figjam, menu, merged, archived; warning strong uses the icon-warning token - new BadgeDot (9px bg-default pill + 5px bg-brand dot)
… UI3 Design file - Radio: button-variant border uses `bordertranslucent` per spec - Tabs: `border-selected` focus ring; unselected hover uses `bg-hover` - Toast: `bg-menu`/`text-menu` surface tokens and the spec's HUD shadow via new `shadow-figma-hud` extension token - VisualBell: `color="default"` is the spec's light bell (`bg-default` + `text`, elevation-100); edges use `bordertranslucent`; hover/active use the secondary-button transparent tokens - ScrollArea: thumb uses the `scrollbar` token via `bg-figma-scrollbar`
- Switch: indeterminate renders the spec's icon.16.mixed glyph instead of a hand-drawn bar - Input/Textarea: disabled state follows the spec per size — default keeps bg-default + border-default; large stays bg-secondary bare - Align disabled colors to spec tokens where values are identical: text-tertiary on Select, ToggleGroup, and ValueField; border-default on ValueField outlines - LinkTooltip.Action: add `strong` prop for the spec's body.medium.strong CTA weight - Separator: document per-surface divider tokens - AlertDialog story: CTA gap aligned to the Modal footer's 8px rhythm
…tical The range bleed only reached -6px while the track overhangs the value domain by 8px, leaving a 2px gap at the min cap and a stray stub inside the hollow thumb on empty ranges. Extend the min-side bleed to -8px and skip it entirely when the range is empty. Vertical sliders were broken end to end: group-data- on the Control could never self-match so the track never became flex-col, and the bottom-anchored indicator's py-1.5 -mt-1.5 painted [v1, v2+12] — 8px short of the bottom cap and past the top thumb's ring. The indicator now mirrors the horizontal geometry ([v1-8, v2+6]).
UI3 scrollable tab lists signal overflow through the fade mask, not a visible scrollbar — hide it while keeping horizontal overflow intact.
Replace the Vite starter with a navigable showcase for the refactored component APIs. Adds six sections, an eight-mode theme switcher, and the library ScrollArea. Slider demos include 0% and min-edge range boundary cases plus a vertical group.
The playground resolves @thinkbuff/figma-react types through dist artifacts, so vp check and tsc need the packages built first.
The eight-mode rework scopes figjam under .figjam/.figma-light combinators instead of html.figjam; update the stale assertion.
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
Lands the full 0.1.0 rework: the library is rebuilt on Base UI primitives and Tailwind CSS v4, with every component audited against the official UI3 Design file.
Styling & tokens (breaking)
@thinkbuff/figma-theme/css/*,@thinkbuff/figma-react/styles.css).pnpm tokens:import) and support all eight editor theme modes (Figma/FigJam/Dev Mode/Slides × light/dark).Primitives (breaking)
renderprop,aria-expandedopen-state styling); Radix dependency removed.Component alignment with the UI3 Design file
variantprop +size="wide"+iconslot; ActionIcon gainsvariant; Togglestroke→variant.createIcon.Toolchain & docs
vp check); vitest unit + browser tests; CI runs check/typecheck/tests/build.v*tag runsrelease.yml— tag-vs-version guard, full verify, npm publish via trusted publishing (OIDC + provenance), and an auto-created GitHub release.pages.ymldeploys the Storybook + playground site to GitHub Pages on every push tomain(pnpm pages:buildassemblessite/figma/: redirect index + storybook + playground).NOTICE.md; published tarballs now shipLICENSE(andNOTICE.mdforfigma-react).Test plan
pnpm test— 373 unit + browser testspnpm check/pnpm typecheck/pnpm buildpnpm test:visual— 620/620 pixel-exact baselines (threshold 0)pnpm -F @thinkbuff/figma-react build-storybookpnpm packtarball verified —LICENSE/NOTICE.mdincluded, no stale attribution comments indist