@motion-proto/live-tokens 0.61.0 → 0.63.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-adjust-geometry/SKILL.md +4 -4
- package/.claude/skills/live-tokens-build-page/SKILL.md +21 -3
- package/.claude/skills/live-tokens-create-component/SKILL.md +16 -48
- package/.claude/skills/live-tokens-create-component/references/fixed-overlays.md +10 -1
- package/.claude/skills/live-tokens-create-component/references/intrinsics.md +7 -5
- package/.claude/skills/live-tokens-create-component/references/sketch-mode.md +1 -1
- package/.claude/skills/live-tokens-create-component/references/token-naming.md +50 -0
- package/.claude/skills/live-tokens-generate-theme/SKILL.md +16 -9
- package/.claude/skills/live-tokens-pair-fonts/SKILL.md +8 -6
- package/.claude/skills/live-tokens-pick-component/SKILL.md +19 -5
- package/CHANGELOG.md +114 -0
- package/bin/migrate.mjs +6 -2
- package/dist-plugin/adjust/index.cjs +1 -1
- package/dist-plugin/adjust/index.d.cts +1 -1
- package/dist-plugin/adjust/index.d.ts +1 -1
- package/dist-plugin/adjust/index.js +1 -1
- package/dist-plugin/{chunk-232GZGQU.js → chunk-NDJJORKJ.js} +342 -5
- package/dist-plugin/{chunk-Y5CNFSSV.js → chunk-RVE3MNKM.js} +1 -1
- package/dist-plugin/{chunk-OIOXU7FR.js → chunk-ZHPX7ZYQ.js} +83 -25
- package/dist-plugin/{dataPaths-CRfD1LdA.d.ts → dataPaths-DZUzVv8H.d.cts} +3 -3
- package/dist-plugin/{dataPaths-CRfD1LdA.d.cts → dataPaths-DZUzVv8H.d.ts} +3 -3
- package/dist-plugin/fontPairing/index.cjs +1 -1
- package/dist-plugin/fontPairing/index.d.cts +1 -1
- package/dist-plugin/fontPairing/index.d.ts +1 -1
- package/dist-plugin/fontPairing/index.js +1 -1
- package/dist-plugin/generateColorsAndType/index.cjs +1 -1
- package/dist-plugin/generateColorsAndType/index.d.cts +1 -1
- package/dist-plugin/generateColorsAndType/index.d.ts +1 -1
- package/dist-plugin/generateColorsAndType/index.js +1 -1
- package/dist-plugin/index.cjs +461 -58
- package/dist-plugin/index.d.cts +1 -1
- package/dist-plugin/index.d.ts +1 -1
- package/dist-plugin/index.js +31 -23
- package/dist-plugin/migrateData/index.cjs +350 -9
- package/dist-plugin/migrateData/index.d.cts +1 -1
- package/dist-plugin/migrateData/index.d.ts +1 -1
- package/dist-plugin/migrateData/index.js +9 -5
- package/dist-plugin/tokensCssMigrations/index.cjs +83 -25
- package/dist-plugin/tokensCssMigrations/index.d.cts +1 -1
- package/dist-plugin/tokensCssMigrations/index.d.ts +1 -1
- package/dist-plugin/tokensCssMigrations/index.js +2 -2
- package/package.json +4 -2
- package/src/app/site.css +32 -0
- package/src/editor/component-editor/CardEditor.svelte +7 -1
- package/src/editor/component-editor/scaffolding/VariantGroup.svelte +25 -2
- package/src/editor/core/preview/lookPreview.ts +46 -5
- package/src/editor/core/productionPulse.ts +6 -2
- package/src/editor/core/sketch/maskField.ts +75 -39
- package/src/editor/core/sketch/sketchLayer.ts +32 -11
- package/src/editor/core/sketch/sketchStore.ts +311 -86
- package/src/editor/core/sketch/{sketchPresetService.ts → sketchStyleService.ts} +14 -14
- package/src/editor/core/sketch/{sketchPresets.ts → sketchStyles.ts} +27 -28
- package/src/editor/core/themes/themeDocumentSync.ts +2 -0
- package/src/editor/core/themes/themeInit.ts +19 -1
- package/src/editor/core/themes/themeService.ts +7 -2
- package/src/editor/core/themes/themeTypes.ts +5 -0
- package/src/editor/docs/content/editing-tokens.md +1 -1
- package/src/editor/docs/content/sketch-mode.md +34 -18
- package/src/editor/docs/content/themes-workflow.md +30 -21
- package/src/editor/docs/content/where-themes-live.md +9 -5
- package/src/editor/docs/content.generated.ts +4 -4
- package/src/editor/overlay/LiveTokensRouter.svelte +8 -0
- package/src/editor/ui/EditorViewSwitcher.svelte +3 -3
- package/src/editor/ui/ThemePanel.svelte +47 -1
- package/src/editor/ui/sections/textStyles.ts +29 -1
- package/src/editor/ui/sketch/SketchPreview.svelte +3 -3
- package/src/editor/ui/sketch/SketchTab.svelte +120 -134
- package/src/live-tokens/data/colors-and-type/midnight-study.json +40 -30
- package/src/live-tokens/data/themes/autumn.json +3 -3
- package/src/live-tokens/data/themes/halloween.json +3 -3
- package/src/live-tokens/data/themes/midnight-study.json +61 -49
- package/src/live-tokens/data/themes/ocean.json +3 -3
- package/src/live-tokens/data/themes/royal-velvet.json +3 -3
- package/src/live-tokens/data/themes/sketchy.json +3 -3
- package/src/live-tokens/data/themes/spring-meadow.json +3 -3
- package/src/live-tokens/data/themes/sunset.json +3 -3
- package/src/system/components/Card.svelte +27 -9
- package/src/system/components/FloatingTokenTags.css +10 -8
- package/src/system/components/ImageLightbox.svelte +5 -2
- package/src/system/components/SectionDivider.svelte +3 -3
- package/src/system/components/SegmentedControl.svelte +11 -9
- package/src/system/styles/tokens.css +28 -5
- package/template/src/pages/Home.svelte +1 -11
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: live-tokens-adjust-geometry
|
|
3
|
-
description: Adjust corner radius, padding, gap, and border width across live-tokens components by moving each token alias along the shipped scales. Use when the user asks for pill or capsule buttons
|
|
3
|
+
description: Adjust corner radius, padding, gap, and border width across live-tokens components by moving each token alias along the shipped scales. Use when the user asks for pill or capsule buttons; rounded, rounder, sharp, sharper, square, softer, or harder corners; thicker or thinner borders; or density — space it out, tighter, denser, more compact, airier, more breathing room. Also invoked by live-tokens-generate-theme for the geometry half of a whole look. Changes shape and space aliases per component, never color, fonts, or tokens.css. Not for editing a single token (use the editor) or for color (see live-tokens-generate-theme).
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Adjusting geometry
|
|
@@ -12,7 +12,7 @@ You translate the request into a small ops file; the CLI resolves each matching
|
|
|
12
12
|
1. Write the ops file to `scratch/adjust-ops.json`.
|
|
13
13
|
2. Run `npx live-tokens adjust scratch/adjust-ops.json`. It writes `component-configs/<id>/_working.json` for every component the ops change, which is the buffer the page already runs. `--dry-run` prints the report without writing.
|
|
14
14
|
3. Read the report card: every changed alias old → new, plus skips (raw value, off the ladder, already at the ladder end, pill preserved). Exit 1 means the run was rejected; the message names the offending op or the missing input, so fix it and re-run. Read where the controls landed, not only that the run succeeded: a button, badge, input, or tab padding sitting at `--space-6` is on its floor, and one that also carries `--radius-full` wants a targeted lift.
|
|
15
|
-
4. Tell the user to reload the
|
|
15
|
+
4. Tell the user to reload the page before saving. The editor keeps the look in the browser and writes the buffers from that copy, so a Save in a tab that was open during the run puts the pre-run shape back and the report you just showed them becomes a lie. After the reload, offer the inverse op as the undo and say the edit is unsaved until they save the open theme.
|
|
16
16
|
|
|
17
17
|
Each run reads the LIVE config (buffer, else the open theme, else the shipped default), so "a bit more" and "back one" compound naturally.
|
|
18
18
|
|
|
@@ -31,7 +31,7 @@ Targeted, absolute:
|
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
- `name`: ignored. Buffers are fixed slots, so a name names no file, and the CLI says it dropped one. Leave it out.
|
|
34
|
-
- `target` (optional): a component id (the folder names under `src/live-tokens/data/component-configs
|
|
34
|
+
- `target` (optional): a component id (the folder names under `src/live-tokens/data/component-configs/`, which the Catalogue in **live-tokens-pick-component** also names in full). A named component targets its id: "windows" or "modals" is `dialog`, "cards" is `card`, "tabs" is `tabbar`; an unknown target is a hard error. "The UI", "everything", or no noun at all means global, so omit it.
|
|
35
35
|
- `kind`: `radius | padding | gap | border-width`.
|
|
36
36
|
- `set` or `shift`, exactly one of the two. `set` takes an existing token on that kind's ladder. `shift` is a whole number of steps, clamped at the ladder ends.
|
|
37
37
|
- `full` (radius shifts only): admits `--radius-full` as the ladder's top rung. `set` plus `full` is an error, so a pill request is `set: "--radius-full"` with no `full` flag.
|
|
@@ -56,7 +56,7 @@ Magnitude words: "slightly" or "a bit" is 1 step, unqualified is 1 to 2, "much",
|
|
|
56
56
|
|
|
57
57
|
A global op spends the same number of steps everywhere, but a step costs a control far more than a container. `padding shift: -2` takes a card from a 16px inset to 10px and it is still a card. It takes a button from 8 to 4, doubled to 8px at each end, around an 18px line. The button stops reading as a button.
|
|
58
58
|
|
|
59
|
-
So a global compaction is `shift: -1`. When the brief wants more, spend the extra steps on the containers by name (`card`, `dialog`, `panel`, `sidenavigation`, `table`, `codesnippet`) and leave the controls alone. Loosening is not symmetric: airier is safe globally, because nothing breaks by growing.
|
|
59
|
+
So a global compaction is `shift: -1`. When the brief wants more, spend the extra steps on the containers by name (`card`, `dialog`, `panel`, `collapsiblesection`, `sidenavigation`, `table`, `codesnippet`) and leave the controls alone. Loosening is not symmetric: airier is safe globally, because nothing breaks by growing.
|
|
60
60
|
|
|
61
61
|
A pill needs the room most. `--radius-full` bends the corner in over the first and last glyph, so a capsule wants more horizontal inset than a square-cornered control, never less. `--space-8` is the floor for a large-text pill, which is where compact Midnight Study sits; the roomier pill presets (Ocean, Sunset, Royal Velvet) run `--space-10` to `--space-12`. Pair the radius op with a padding `set` on the same target, placed after any global compaction so it wins outright:
|
|
62
62
|
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: live-tokens-build-page
|
|
3
|
-
description: Apply the @motion-proto/live-tokens project conventions when building a page:
|
|
3
|
+
description: Apply the @motion-proto/live-tokens project conventions when building a page: shipped components, theme tokens over hex/pixel literals, dynamic route mounting, per-page site.css. Use when the user asks to build, create, or lay out a page, route, hero, landing page, dashboard, settings screen, or pricing page; add a route; place an existing component on a page; or assemble a screen from the catalogue. For component choice see live-tokens-pick-component; for a brand-new component, live-tokens-create-component; for look and feel mid-build, live-tokens-generate-theme or live-tokens-adjust-geometry.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Building pages in a live-tokens project
|
|
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
|
|
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
11
|
2. **Use theme tokens for every value.** Every color, spacing, radius, font-size, and font-family in page CSS is a `var(--token-*)`. No hex literals. No pixel literals. A change in `/live-tokens/editor` should repaint your page.
|
|
12
12
|
|
|
13
|
-
For text, reach for a whole text style rather than assembling one: `--heading-xl` through `--heading-sm`, `--body-md`, `--body-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.
|
|
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
|
+
|
|
15
|
+
Text inside a `Card` or a `CollapsibleSection` is typed by that container, not by the page: the slot pins the axes the container owns onto nested `p`, `ul`, `ol`, and `li`, so a consumer's global element rules cannot break a card's body. Pass `prose={false}` when the page should own the type instead, which is also what full-bleed media wants.
|
|
14
16
|
|
|
15
17
|
## Layout
|
|
16
18
|
|
|
@@ -26,6 +28,21 @@ To place children at specific page-column positions, span the parent grid (`grid
|
|
|
26
28
|
Either way use `lazy`, not a static top-level import: static imports evaluate every page module at boot and leak page CSS into the editor routes.
|
|
27
29
|
- Import `site.css` from each page's `<script>` block, never from `main.ts` (would leak into editor routes).
|
|
28
30
|
|
|
31
|
+
The entry shape, for a project whose `App.svelte` has moved on from the template:
|
|
32
|
+
|
|
33
|
+
```svelte
|
|
34
|
+
const pages = {
|
|
35
|
+
'/pricing': {
|
|
36
|
+
lazy: () => import('./pages/Pricing.svelte'),
|
|
37
|
+
source: 'src/pages/Pricing.svelte',
|
|
38
|
+
label: 'Pricing',
|
|
39
|
+
icon: 'fa-tag',
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`source` is what makes Page Source work; drop `label` to keep a route reachable by URL but off the nav rail.
|
|
45
|
+
|
|
29
46
|
## Avoid
|
|
30
47
|
|
|
31
48
|
- Hex or pixel literals in page CSS.
|
|
@@ -33,6 +50,7 @@ To place children at specific page-column positions, span the parent grid (`grid
|
|
|
33
50
|
- Utility classes overriding shipped components. Extend via the `/live-tokens/components` editor instead.
|
|
34
51
|
- Deep imports from `node_modules/@motion-proto/live-tokens/src/...`. Use public entry points only.
|
|
35
52
|
- Mounting `Editor` or `ComponentEditorPage` outside their dedicated routes.
|
|
53
|
+
- A page route under `/live-tokens/*`. That namespace is reserved for the package's own dev surfaces so they can never shadow your routes; the rest of the URL space is yours.
|
|
36
54
|
|
|
37
55
|
## Verify
|
|
38
56
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: live-tokens-create-component
|
|
3
|
-
description: Author a brand-new editable component for a @motion-proto/live-tokens project when nothing in the shipped catalogue fits
|
|
3
|
+
description: Author a brand-new editable component for a @motion-proto/live-tokens project when nothing in the shipped catalogue fits — runtime and editor Svelte files, registration, naming, state model, and verification. Use when the user asks to author, create, or build a new tokenized component; make an existing Svelte component editable in the live-tokens editor; add a component to the catalogue; register a custom component with the editor; or build a [Thing] component that does not exist in the shipped set. Not for placing an existing shipped component on a page (see live-tokens-build-page); read live-tokens-pick-component first to confirm nothing in the catalogue fits.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Authoring a component for a live-tokens project
|
|
@@ -43,80 +43,48 @@ For pattern reference, read any shipped component's source directly from the con
|
|
|
43
43
|
});
|
|
44
44
|
```
|
|
45
45
|
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. **Tell the picker** — open `.claude/skills/live-tokens-pick-component/SKILL.md` and add your new component to the **Catalogue** line under the family it belongs to (Action / Input / Selection / Containers / Messaging / Display). If it's confusable with an existing component (a second selection control, a competing container), add a row to that family's decision table explaining the use-case it owns. Without this step, the component exists but
|
|
46
|
+
4. **Tell the picker** — open `.claude/skills/live-tokens-pick-component/SKILL.md` and add your new component to the **Catalogue** line under the family it belongs to (Action / Input / Selection / Containers / Messaging / Display). If it's confusable with an existing component (a second selection control, a competing container), add a row to that family's decision table explaining the use-case it owns. Without this step, the component exists but **live-tokens-pick-component** can't recommend it when a user asks "which component should I use?" — the same rule applies whether the component is first-party (update the picker shipped in this package) or consumer-authored (update the local copy at `.claude/skills/live-tokens-pick-component/SKILL.md` that `setup-claude` placed in your project).
|
|
47
47
|
5. **Join the sketch layer** — the effect draws a fixed set of parts, so a new
|
|
48
48
|
component stays crisp while the page around it goes hand-drawn until it opts
|
|
49
49
|
in. A consumer component carries one of four reserved classes on its root and
|
|
50
|
-
names the five `--sketch-*`
|
|
50
|
+
names the five `--sketch-*` values it is drawn with; a first-party component
|
|
51
51
|
adds a `PartSpec` row instead. The layer also takes `background`,
|
|
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. **Verify** with the checklist at the bottom of this file
|
|
55
|
+
6. **Verify** with the checklist at the bottom of this file, then place the component on a page with **live-tokens-build-page**.
|
|
56
56
|
|
|
57
57
|
## Token discipline
|
|
58
58
|
|
|
59
59
|
### Naming scheme
|
|
60
60
|
|
|
61
61
|
```
|
|
62
|
-
--<componentId>-<part>[-<state>][-<element>]-<property>
|
|
62
|
+
--<componentId>-<part|variant>[-<state>][-<element>]-<property>
|
|
63
63
|
```
|
|
64
64
|
|
|
65
65
|
- `componentId` — the literal id passed to `registerComponent()`. Lowercase, no dashes, no abbreviations (`segmentedcontrol` not `sc`). The file id matches: `MyWidget.svelte` → id `mywidget`.
|
|
66
|
-
- `part` — sub-region (`bar`, `option`, `track`, `header`, `body`, `footer`, `overlay`, `value`, `label`)
|
|
66
|
+
- `part` or `variant` — the sub-region (`bar`, `option`, `track`, `header`, `body`, `footer`, `overlay`, `value`, `label`), or, on a component whose variants differ in more than one property, the variant name: `--badge-accent-surface`, `--callout-danger-border`. A component with both stacks them outer to inner, so the bar in its small size is `--segmentedcontrol-bar-small-padding`.
|
|
67
67
|
- `state` (optional) — interaction or component state (`hover`, `disabled`, `selected`, `focus`). **Always before the property.**
|
|
68
68
|
- `element` (optional) — sub-element inside the part (`dot`, `icon`, `label`, `text`).
|
|
69
69
|
- `property` — theme role or CSS property. Always last.
|
|
70
70
|
|
|
71
71
|
### Suffix vocabulary
|
|
72
72
|
|
|
73
|
-
The editor picker is chosen by
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
| `-icon` | Icon color |
|
|
83
|
-
| `-label` | Label text color |
|
|
84
|
-
| `-fill` | Inner fill (distinct from outer surface) |
|
|
85
|
-
| `-divider` | Divider / separator color |
|
|
86
|
-
| `-color` | Generic color, when none of the above name the role |
|
|
87
|
-
| `-shadow` | Box-shadow |
|
|
88
|
-
| `-opacity` | Opacity (0–1) |
|
|
89
|
-
| `-blur` | Backdrop or filter blur radius |
|
|
90
|
-
|
|
91
|
-
**Geometry**
|
|
92
|
-
|
|
93
|
-
| Suffix | Meaning |
|
|
94
|
-
|-----------------|---------------------------------------------------------------|
|
|
95
|
-
| `-radius` | Corner radius |
|
|
96
|
-
| `-border-width` | Stroke thickness (used even when CSS uses `outline:`) |
|
|
97
|
-
| `-thickness` | Alternative to `-width` when fallback siblings would collide |
|
|
98
|
-
| `-width` | Width dimension |
|
|
99
|
-
| `-size` | Square / uniform dimension |
|
|
100
|
-
| `-padding` | Internal spacing |
|
|
101
|
-
| `-gap` | Spacing between sibling elements |
|
|
102
|
-
|
|
103
|
-
**Typography**
|
|
104
|
-
|
|
105
|
-
| Suffix | Meaning |
|
|
106
|
-
|--------------------|--------------------------|
|
|
107
|
-
| `-font-family` | Font family reference |
|
|
108
|
-
| `-font-weight` | Font weight reference |
|
|
109
|
-
| `-font-size` | Font size reference |
|
|
110
|
-
| `-line-height` | Line height |
|
|
111
|
-
| `-letter-spacing` | Letter spacing |
|
|
112
|
-
|
|
113
|
-
The authoritative recognised list lives in `bin/check-component.mjs` (`KNOWN_SUFFIXES`). If you need a suffix that isn't listed, either rename to one that is, or open an issue against `@motion-proto/live-tokens` to add it. Don't invent suffixes; the editor falls back to a plain text input and your token won't get a real picker.
|
|
73
|
+
The editor picker is chosen by the token's suffix, so the suffix is the naming
|
|
74
|
+
decision that matters. Color and surface: `-surface`, `-border`, `-text`,
|
|
75
|
+
`-icon`, `-label`, `-fill`, `-divider`, `-color`, `-shadow`, `-opacity`,
|
|
76
|
+
`-blur`. Geometry: `-radius`, `-border-width`, `-thickness`, `-width`, `-size`,
|
|
77
|
+
`-padding`, `-gap`. Typography: `-font-family`, `-font-weight`, `-font-size`,
|
|
78
|
+
`-line-height`, `-letter-spacing`.
|
|
79
|
+
|
|
80
|
+
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`.
|
|
114
82
|
|
|
115
83
|
### Rules that bite
|
|
116
84
|
|
|
117
85
|
- **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.
|
|
118
86
|
- **State before property.** `--mywidget-button-hover-surface` ✓ — `--mywidget-button-surface-hover` ✗ (breaks sibling matching).
|
|
119
|
-
- **Defaults reference theme tokens, never raw
|
|
87
|
+
- **Defaults reference theme tokens, never raw colours.** `var(--surface-primary)` ✓ — `#6a4ce8` ✗, and `check-component` fails the build on one. Composing a token counts and is common: `color-mix(in srgb, var(--surface-neutral-lower) 70%, transparent)`. A property with no theme token behind it takes a bare keyword (`contain`, `start`, `none`). Dimensions are the gap: a raw `16rem` passes the check, so reach for a token anyway unless the component genuinely owns that measurement.
|
|
120
88
|
- **No abbreviations.** `bg` → `surface`; `fg` → `text`; component ids are never abbreviated.
|
|
121
89
|
- **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`.
|
|
122
90
|
- **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.
|
|
@@ -1,3 +1,12 @@
|
|
|
1
1
|
# Fixed overlays must portal to body
|
|
2
2
|
|
|
3
|
-
Any `position: fixed` layer (modal, lightbox, full-screen backdrop) is trapped
|
|
3
|
+
Any `position: fixed` layer (modal, lightbox, full-screen backdrop) is trapped, clipped or painted under other chrome, by a transformed / `isolation` / `contain` / `will-change` ancestor. Real consumer pages and the editor's own preview pane both have one, so this is the normal case rather than the edge.
|
|
4
|
+
|
|
5
|
+
Render the layer with `use:portal` from `src/system/internal/portal.ts` so it escapes to `<body>`. `use:portal={enabled}` keeps an in-flow preview variant where it is; `Dialog` is the worked example. `check:overlay-portal` fails the build when a component sets `position: fixed` without it. Anchored popovers are exempt: `Tooltip` is `position: absolute` against its trigger and belongs in the flow.
|
|
6
|
+
|
|
7
|
+
Moving to `<body>` costs two things:
|
|
8
|
+
|
|
9
|
+
- DOM events from the layer no longer bubble to a consumer ancestor, so pass component callbacks the way `Dialog` does.
|
|
10
|
+
- A subtree-scoped CSS-variable theme no longer reaches it. This library themes via `:root`, so nothing breaks here.
|
|
11
|
+
|
|
12
|
+
A modal also needs `role="dialog"` with `aria-modal`, focus moved in on open and restored on close, and `Tab` trapped inside. `ImageLightbox` is the worked example.
|
|
@@ -45,13 +45,15 @@ Declare intrinsics so the editor and the contract test stay honest:
|
|
|
45
45
|
|
|
46
46
|
Writes go through `setComponentAlias(component, spec.variable(v), { kind: 'literal', value })` so the choice cascades to `:root` like any token.
|
|
47
47
|
|
|
48
|
-
4. **
|
|
48
|
+
4. **Put `intrinsics` on the registry entry** so the contract test can see it. That is the same entry the recipe passes to `bootLiveTokens`, with one more field:
|
|
49
49
|
|
|
50
50
|
```ts
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
bootLiveTokens(App, '#app', {
|
|
52
|
+
components: [{
|
|
53
|
+
id: 'mywidget',
|
|
54
|
+
// ...label, icon, sourceFile, editorComponent, schema...
|
|
55
|
+
intrinsics: myWidgetIntrinsics,
|
|
56
|
+
}],
|
|
55
57
|
});
|
|
56
58
|
```
|
|
57
59
|
|
|
@@ -190,7 +190,7 @@ against the compiled `<style>` block.
|
|
|
190
190
|
|
|
191
191
|
## Verify
|
|
192
192
|
|
|
193
|
-
Switch Sketch mode on from the editor's **
|
|
193
|
+
Switch Sketch mode on from the editor's **Sketchstyle** view, then check the
|
|
194
194
|
component in place:
|
|
195
195
|
|
|
196
196
|
- [ ] Drawn, not crisp, in every variant.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Suffix vocabulary
|
|
2
|
+
|
|
3
|
+
The editor picker is chosen by suffix. There is no per-token override; if a
|
|
4
|
+
token renders with the wrong picker, rename it to one of these.
|
|
5
|
+
|
|
6
|
+
`KNOWN_SUFFIXES` in `bin/check-component.mjs` is authoritative, and
|
|
7
|
+
`check-component` fails on a suffix outside it. `check:skills` holds this file
|
|
8
|
+
to that list, so the two cannot drift apart.
|
|
9
|
+
|
|
10
|
+
## Color and surface
|
|
11
|
+
|
|
12
|
+
| Suffix | Meaning |
|
|
13
|
+
|-------------|---------------------------------------------------------------|
|
|
14
|
+
| `-surface` | Fill / background color |
|
|
15
|
+
| `-border` | Border color |
|
|
16
|
+
| `-text` | Text color |
|
|
17
|
+
| `-icon` | Icon color |
|
|
18
|
+
| `-label` | Label text color |
|
|
19
|
+
| `-fill` | Inner fill (distinct from outer surface) |
|
|
20
|
+
| `-divider` | Divider / separator color |
|
|
21
|
+
| `-color` | Generic color, when none of the above name the role |
|
|
22
|
+
| `-shadow` | Box-shadow |
|
|
23
|
+
| `-opacity` | Opacity (0–1) |
|
|
24
|
+
| `-blur` | Backdrop or filter blur radius |
|
|
25
|
+
|
|
26
|
+
## Geometry
|
|
27
|
+
|
|
28
|
+
| Suffix | Meaning |
|
|
29
|
+
|-----------------|---------------------------------------------------------------|
|
|
30
|
+
| `-radius` | Corner radius |
|
|
31
|
+
| `-border-width` | Stroke thickness (used even when CSS uses `outline:`) |
|
|
32
|
+
| `-thickness` | Alternative to `-width` when fallback siblings would collide |
|
|
33
|
+
| `-width` | Width dimension |
|
|
34
|
+
| `-size` | Square / uniform dimension |
|
|
35
|
+
| `-padding` | Internal spacing |
|
|
36
|
+
| `-gap` | Spacing between sibling elements |
|
|
37
|
+
|
|
38
|
+
## Typography
|
|
39
|
+
|
|
40
|
+
| Suffix | Meaning |
|
|
41
|
+
|--------------------|--------------------------|
|
|
42
|
+
| `-font-family` | Font family reference |
|
|
43
|
+
| `-font-weight` | Font weight reference |
|
|
44
|
+
| `-font-size` | Font size reference |
|
|
45
|
+
| `-line-height` | Line height |
|
|
46
|
+
| `-letter-spacing` | Letter spacing |
|
|
47
|
+
|
|
48
|
+
A suffix you need that is not here is either a rename away from one that is, or
|
|
49
|
+
an issue against `@motion-proto/live-tokens`. Inventing one costs the token its
|
|
50
|
+
picker: the editor falls back to a plain text input.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: live-tokens-generate-theme
|
|
3
|
-
description: Generate a complete live-tokens theme
|
|
3
|
+
description: Generate a complete live-tokens theme — color, type, and geometry — from a natural-language brief, delegating the type and geometry halves to its sibling skills. Use whenever the user asks for a theme, look, vibe, brand feel, color scheme, or palette by mood, style, era, season, holiday, or hue; when they name only a color (something red-based, green and gold for St. Patrick's Day); or when they refine an existing theme (warmer, more contrast, calmer). Examples: bright and cheerful, dark and moody, brutalist, mid-century modern, Swiss and minimal, cyberpunk neon, editorial magazine, make it feel like a terminal. Not for a single token (use the editor), type alone (live-tokens-pair-fonts), or geometry alone (live-tokens-adjust-geometry).
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Generating a theme from a brief
|
|
@@ -9,16 +9,17 @@ A theme is three decisions made from one brief: color, type, and geometry. This
|
|
|
9
9
|
|
|
10
10
|
## Workflow
|
|
11
11
|
|
|
12
|
-
1. Read the brief once and name its voice in a sentence: the mood, the hue family, the scheme, and the type and geometry that mood implies. Everything below keys off that sentence.
|
|
13
|
-
2.
|
|
14
|
-
3.
|
|
15
|
-
4.
|
|
16
|
-
5. Invoke **live-tokens-
|
|
17
|
-
6.
|
|
12
|
+
1. Read the brief once and name its voice in a sentence: the mood, the hue family, the scheme, and the type and geometry that mood implies. Everything below keys off that sentence.
|
|
13
|
+
2. Read the anchor reference that matches the voice (feeling, idiom, or occasion; see Anchor references) before seeding. Each entry fixes all three decisions together and overrides the generic defaults here.
|
|
14
|
+
3. Translate the brief into a seed file using the framework below. Write it to `scratch/<slug>-brief.json`. Nothing else records the seeds, so this file is the only copy; one per slug is what makes the refinement pass below cheap.
|
|
15
|
+
4. Run `npx live-tokens generate-theme scratch/<slug>-brief.json`. It writes `themes/<slug>.json`, opens that theme, and prints a contrast report. Auto-corrections are fine. Unmet floors (exit 1) mean the seeds themselves are unworkable; each failure line names the seed to change, usually by raising its lightness or cutting its chroma. Fix the brief and re-run; the same name overwrites. Regeneration replaces that theme's whole color state, including palette edits made in the editor since the last run, so say so once when iterating.
|
|
16
|
+
5. Invoke **live-tokens-pair-fonts** with the same voice. Skip only when the user asked for colors specifically and said to leave the type alone.
|
|
17
|
+
6. Invoke **live-tokens-adjust-geometry** with the geometry the voice implies (table below). Skip when the voice implies nothing about geometry.
|
|
18
|
+
7. Tell the user to look at the running app, and that type and geometry sit in the unsaved buffer until they save the open theme. Offer refinements as edits to the same brief (see Refining a theme that exists).
|
|
18
19
|
|
|
19
20
|
Order matters only for safety, and the order above is safe: the color generator carries the live buffers forward into the new theme file, so a color re-roll after fonts and geometry keeps both.
|
|
20
21
|
|
|
21
|
-
Flags: `--dry-run` prints the report without writing; `--no-activate` writes without opening. Opening a theme never changes what the site ships. Only Adopt, in the editor, does that.
|
|
22
|
+
Flags: `--dry-run` prints the report without writing; `--no-activate` writes without opening; `--carry-from <theme>` takes the non-color content (gradients, fonts, component aliases) from a named theme rather than from the live look. Generating a set needs it: the first run becomes the live look, so a second run without it carries the first theme's fonts and geometry into the second. Opening a theme never changes what the site ships. Only Adopt, in the editor, does that.
|
|
22
23
|
|
|
23
24
|
## The brief
|
|
24
25
|
|
|
@@ -123,7 +124,7 @@ Read the matching reference before seeding, and apply the bands above on top of
|
|
|
123
124
|
- `references/style-vocabulary.md` covers named idioms, eras, and genres: Swiss, Bauhaus, mid-century, art deco, terminal, cyberpunk, vaporwave, Y2K, blueprint, Scandinavian, Japandi, cottagecore, editorial, newsprint, riso, corporate, brutalist, Memphis, industrial. Each entry fixes color, type, and geometry as one set, so hand its Type and Geometry columns to the sibling skills verbatim.
|
|
124
125
|
- `references/named-themes.md` covers holidays, seasons, and natural scenes: Christmas, Halloween, St. Patrick's, Ocean, Sunset, Autumn, Spring. A holiday or season brief is a statement brief: commitment level 2 or 3, with the named color on the ground rather than only on the buttons.
|
|
125
126
|
|
|
126
|
-
Most briefs hit the first file. A brief that names no feeling, idiom, or occasion at all takes the bands above and the geometry table below.
|
|
127
|
+
Most briefs hit the first file. A brief that matches two ("cozy brutalist", "clinical Swiss") reads the idiom first and lets the feeling move the dials inside it: an idiom sets constraints, and dials move within constraints. A brief that names no feeling, idiom, or occasion at all takes the bands above and the geometry table below.
|
|
127
128
|
|
|
128
129
|
## Geometry from the voice
|
|
129
130
|
|
|
@@ -138,6 +139,12 @@ The geometry lives in radius, padding, gap, and border width, and `live-tokens-a
|
|
|
138
139
|
|
|
139
140
|
This table is the fallback. When the brief matched an entry in the mood or style reference, take the geometry from that entry instead: it is tuned to the same reading the color came from, and a style's geometry is often targeted rather than global.
|
|
140
141
|
|
|
142
|
+
## Refining a theme that exists
|
|
143
|
+
|
|
144
|
+
"Warmer", "calmer", "more contrast" arrive against a theme that is already open, and the answer is a new brief rather than hand-edits. Edit `scratch/<slug>-brief.json` when it is still there. When it is not, recover the seeds: `src/live-tokens/data/themes/<slug>.json` holds each one verbatim at `colorsAndType.editorConfigs.<Palette>.baseColor` as `{l, c, h}`, and the Canvas seed's lightness tells you the scheme. Rebuild the brief from those ten values, move the dial the user named, re-run under the same name.
|
|
145
|
+
|
|
146
|
+
One adjective moves one dial. Warmer and cooler rotate hue; calmer and louder move chroma; lighter, darker, and moodier move Canvas L and the scheme; more contrast widens the L gap between Canvas and Brand and takes chroma out of the ground rather than adding it to the garnish. Leave every seed the user did not name alone, because a refinement that re-rolls the whole palette reads as a different theme and loses the thing they liked.
|
|
147
|
+
|
|
141
148
|
## What each step writes
|
|
142
149
|
|
|
143
150
|
Color writes `themes/<slug>.json` and opens it. Type and geometry write the unsaved buffers, which the page already runs. One Save in the editor keeps all three; Adopt ships them. Component aliases and gradients carry forward from the live look into a generated theme; user-tuned gradients survive, stock ones rebuild from the new families.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: live-tokens-pair-fonts
|
|
3
|
-
description: Choose and apply a Google Fonts pairing for a live-tokens theme
|
|
3
|
+
description: Choose and apply a Google Fonts pairing for a live-tokens theme, binding families to the shipped --font-* stacks. Use whenever the user asks to pair fonts, pick a typeface, change or set the fonts, or describes type by voice: what font should the headings use, make the type more editorial, friendlier, more technical, more elegant, a serif for headings, a display font for this theme, less generic type, match the fonts to the theme. Also invoked by live-tokens-generate-theme for the type half of a whole look. Changes type only, never color. Not for a single token (use the editor) or for color (see live-tokens-generate-theme).
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Pairing fonts for a theme
|
|
@@ -11,8 +11,8 @@ You choose the families; the CLI verifies each against Google Fonts, builds the
|
|
|
11
11
|
|
|
12
12
|
1. Choose the pairing with the framework below and write a brief to `scratch/font-brief.json`.
|
|
13
13
|
2. Run `npx live-tokens set-fonts scratch/font-brief.json`. It prints each stack that moved, each family's real weights and URL, and the weights your typography tokens ask for that the family lacks.
|
|
14
|
-
3. Read the report. A weight gap is a quality note: name it and offer an alternative only if it matters (a body face without 400 or
|
|
15
|
-
4. Tell the user to reload and
|
|
14
|
+
3. Read the report. A weight gap is a quality note: name it and offer an alternative only if it matters (a body face without 400, 700, or italic matters; a display face without 300 does not). A family not on Google Fonts fails the run; fix the spelling and re-run.
|
|
15
|
+
4. Tell the user to reload the editor page before saving. A running editor holds its own copy of the buffer this CLI just wrote and never re-reads it, so a Save without a reload writes the stale copy back and the pairing vanishes with a success report still on screen. After the reload the type is on the page, and unsaved until they save the open theme.
|
|
16
16
|
|
|
17
17
|
State your reasoning when you propose the pairing: each face's form model and the matrix verdict, in one sentence, so the user can argue with the argument rather than only the result.
|
|
18
18
|
|
|
@@ -24,12 +24,14 @@ Flags: `--dry-run` reports without writing. `--no-verify` skips the network and
|
|
|
24
24
|
{ "display": "Fraunces", "body": "Nunito Sans" }
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
Every slot is optional and an omitted slot is left exactly as it is. `display` is `--font-display`, `body` is `--font-sans`; `serif`, `mono` and `editorial` exist when a theme needs them. `editorial` is `--font-editorial`, the long-reading face behind the `--editorial-*` text
|
|
27
|
+
Every slot is optional and an omitted slot is left exactly as it is. `display` is `--font-display`, `body` is `--font-sans`; `serif`, `mono` and `editorial` exist when a theme needs them. `editorial` is `--font-editorial`, the long-reading face behind the `--editorial-*` text styles: it tracks the body face until a theme repoints it, so set it only when essays and articles should not carry the body face. A slot may be `{ "name": "...", "url": "..." }` to pin an exact URL. Spell families as Google does; the CLI reports the canonical spelling back.
|
|
28
28
|
|
|
29
29
|
## Choose the body face first
|
|
30
30
|
|
|
31
31
|
The body face is the anchor. It carries most of the words, and text faces survive small sizes where display faces do not. Pick it against the brief, then pick the display face against it. A body face must have regular, bold, and italic; low to moderate stroke contrast; open apertures; and a large x-height. A face failing any of these is a display face whatever its name says. Single-weight families are fine for `display` and disqualifying for `body`.
|
|
32
32
|
|
|
33
|
+
The shipped text styles ask the display face for 600, across all four heading levels, and the body face for 400; prose markup adds 700 and italic for `strong` and `em`. Screen candidates against those four before running, so the report confirms a decision instead of reporting a surprise.
|
|
34
|
+
|
|
33
35
|
## The font matrix: the decision rule
|
|
34
36
|
|
|
35
37
|
Classify each candidate on two layers. The **skeleton** is its form model; the **flesh** is its stroke contrast and serif treatment.
|
|
@@ -64,7 +66,7 @@ Match the type to the same brief the color came from. A warm autumn palette unde
|
|
|
64
66
|
|
|
65
67
|
These find an adequate pairing fast and skip the reasoning; use them when the brief is vague or the type should stay quiet.
|
|
66
68
|
|
|
67
|
-
- **A superfamily.** Google Fonts families with both sans and serif siblings
|
|
69
|
+
- **A superfamily.** Google Fonts families with both sans and serif siblings, among them Alegreya, Ancizar, IBM Plex, Inria, Merriweather, Noto, PT, Roboto, Source. The catalogue moves and this list does not, so treat it as a starting set: `set-fonts` verifies every family against the API and fails loudly on one that is gone.
|
|
68
70
|
- **One family across weights.**
|
|
69
71
|
- **Same designer or foundry.**
|
|
70
72
|
- **Serif display over sans body** when nothing else decides it.
|
|
@@ -78,7 +80,7 @@ These find an adequate pairing fast and skip the reasoning; use them when the br
|
|
|
78
80
|
|
|
79
81
|
## Scope
|
|
80
82
|
|
|
81
|
-
Type only. Color, component aliases, shape, and the type scale are untouched: `set-fonts` moves families between stacks and nothing else, writing only the unsaved colors-and-type buffer. Save the theme to keep it, Adopt to ship it.
|
|
83
|
+
Type only. Color, component aliases, shape, and the type scale are untouched: `set-fonts` moves families between stacks and nothing else, writing only the unsaved colors-and-type buffer. Save the theme to keep it, Adopt to ship it. Adopt is also what rewrites `fonts.css`, which is how a build with no editor in it loads the family at all.
|
|
82
84
|
|
|
83
85
|
## Verify
|
|
84
86
|
|
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: live-tokens-pick-component
|
|
3
|
-
description: Recommend which shipped @motion-proto/live-tokens component fits a UX need, with decision trees for the confusable pairs (SegmentedControl
|
|
3
|
+
description: Recommend which shipped @motion-proto/live-tokens component fits a UX need, with decision trees for the confusable pairs (SegmentedControl / TabBar / RadioButton / MenuSelect, Card / CollapsibleSection / Dialog, Callout / Notification / Tooltip, and others). Use when the user asks which component to use, should I use X or Y, what is the difference between two components, how do I show / let the user / capture some UX outcome, or starts authoring a custom component before checking the catalogue. Read this before live-tokens-create-component. Not for placing the chosen component on a page (see live-tokens-build-page).
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Picking the right live-tokens component
|
|
7
7
|
|
|
8
8
|
This skill helps you choose between shipped components when several could plausibly fit. The catalogue is small; the hard part is semantic intent. A `RadioButton` set and a `SegmentedControl` can render identical-looking UIs but communicate different things.
|
|
9
9
|
|
|
10
|
-
For composing a page once you've picked components, see
|
|
10
|
+
For composing a page once you've picked components, see **live-tokens-build-page**. For authoring a brand-new component when nothing fits, see **live-tokens-create-component** (but read this skill first to confirm nothing in the catalogue fits).
|
|
11
11
|
|
|
12
12
|
## Catalogue
|
|
13
13
|
|
|
14
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`.
|
|
15
15
|
|
|
16
|
-
`CodeSnippet` is for a single-line command or value the user is meant to copy and paste back into a terminal (install commands, generated keys, ids). Click-to-copy with a brief "Copied" popover. Use it whenever your page asks the reader to *run* something, rather than just *read* it.
|
|
17
|
-
|
|
18
16
|
## Action family: Button vs IconButton
|
|
19
17
|
|
|
20
18
|
Both trigger an action and share the same six variants (primary, secondary, outline, success, danger, warning), three states (default, hover, disabled) and two sizes (default, small). They differ only in content.
|
|
@@ -40,6 +38,13 @@ All four pick one option from a set. The right one depends on **option count**,
|
|
|
40
38
|
- Use `MenuSelect` when options would overflow horizontally or there are too many to display at once.
|
|
41
39
|
- **Don't pick `SegmentedControl` when option labels are long enough to wrap.** It loses its compactness; use `RadioButton` rows instead.
|
|
42
40
|
|
|
41
|
+
## Text entry: Input vs the selection family
|
|
42
|
+
|
|
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
|
+
- 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
|
+
- **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
|
+
- 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
|
+
|
|
43
48
|
## Container family: Card vs CollapsibleSection vs Dialog
|
|
44
49
|
|
|
45
50
|
| Component | Modality | Use for |
|
|
@@ -69,6 +74,15 @@ All four pick one option from a set. The right one depends on **option count**,
|
|
|
69
74
|
- `Tooltip` is for *what an element means*. **Don't use `Tooltip` as the primary location of important content;** it auto-dismisses and isn't accessible for must-read content.
|
|
70
75
|
- `Badge` and `CornerBadge` differ only in positioning. `CornerBadge` lives at a `top-right` / `bottom-left` anchor on a parent (notification counts, "NEW" stickers).
|
|
71
76
|
|
|
77
|
+
## Display family: what the page shows rather than what it asks
|
|
78
|
+
|
|
79
|
+
- `Image` frames a picture in the flow at one of four sizes, with an optional hover zoom. It is the default for any picture the page simply shows.
|
|
80
|
+
- `ImageLightbox` adds click-to-open at full size and takes an array for a gallery. Use it when the detail is the point (screenshots, artwork, charts that need reading), and not for decoration: it puts a modal behind every picture it wraps.
|
|
81
|
+
- `Table` themes your own rows and cells without owning the data. Records go here; a set of *things the user acts on* is a stack of `Card`s instead.
|
|
82
|
+
- `ProgressBar` reports progress against a labelled track. It is a read-out, never a control.
|
|
83
|
+
- `CodeSnippet` is for a single-line command or value the reader is meant to copy back into a terminal (install commands, generated keys, ids), with click-to-copy and a brief "Copied" popover. Use it whenever the page asks the reader to *run* something rather than just *read* it.
|
|
84
|
+
- `SectionDivider` separates sections of one page. `SideNavigation` moves between pages, driven by the current path. **Don't use `SideNavigation` to switch panels inside one page;** that is `TabBar`, and the difference is whether the URL changes.
|
|
85
|
+
|
|
72
86
|
## Toggle vs SegmentedControl vs RadioButton (for on/off)
|
|
73
87
|
|
|
74
88
|
All three can express a binary choice. The right one depends on what the choice *is*.
|
|
@@ -85,4 +99,4 @@ All three can express a binary choice. The right one depends on what the choice
|
|
|
85
99
|
|
|
86
100
|
---
|
|
87
101
|
|
|
88
|
-
If nothing in the catalogue fits (a `Slider`, a `DatePicker`, a `Stepper`, a custom widget), author it via
|
|
102
|
+
If nothing in the catalogue fits (a `Slider`, a `DatePicker`, a `Stepper`, a custom widget), author it via **live-tokens-create-component**. **Don't reach for a custom component before checking the catalogue;** a custom component is a maintenance commitment.
|