Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
162 commits
Select commit Hold shift + click to select a range
14a049a
docs: add glossary and adr for figma-theme single source
eteplus Oct 25, 2026
61adc08
test: add vitest unit and browser-mode behavior tests
eteplus Oct 25, 2026
3dc51a9
test(react): add vitest visual regression baselines
eteplus Oct 25, 2026
7848587
build: migrate toolchain to vite-plus, oxlint and tsdown
eteplus Oct 25, 2026
98e6437
style: adopt oxfmt and fix lint warnings
eteplus Oct 25, 2026
65dbaaf
refactor!: migrate from UnoCSS to Tailwind CSS v4
eteplus Oct 25, 2026
506451a
build(theme): exclude generated css from oxfmt
eteplus Oct 25, 2026
422c341
refactor(separator): migrate to base ui
eteplus Oct 25, 2026
72444c9
refactor(label): replace radix label with native label
eteplus Oct 25, 2026
abbe340
refactor(button): migrate button and action-icon to base ui
eteplus Oct 25, 2026
a99aeb9
refactor(toggle): migrate to base ui
eteplus Oct 25, 2026
e1c96c3
refactor(toggle-group)!: migrate to base ui
eteplus Oct 25, 2026
ce9f65c
refactor(checkbox)!: migrate to base ui
eteplus Oct 25, 2026
90d7909
refactor(switch): migrate to base ui
eteplus Oct 25, 2026
8e6d9b7
refactor(radio)!: migrate to base ui
eteplus Oct 25, 2026
e7f38b6
refactor(slider)!: migrate to base ui
eteplus Oct 25, 2026
60faeae
refactor(scroll-area)!: migrate to base ui
eteplus Oct 25, 2026
70d7dd6
refactor(tabs)!: migrate to base ui
eteplus Oct 25, 2026
c7a88bd
refactor(tooltip)!: migrate to base ui
eteplus Oct 25, 2026
e4eff16
fix(playground): adapt slider onValueChange to base ui value type
eteplus Oct 25, 2026
d29d27c
refactor(popover)!: migrate to base ui
eteplus Oct 25, 2026
763298d
refactor(dropdown-menu)!: migrate to base ui
eteplus Oct 25, 2026
42d52e5
refactor(select)!: migrate to base ui
eteplus Oct 25, 2026
2e5a9c5
fix(playground): adapt tooltip usage to base ui
eteplus Oct 25, 2026
f2e89e3
refactor(dialog)!: migrate to base ui
eteplus Oct 25, 2026
32893e7
refactor(alert-dialog)!: migrate to base ui
eteplus Oct 25, 2026
097368c
refactor(sheet)!: migrate to base ui
eteplus Oct 25, 2026
f90f237
chore!: remove radix ui and release 0.1.0
eteplus Oct 25, 2026
964cf66
style(react): use canonical tailwind classes for data variants and ar…
eteplus Oct 25, 2026
4c78cb4
docs: define UI Kit and Elevation; ignore local devin config
eteplus Oct 25, 2026
6645e7a
feat(theme)!: add UI3 typography, elevation tokens and renumber spacing
eteplus Oct 25, 2026
200068d
test(react): require pixel-exact visual matches
eteplus Oct 25, 2026
002700f
style(button,action-icon): adopt UI3 geometry, focus ring and states …
eteplus Oct 25, 2026
261c64b
style(input,textarea): adopt UI3 24px outline-only fields from figma-kit
eteplus Oct 25, 2026
0190419
style(checkbox): adopt UI3 16px checkbox from figma-kit
eteplus Oct 25, 2026
450ab1e
style(radio): adopt UI3 radio and fix off-center checked dot
eteplus Oct 25, 2026
0efc0f8
style(switch): adopt UI3 32x16 switch from figma-kit
eteplus Oct 25, 2026
ee39010
style(tabs): adopt UI3 chip tabs from figma-kit
eteplus Oct 25, 2026
f293d5c
style(slider): adopt UI3 slider with centered thumbs from figma-kit
eteplus Oct 25, 2026
8d102a4
style(toggle-group): adopt UI3 segmented control from figma-kit
eteplus Oct 25, 2026
f29a7ca
style(tooltip): adopt UI3 tooltip with elevation-300 shadow
eteplus Oct 25, 2026
11793ed
style(popover): adopt UI3 dialog-base surface with elevation-500
eteplus Oct 25, 2026
ba50ff0
style(dropdown-menu): adopt UI3 menu surface from figma-kit
eteplus Oct 25, 2026
f961f4e
style(select): adopt UI3 select trigger and menu from figma-kit
eteplus Oct 25, 2026
1b34130
style(dialog): adopt UI3 dialog surface, overlay and title
eteplus Oct 25, 2026
eac1827
style(alert-dialog): adopt UI3 dialog surface and spacing
eteplus Oct 25, 2026
211eab3
style(sheet): use theme overlay and dialog title typography
eteplus Oct 25, 2026
5db6294
style(toast,toggle,label): switch generic Tailwind values to theme to…
eteplus Oct 25, 2026
e517b77
docs(changelog): describe UI3 component restyle
eteplus Oct 25, 2026
9951305
docs: move migration reports to docs/migration and drop scratch notes
eteplus Oct 26, 2026
ed3ff1a
test(react): harden visual test tooling
eteplus Oct 26, 2026
2c0e895
docs: add AGENTS.md and figma runtime color extraction notes
eteplus Oct 26, 2026
79de53d
ci: run check, typecheck, tests and build on github actions
eteplus Oct 26, 2026
5e37b31
ci: bump actions to v6/v7 and cache playwright browsers
eteplus Oct 26, 2026
0d4feda
test(react): honor storybook centered layout and kebab-case baselines
eteplus Oct 26, 2026
0404143
fix(react): resolve remaining a11y lint warnings
eteplus Oct 26, 2026
b72691c
refactor: colocate tests under tests/ directories
eteplus Oct 26, 2026
ea2b7e2
chore: replace eslint vscode config with oxc toolchain settings
eteplus Oct 26, 2026
324fec1
refactor: enforce func-style declarations
eteplus Oct 26, 2026
3849213
chore(react)!: require react 19
eteplus Oct 26, 2026
36ed77d
chore: group pnpm catalogs, bump typescript 7 and vite-plus 1.4, add …
eteplus Oct 26, 2026
ec4917a
chore: bump deps to latest and pnpm to 12
eteplus Oct 26, 2026
e8a645c
refactor(react): add base-ui infra utils and shared menu classes
eteplus Oct 26, 2026
b1b153b
feat(theme): add icon-* color scope writing --color-icon
eteplus Oct 26, 2026
4039e3f
feat(react)!: require aria-label on ActionIcon
eteplus Oct 26, 2026
b02c12b
feat(react): add selectOnClick to input
eteplus Oct 26, 2026
a290e73
feat(react): add context-menu and segmented-control
eteplus Oct 26, 2026
67632bc
feat(react): add value-field family
eteplus Oct 26, 2026
f661179
test(react): add utility contract tests
eteplus Oct 26, 2026
d815339
docs: acknowledge figma-kit in readme
eteplus Oct 26, 2026
10b7446
feat(react): add ui3 icon set via createIcon factory
eteplus Oct 26, 2026
d9118e1
fix(react): select scroll arrows, context-menu trigger, multi-field s…
eteplus Oct 26, 2026
120317c
refactor(react)!: fold segmented-control into toggle-group
eteplus Oct 26, 2026
75adcfd
fix(react): pin select trigger chevron to the right edge
eteplus Oct 26, 2026
7a715f4
feat(react)!: align control sizes and variants with ui3 spec
eteplus Oct 26, 2026
990bc0f
fix(react): apply ui3 spec details to checkbox, menus, tabs
eteplus Oct 26, 2026
ab167ab
feat(react): add switch indeterminate state and refine toggle pressed…
eteplus Oct 26, 2026
a4e8d66
feat(react): add slider hints/baseValue and dialog chrome
eteplus Oct 26, 2026
38973d7
feat(react): add Badge component per UI3 spec
eteplus Oct 27, 2026
a4e9c3e
feat(react): add Avatar and AvatarGroup per UI3 spec
eteplus Oct 27, 2026
3ef8fcc
feat(react): add VisualBell component per UI3 spec
eteplus Oct 27, 2026
d71e0c6
feat(react): add Swatch fill-preview chit
eteplus Oct 27, 2026
b088bb4
feat(react): restyle toast per UI3 notification spec
eteplus Oct 27, 2026
4d5f99d
fix(react): toast close button and loading icon placement
eteplus Oct 27, 2026
3e4397e
feat(react): drop non-spec toast close button
eteplus Oct 27, 2026
3f21bac
feat(react): add Radio button variant per UI3 spec
eteplus Oct 27, 2026
52af88e
feat(react): add Checkbox muted/ghost variants + description story
eteplus Oct 27, 2026
cda58b7
fix(react): render indeterminate checkbox as a filled box
eteplus Oct 27, 2026
4fe61c6
feat(react): add menu trail parts per UI3 spec
eteplus Oct 27, 2026
ceac639
feat(react): add Toggle stroke variant per UI3 spec
eteplus Oct 27, 2026
34c8525
feat(react): add icon prop to SelectTrigger per UI3 spec
eteplus Oct 27, 2026
2516f7a
fix(react): flush select chevron to the trigger edge
eteplus Oct 27, 2026
8e377a2
feat(react): add color slider variants per UI3 spec
eteplus Oct 27, 2026
cf556c9
fix(react): match slider hints and modified thumb to UI3 spec
eteplus Oct 27, 2026
3e474fc
fix(react): inset slider draggable span by a full thumb width
eteplus Oct 27, 2026
e0ecb33
fix(react): restore slider thumb flush to track end
eteplus Oct 27, 2026
1a23c9a
fix(react): clip slider range to track bounds
eteplus Oct 27, 2026
4444ba1
fix(react): resolve slider range percentages against control width
eteplus Oct 27, 2026
fec25c0
fix(react): render gradient slider thumbs as floating pin chits
eteplus Oct 27, 2026
8e93967
fix(react): sharpen gradient pin notch to spec triangle
eteplus Oct 27, 2026
c065535
fix(react): widen gradient pin inner inset when focused
eteplus Oct 27, 2026
1b2cee4
fix(react): unify gradient pin inset and neutral swatch base
eteplus Oct 27, 2026
37e3c9d
feat(react): add VariableChip for applied-variable pills
eteplus Oct 27, 2026
cac3833
fix(react): center LinkBrokenIcon glyph in its viewBox
eteplus Oct 27, 2026
1c27d13
fix(react): match variable-chip story field width to spec
eteplus Oct 27, 2026
9f32e8a
feat(react): add SegmentedControl and align segment states with spec
eteplus Oct 27, 2026
3f3ab8e
feat(react): add LinkTooltip and tooltip hotkey hint
eteplus Oct 27, 2026
38eb01b
fix(react): clamp toast message to two lines per spec
eteplus Oct 27, 2026
26aff16
test(visual): report scroll offsets and focused element in probe
eteplus Oct 27, 2026
1315a47
feat(react): add scrollable overflow fade to tab list
eteplus Oct 27, 2026
e00f7ce
feat(react): add Mail and Folder icons for link tooltip rows
eteplus Oct 27, 2026
71675b3
fix(react): clip link-tooltip action hover to rounded corners
eteplus Oct 27, 2026
165e3ba
feat(react): anchor link tooltips to fields via LinkTooltipPopup
eteplus Oct 27, 2026
7ae28fc
fix(react): align slider geometry with live UI3 dev spec
eteplus Oct 27, 2026
8a436d4
fix(react): align tooltip geometry with live UI3 dev spec
eteplus Oct 27, 2026
b55629b
fix(react): align variable chip with live UI3 dev spec
eteplus Oct 27, 2026
3f8f4f8
fix(react): align toast with live UI3 dev spec
eteplus Oct 27, 2026
ec59881
fix(react): clip toast action hover to rounded corners
eteplus Oct 27, 2026
874ba1c
fix(react): size link tooltip rows to content
eteplus Oct 27, 2026
973811d
fix(react): align menus with live UI3 dev spec
eteplus Oct 27, 2026
8341163
fix(react): align checkbox with live UI3 dev spec
eteplus Oct 27, 2026
3e47c21
fix(react): align radio focus ring and pill label weight with UI3 spec
eteplus Oct 27, 2026
db30ce0
fix(react): align switch with live UI3 dev spec
eteplus Oct 27, 2026
6bef3e0
fix(react): align visual bell with live UI3 dev spec
eteplus Oct 27, 2026
bf76a47
fix(react): align avatar typography with live UI3 dev spec
eteplus Oct 27, 2026
9f308a5
fix(react): align badge variants and padding with live UI3 dev spec
eteplus Oct 27, 2026
9410c8c
fix(react): align dialog section padding with live UI3 dev spec
eteplus Oct 27, 2026
21da546
test(react): rebase icons-set baseline for 1px indeterminate dash
eteplus Oct 27, 2026
4b0ca1b
fix(react): remove section dividers from dialog per UI3 spec
eteplus Oct 27, 2026
6b1eef5
fix(react): align input family geometry with UI3 spec
eteplus Oct 27, 2026
e12149b
fix(theme): reconcile color tokens with exported UI3 variables
eteplus Oct 27, 2026
0802022
fix(theme): prefer Roboto Mono for code font per UI3 typography export
eteplus Oct 27, 2026
ddbeacf
test(vrt): rename PascalCase baselines to kebab-case
eteplus Oct 28, 2026
9a8c328
docs: adopt the UI3 Design file as the single design reference
eteplus Oct 28, 2026
c7051e9
feat(theme): generate tokens from the Design file variable export
eteplus Oct 28, 2026
7b35c30
feat(theme): support all eight editor theme modes
eteplus Oct 28, 2026
70fc74a
docs(agents): note byte-only baseline rewrites after vrt updates
eteplus Oct 28, 2026
1f1f3a0
test(vrt): compare screenshots strictly and refresh stale baselines
eteplus Oct 28, 2026
916f8dc
feat(button): align Button API and styles with the UI3 Design file
eteplus Oct 28, 2026
5286978
feat(react): align icon buttons with the UI3 Design file
eteplus Oct 28, 2026
612b07a
feat(react): add ActionIconSplit for the Button icon split spec
eteplus Oct 28, 2026
636944c
feat(react): align menu rows with the UI3 Design file
eteplus Oct 28, 2026
7aee1a2
feat(react): align fields and chips with the UI3 Design file
eteplus Oct 28, 2026
db79c2c
feat(react): align slider and swatch with the UI3 Design file
eteplus Oct 28, 2026
3942017
fix(react): use a round chit inside slider thumbs
eteplus Oct 28, 2026
51f03d2
fix(react): keep the slider thumb chit round
eteplus Oct 28, 2026
e013235
fix(react): shrink the slider thumb chit to spec size
eteplus Oct 28, 2026
59d0d20
feat(react): align avatar and badge with the UI3 Design file
eteplus Oct 28, 2026
f456054
feat(react): align radio, tabs, toast, bell, and scroll area with the…
eteplus Oct 28, 2026
e54cd1e
fix(react): resolve remaining UI3 audit items
eteplus Oct 28, 2026
d479dbb
docs: correct stale UI3 claims in the 0.1.0 changelog
eteplus Oct 28, 2026
93f8888
fix(react): flush the slider range fill to the track caps and fix ver…
eteplus Oct 28, 2026
14c050e
fix(react): hide the native scrollbar on scrollable tab lists
eteplus Oct 28, 2026
2d40a40
feat(playground): rebuild as a component showcase
eteplus Oct 28, 2026
0fdce97
chore: consolidate third-party attributions into NOTICE.md
eteplus Oct 30, 2026
0582d60
ci: build the workspace before running checks
eteplus Oct 30, 2026
6beea77
ci: publish releases on version tags
eteplus Oct 30, 2026
882ae52
ci: rely on npm trusted publishing for release auth
eteplus Oct 30, 2026
c368c88
test(theme): assert the nested figjam light selectors
eteplus Oct 30, 2026
903ca82
ci: deploy storybook and playground to github pages
eteplus Oct 30, 2026
51ab8af
docs: record the release and pages workflows
eteplus Oct 30, 2026
537aec0
chore: let release.yml own the GitHub release
eteplus Oct 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
29 changes: 29 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: ci

on:
push:
branches: [main]
pull_request:

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v7
with:
node-version: 24
cache: pnpm
- run: pnpm install --frozen-lockfile
- uses: actions/cache@v6
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('pnpm-workspace.yaml') }}
- run: pnpm -F @thinkbuff/figma-react exec playwright install --with-deps chromium
- run: pnpm build
- run: pnpm check
- run: pnpm typecheck
- run: pnpm test
- name: generated theme css is committed
run: git diff --exit-code -- packages/theme/src/css/
37 changes: 37 additions & 0 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: pages

on:
push:
branches: [main]
workflow_dispatch:

permissions:
contents: read
pages: write
id-token: write

concurrency:
group: pages
cancel-in-progress: false

jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- uses: actions/checkout@v7
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v7
with:
node-version: 24
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm pages:build
- uses: actions/configure-pages@v6
- uses: actions/upload-pages-artifact@v5
with:
path: site/figma
- id: deployment
uses: actions/deploy-pages@v5
52 changes: 52 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: release

on:
push:
tags: ['v*']

permissions:
contents: write # create the GitHub release
id-token: write # npm provenance / trusted publishing

jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v7
with:
node-version: 24
cache: pnpm

# A mistyped tag publishes the wrong version; refuse early.
- name: tag matches package version
run: |
pkg=$(node -p "require('./package.json').version")
[ "$GITHUB_REF_NAME" = "v$pkg" ] || {
echo "::error::tag $GITHUB_REF_NAME does not match package.json version v$pkg"
exit 1
}

- run: pnpm install --frozen-lockfile
- uses: actions/cache@v6
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('pnpm-workspace.yaml') }}
- run: pnpm -F @thinkbuff/figma-react exec playwright install --with-deps chromium
- run: pnpm check
- run: pnpm typecheck
- run: pnpm test
- run: pnpm build

# Auth is npm trusted publishing (OIDC) — no token needed.
- name: publish to npm
run: pnpm -r publish --provenance --no-git-checks

- name: create github release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
ver="${GITHUB_REF_NAME#v}"
awk -v v="$ver" '$0=="## v"v{f=1;next} f&&/^## /{exit} f' CHANGELOG.md > notes.md
gh release create "$GITHUB_REF_NAME" --notes-file notes.md --verify-tag
14 changes: 14 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,17 @@ coverage

# parcel-bundler cache (https://parceljs.org/)
.cache

# storybook static build output
storybook-static

# assembled github pages site (scripts/pages.ts)
site/
.vitest

# Devin local config
.devin/*.local.json

# Local Design file working-copy links and component audits
docs/figma-ui3-design.md
docs/audit/
8 changes: 8 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"recommendations": [
"vitest.explorer",
"oxc.oxc-vscode",
"antfu.pnpm-catalog-lens",
"bradlc.vscode-tailwindcss"
]
}
54 changes: 27 additions & 27 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
{
"editor.formatOnSave": false,
"editor.formatOnSave": true,
"editor.formatOnSaveMode": "file",
"editor.defaultFormatter": "oxc.oxc-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.fixAll.oxc": "explicit",
"source.organizeImports": "never"
},
"eslint.useFlatConfig": true,
"eslint.workingDirectories": [
{
"pattern": "./apps/*/"
},
{
"pattern": "./packages/*/"
}
],
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
],
"typescript.tsdk": "node_modules/typescript/lib",
"cSpell.words": [
"onbrand",
"oncomponent",
"ondanger",
"ondisabled",
"oninverse",
"onselected",
"onwarning"
]
"editor.quickSuggestions": {
"strings": "on"
},
"[typescript]": {
"editor.defaultFormatter": "oxc.oxc-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "oxc.oxc-vscode"
},
"[yaml]": {
"editor.defaultFormatter": "oxc.oxc-vscode"
},
"explorer.fileNesting.enabled": true,
"explorer.fileNesting.patterns": {
"package.json": "package-lock.json, pnpm*, .yarnrc*, yarn*, .eslint*, eslint*, .oxlint*, oxlint*, .oxfmt*, oxfmt*, .prettier*, prettier*, .editorconfig",
"tsconfig.json": "tsconfig.*.json, env.d.ts, *.tsbuildinfo",
"vite.config.*": "jsconfig*, vitest.config.*, playwright.config.*"
},
"files.associations": {
"*.css": "tailwindcss"
},
"tailwindCSS.classAttributes": ["class", "className"],
"tailwindCSS.classFunctions": ["cn", "cva", "clsx", "addClassName"]
}
90 changes: 90 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# AGENTS.md

Component library for Figma/FigJam plugin UIs: `packages/react` (React + Base UI
+ Tailwind v4) over shared tokens in `packages/theme`. `playground/` is a
consumer smoke test. Layering, token rules, naming and release policy:
`docs/architecture.md`; decisions in `docs/adr/`; vocabulary in `GLOSSARY.md`.
Per-component design audits live in `docs/audit/` (gitignored, local only).

## Layout

- Tests live in `packages/<pkg>/tests/` mirroring `src/` (e.g.
`src/components/x/x.test.tsx` → `tests/components/x/x.test.tsx`); shared
helpers in `packages/react/tests/test-utils/`; never colocate tests in `src/`.
- React tests import sources via the `~` alias (`~/components/x/x`); theme and
utils tests use relative `../src/...` paths.

## Verify

- `pnpm test` — unit + browser tests.
- `pnpm test:visual` — pixel-exact screenshot suite (207 baselines). CI does not
run it; always run locally before finishing UI work.
- `pnpm typecheck`, `pnpm check`, `pnpm build`.
- `pnpm deps` — taze interactive dependency updates (`-r -I -l`).
- `pnpm -F @thinkbuff/figma-react build-storybook` after component changes.

## Visual tests

- Baselines: `packages/react/tests/visual/__screenshots__/*-chromium-darwin.png`.
`pnpm test:visual:update` rewrites them — inspect every changed image before
committing; an update bakes whatever rendered, including bugs.
- Vite can serve stale styles: a "no diff" result may be a cached render, not a
real match. The vrt scripts clear `node_modules/.vite` first. To verify a
suspicious result, dump computed styles:
`VRT_PROBE="<story id>" pnpm -F @thinkbuff/figma-react probe`.
- `pnpm vrt:diff -- [vitest args]` snapshots baselines, re-runs the update and
lists which shots changed (before-copies under `$TMPDIR/figma-vrt-diff/`).
- An update run can rewrite PNGs byte-differently with identical pixels; compare
decoded pixels against `HEAD` with PIL
`ImageChops.difference(a.convert('RGB'), b.convert('RGB')).getbbox()` (RGBA
`getbbox()` only checks alpha) and `git restore` the pixel-identical ones
before committing.
- The comparator is pixelmatch with `threshold: 0` — strict, any changed pixel
counts.

## Theme (`packages/theme`)

- Token values live only in `tokens/*.json`. `tokens/colors/*`, `sizing.json`
and `typography.json` come from `pnpm tokens:import <dir>` (a Figma "Export
modes" folder; copy it out of `~/Downloads` first — the sandbox can't read
it); `elevation.json` and `extensions.json` are hand-maintained. Never edit
imported files by hand unless the Design file can't be exported.
- `src/css/**` is generated by `pnpm generate:css` — edit `tokens/` or
`src/theme/`, never the output. CI fails on uncommitted drift.
- Styles resolve through built artifacts: `styles.css` imports the theme's
`dist/css` and scans `packages/react/dist` via `@source`. After adding a
utility or changing classes, rebuild (`pnpm build`) or VRT/Storybook renders
stale CSS with silently missing rules.
- `--figma-color-*` values are injected by the Figma editor at runtime
(`themeColors: true`); see `docs/figma-runtime-colors.md` to extract them.
- Register every new utility family in `packages/react/src/utils/cn.ts`
(tailwind-merge groups) or `cn()` merges it into the wrong group.
- Elevation/shadow variables live in the per-theme blocks (`.figma-light`,
`.figma-dark`, `.figjam`), not `@theme`, so nested `.figma-dark` resolves dark
values.
- Design reference: the UI3 Design file (official community file linked in
`docs/architecture.md` §1). Match component sets by page and set name, never
by node id; working-copy links live in the gitignored
`docs/figma-ui3-design.md`.

## Components (`packages/react`)

- Base UI conventions: `render` prop (never `asChild`), `aria-expanded` for
open-state styling, `addClassName` for callback classNames, `cn()` to merge.
- Controlled `Tabs.Root value` scrolls the tab list to the end on mount (Base UI
composite scrolls the active item into view). Prefer `defaultValue` unless
external state control is required.
- Prefer canonical Tailwind forms (`data-popup-open`, `inset-0.5`,
`-top-1.25`) over bracket variants and arbitrary values.
- Component styles are cva variants in `<name>-variants.ts` (or inline classes)
built only from Utility contract classes; `packages/react/styles.css`
`@layer components` is only for what cva cannot express (keyframes,
third-party DOM).

## Commits

- Conventional Commits (commitlint enforced); pre-commit runs `vp check --fix`
on staged files.
- File names are kebab-case (`unicorn/filename-case` is an error); conventional
uppercase files like `README.md` and `AGENTS.md` are the exception.
- Do not kill listeners on dev ports (Storybook uses 6006) you did not start.
Loading
Loading