@motion-proto/live-tokens 0.68.1 → 0.70.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 +55 -19
- package/.claude/skills/live-tokens-create-component/references/token-naming.md +30 -1
- package/.claude/skills/live-tokens-fix-findings/SKILL.md +133 -0
- package/.claude/skills/live-tokens-pick-component/SKILL.md +10 -1
- package/CHANGELOG.md +236 -0
- package/README.md +13 -4
- package/bin/check-component.mjs +367 -63
- package/bin/check-page.mjs +409 -0
- package/bin/cli.mjs +107 -9
- package/bin/lib/catalogue.mjs +123 -0
- package/bin/lib/cssValues.mjs +50 -0
- package/bin/lib/findings.mjs +106 -0
- package/bin/lib/tokenVocabulary.mjs +240 -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/index.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 it declares, with variant and size values from its union: `npx live-tokens components <id>` prints them (`--json` for data), and the list includes the project's own components beside the shipped ones. A prop a component 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`.
|
|
@@ -15,11 +15,10 @@ For pattern reference, read any shipped component's source directly from the con
|
|
|
15
15
|
- Simplest reads (no state, no linked-block): `Card` (single variant with parts), `Badge` and `Callout` (multi-variant).
|
|
16
16
|
- Multi-state (hover, disabled, focus): `Button`, `Input`.
|
|
17
17
|
- Multi-part (overlay / header / body / footer): `Dialog`.
|
|
18
|
-
- Multi-variant with linked siblings (`canBeLinked` + `groupKey`): `SegmentedControl`, `TabBar`.
|
|
19
|
-
- Composes another shipped component: `CodeSnippet` (renders a `Tooltip` for the copy-confirmation popover).
|
|
18
|
+
- Multi-variant with linked siblings (`canBeLinked` + `groupKey`): `SegmentedControl`, `TabBar`. Composes another shipped component: `CodeSnippet`.
|
|
20
19
|
- Editor files: `node_modules/@motion-proto/live-tokens/src/editor/component-editor/<Name>Editor.svelte`.
|
|
21
20
|
|
|
22
|
-
**File-location note.** Shipped editors live in `src/editor/component-editor/` because they're library-internal. For *your* component, **co-locate** both files in `src/system/components
|
|
21
|
+
**File-location note.** Shipped editors live in `src/editor/component-editor/` because they're library-internal. For *your* component, **co-locate** both files in `src/system/components/`. Read the shipped files for pattern, ignore their location.
|
|
23
22
|
|
|
24
23
|
## The recipe
|
|
25
24
|
|
|
@@ -43,7 +42,15 @@ For pattern reference, read any shipped component's source directly from the con
|
|
|
43
42
|
});
|
|
44
43
|
```
|
|
45
44
|
The schema side-effect happens inside `registerComponent` (which `bootLiveTokens` calls for you), so you don't call `registerComponentSchema` separately. **Do not place a standalone `registerComponent(...)` *before* `bootLiveTokens`** — that registers before the editor's init hooks run, which is the wrong window and can leave editor changes disconnected from the live page. Only call `registerComponent` directly if your app mounts manually (no `bootLiveTokens`), in which case call it before `mount(App, ...)`.
|
|
46
|
-
4. **
|
|
45
|
+
4. **Say what it is for.** The runtime file's leading HTML comment is the
|
|
46
|
+
component's description. `npx live-tokens components` prints it beside the
|
|
47
|
+
id with the variants and props read from `interface Props` (`--json` for
|
|
48
|
+
data); that is how **live-tokens-pick-component** weighs a project's own
|
|
49
|
+
component against the shipped set, so no skill file is edited and nothing
|
|
50
|
+
is lost when `setup-claude` refreshes the skills. Name the job it does and
|
|
51
|
+
what it is not for. A directory other than `src/system/components` goes in
|
|
52
|
+
`"componentDirs"` in `live-tokens.config.json`; a first-party component is
|
|
53
|
+
also added to the picker's **Catalogue** line, which `check:skills` holds.
|
|
47
54
|
5. **Join the sketch layer** — the effect draws a fixed set of parts, so a new
|
|
48
55
|
component stays crisp while the page around it goes hand-drawn until it opts
|
|
49
56
|
in. A consumer component carries one of four reserved classes on its root and
|
|
@@ -52,7 +59,24 @@ For pattern reference, read any shipped component's source directly from the con
|
|
|
52
59
|
`border-color`, `box-shadow`, `overflow`, `position` and both pseudo-elements
|
|
53
60
|
away from the element it draws, which constrains where the class can go. Read
|
|
54
61
|
`references/sketch-mode.md`.
|
|
55
|
-
6. **
|
|
62
|
+
6. **Gate on the checker.** Run it, fix every error, and run it again. Do not
|
|
63
|
+
call the component done while it reports one:
|
|
64
|
+
```bash
|
|
65
|
+
npx live-tokens check-component <id> --strict --json
|
|
66
|
+
```
|
|
67
|
+
`--json` gives each finding a stable `rule` id and a line number, so work one
|
|
68
|
+
rule at a time and re-run rather than guessing. `--strict` fails on warnings
|
|
69
|
+
too, which is the right setting for a new component: every warning it raises
|
|
70
|
+
is a naming or token decision that is cheaper to make now than to migrate
|
|
71
|
+
later. Exit code 0 is the gate. With no id it checks every component under
|
|
72
|
+
`src/system/components`; a project scaffolded by `create` runs that as
|
|
73
|
+
`npm run check:design` before every `vite build`.
|
|
74
|
+
|
|
75
|
+
If it rejects a suffix, do not invent a new name for the role. Find a shipped
|
|
76
|
+
component that paints the same thing and use the name it uses: the catalogue
|
|
77
|
+
is the worked reference, and `bin/check-component.test.ts` holds all 26 of
|
|
78
|
+
them to this same contract.
|
|
79
|
+
7. **Verify** with the checklist at the bottom of this file, then place the component on a page with **live-tokens-build-page**.
|
|
56
80
|
|
|
57
81
|
## Token discipline
|
|
58
82
|
|
|
@@ -73,18 +97,32 @@ For pattern reference, read any shipped component's source directly from the con
|
|
|
73
97
|
The editor picker is chosen by the token's suffix, so the suffix is the naming
|
|
74
98
|
decision that matters. Color and surface: `-surface`, `-border`, `-text`,
|
|
75
99
|
`-icon`, `-label`, `-fill`, `-divider`, `-color`, `-shadow`, `-opacity`,
|
|
76
|
-
`-
|
|
77
|
-
|
|
78
|
-
`-
|
|
100
|
+
`-tint`, `-background`, `-accent`, `-indicator`, `-thumb`, and the
|
|
101
|
+
element-named text roles `-title`, `-body`, `-eyebrow`, `-description`,
|
|
102
|
+
`-hint`, `-error`, `-placeholder`, `-value`. Geometry: `-radius`,
|
|
103
|
+
`-border-width`, `-accent-width`, `-hairline-thickness`, `-thickness`,
|
|
104
|
+
`-width`, `-height`, `-size`, `-padding`, `-margin`, `-gap`, `-inset`,
|
|
105
|
+
`-divider-width`, `-divider-thickness`, `-divider-height`, `-divider-inset`,
|
|
106
|
+
`-track-height`, `-dot-size`, `-thumb-size`, `-icon-size`, `-scale`, `-blur`.
|
|
107
|
+
Motion: `-duration`, `-easing`. Typography: `-font-family`, `-font-weight`,
|
|
108
|
+
`-font-size`, `-line-height`, `-letter-spacing`.
|
|
109
|
+
|
|
110
|
+
A token that carries a structural keyword rather than a value takes no suffix
|
|
111
|
+
from this list. Declare it in the editor's `intrinsics` instead, which is what
|
|
112
|
+
exempts it, and never end its name in a state word, which reads as
|
|
113
|
+
state-after-property and fails.
|
|
79
114
|
|
|
80
115
|
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`.
|
|
116
|
+
compete. A suffix outside that list fails `check-component`. The list lives in
|
|
117
|
+
`KIND_RULES` in the editor's `aliasKinds.ts`, which the picker, the `adjust`
|
|
118
|
+
CLI, and `check-component` all read, so a name accepted here always has a
|
|
119
|
+
control behind it.
|
|
82
120
|
|
|
83
121
|
### Rules that bite
|
|
84
122
|
|
|
85
123
|
- **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
|
-
- **
|
|
124
|
+
- **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.
|
|
125
|
+
- **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
126
|
- **No abbreviations.** `bg` → `surface`; `fg` → `text`; component ids are never abbreviated.
|
|
89
127
|
- **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
128
|
- **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,17 +224,15 @@ npx live-tokens check-component <id>
|
|
|
186
224
|
# or: npx @motion-proto/live-tokens check-component <id>
|
|
187
225
|
```
|
|
188
226
|
|
|
189
|
-
It enforces the file layout, the `:global(:root)` block, token-suffix vocabulary, state-before-property rule,
|
|
227
|
+
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.
|
|
228
|
+
|
|
229
|
+
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.
|
|
190
230
|
|
|
191
|
-
|
|
231
|
+
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.
|
|
192
232
|
|
|
193
|
-
|
|
194
|
-
2. Schema variables are unique within the component.
|
|
195
|
-
3. Every editable token (excluding `hidden: true`, `kind: 'gradient'`, and padding-side suffixes) is declared in the runtime `<style>` block.
|
|
196
|
-
4. Every editable token is seeded in `src/live-tokens/data/component-configs/<id>/default.json`.
|
|
197
|
-
5. `setComponentAlias` round-trips the alias through the slice.
|
|
233
|
+
**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, that the registration resolves to a real `sourceFile` and a non-empty schema, that schema variables are unique, that every editable token (excluding `hidden: true`, `kind: 'gradient'`, and padding-side suffixes) is declared in the runtime `<style>` block and seeded in `src/live-tokens/data/component-configs/<id>/default.json`, and that `setComponentAlias` round-trips the alias through the slice.
|
|
198
234
|
|
|
199
|
-
A new first-party component is auto-covered the moment it lands in `builtInRegistry` — `npm test` will fail if any of the five checks miss. For a consumer-authored component, mirror this pattern in your own test suite if you want the same drift protection
|
|
235
|
+
A new first-party component is auto-covered the moment it lands in `builtInRegistry` — `npm test` will fail if any of the five checks miss. For a consumer-authored component, mirror this pattern in your own test suite if you want the same drift protection: `getComponentRegistryEntries` is exported from `@motion-proto/live-tokens` and returns every registration, shipped and custom, once your `main.ts` has run.
|
|
200
236
|
|
|
201
237
|
**If your component declares `intrinsics`, the intrinsics contract test covers it too.** `src/editor/component-editor/intrinsicsContract.test.ts` iterates every entry with an `intrinsics` array and asserts, per (intrinsic, variant), that the runtime `:global(:root)` declares a default, the default is one of the spec's `values`, and the editor's `default` equals the runtime default. This is what would have caught a getter defaulting to `center` while `:global(:root)` says `start`. Same auto-coverage rule: declare `intrinsics` on the registry entry and the test picks it up.
|
|
202
238
|
|
|
@@ -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,133 @@
|
|
|
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. `npx live-tokens tokens --family surface` prints a family's names and
|
|
68
|
+
values (`text`, `border`, `scrim`, `tint` likewise; `--json` for data); the
|
|
69
|
+
families are fixed.
|
|
70
|
+
|
|
71
|
+
| The literal is | Token family | Notes |
|
|
72
|
+
| --- | --- | --- |
|
|
73
|
+
| Text on a surface | `--text-primary`, `-secondary`, `-tertiary`, `-muted`, `-disabled` | The neutral scale. Family colour is `--text-accent`, `--text-success`, and so on. |
|
|
74
|
+
| Light text on a dark chip over the page | `--text-inverted` | The one flip; no AA guarantee. |
|
|
75
|
+
| A box's fill | `--surface-<family>-<level>` | `neutral` for chrome; `brand`, `accent`, `special` for emphasis; `info`, `success`, `warning`, `danger` for status. |
|
|
76
|
+
| A stroke | `--border-<family>-<level>` | `faint`, `subtle`, base, `medium`, `strong` in the neutral family. |
|
|
77
|
+
| A translucent layer that dims what is behind it | `--scrim-low`, `--scrim`, `--scrim-high` | Behind a modal, under a floating control. |
|
|
78
|
+
| A translucent wash on a surface | `--tint-low`, `--tint`, `--tint-high` | Hover, an active tab, a code chip's background. |
|
|
79
|
+
| Fully transparent | `--color-transparent` | Never `transparent` inside a component default. |
|
|
80
|
+
| A gradient | `--gradient-*` | Or compose one from surface tokens. |
|
|
81
|
+
|
|
82
|
+
A `var(--x, #fff)` fallback is not a finding. A named colour is: `white` and
|
|
83
|
+
`rebeccapurple` are literals like any hex.
|
|
84
|
+
|
|
85
|
+
## Geometry by scale
|
|
86
|
+
|
|
87
|
+
`dimension-literal` fires only on the geometry the theme owns: padding,
|
|
88
|
+
margin, gap, border and outline widths, inset offsets, radius, and shadow.
|
|
89
|
+
Sizing (a hero's height, a max content width, a `minmax()` floor) is layout
|
|
90
|
+
and is never reported, so leave it.
|
|
91
|
+
|
|
92
|
+
| The literal is | Token | Notes |
|
|
93
|
+
| --- | --- | --- |
|
|
94
|
+
| Padding, margin, gap, an offset | `--space-<px>` | `npx live-tokens tokens --family space` prints the steps. Round to the nearest one and name the shift. |
|
|
95
|
+
| A stroke width | `--border-width-1`, `-2`, `-4` | Also for `outline`. |
|
|
96
|
+
| A corner | `--radius-sm` through `-4xl`, `--radius-full` | |
|
|
97
|
+
| A shadow | `--shadow-sm` through `-xl` | Replace the whole value, never one offset. |
|
|
98
|
+
| Part of a `calc()` | The token inside the calc | `calc(var(--space-64) * -2 + var(--space-8))` |
|
|
99
|
+
|
|
100
|
+
While in the file, motion values take `--duration-*` and `--ease-*` even
|
|
101
|
+
though no rule reports them, and a `blur()` takes `--blur-*`.
|
|
102
|
+
|
|
103
|
+
## Every other rule
|
|
104
|
+
|
|
105
|
+
| Rule | Fix |
|
|
106
|
+
| --- | --- |
|
|
107
|
+
| `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. |
|
|
108
|
+
| `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. |
|
|
109
|
+
| `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**. |
|
|
110
|
+
| `unknown-prop` | The component drops it at runtime. `npx live-tokens components <id>` prints the props it declares and the values each union accepts; map the prop to one of them or delete it. A `class` on a component that declares none does nothing. |
|
|
111
|
+
| `unknown-prop-value` | Pick a value from the union the message lists. |
|
|
112
|
+
| `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. |
|
|
113
|
+
| `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. |
|
|
114
|
+
| `missing-source` | Add `source: 'src/...'` to the route entry so Page Source can open it. |
|
|
115
|
+
| `reserved-route` | Move the route out of `/live-tokens/*`; the package owns that namespace. |
|
|
116
|
+
| `deep-import` | Import from `@motion-proto/live-tokens` or `/component-editor` or `/components/<Name>.svelte`, never from `/src/`. |
|
|
117
|
+
| `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**. |
|
|
118
|
+
| `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`. |
|
|
119
|
+
| `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. |
|
|
120
|
+
| `missing-registration`, `missing-file`, `missing-root-block` | The component is not wired the way the recipe in **live-tokens-create-component** wires it. |
|
|
121
|
+
|
|
122
|
+
## Report
|
|
123
|
+
|
|
124
|
+
Say what changed by rule, one line per rule with the count and any visible
|
|
125
|
+
shift. Say what was left and why, with the config entry if the user chose to
|
|
126
|
+
lower a severity. End with the two commands and their exit codes.
|
|
127
|
+
|
|
128
|
+
## Verify
|
|
129
|
+
|
|
130
|
+
Open `/live-tokens/editor` in dev and change a surface colour and a spacing
|
|
131
|
+
step. Every file the loop touched should repaint. One that does not still
|
|
132
|
+
holds a literal the checker cannot see, which is worth reporting as a gap in
|
|
133
|
+
the checker rather than patching around.
|
|
@@ -11,7 +11,15 @@ 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
|
+
|
|
16
|
+
That line is the shipped set. A project can register components of its own,
|
|
17
|
+
and those never appear in this file: run `npx live-tokens components` before
|
|
18
|
+
choosing. It lists every component the project has, shipped and custom, with
|
|
19
|
+
the variants each takes and the purpose its header comment states, so a custom
|
|
20
|
+
component is weighed against the shipped set on the same footing.
|
|
21
|
+
`npx live-tokens components <id>` prints one component's props, the values each
|
|
22
|
+
union accepts, and its tokens with defaults; `--json` returns the same as data.
|
|
15
23
|
|
|
16
24
|
## Action family: Button vs IconButton
|
|
17
25
|
|
|
@@ -42,6 +50,7 @@ All four pick one option from a set. The right one depends on **option count**,
|
|
|
42
50
|
|
|
43
51
|
- `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
52
|
- 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`.
|
|
53
|
+
- `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
54
|
- **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
55
|
- 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
56
|
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,241 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.70.0 — The registry is a query
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **The registry is a query.** `npx live-tokens components` lists every
|
|
8
|
+
component a project has, shipped and its own, with the variants and props
|
|
9
|
+
read from each `interface Props` and the purpose its header comment states;
|
|
10
|
+
`components <id>` prints one component's props, unions, tokens, and
|
|
11
|
+
defaults. `npx live-tokens tokens` lists every theme token the project's
|
|
12
|
+
`tokens.css` declares by family with its value, `--family <name>` for one
|
|
13
|
+
scale. Both take `--json`. A project's components in a directory other than
|
|
14
|
+
`src/system/components` are found through `"componentDirs"` in
|
|
15
|
+
`live-tokens.config.json`. The same vocabulary the checkers read answers the
|
|
16
|
+
query, so a skill sees exactly what the checkers will hold it to.
|
|
17
|
+
|
|
18
|
+
- **`getComponentRegistryEntries` is exported from the package**, so a
|
|
19
|
+
project's own test suite can run the registry contract over every
|
|
20
|
+
registration, shipped and custom. The create-component skill pointed at it
|
|
21
|
+
before it was public.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- **The skills read the registry instead of carrying it.** The picker's
|
|
26
|
+
catalogue line is the shipped set only; a project's own component is found
|
|
27
|
+
by `live-tokens components`, weighed by the description its header comment
|
|
28
|
+
states, and never written into a skill file, so `setup-claude --force` no
|
|
29
|
+
longer loses anything. build-page and fix-findings read a component's props
|
|
30
|
+
from the same query, and fix-findings reads a token scale from `tokens`.
|
|
31
|
+
|
|
32
|
+
## 0.69.0 — Every value reads a token, and the build says so
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- **SideNavigation's panel widths read the spacing scale.** `16rem` and `3rem`
|
|
37
|
+
were the only shipped defaults with no token behind them; both now derive
|
|
38
|
+
from the largest step, `calc(var(--space-64) * 4)` and
|
|
39
|
+
`calc(var(--space-64) * 0.75)`. Values are unchanged.
|
|
40
|
+
|
|
41
|
+
- **The starter `site.css` is fully tokenized.** A paragraph margin and three
|
|
42
|
+
rule and blockquote strokes were px literals; they read `--space-16` and
|
|
43
|
+
`--border-width-*` now, so a scaffolded project starts clean under
|
|
44
|
+
`check-page --strict`. The paragraph margin moves from 14px to 16px.
|
|
45
|
+
|
|
46
|
+
- **TabBar's active tab and Button's inline-code badge are tints, not scrims.**
|
|
47
|
+
Both washed a surface rather than dimming what sat behind it, and only read a
|
|
48
|
+
scrim because no tint family existed. **They restyle**: a 38% near-black wash
|
|
49
|
+
becomes a 10% white one, so each reads lighter and softer. A theme that pointed
|
|
50
|
+
the TabBar alias somewhere else keeps its choice.
|
|
51
|
+
|
|
52
|
+
- **Optional-interaction gates take `-enabled`, not a state word.**
|
|
53
|
+
`--card-hover-border-active`, `--card-hover-shadow-active`,
|
|
54
|
+
`--image-zoom-hover`, and `--image-grow-hover` read as state-after-property and
|
|
55
|
+
failed `check-component`, which meant the documented gate pattern was one a
|
|
56
|
+
consumer could not use. A gate is not a state: it says whether the interaction
|
|
57
|
+
is on at all. Values are unchanged.
|
|
58
|
+
|
|
59
|
+
- **Button's shimmer and ImageLightbox's tile fit are declared intrinsics.**
|
|
60
|
+
Both were bare keywords with no theme token and no declaration, which is the
|
|
61
|
+
thing `intrinsics` exists to record. `--button-shimmer` now defaults to
|
|
62
|
+
`var(--shimmer-on)`, the token that was already there for it.
|
|
63
|
+
|
|
64
|
+
- **`--hover-*` is now `--tint-*`, and it has a baseline for the first time.** A
|
|
65
|
+
state is a segment of a property name (`--button-outline-hover-surface`), not
|
|
66
|
+
a token of its own, so the three stops are named for what they are: a tint
|
|
67
|
+
shades the surface it sits on. Values are unchanged.
|
|
68
|
+
|
|
69
|
+
The theme engine had always emitted these stops, but `tokens.css` never
|
|
70
|
+
declared them, so they resolved to nothing until a theme was adopted. That is
|
|
71
|
+
why `var(--hover)` painted no pressed state on a fresh install. `--tint-*` is
|
|
72
|
+
baselined, and that half of the migration is additive, so it auto-applies.
|
|
73
|
+
|
|
74
|
+
- **`--overlay-*` is now `--scrim-*`.** A scrim is a translucent layer that dims
|
|
75
|
+
what sits behind it, which is what a dialog draws over the page. The old name
|
|
76
|
+
had spread to cover surface tints as well, which are the opposite operation,
|
|
77
|
+
and it collided with `backdrop`, the exported concept for what paints behind
|
|
78
|
+
an element and which way it leans. Each name now means one thing. Values are
|
|
79
|
+
unchanged, so nothing repaints.
|
|
80
|
+
|
|
81
|
+
`npx live-tokens migrate` renames the three tokens in a vendored `tokens.css`.
|
|
82
|
+
Token names are public API, so the migration is breaking and never
|
|
83
|
+
auto-applies. Saved themes and component configs migrate on load.
|
|
84
|
+
|
|
85
|
+
Dialog's part follows its token: `--dialog-overlay-surface` is
|
|
86
|
+
`--dialog-scrim-surface`, and the editor labels it "scrim color" rather than
|
|
87
|
+
the "backdrop color" that named a third thing again. The editor's Overlays
|
|
88
|
+
section is now Washes, holding Scrims and Tints.
|
|
89
|
+
|
|
90
|
+
### Added
|
|
91
|
+
|
|
92
|
+
- **The shipped catalogue is now the component contract's fixture.**
|
|
93
|
+
`check-component` reported 109 errors across all 26 shipped components, and
|
|
94
|
+
none of them were defects in the components: the checker's suffix list had
|
|
95
|
+
simply drifted narrower than the catalogue it governs, rejecting `-accent`,
|
|
96
|
+
`-title`, `-margin`, `-easing` and a dozen more names our own components use.
|
|
97
|
+
A test now runs the full contract over every registered component and requires
|
|
98
|
+
zero errors, so the rule and the components can never disagree again.
|
|
99
|
+
|
|
100
|
+
The suffix vocabulary moved to `KIND_RULES` in the editor's `aliasKinds.ts`.
|
|
101
|
+
The picker, the `adjust` CLI, `check-component`, and `check:skills` all read
|
|
102
|
+
that one table, so a name the checker accepts always has a control behind it.
|
|
103
|
+
|
|
104
|
+
Three rules got more accurate along the way. A token the editor declares in
|
|
105
|
+
`intrinsics` is exempt from the suffix check, because a structural keyword is
|
|
106
|
+
not a themeable value. Membership in the package's own `builtInRegistry`
|
|
107
|
+
counts as registration. And a component may prefix its tokens with the
|
|
108
|
+
hyphenated form of its id, which is what CornerBadge has always done.
|
|
109
|
+
|
|
110
|
+
- **An optional hover tint on Button, IconButton, TabBar, SegmentedControl,
|
|
111
|
+
MenuSelect, and SideNavigation.** One stop for the whole component rather than
|
|
112
|
+
one hover surface per variant: Button and IconButton carried 36 hover tokens
|
|
113
|
+
each, and every one was tuned by hand. `--<id>-hover-tint` aliases a `--tint-*`
|
|
114
|
+
stop, and `--<id>-hover-tint-enabled` gates it.
|
|
115
|
+
|
|
116
|
+
Off by default, so nothing changes until a project turns it on. The tint rides
|
|
117
|
+
as a `background-image` over the hover rule's own `background-color`, so it
|
|
118
|
+
needs no pseudo-element.
|
|
119
|
+
|
|
120
|
+
A **tint layer** switch in the component editor's hover state turns it on and
|
|
121
|
+
points every hover surface at its own base surface, so hover is the tint alone
|
|
122
|
+
rather than a swap wearing a wash. The hover-surface rows grey out while it is
|
|
123
|
+
on, since they no longer change anything. Switching it off clears those
|
|
124
|
+
overrides, returning each surface to its shipped default.
|
|
125
|
+
|
|
126
|
+
Switching it on reveals a **tint color** row beside it. It starts on `--tint`,
|
|
127
|
+
the theme's middle tint stop, and takes any colour token with an alpha, like
|
|
128
|
+
every other colour row. A `-tint` suffix now resolves to the surface picker
|
|
129
|
+
rather than falling through, so the row offers the whole palette, not only the
|
|
130
|
+
tint stops.
|
|
131
|
+
|
|
132
|
+
Per instance, the `hoverTint` prop overrides the global default (`undefined`
|
|
133
|
+
inherits, `true` and `false` force).
|
|
134
|
+
|
|
135
|
+
- **`live-tokens check-page` validates a page against the build-page
|
|
136
|
+
contract.** It fails on a component outside the catalogue, a deep import into
|
|
137
|
+
package internals, a `var()` naming a token that does not exist, a colour
|
|
138
|
+
literal, a route under the reserved `/live-tokens/*` namespace, and `site.css`
|
|
139
|
+
imported from `main.ts`, a prop a shipped component does not declare, and a
|
|
140
|
+
variant or size outside that prop's union. It warns on a px or rem literal
|
|
141
|
+
in spacing, stroke, radius, or shadow, a hardcoded page-grid count of four
|
|
142
|
+
columns or more, an absolute type value (the `font` shorthand included), and
|
|
143
|
+
a route entry with no `source`. Sizing is layout and is never reported.
|
|
144
|
+
Inline `style=` attributes and `style:` directives are read under the same
|
|
145
|
+
rules as the `<style>` block, and a named colour is a literal like any hex.
|
|
146
|
+
Given no paths it checks every page under `src/`.
|
|
147
|
+
|
|
148
|
+
- **Both check commands take `--json`, `--strict`, and per-rule severity
|
|
149
|
+
flags.** `--json` prints findings with a stable `rule` id and line number, so
|
|
150
|
+
a skill can fix one rule at a time and re-run until the exit code is 0.
|
|
151
|
+
`--strict` promotes warnings to errors. `--off=<rule>`, `--warn=<rule>`, and
|
|
152
|
+
`--error=<rule>` change a rule for one run; `"checks": { "rules": { ... } }`
|
|
153
|
+
in `live-tokens.config.json` sets it for the project.
|
|
154
|
+
|
|
155
|
+
- **`check-component` now checks what a default *resolves to*, not just what it
|
|
156
|
+
is named.** A component token names a semantic property and its default is the
|
|
157
|
+
theme token that property reads, which is what makes the component repaint
|
|
158
|
+
when the theme changes. A default reading a token that does not exist is now
|
|
159
|
+
an error, including a `var()` naming a state word rather than the token that
|
|
160
|
+
state should paint. A default with no token behind it is an error unless the
|
|
161
|
+
editor declares it in `intrinsics`; a colour literal in any notation is an
|
|
162
|
+
error; a token-backed default that still carries a px or rem term warns.
|
|
163
|
+
Two more rules read the name alone: `disabled-is-terminal` rejects a token
|
|
164
|
+
that combines `disabled` with `hover`, `focus`, `selected`, `on`, `active`,
|
|
165
|
+
or `checked`, and `phantom-editor-token` rejects an editor row naming a
|
|
166
|
+
token the runtime never declares. Given no id, `check-component` checks
|
|
167
|
+
every component authored under `src/system/components`, and a scaffolded
|
|
168
|
+
project runs both checkers as `npm run check:design` before every
|
|
169
|
+
`vite build`. `check-component` also finds a shipped component's editor
|
|
170
|
+
beside the other editors, not only next to its runtime.
|
|
171
|
+
|
|
172
|
+
- **`npm run check:pages` runs the page check over this repo under `--strict`
|
|
173
|
+
and is part of `prepublishOnly`.** The unit suite covers the same ground:
|
|
174
|
+
the repo's pages carry no finding at all, and every shipped component
|
|
175
|
+
default resolves to a real token. Both suites also hold a mutation table: a
|
|
176
|
+
clean component and a clean page that pass `--strict`, and one smallest
|
|
177
|
+
break per rule that must fail, so a rule cannot stop firing unnoticed.
|
|
178
|
+
|
|
179
|
+
- **`Slider`, in two variants.** `single` moves one thumb to a value; `range`
|
|
180
|
+
moves two thumbs to a low and a high bound on one track. Both share track,
|
|
181
|
+
fill, and thumb tokens, linked in the editor so an edit to one moves the
|
|
182
|
+
other until deliberately unlinked, with hover and disabled states and a
|
|
183
|
+
label and value readout. It was authored by following
|
|
184
|
+
`live-tokens-create-component` end to end, and `check-component --strict`
|
|
185
|
+
was clean on the first run.
|
|
186
|
+
|
|
187
|
+
- **`live-tokens-fix-findings`, the seventh skill.** The loop for code that
|
|
188
|
+
already exists: run both checkers with `--json`, take the largest group of
|
|
189
|
+
errors first, apply that rule's recipe, re-run, stop at exit 0. It carries
|
|
190
|
+
one recipe per rule id, with colour mapped by role rather than hue and
|
|
191
|
+
geometry by scale, and three refusals: never silence a rule to pass, never
|
|
192
|
+
mint a token, never shift the look without saying so. Its first run, on the
|
|
193
|
+
package's own demo site, took three rounds and ended clean.
|
|
194
|
+
|
|
195
|
+
### Fixed
|
|
196
|
+
|
|
197
|
+
- **The tint layer switch was unreachable in four editors.** SegmentedControl,
|
|
198
|
+
TabBar, MenuSelect, and SideNavigation gated the row on a state named
|
|
199
|
+
`hover`, and their hover states are `hover option`, `hover tab`,
|
|
200
|
+
`hover item`, and `<Part> / Hover`, so the switch and the tint colour row
|
|
201
|
+
never rendered. Each condition now names the state the editor has. The
|
|
202
|
+
render contract caught it once it learned to turn a gate on: a gate row
|
|
203
|
+
carries `data-token-variables` and the harness flips a `role="switch"`
|
|
204
|
+
Toggle the way it clicks a checkbox, then exercises the row the gate
|
|
205
|
+
revealed. A selector whose selections are locked carries a `locked` class,
|
|
206
|
+
which the harness skips instead of retrying a chip it can never click.
|
|
207
|
+
|
|
208
|
+
- **`check-page` no longer reports a `var()` fallback as a colour literal.**
|
|
209
|
+
`var(--surface-neutral, #111)` paints the token; the literal only renders
|
|
210
|
+
when the token is missing. Against the package's own demo site this was 33
|
|
211
|
+
of 39 errors.
|
|
212
|
+
|
|
213
|
+
- **`check-page` reads a custom property with a digit in its name as one
|
|
214
|
+
declaration.** `--heading-2xl: 1.875rem` was parsed as the property `xl`
|
|
215
|
+
and reported as a raw dimension. The project's own `tokens.css` and the
|
|
216
|
+
generated token files are also no longer discovered as pages.
|
|
217
|
+
|
|
218
|
+
- **Both checkers read a `:global(:root)` block the same way.** They had two
|
|
219
|
+
extractors, one of which stopped at the first `}`, so a nested at-rule or
|
|
220
|
+
SCSS block truncated the block. One brace-balanced extractor is shared.
|
|
221
|
+
|
|
222
|
+
- **An `intrinsics` array on one line still exempts its token.** The
|
|
223
|
+
exemption required the closing `];` on its own line.
|
|
224
|
+
|
|
225
|
+
- **A persisted editor session from before the rename no longer breaks the
|
|
226
|
+
renderer.** `hydrate` shallow-merges persisted state, so a `washes` (or
|
|
227
|
+
`overlays`) slice saved by an older build replaced the current one wholesale
|
|
228
|
+
and arrived without its tint stops, throwing `w.tints is not iterable` out of
|
|
229
|
+
the render path on load. Hydration now reshapes the slice: it carries the
|
|
230
|
+
saved stops across under their new names and falls back to the shipped
|
|
231
|
+
defaults for anything unusable.
|
|
232
|
+
|
|
233
|
+
- **The outline Button and IconButton pressed state had no colour.** Both read
|
|
234
|
+
`var(--hover)`, which names nothing: a state is a segment of a semantic
|
|
235
|
+
property name (`--button-outline-hover-surface`), never a token of its own.
|
|
236
|
+
They read `--surface-neutral-low` now, one step along the scale from their
|
|
237
|
+
hover surface. `check-component` catches this class of mistake by name.
|
|
238
|
+
|
|
3
239
|
## 0.68.1 — A look is a Theme, or it's a sketch style
|
|
4
240
|
|
|
5
241
|
### Changed
|