@motion-proto/live-tokens 0.68.1 → 0.69.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/live-tokens-build-page/SKILL.md +16 -5
- package/.claude/skills/live-tokens-create-component/SKILL.md +43 -8
- package/.claude/skills/live-tokens-create-component/references/token-naming.md +30 -1
- package/.claude/skills/live-tokens-fix-findings/SKILL.md +131 -0
- package/.claude/skills/live-tokens-pick-component/SKILL.md +2 -1
- package/CHANGELOG.md +207 -0
- package/README.md +11 -4
- package/bin/check-component.mjs +367 -63
- package/bin/check-page.mjs +409 -0
- package/bin/cli.mjs +57 -8
- package/bin/lib/cssValues.mjs +50 -0
- package/bin/lib/findings.mjs +106 -0
- package/bin/lib/tokenVocabulary.mjs +213 -0
- package/dist-plugin/adjust/index.cjs +174 -23
- package/dist-plugin/adjust/index.js +68 -23
- package/dist-plugin/{chunk-2UX6EVVA.js → chunk-2YNERPXY.js} +1 -1
- package/dist-plugin/{chunk-NE6N66EE.js → chunk-GPIBU44G.js} +107 -1
- package/dist-plugin/{chunk-ZHPX7ZYQ.js → chunk-RFVYPNRO.js} +39 -1
- package/dist-plugin/generateColorsAndType/index.cjs +107 -1
- package/dist-plugin/generateColorsAndType/index.js +1 -1
- package/dist-plugin/index.cjs +146 -2
- package/dist-plugin/index.js +3 -3
- package/dist-plugin/migrateData/index.cjs +107 -1
- package/dist-plugin/migrateData/index.js +2 -2
- package/dist-plugin/tokensCssMigrations/index.cjs +39 -1
- package/dist-plugin/tokensCssMigrations/index.js +1 -1
- package/package.json +3 -2
- package/src/app/site.css +4 -4
- package/src/editor/component-editor/ButtonEditor.svelte +71 -4
- package/src/editor/component-editor/CardEditor.svelte +6 -6
- package/src/editor/component-editor/DialogEditor.svelte +3 -3
- package/src/editor/component-editor/IconButtonEditor.svelte +68 -3
- package/src/editor/component-editor/ImageEditor.svelte +8 -8
- package/src/editor/component-editor/ImageLightboxEditor.svelte +12 -1
- package/src/editor/component-editor/MenuSelectEditor.svelte +63 -3
- package/src/editor/component-editor/SegmentedControlEditor.svelte +63 -3
- package/src/editor/component-editor/SideNavigationEditor.svelte +67 -3
- package/src/editor/component-editor/SliderEditor.svelte +186 -0
- package/src/editor/component-editor/TabBarEditor.svelte +63 -3
- package/src/editor/component-editor/registry.ts +10 -0
- package/src/editor/core/components/aliasKinds.ts +51 -28
- package/src/editor/core/sketch/sketchLayer.ts +16 -0
- package/src/editor/core/store/editorPersistence.ts +44 -1
- package/src/editor/core/store/editorRenderer.ts +2 -2
- package/src/editor/core/store/editorStore.ts +18 -18
- package/src/editor/core/store/editorTypes.ts +7 -6
- package/src/editor/core/themes/migrations/2026-09-01-gate-suffix-enabled.ts +31 -0
- package/src/editor/core/themes/migrations/2026-09-01-scrim-rename.ts +52 -0
- package/src/editor/core/themes/migrations/2026-09-01-tabbar-active-tint.ts +27 -0
- package/src/editor/core/themes/migrations/2026-09-01-tint-rename.ts +42 -0
- package/src/editor/core/themes/migrations/index.ts +16 -0
- package/src/editor/core/themes/slices/domainVars.ts +2 -2
- package/src/editor/core/themes/slices/washes.ts +107 -0
- package/src/editor/docs/content/editing-tokens.md +5 -3
- package/src/editor/docs/content.generated.ts +1 -1
- package/src/editor/pages/EditorShell.svelte +1 -1
- package/src/editor/ui/SurfacesTab.svelte +3 -3
- package/src/editor/ui/UITokenSelector.svelte +1 -0
- package/src/editor/ui/VariablesTab.svelte +2 -2
- package/src/editor/ui/sections/{OverlaysSection.svelte → WashesSection.svelte} +44 -43
- package/src/live-tokens/data/colors-and-type/autumn.json +6 -6
- package/src/live-tokens/data/colors-and-type/default.json +6 -6
- package/src/live-tokens/data/colors-and-type/halloween.json +6 -6
- package/src/live-tokens/data/colors-and-type/midnight-study.json +6 -6
- package/src/live-tokens/data/colors-and-type/ocean.json +6 -6
- package/src/live-tokens/data/colors-and-type/royal-velvet.json +6 -6
- package/src/live-tokens/data/colors-and-type/sketchy.json +6 -6
- package/src/live-tokens/data/colors-and-type/spring-meadow.json +6 -6
- package/src/live-tokens/data/colors-and-type/sunset.json +6 -6
- package/src/live-tokens/data/themes/autumn.json +81 -13
- package/src/live-tokens/data/themes/halloween.json +81 -13
- package/src/live-tokens/data/themes/midnight-study.json +81 -13
- package/src/live-tokens/data/themes/ocean.json +81 -13
- package/src/live-tokens/data/themes/royal-velvet.json +81 -13
- package/src/live-tokens/data/themes/sketchy.json +81 -13
- package/src/live-tokens/data/themes/spring-meadow.json +81 -13
- package/src/live-tokens/data/themes/sunset.json +81 -13
- package/src/live-tokens/data/tokens.generated.css +6 -6
- package/src/system/components/Button.svelte +28 -10
- package/src/system/components/Card.svelte +6 -6
- package/src/system/components/Dialog.svelte +3 -3
- package/src/system/components/IconButton.svelte +23 -7
- package/src/system/components/Image.svelte +6 -6
- package/src/system/components/MenuSelect.svelte +17 -1
- package/src/system/components/SegmentedControl.svelte +20 -2
- package/src/system/components/SideNavigation.svelte +22 -2
- package/src/system/components/Slider.svelte +348 -0
- package/src/system/components/TabBar.svelte +20 -2
- package/src/system/styles/CONVENTIONS.md +2 -2
- package/src/system/styles/tokens.css +12 -4
- package/template/package.json +3 -2
- package/template/src/pages/Home.svelte +1 -1
- package/src/editor/core/themes/slices/overlays.ts +0 -101
|
@@ -7,8 +7,8 @@ description: Apply the @motion-proto/live-tokens project conventions when buildi
|
|
|
7
7
|
|
|
8
8
|
Two rules above all else:
|
|
9
9
|
|
|
10
|
-
1. **Use a shipped component if one fits.** Import from `@motion-proto/live-tokens/components/<Name>.svelte`. See **live-tokens-pick-component** for the catalogue and the confusing-pair decisions. Author custom markup only when nothing fits, and then consider **live-tokens-create-component** so the new piece is editable too.
|
|
11
|
-
2. **Use theme tokens for every value.** Every color, spacing, radius, font-size, and font-family in page CSS is a `var(--token-*)
|
|
10
|
+
1. **Use a shipped component if one fits.** Import from `@motion-proto/live-tokens/components/<Name>.svelte`. See **live-tokens-pick-component** for the catalogue and the confusing-pair decisions. Pass only the props its `interface Props` declares, with variant and size values from its union: a prop it does not declare is dropped silently at runtime, and the checker reports it. Author custom markup only when nothing fits, and then consider **live-tokens-create-component** so the new piece is editable too.
|
|
11
|
+
2. **Use theme tokens for every value.** Every color, spacing, radius, font-size, and font-family in page CSS is a `var(--token-*)`, whether it sits in the `<style>` block, an inline `style=` attribute, or a `style:` directive. No colour literals in any notation, `white` and `rgb()` included. No px or rem in spacing, stroke, radius, or shadow: that is the geometry the theme owns and `adjust` moves. Sizing is layout, not theme: a hero's height, a max content width, or a column's minimum width stays a literal. A change in `/live-tokens/editor` should repaint your page.
|
|
12
12
|
|
|
13
13
|
For text, reach for a whole text style rather than assembling one: `--heading-xl` through `--heading-sm`, `--body-md`, `--body-sm`, `--editorial-xl` through `--editorial-sm`, `--eyebrow`, and `--code` each carry a `-font-family`, `-font-size`, `-font-weight`, `-line-height`, and `-letter-spacing`. A heading set from `--heading-lg-*` retypes when the theme's fonts change; one set from a raw `font-size` does not.
|
|
14
14
|
|
|
@@ -45,8 +45,8 @@ const pages = {
|
|
|
45
45
|
|
|
46
46
|
## Avoid
|
|
47
47
|
|
|
48
|
-
-
|
|
49
|
-
- Hardcoded
|
|
48
|
+
- Colour literals, and px or rem in spacing, stroke, radius, or shadow.
|
|
49
|
+
- Hardcoded page-grid counts (`repeat(10, 1fr)`). Use `repeat(var(--columns-count), 1fr)`, or `calc(var(--columns-count) - 2)` for a sub-grid that spans fewer page columns. A local two-up or three-up is a layout and is fine.
|
|
50
50
|
- Utility classes overriding shipped components. Extend via the `/live-tokens/components` editor instead.
|
|
51
51
|
- Deep imports from `node_modules/@motion-proto/live-tokens/src/...`. Use public entry points only.
|
|
52
52
|
- Mounting `Editor` or `ComponentEditorPage` outside their dedicated routes.
|
|
@@ -54,4 +54,15 @@ const pages = {
|
|
|
54
54
|
|
|
55
55
|
## Verify
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
Run the checker and fix what it reports. Repeat until it exits 0:
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
npx live-tokens check-page src/pages/YourPage.svelte
|
|
61
|
+
# or: npx @motion-proto/live-tokens check-page (every page under src/)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
It fails on a component outside the catalogue, a prop a component does not declare, a variant or size outside the prop's union, a deep import, a `var()` that resolves to nothing, a colour literal in any notation, a route under `/live-tokens/*`, and `site.css` imported from `main.ts`. It warns on a px or rem literal in spacing, stroke, radius, or shadow, a hardcoded column count of four or more, an absolute type value, and a route entry with no `source`. Inline `style=` attributes and `style:` directives are read the same way as the `<style>` block; a `var()` fallback is not the page's value and is never a finding.
|
|
65
|
+
|
|
66
|
+
Warnings do not fail the run. `--strict` makes them fail, which is the setting to use when the page is meant to be fully tokenized. `--json` prints findings with a stable `rule` id, so you can work through one rule at a time and re-run. `--off=<rule>` silences a rule for a run; `"checks": { "rules": { ... } }` in `live-tokens.config.json` sets it for the project. A project scaffolded by `create` runs the checker, with `check-component`, as `npm run check:design` before every `vite build`, so the page has to pass before it can ship.
|
|
67
|
+
|
|
68
|
+
Then in dev: change a colour in `/live-tokens/editor` and confirm your page repaints (proves token usage). The overlay's "Page Source" button on the new route opens the page in VS Code (proves the route's `source`). `ColumnsOverlay` (Cmd+G) shows content sitting inside `--columns-max-width`.
|
|
@@ -52,7 +52,24 @@ For pattern reference, read any shipped component's source directly from the con
|
|
|
52
52
|
`border-color`, `box-shadow`, `overflow`, `position` and both pseudo-elements
|
|
53
53
|
away from the element it draws, which constrains where the class can go. Read
|
|
54
54
|
`references/sketch-mode.md`.
|
|
55
|
-
6. **
|
|
55
|
+
6. **Gate on the checker.** Run it, fix every error, and run it again. Do not
|
|
56
|
+
call the component done while it reports one:
|
|
57
|
+
```bash
|
|
58
|
+
npx live-tokens check-component <id> --strict --json
|
|
59
|
+
```
|
|
60
|
+
`--json` gives each finding a stable `rule` id and a line number, so work one
|
|
61
|
+
rule at a time and re-run rather than guessing. `--strict` fails on warnings
|
|
62
|
+
too, which is the right setting for a new component: every warning it raises
|
|
63
|
+
is a naming or token decision that is cheaper to make now than to migrate
|
|
64
|
+
later. Exit code 0 is the gate. With no id it checks every component under
|
|
65
|
+
`src/system/components`; a project scaffolded by `create` runs that as
|
|
66
|
+
`npm run check:design` before every `vite build`.
|
|
67
|
+
|
|
68
|
+
If it rejects a suffix, do not invent a new name for the role. Find a shipped
|
|
69
|
+
component that paints the same thing and use the name it uses: the catalogue
|
|
70
|
+
is the worked reference, and `bin/check-component.test.ts` holds all 26 of
|
|
71
|
+
them to this same contract.
|
|
72
|
+
7. **Verify** with the checklist at the bottom of this file, then place the component on a page with **live-tokens-build-page**.
|
|
56
73
|
|
|
57
74
|
## Token discipline
|
|
58
75
|
|
|
@@ -73,18 +90,32 @@ For pattern reference, read any shipped component's source directly from the con
|
|
|
73
90
|
The editor picker is chosen by the token's suffix, so the suffix is the naming
|
|
74
91
|
decision that matters. Color and surface: `-surface`, `-border`, `-text`,
|
|
75
92
|
`-icon`, `-label`, `-fill`, `-divider`, `-color`, `-shadow`, `-opacity`,
|
|
76
|
-
`-
|
|
77
|
-
|
|
78
|
-
`-
|
|
93
|
+
`-tint`, `-background`, `-accent`, `-indicator`, `-thumb`, and the
|
|
94
|
+
element-named text roles `-title`, `-body`, `-eyebrow`, `-description`,
|
|
95
|
+
`-hint`, `-error`, `-placeholder`, `-value`. Geometry: `-radius`,
|
|
96
|
+
`-border-width`, `-accent-width`, `-hairline-thickness`, `-thickness`,
|
|
97
|
+
`-width`, `-height`, `-size`, `-padding`, `-margin`, `-gap`, `-inset`,
|
|
98
|
+
`-divider-width`, `-divider-thickness`, `-divider-height`, `-divider-inset`,
|
|
99
|
+
`-track-height`, `-dot-size`, `-thumb-size`, `-icon-size`, `-scale`, `-blur`.
|
|
100
|
+
Motion: `-duration`, `-easing`. Typography: `-font-family`, `-font-weight`,
|
|
101
|
+
`-font-size`, `-line-height`, `-letter-spacing`.
|
|
102
|
+
|
|
103
|
+
A token that carries a structural keyword rather than a value takes no suffix
|
|
104
|
+
from this list. Declare it in the editor's `intrinsics` instead, which is what
|
|
105
|
+
exempts it, and never end its name in a state word, which reads as
|
|
106
|
+
state-after-property and fails.
|
|
79
107
|
|
|
80
108
|
Read `references/token-naming.md` for what each one means and when two of them
|
|
81
|
-
compete. A suffix outside that list fails `check-component`.
|
|
109
|
+
compete. A suffix outside that list fails `check-component`. The list lives in
|
|
110
|
+
`KIND_RULES` in the editor's `aliasKinds.ts`, which the picker, the `adjust`
|
|
111
|
+
CLI, and `check-component` all read, so a name accepted here always has a
|
|
112
|
+
control behind it.
|
|
82
113
|
|
|
83
114
|
### Rules that bite
|
|
84
115
|
|
|
85
116
|
- **Fixed overlays must portal to `<body>`.** Any `position: fixed` layer is trapped by a transformed or `contain`ed ancestor, which real pages and the editor's preview pane both have. `check:overlay-portal` fails the build without it. Read `references/fixed-overlays.md` before authoring a modal, lightbox, or backdrop.
|
|
86
|
-
- **State before property.** `--mywidget-button-hover-surface` ✓ — `--mywidget-button-surface-hover` ✗ (breaks sibling matching).
|
|
87
|
-
- **
|
|
117
|
+
- **State before property.** `--mywidget-button-hover-surface` ✓ — `--mywidget-button-surface-hover` ✗ (breaks sibling matching). Disabled is terminal in the name too: `-disabled-hover-` and `-selected-disabled-` describe states that never paint, and `check-component` rejects both.
|
|
118
|
+
- **Every default resolves to a theme token.** A component token names a semantic property; its default is the theme token that property reads. That is what makes the component repaint when the theme changes. `var(--surface-primary)` ✓, `#6a4ce8` ✗, `white` ✗, and `var(--surface-imaginary)` ✗: `check-component` fails on a colour literal in any notation, on a `var()` naming a token that does not exist, and on a default with no token behind it at all, so a raw `16rem` fails too. Composing tokens counts and is common: `color-mix(in srgb, var(--surface-neutral-lower) 70%, transparent)`, or `calc(var(--space-64) * 4)` for a width the spacing scale does not reach. The one value allowed without a token is a structural keyword (`contain`, `start`, `none`), and only when the editor declares it in `intrinsics`.
|
|
88
119
|
- **No abbreviations.** `bg` → `surface`; `fg` → `text`; component ids are never abbreviated.
|
|
89
120
|
- **Text aliases.** Neutral scale is `--text-primary` / `--text-secondary` / `--text-tertiary` / `--text-muted` / `--text-disabled`. Family-tinted is `--text-primary-color`, `--text-accent`, `--text-success`. There is no `--text-neutral`.
|
|
90
121
|
- **Typography `groupKey` on multi-slot components must include the slot prefix.** `groupKey: 'value-font-family'` and `groupKey: 'label-font-family'` ✓ — bare `groupKey: 'font-family'` silently merges them into one link tree ✗. Single-slot components can use a bare typography `groupKey`; add the slot prefix the moment a second slot appears. The same trap applies to type-group **colors** (two slots ending in `-text` collapsing to one `text` key). Let the helpers handle both, below.
|
|
@@ -186,7 +217,11 @@ npx live-tokens check-component <id>
|
|
|
186
217
|
# or: npx @motion-proto/live-tokens check-component <id>
|
|
187
218
|
```
|
|
188
219
|
|
|
189
|
-
It enforces the file layout, the `:global(:root)` block, token-suffix vocabulary, state-before-property rule,
|
|
220
|
+
It enforces the file layout, the `:global(:root)` block, token-suffix vocabulary, state-before-property rule, the terminal disabled state, public-imports rule, that every token an editor row names is declared in the runtime, and that the id is registered, via either `bootLiveTokens({ components: [{ id }] })` or a direct `registerComponent({ id })` call. On the value side it fails on a colour literal in any notation, on a default reading a token that does not exist, and on a default with no theme token behind it that the editor does not declare an intrinsic.
|
|
221
|
+
|
|
222
|
+
It *warns* (non-fatal) when a token-backed default still carries a px or rem term, and when a type-group font helper is called bare across multiple slots, which would merge their fonts into one link tree.
|
|
223
|
+
|
|
224
|
+
Exit code 0 means the static contract is met. Resolve warnings before shipping, or run with `--strict` to make them fail. `--json` prints findings with a stable `rule` id, so you can work through one rule at a time and re-run.
|
|
190
225
|
|
|
191
226
|
**Then run the registry contract test.** If you're authoring inside the package itself, `src/editor/component-editor/registryContract.test.ts` runs `describe.each(getComponentRegistryEntries())` and verifies, per component:
|
|
192
227
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
The editor picker is chosen by suffix. There is no per-token override; if a
|
|
4
4
|
token renders with the wrong picker, rename it to one of these.
|
|
5
5
|
|
|
6
|
-
`
|
|
6
|
+
`KIND_RULES` in `src/editor/core/components/aliasKinds.ts` is authoritative, and
|
|
7
7
|
`check-component` fails on a suffix outside it. `check:skills` holds this file
|
|
8
8
|
to that list, so the two cannot drift apart.
|
|
9
9
|
|
|
@@ -22,6 +22,19 @@ to that list, so the two cannot drift apart.
|
|
|
22
22
|
| `-shadow` | Box-shadow |
|
|
23
23
|
| `-opacity` | Opacity (0–1) |
|
|
24
24
|
| `-blur` | Backdrop or filter blur radius |
|
|
25
|
+
| `-tint` | A wash over the surface, aliasing a `--tint-*` stop |
|
|
26
|
+
| `-background` | Fill, where the component's own vocabulary says background |
|
|
27
|
+
| `-accent` | An accent bar or indicator's colour |
|
|
28
|
+
| `-indicator` | A selection indicator's colour |
|
|
29
|
+
| `-thumb` | A scrollbar or slider thumb's colour |
|
|
30
|
+
| `-title` | Title text colour |
|
|
31
|
+
| `-body` | Body text colour |
|
|
32
|
+
| `-eyebrow` | Eyebrow text colour |
|
|
33
|
+
| `-description` | Description text colour |
|
|
34
|
+
| `-hint` | Hint text colour |
|
|
35
|
+
| `-error` | Error text colour |
|
|
36
|
+
| `-placeholder` | Placeholder text colour |
|
|
37
|
+
| `-value` | A displayed value's colour |
|
|
25
38
|
|
|
26
39
|
## Geometry
|
|
27
40
|
|
|
@@ -30,6 +43,22 @@ to that list, so the two cannot drift apart.
|
|
|
30
43
|
| `-radius` | Corner radius |
|
|
31
44
|
| `-border-width` | Stroke thickness (used even when CSS uses `outline:`) |
|
|
32
45
|
| `-thickness` | Alternative to `-width` when fallback siblings would collide |
|
|
46
|
+
| `-accent-width` | An accent bar's thickness |
|
|
47
|
+
| `-hairline-thickness` | A hairline rule's thickness |
|
|
48
|
+
| `-dot-size` | A dot indicator's diameter |
|
|
49
|
+
| `-divider-width` | A divider's thickness |
|
|
50
|
+
| `-divider-thickness` | Alternative to `-divider-width` |
|
|
51
|
+
| `-divider-height` | A divider's length |
|
|
52
|
+
| `-divider-inset` | Inset trimmed from a stretched divider |
|
|
53
|
+
| `-track-height` | A track's height (progress bar, slider) |
|
|
54
|
+
| `-icon-size` | An icon's rendered size |
|
|
55
|
+
| `-thumb-size` | A thumb's rendered size |
|
|
56
|
+
| `-height` | A measured height (a track, a panel) |
|
|
57
|
+
| `-margin` | Outer spacing, moved on the same scale as `-padding` |
|
|
58
|
+
| `-inset` | Inset trimmed from a stretched element |
|
|
59
|
+
| `-duration` | Motion duration |
|
|
60
|
+
| `-easing` | Motion easing curve |
|
|
61
|
+
| `-scale` | A transform scale factor |
|
|
33
62
|
| `-width` | Width dimension |
|
|
34
63
|
| `-size` | Square / uniform dimension |
|
|
35
64
|
| `-padding` | Internal spacing |
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: live-tokens-fix-findings
|
|
3
|
+
description: Bring an existing @motion-proto/live-tokens project into line with its design system by running check-page and check-component, reading the findings, and fixing each by rule until both exit 0. Use when the user asks to make the build pass, fix the design-system errors or warnings, clean up the literals, replace hex or pixel values with tokens, make a page or component themeable, audit the site or a file against the design system, or asks why check:design fails. Not for building a new page (live-tokens-build-page) or a new component (live-tokens-create-component), which run the same gate as their last step, and not for a single token edit (use the editor).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Fixing what the checkers report
|
|
7
|
+
|
|
8
|
+
Two checkers hold a project to its design system. `check-page` holds pages:
|
|
9
|
+
every component comes from the catalogue and is passed only the props it
|
|
10
|
+
declares, and every value in page CSS is a theme token. `check-component`
|
|
11
|
+
holds authored components: every token names a semantic property and its
|
|
12
|
+
default is the theme token that property reads. A page or component that
|
|
13
|
+
passes repaints when the theme changes. One that does not has opted out of the
|
|
14
|
+
system silently, and these findings are where.
|
|
15
|
+
|
|
16
|
+
This skill is the loop for code that already exists. Run the checker, fix one
|
|
17
|
+
rule at a time, run it again, and stop only when both exit 0.
|
|
18
|
+
|
|
19
|
+
## Reach the checkers
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
npx live-tokens check-page --json # every page under src/
|
|
23
|
+
npx live-tokens check-component --json # every component authored under src/system/components
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
- **Unknown command.** The installed package predates the checkers. Upgrade
|
|
27
|
+
`@motion-proto/live-tokens`, then run `npx live-tokens migrate --check` and
|
|
28
|
+
apply what it plans with `--write`; `--tokens <path>` names a tokens.css that
|
|
29
|
+
sits somewhere other than the four default locations.
|
|
30
|
+
- **No `check:design` script.** A project scaffolded by `create` has one. Add
|
|
31
|
+
it to any other project's `package.json`:
|
|
32
|
+
`"check:design": "live-tokens check-page && live-tokens check-component"`.
|
|
33
|
+
Once it passes, gate the build: `"build": "npm run check:design && vite build"`.
|
|
34
|
+
- **A file, not the project.** `check-page src/pages/Home.svelte` and
|
|
35
|
+
`check-component <id>` scope a run when the user names one thing.
|
|
36
|
+
|
|
37
|
+
## The loop
|
|
38
|
+
|
|
39
|
+
1. Run with `--json`. Each finding carries a stable `rule`, a file, and a line.
|
|
40
|
+
2. Group by rule. Take errors before warnings, and the rule with the most
|
|
41
|
+
findings first, because one recipe clears the whole group.
|
|
42
|
+
3. Apply that rule's recipe, below, to every finding in the group.
|
|
43
|
+
4. Run again. New findings can appear as old ones clear: a token you reached
|
|
44
|
+
for may not exist, or a moved import may land somewhere the rule now sees.
|
|
45
|
+
5. Stop at exit 0. Then run once with `--strict` and report what it adds, so
|
|
46
|
+
the user can decide whether warnings are worth clearing now.
|
|
47
|
+
|
|
48
|
+
Three things the loop never does:
|
|
49
|
+
|
|
50
|
+
- **Silence a rule to pass.** `--off=<rule>` is for a single run while
|
|
51
|
+
working. A severity the project wants changed goes in
|
|
52
|
+
`live-tokens.config.json` under `"checks": { "rules": { "<rule>": "warn" } }`,
|
|
53
|
+
with the reason in the commit, and only when the user has made that call.
|
|
54
|
+
- **Mint a token.** A literal with no token behind it is remapped to the
|
|
55
|
+
nearest existing token by role. No new `--surface-*`, `--text-*`, or
|
|
56
|
+
`--space-*` is added to `tokens.css` to match a value the page happened to
|
|
57
|
+
use. If nothing fits, say so and leave the finding.
|
|
58
|
+
- **Change what the page looks like without saying so.** Most remaps land on
|
|
59
|
+
the same value. When the nearest token differs, `14px` to `--space-16` or a
|
|
60
|
+
55% black to `--scrim`, name the shift in the report.
|
|
61
|
+
|
|
62
|
+
## Colour by role, never by hue
|
|
63
|
+
|
|
64
|
+
`color-literal` is the finding that takes judgement. The replacement is the
|
|
65
|
+
token for what the colour *does*, not the token that happens to be closest in
|
|
66
|
+
hue, because the theme will move every role together and the page must move
|
|
67
|
+
with it. Read `tokens.css` for the names; the families are fixed.
|
|
68
|
+
|
|
69
|
+
| The literal is | Token family | Notes |
|
|
70
|
+
| --- | --- | --- |
|
|
71
|
+
| Text on a surface | `--text-primary`, `-secondary`, `-tertiary`, `-muted`, `-disabled` | The neutral scale. Family colour is `--text-accent`, `--text-success`, and so on. |
|
|
72
|
+
| Light text on a dark chip over the page | `--text-inverted` | The one flip; no AA guarantee. |
|
|
73
|
+
| A box's fill | `--surface-<family>-<level>` | `neutral` for chrome; `brand`, `accent`, `special` for emphasis; `info`, `success`, `warning`, `danger` for status. |
|
|
74
|
+
| A stroke | `--border-<family>-<level>` | `faint`, `subtle`, base, `medium`, `strong` in the neutral family. |
|
|
75
|
+
| A translucent layer that dims what is behind it | `--scrim-low`, `--scrim`, `--scrim-high` | Behind a modal, under a floating control. |
|
|
76
|
+
| A translucent wash on a surface | `--tint-low`, `--tint`, `--tint-high` | Hover, an active tab, a code chip's background. |
|
|
77
|
+
| Fully transparent | `--color-transparent` | Never `transparent` inside a component default. |
|
|
78
|
+
| A gradient | `--gradient-*` | Or compose one from surface tokens. |
|
|
79
|
+
|
|
80
|
+
A `var(--x, #fff)` fallback is not a finding. A named colour is: `white` and
|
|
81
|
+
`rebeccapurple` are literals like any hex.
|
|
82
|
+
|
|
83
|
+
## Geometry by scale
|
|
84
|
+
|
|
85
|
+
`dimension-literal` fires only on the geometry the theme owns: padding,
|
|
86
|
+
margin, gap, border and outline widths, inset offsets, radius, and shadow.
|
|
87
|
+
Sizing (a hero's height, a max content width, a `minmax()` floor) is layout
|
|
88
|
+
and is never reported, so leave it.
|
|
89
|
+
|
|
90
|
+
| The literal is | Token | Notes |
|
|
91
|
+
| --- | --- | --- |
|
|
92
|
+
| Padding, margin, gap, an offset | `--space-<px>` | Steps: 0, 2, 4, 6, 8, 10, 12, 16, 20, 24, 32, 40, 48, 64, 96, 128. Round to the nearest step and name the shift. |
|
|
93
|
+
| A stroke width | `--border-width-1`, `-2`, `-4` | Also for `outline`. |
|
|
94
|
+
| A corner | `--radius-sm` through `-4xl`, `--radius-full` | |
|
|
95
|
+
| A shadow | `--shadow-sm` through `-xl` | Replace the whole value, never one offset. |
|
|
96
|
+
| Part of a `calc()` | The token inside the calc | `calc(var(--space-64) * -2 + var(--space-8))` |
|
|
97
|
+
|
|
98
|
+
While in the file, motion values take `--duration-*` and `--ease-*` even
|
|
99
|
+
though no rule reports them, and a `blur()` takes `--blur-*`.
|
|
100
|
+
|
|
101
|
+
## Every other rule
|
|
102
|
+
|
|
103
|
+
| Rule | Fix |
|
|
104
|
+
| --- | --- |
|
|
105
|
+
| `unknown-token` | A typo or a rename. Search `tokens.css` for the stem. A contract-family name (`--surface-…`, `--text-…`) that is gone was renamed: `npx live-tokens migrate --check` names the migration. |
|
|
106
|
+
| `raw-text-axis` | Set the whole axis set from one text style: `--heading-xl` through `-sm`, `--body-md`, `--body-sm`, `--editorial-*`, `--eyebrow`, `--code`, each carrying `-font-family`, `-font-size`, `-font-weight`, `-line-height`, `-letter-spacing`. A `font:` shorthand is rewritten the same way. `em`, `%`, and a unitless line-height are relative and fine. |
|
|
107
|
+
| `unknown-component` | Not in the catalogue. Read **live-tokens-pick-component** for the shipped one that fits, or author it with **live-tokens-create-component**. |
|
|
108
|
+
| `unknown-prop` | The component drops it at runtime. Read its `interface Props` in `node_modules/@motion-proto/live-tokens/src/system/components/<Name>.svelte` and either map it to a declared prop or delete it. A `class` on a component that declares none does nothing. |
|
|
109
|
+
| `unknown-prop-value` | Pick a value from the union the message lists. |
|
|
110
|
+
| `hardcoded-columns` | `repeat(var(--columns-count), 1fr)` for the page grid; `calc(var(--columns-count) - 2)` for a sub-grid spanning fewer page columns. A two-up or three-up is a layout and is not reported. |
|
|
111
|
+
| `site-css-in-main` | Delete the import from `main.ts` and add it to each page's `<script>`, so page CSS never reaches the editor routes. |
|
|
112
|
+
| `missing-source` | Add `source: 'src/...'` to the route entry so Page Source can open it. |
|
|
113
|
+
| `reserved-route` | Move the route out of `/live-tokens/*`; the package owns that namespace. |
|
|
114
|
+
| `deep-import` | Import from `@motion-proto/live-tokens` or `/component-editor` or `/components/<Name>.svelte`, never from `/src/`. |
|
|
115
|
+
| `unknown-suffix`, `state-after-property`, `disabled-is-terminal` | Rename the token. Borrow the name a shipped component uses for the same role; the vocabulary and the state model are in **live-tokens-create-component**. |
|
|
116
|
+
| `color-literal`, `unknown-token-ref`, `default-not-token` (component) | The `:global(:root)` default reads a theme token, composed if needed. A structural keyword (`start`, `contain`) is declared in the editor's `intrinsics`. |
|
|
117
|
+
| `phantom-editor-token`, `phantom-link` | The editor names a token the runtime never declares, or a bare font helper spans slots. Both are editor fixes; see the same skill. |
|
|
118
|
+
| `missing-registration`, `missing-file`, `missing-root-block` | The component is not wired the way the recipe in **live-tokens-create-component** wires it. |
|
|
119
|
+
|
|
120
|
+
## Report
|
|
121
|
+
|
|
122
|
+
Say what changed by rule, one line per rule with the count and any visible
|
|
123
|
+
shift. Say what was left and why, with the config entry if the user chose to
|
|
124
|
+
lower a severity. End with the two commands and their exit codes.
|
|
125
|
+
|
|
126
|
+
## Verify
|
|
127
|
+
|
|
128
|
+
Open `/live-tokens/editor` in dev and change a surface colour and a spacing
|
|
129
|
+
step. Every file the loop touched should repaint. One that does not still
|
|
130
|
+
holds a literal the checker cannot see, which is worth reporting as a gap in
|
|
131
|
+
the checker rather than patching around.
|
|
@@ -11,7 +11,7 @@ For composing a page once you've picked components, see **live-tokens-build-page
|
|
|
11
11
|
|
|
12
12
|
## Catalogue
|
|
13
13
|
|
|
14
|
-
Action: `Button`, `IconButton`, `InlineEditActions`. Input: `Input`. Selection: `SegmentedControl`, `TabBar`, `RadioButton`, `MenuSelect`, `Toggle`. Containers: `Card`, `CollapsibleSection`, `Dialog`, `Panel`. Messaging: `Callout`, `Notification`, `Tooltip`, `Badge`, `CornerBadge`. Display: `Table`, `Image`, `ImageLightbox`, `ProgressBar`, `SectionDivider`, `SideNavigation`, `CodeSnippet`.
|
|
14
|
+
Action: `Button`, `IconButton`, `InlineEditActions`. Input: `Input`, `Slider`. Selection: `SegmentedControl`, `TabBar`, `RadioButton`, `MenuSelect`, `Toggle`. Containers: `Card`, `CollapsibleSection`, `Dialog`, `Panel`. Messaging: `Callout`, `Notification`, `Tooltip`, `Badge`, `CornerBadge`. Display: `Table`, `Image`, `ImageLightbox`, `ProgressBar`, `SectionDivider`, `SideNavigation`, `CodeSnippet`.
|
|
15
15
|
|
|
16
16
|
## Action family: Button vs IconButton
|
|
17
17
|
|
|
@@ -42,6 +42,7 @@ All four pick one option from a set. The right one depends on **option count**,
|
|
|
42
42
|
|
|
43
43
|
- `Input` takes an answer the page cannot enumerate: a name, an email, a search string, an amount. It ships the label, the hint line, and the error state as parts (`--input-label-*`, `--input-hint-*`, `--input-error-*`), so style those rather than stacking your own text under a bare field.
|
|
44
44
|
- The boundary is whether you can list the answers. A short fixed set is the single-selection family above; a long fixed set is `MenuSelect`; anything you cannot write down is `Input`.
|
|
45
|
+
- `Slider` takes a number inside a known range where the position carries the meaning: a volume, a price band, a percentage. Its `range` variant takes a low and a high bound on one track. A number the user knows exactly and would rather type is `Input` with `type="number"`.
|
|
45
46
|
- **Don't use it for on/off.** That is `Toggle`, and a one-field form asking for yes or no is the usual way this goes wrong.
|
|
46
47
|
- Its four variants are `default`, `focused`, `disabled`, and `error`. A validation message belongs in the `error` variant, not in a `Callout` next to the field.
|
|
47
48
|
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,212 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.69.0 — Every value reads a token, and the build says so
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- **SideNavigation's panel widths read the spacing scale.** `16rem` and `3rem`
|
|
8
|
+
were the only shipped defaults with no token behind them; both now derive
|
|
9
|
+
from the largest step, `calc(var(--space-64) * 4)` and
|
|
10
|
+
`calc(var(--space-64) * 0.75)`. Values are unchanged.
|
|
11
|
+
|
|
12
|
+
- **The starter `site.css` is fully tokenized.** A paragraph margin and three
|
|
13
|
+
rule and blockquote strokes were px literals; they read `--space-16` and
|
|
14
|
+
`--border-width-*` now, so a scaffolded project starts clean under
|
|
15
|
+
`check-page --strict`. The paragraph margin moves from 14px to 16px.
|
|
16
|
+
|
|
17
|
+
- **TabBar's active tab and Button's inline-code badge are tints, not scrims.**
|
|
18
|
+
Both washed a surface rather than dimming what sat behind it, and only read a
|
|
19
|
+
scrim because no tint family existed. **They restyle**: a 38% near-black wash
|
|
20
|
+
becomes a 10% white one, so each reads lighter and softer. A theme that pointed
|
|
21
|
+
the TabBar alias somewhere else keeps its choice.
|
|
22
|
+
|
|
23
|
+
- **Optional-interaction gates take `-enabled`, not a state word.**
|
|
24
|
+
`--card-hover-border-active`, `--card-hover-shadow-active`,
|
|
25
|
+
`--image-zoom-hover`, and `--image-grow-hover` read as state-after-property and
|
|
26
|
+
failed `check-component`, which meant the documented gate pattern was one a
|
|
27
|
+
consumer could not use. A gate is not a state: it says whether the interaction
|
|
28
|
+
is on at all. Values are unchanged.
|
|
29
|
+
|
|
30
|
+
- **Button's shimmer and ImageLightbox's tile fit are declared intrinsics.**
|
|
31
|
+
Both were bare keywords with no theme token and no declaration, which is the
|
|
32
|
+
thing `intrinsics` exists to record. `--button-shimmer` now defaults to
|
|
33
|
+
`var(--shimmer-on)`, the token that was already there for it.
|
|
34
|
+
|
|
35
|
+
- **`--hover-*` is now `--tint-*`, and it has a baseline for the first time.** A
|
|
36
|
+
state is a segment of a property name (`--button-outline-hover-surface`), not
|
|
37
|
+
a token of its own, so the three stops are named for what they are: a tint
|
|
38
|
+
shades the surface it sits on. Values are unchanged.
|
|
39
|
+
|
|
40
|
+
The theme engine had always emitted these stops, but `tokens.css` never
|
|
41
|
+
declared them, so they resolved to nothing until a theme was adopted. That is
|
|
42
|
+
why `var(--hover)` painted no pressed state on a fresh install. `--tint-*` is
|
|
43
|
+
baselined, and that half of the migration is additive, so it auto-applies.
|
|
44
|
+
|
|
45
|
+
- **`--overlay-*` is now `--scrim-*`.** A scrim is a translucent layer that dims
|
|
46
|
+
what sits behind it, which is what a dialog draws over the page. The old name
|
|
47
|
+
had spread to cover surface tints as well, which are the opposite operation,
|
|
48
|
+
and it collided with `backdrop`, the exported concept for what paints behind
|
|
49
|
+
an element and which way it leans. Each name now means one thing. Values are
|
|
50
|
+
unchanged, so nothing repaints.
|
|
51
|
+
|
|
52
|
+
`npx live-tokens migrate` renames the three tokens in a vendored `tokens.css`.
|
|
53
|
+
Token names are public API, so the migration is breaking and never
|
|
54
|
+
auto-applies. Saved themes and component configs migrate on load.
|
|
55
|
+
|
|
56
|
+
Dialog's part follows its token: `--dialog-overlay-surface` is
|
|
57
|
+
`--dialog-scrim-surface`, and the editor labels it "scrim color" rather than
|
|
58
|
+
the "backdrop color" that named a third thing again. The editor's Overlays
|
|
59
|
+
section is now Washes, holding Scrims and Tints.
|
|
60
|
+
|
|
61
|
+
### Added
|
|
62
|
+
|
|
63
|
+
- **The shipped catalogue is now the component contract's fixture.**
|
|
64
|
+
`check-component` reported 109 errors across all 26 shipped components, and
|
|
65
|
+
none of them were defects in the components: the checker's suffix list had
|
|
66
|
+
simply drifted narrower than the catalogue it governs, rejecting `-accent`,
|
|
67
|
+
`-title`, `-margin`, `-easing` and a dozen more names our own components use.
|
|
68
|
+
A test now runs the full contract over every registered component and requires
|
|
69
|
+
zero errors, so the rule and the components can never disagree again.
|
|
70
|
+
|
|
71
|
+
The suffix vocabulary moved to `KIND_RULES` in the editor's `aliasKinds.ts`.
|
|
72
|
+
The picker, the `adjust` CLI, `check-component`, and `check:skills` all read
|
|
73
|
+
that one table, so a name the checker accepts always has a control behind it.
|
|
74
|
+
|
|
75
|
+
Three rules got more accurate along the way. A token the editor declares in
|
|
76
|
+
`intrinsics` is exempt from the suffix check, because a structural keyword is
|
|
77
|
+
not a themeable value. Membership in the package's own `builtInRegistry`
|
|
78
|
+
counts as registration. And a component may prefix its tokens with the
|
|
79
|
+
hyphenated form of its id, which is what CornerBadge has always done.
|
|
80
|
+
|
|
81
|
+
- **An optional hover tint on Button, IconButton, TabBar, SegmentedControl,
|
|
82
|
+
MenuSelect, and SideNavigation.** One stop for the whole component rather than
|
|
83
|
+
one hover surface per variant: Button and IconButton carried 36 hover tokens
|
|
84
|
+
each, and every one was tuned by hand. `--<id>-hover-tint` aliases a `--tint-*`
|
|
85
|
+
stop, and `--<id>-hover-tint-enabled` gates it.
|
|
86
|
+
|
|
87
|
+
Off by default, so nothing changes until a project turns it on. The tint rides
|
|
88
|
+
as a `background-image` over the hover rule's own `background-color`, so it
|
|
89
|
+
needs no pseudo-element.
|
|
90
|
+
|
|
91
|
+
A **tint layer** switch in the component editor's hover state turns it on and
|
|
92
|
+
points every hover surface at its own base surface, so hover is the tint alone
|
|
93
|
+
rather than a swap wearing a wash. The hover-surface rows grey out while it is
|
|
94
|
+
on, since they no longer change anything. Switching it off clears those
|
|
95
|
+
overrides, returning each surface to its shipped default.
|
|
96
|
+
|
|
97
|
+
Switching it on reveals a **tint color** row beside it. It starts on `--tint`,
|
|
98
|
+
the theme's middle tint stop, and takes any colour token with an alpha, like
|
|
99
|
+
every other colour row. A `-tint` suffix now resolves to the surface picker
|
|
100
|
+
rather than falling through, so the row offers the whole palette, not only the
|
|
101
|
+
tint stops.
|
|
102
|
+
|
|
103
|
+
Per instance, the `hoverTint` prop overrides the global default (`undefined`
|
|
104
|
+
inherits, `true` and `false` force).
|
|
105
|
+
|
|
106
|
+
- **`live-tokens check-page` validates a page against the build-page
|
|
107
|
+
contract.** It fails on a component outside the catalogue, a deep import into
|
|
108
|
+
package internals, a `var()` naming a token that does not exist, a colour
|
|
109
|
+
literal, a route under the reserved `/live-tokens/*` namespace, and `site.css`
|
|
110
|
+
imported from `main.ts`, a prop a shipped component does not declare, and a
|
|
111
|
+
variant or size outside that prop's union. It warns on a px or rem literal
|
|
112
|
+
in spacing, stroke, radius, or shadow, a hardcoded page-grid count of four
|
|
113
|
+
columns or more, an absolute type value (the `font` shorthand included), and
|
|
114
|
+
a route entry with no `source`. Sizing is layout and is never reported.
|
|
115
|
+
Inline `style=` attributes and `style:` directives are read under the same
|
|
116
|
+
rules as the `<style>` block, and a named colour is a literal like any hex.
|
|
117
|
+
Given no paths it checks every page under `src/`.
|
|
118
|
+
|
|
119
|
+
- **Both check commands take `--json`, `--strict`, and per-rule severity
|
|
120
|
+
flags.** `--json` prints findings with a stable `rule` id and line number, so
|
|
121
|
+
a skill can fix one rule at a time and re-run until the exit code is 0.
|
|
122
|
+
`--strict` promotes warnings to errors. `--off=<rule>`, `--warn=<rule>`, and
|
|
123
|
+
`--error=<rule>` change a rule for one run; `"checks": { "rules": { ... } }`
|
|
124
|
+
in `live-tokens.config.json` sets it for the project.
|
|
125
|
+
|
|
126
|
+
- **`check-component` now checks what a default *resolves to*, not just what it
|
|
127
|
+
is named.** A component token names a semantic property and its default is the
|
|
128
|
+
theme token that property reads, which is what makes the component repaint
|
|
129
|
+
when the theme changes. A default reading a token that does not exist is now
|
|
130
|
+
an error, including a `var()` naming a state word rather than the token that
|
|
131
|
+
state should paint. A default with no token behind it is an error unless the
|
|
132
|
+
editor declares it in `intrinsics`; a colour literal in any notation is an
|
|
133
|
+
error; a token-backed default that still carries a px or rem term warns.
|
|
134
|
+
Two more rules read the name alone: `disabled-is-terminal` rejects a token
|
|
135
|
+
that combines `disabled` with `hover`, `focus`, `selected`, `on`, `active`,
|
|
136
|
+
or `checked`, and `phantom-editor-token` rejects an editor row naming a
|
|
137
|
+
token the runtime never declares. Given no id, `check-component` checks
|
|
138
|
+
every component authored under `src/system/components`, and a scaffolded
|
|
139
|
+
project runs both checkers as `npm run check:design` before every
|
|
140
|
+
`vite build`. `check-component` also finds a shipped component's editor
|
|
141
|
+
beside the other editors, not only next to its runtime.
|
|
142
|
+
|
|
143
|
+
- **`npm run check:pages` runs the page check over this repo under `--strict`
|
|
144
|
+
and is part of `prepublishOnly`.** The unit suite covers the same ground:
|
|
145
|
+
the repo's pages carry no finding at all, and every shipped component
|
|
146
|
+
default resolves to a real token. Both suites also hold a mutation table: a
|
|
147
|
+
clean component and a clean page that pass `--strict`, and one smallest
|
|
148
|
+
break per rule that must fail, so a rule cannot stop firing unnoticed.
|
|
149
|
+
|
|
150
|
+
- **`Slider`, in two variants.** `single` moves one thumb to a value; `range`
|
|
151
|
+
moves two thumbs to a low and a high bound on one track. Both share track,
|
|
152
|
+
fill, and thumb tokens, linked in the editor so an edit to one moves the
|
|
153
|
+
other until deliberately unlinked, with hover and disabled states and a
|
|
154
|
+
label and value readout. It was authored by following
|
|
155
|
+
`live-tokens-create-component` end to end, and `check-component --strict`
|
|
156
|
+
was clean on the first run.
|
|
157
|
+
|
|
158
|
+
- **`live-tokens-fix-findings`, the seventh skill.** The loop for code that
|
|
159
|
+
already exists: run both checkers with `--json`, take the largest group of
|
|
160
|
+
errors first, apply that rule's recipe, re-run, stop at exit 0. It carries
|
|
161
|
+
one recipe per rule id, with colour mapped by role rather than hue and
|
|
162
|
+
geometry by scale, and three refusals: never silence a rule to pass, never
|
|
163
|
+
mint a token, never shift the look without saying so. Its first run, on the
|
|
164
|
+
package's own demo site, took three rounds and ended clean.
|
|
165
|
+
|
|
166
|
+
### Fixed
|
|
167
|
+
|
|
168
|
+
- **The tint layer switch was unreachable in four editors.** SegmentedControl,
|
|
169
|
+
TabBar, MenuSelect, and SideNavigation gated the row on a state named
|
|
170
|
+
`hover`, and their hover states are `hover option`, `hover tab`,
|
|
171
|
+
`hover item`, and `<Part> / Hover`, so the switch and the tint colour row
|
|
172
|
+
never rendered. Each condition now names the state the editor has. The
|
|
173
|
+
render contract caught it once it learned to turn a gate on: a gate row
|
|
174
|
+
carries `data-token-variables` and the harness flips a `role="switch"`
|
|
175
|
+
Toggle the way it clicks a checkbox, then exercises the row the gate
|
|
176
|
+
revealed. A selector whose selections are locked carries a `locked` class,
|
|
177
|
+
which the harness skips instead of retrying a chip it can never click.
|
|
178
|
+
|
|
179
|
+
- **`check-page` no longer reports a `var()` fallback as a colour literal.**
|
|
180
|
+
`var(--surface-neutral, #111)` paints the token; the literal only renders
|
|
181
|
+
when the token is missing. Against the package's own demo site this was 33
|
|
182
|
+
of 39 errors.
|
|
183
|
+
|
|
184
|
+
- **`check-page` reads a custom property with a digit in its name as one
|
|
185
|
+
declaration.** `--heading-2xl: 1.875rem` was parsed as the property `xl`
|
|
186
|
+
and reported as a raw dimension. The project's own `tokens.css` and the
|
|
187
|
+
generated token files are also no longer discovered as pages.
|
|
188
|
+
|
|
189
|
+
- **Both checkers read a `:global(:root)` block the same way.** They had two
|
|
190
|
+
extractors, one of which stopped at the first `}`, so a nested at-rule or
|
|
191
|
+
SCSS block truncated the block. One brace-balanced extractor is shared.
|
|
192
|
+
|
|
193
|
+
- **An `intrinsics` array on one line still exempts its token.** The
|
|
194
|
+
exemption required the closing `];` on its own line.
|
|
195
|
+
|
|
196
|
+
- **A persisted editor session from before the rename no longer breaks the
|
|
197
|
+
renderer.** `hydrate` shallow-merges persisted state, so a `washes` (or
|
|
198
|
+
`overlays`) slice saved by an older build replaced the current one wholesale
|
|
199
|
+
and arrived without its tint stops, throwing `w.tints is not iterable` out of
|
|
200
|
+
the render path on load. Hydration now reshapes the slice: it carries the
|
|
201
|
+
saved stops across under their new names and falls back to the shipped
|
|
202
|
+
defaults for anything unusable.
|
|
203
|
+
|
|
204
|
+
- **The outline Button and IconButton pressed state had no colour.** Both read
|
|
205
|
+
`var(--hover)`, which names nothing: a state is a segment of a semantic
|
|
206
|
+
property name (`--button-outline-hover-surface`), never a token of its own.
|
|
207
|
+
They read `--surface-neutral-low` now, one step along the scale from their
|
|
208
|
+
hover surface. `check-component` catches this class of mistake by name.
|
|
209
|
+
|
|
3
210
|
## 0.68.1 — A look is a Theme, or it's a sketch style
|
|
4
211
|
|
|
5
212
|
### Changed
|
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ The editor is dev-only. Production builds get plain CSS variables and the compon
|
|
|
11
11
|
## Features
|
|
12
12
|
|
|
13
13
|
- **Live token editing.** Colors, typography, spacing, radii, shadows, motion, palettes, and gradients. Every input writes a CSS variable, so the page repaints with no reload and no build step.
|
|
14
|
-
- **Live component editing.**
|
|
14
|
+
- **Live component editing.** 26 shipped Svelte components (Button, IconButton, Input, Card, Dialog, Badge, Callout, Table, Tooltip, Toggle, TabBar, SegmentedControl, RadioButton, MenuSelect, ProgressBar, CornerBadge, SectionDivider, CollapsibleSection, Notification, Image, ImageLightbox, CodeSnippet, SideNavigation, Panel, InlineEditActions) declare their design-token aliases in a `:global(:root)` block. Rewire an alias from the component's editor and it updates everywhere that component is used, on your real pages.
|
|
15
15
|
- **Four dev-only routes.** `/live-tokens/editor` for tokens, `/live-tokens/colors` for palettes, `/live-tokens/components` for per-component aliases, `/live-tokens/docs` for the user guide.
|
|
16
16
|
- **Editor overlay.** Pins to the top right of every dev page and opens the editor in a side panel or floating window, so you edit on the page you are styling. Its "Page Source" button opens the current page's `.svelte` file in VS Code.
|
|
17
17
|
- **Themes.** A theme is a whole look in one file: colors and type plus a config for every component, stored by value. Loading one changes a single pointer file, and nothing your site ships changes until you Adopt. Export a theme and import it into another project to restore the look in one step.
|
|
@@ -323,7 +323,8 @@ npx @motion-proto/live-tokens <command>
|
|
|
323
323
|
|---|---|
|
|
324
324
|
| `create <dir> [--force]` | Scaffold a new Svelte + Vite app wired up with live-tokens. |
|
|
325
325
|
| `setup-claude [--force]` | Install the bundled Claude Code skills into `./.claude/skills/`. |
|
|
326
|
-
| `check-component
|
|
326
|
+
| `check-component [id]` | Validate a component's runtime, editor, and registration against the authoring contract; with no id, every component authored under `src/system/components`. |
|
|
327
|
+
| `check-page [paths...]` | Validate pages against the build-page contract: catalogue components and their props, theme tokens over literals, route wiring. |
|
|
327
328
|
| `generate-theme <brief.json> [--no-activate] [--dry-run] [--carry-from <name>]` | Build a full theme from a 10-seed OKLCH brief, enforce AA contrast, write `themes/<slug>.json`, and open it. |
|
|
328
329
|
| `adjust <ops.json> [--dry-run]` | Move radius, padding, gap, and border-width aliases along their token scales. |
|
|
329
330
|
| `set-fonts <brief.json> [--dry-run] [--no-verify]` | Bind Google Fonts families to the theme's font stacks, verified against the API. |
|
|
@@ -333,7 +334,7 @@ Once installed in a project, the same commands are available as `npx live-tokens
|
|
|
333
334
|
|
|
334
335
|
## Claude Code skills
|
|
335
336
|
|
|
336
|
-
The package bundles
|
|
337
|
+
The package bundles seven Claude Code skills. They encode the conventions this README cannot carry in full: which component fits a need, how a page is wired, what a valid theme looks like in OKLCH, how two typefaces sit together, how geometry moves along the token scales, and how an existing page or component is brought back into line with all of that. Each triggers from an ordinary request, so there are no slash commands to learn.
|
|
337
338
|
|
|
338
339
|
### Install
|
|
339
340
|
|
|
@@ -397,13 +398,19 @@ Ask for something the catalogue lacks: "author a Rating component", "make my Chi
|
|
|
397
398
|
|
|
398
399
|
The skill covers the recipe: the runtime `.svelte` file with its `:global(:root)` token block, the editor `.svelte` file exporting `allTokens` and its variant groups, the `registerComponent()` call, and the catalogue entry that keeps `live-tokens-pick-component` current. It carries the naming scheme, the token suffix vocabulary, the state model (component states such as selected and disabled are separate from interaction states such as hover), and the public-imports rule, and points at the shipped `Toggle` in `node_modules` as the worked example. Linked siblings, intrinsics, and the fixed-overlay portal rule sit in reference files the skill reads only when a component needs them.
|
|
399
400
|
|
|
401
|
+
### `live-tokens-fix-findings`
|
|
402
|
+
|
|
403
|
+
Ask for the existing code to catch up: "make check:design pass", "fix the design-system warnings", "replace the hex and pixel values with tokens", "why is check-page failing on the pricing page?".
|
|
404
|
+
|
|
405
|
+
The two checkers report a stable rule id per finding. The skill runs them with `--json`, groups the findings by rule, and carries one fix recipe per rule: a colour literal becomes the token for its role rather than the nearest hue, a spacing literal moves to the nearest `--space-*` step with the shift named, a raw `font-size` becomes a whole text style, a prop the component does not declare is mapped or dropped, and `site.css` moves out of `main.ts` into each page. It re-runs after every rule and stops at exit 0, then reports what changed, what it left and why, and what `--strict` would add. It never silences a rule to pass and never adds a token to `tokens.css` to match a value a page happened to use.
|
|
406
|
+
|
|
400
407
|
Verify the result:
|
|
401
408
|
|
|
402
409
|
```bash
|
|
403
410
|
npx @motion-proto/live-tokens check-component <id>
|
|
404
411
|
```
|
|
405
412
|
|
|
406
|
-
The validator checks the file layout, the `:global(:root)` block, the token-suffix vocabulary, the state-before-property rule, the
|
|
413
|
+
The validator checks the file layout, the `:global(:root)` block, the token-suffix vocabulary, the state-before-property rule, the public-imports rule, the `registerComponent({ id })` call, and that every default resolves to a theme token rather than a literal. Exit code 0 means the static contract is met. A project scaffolded by `create` runs it, with `check-page`, as `npm run check:design` before every `vite build`, so a component or page that opts out of the theme cannot ship by accident.
|
|
407
414
|
|
|
408
415
|
## From edit to production
|
|
409
416
|
|