@motion-proto/live-tokens 0.17.0 → 0.17.1
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-create-component/SKILL.md +11 -1
- package/package.json +1 -1
- package/src/editor/component-editor/CornerBadgeEditor.svelte +0 -4
- package/src/editor/component-editor/InputEditor.svelte +0 -4
- package/src/editor/component-editor/MenuSelectEditor.svelte +0 -8
- package/src/editor/component-editor/SegmentedControlEditor.svelte +0 -16
- package/src/live-tokens/data/tokens.generated.css +24 -0
- package/src/system/components/SideNavigation.svelte +15 -0
|
@@ -473,7 +473,17 @@ npx live-tokens check-component <id>
|
|
|
473
473
|
|
|
474
474
|
It enforces the file layout, the `:global(:root)` block, token-suffix vocabulary, state-before-property rule, theme-token defaults (no raw colour literals), public-imports rule, and the `registerComponent({ id })` call. Exit code 0 means the static contract is met.
|
|
475
475
|
|
|
476
|
-
Then
|
|
476
|
+
**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:
|
|
477
|
+
|
|
478
|
+
1. Registration resolves to a real `sourceFile` and a non-empty schema.
|
|
479
|
+
2. Schema variables are unique within the component.
|
|
480
|
+
3. Every editable token (excluding `hidden: true`, `kind: 'gradient'`, and padding-side suffixes) is declared in the runtime `<style>` block.
|
|
481
|
+
4. Every editable token is seeded in the production-pointed config under `src/live-tokens/data/component-configs/<id>/`.
|
|
482
|
+
5. `setComponentAlias` round-trips the alias through the slice.
|
|
483
|
+
|
|
484
|
+
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 (the same test logic works against any `registerComponent` registration; iterate `getComponentRegistryEntries()` after your `main.ts` has run).
|
|
485
|
+
|
|
486
|
+
Finally navigate to `/components` and confirm the runtime behaviours no static check can see:
|
|
477
487
|
|
|
478
488
|
- [ ] The new component appears in the nav rail under the **CUSTOM** group (system entries above, custom below the labeled divider).
|
|
479
489
|
- [ ] Token rows render. Color pickers, radius selectors, font selectors all work.
|
package/package.json
CHANGED
|
@@ -10,10 +10,6 @@
|
|
|
10
10
|
const baseTokens: Token[] = [
|
|
11
11
|
{ label: 'offset from corner', canBeLinked: true, groupKey: 'margin', variable: '--corner-badge-margin', element: 'frame' },
|
|
12
12
|
{ label: 'padding', canBeLinked: true, groupKey: 'padding', variable: '--corner-badge-padding', element: 'frame' },
|
|
13
|
-
{ label: 'padding-top', canBeLinked: true, groupKey: 'padding-top', variable: '--corner-badge-padding-top', hidden: true, element: 'frame' },
|
|
14
|
-
{ label: 'padding-right', canBeLinked: true, groupKey: 'padding-right', variable: '--corner-badge-padding-right', hidden: true, element: 'frame' },
|
|
15
|
-
{ label: 'padding-bottom', canBeLinked: true, groupKey: 'padding-bottom', variable: '--corner-badge-padding-bottom', hidden: true, element: 'frame' },
|
|
16
|
-
{ label: 'padding-left', canBeLinked: true, groupKey: 'padding-left', variable: '--corner-badge-padding-left', hidden: true, element: 'frame' },
|
|
17
13
|
{ label: 'outer corner radius', canBeLinked: true, groupKey: 'outer-radius', variable: '--corner-badge-outer-radius', element: 'frame' },
|
|
18
14
|
{ label: 'inner corner radius', canBeLinked: true, groupKey: 'inner-radius', variable: '--corner-badge-inner-radius', element: 'frame' },
|
|
19
15
|
{ label: 'horizontal-axis radius', canBeLinked: true, groupKey: 'h-axis-radius', variable: '--corner-badge-h-axis-radius', element: 'frame' },
|
|
@@ -12,10 +12,6 @@
|
|
|
12
12
|
{ label: 'corner radius', groupKey: 'radius', variable: '--input-radius' },
|
|
13
13
|
{ label: 'border width', groupKey: 'border-width', variable: '--input-border-width' },
|
|
14
14
|
{ label: 'padding', variable: '--input-padding', groupKey: 'padding' },
|
|
15
|
-
{ label: 'padding-top', variable: '--input-padding-top', groupKey: 'padding-top', hidden: true },
|
|
16
|
-
{ label: 'padding-right', variable: '--input-padding-right', groupKey: 'padding-right', hidden: true },
|
|
17
|
-
{ label: 'padding-bottom', variable: '--input-padding-bottom', groupKey: 'padding-bottom', hidden: true },
|
|
18
|
-
{ label: 'padding-left', variable: '--input-padding-left', groupKey: 'padding-left', hidden: true },
|
|
19
15
|
{ label: 'message gap', groupKey: 'gap', variable: '--input-gap' },
|
|
20
16
|
],
|
|
21
17
|
default: [
|
|
@@ -12,18 +12,10 @@
|
|
|
12
12
|
{ label: 'border width', groupKey: 'width', variable: '--menuselect-menu-border-width' },
|
|
13
13
|
{ label: 'corner radius', groupKey: 'menu-radius', variable: '--menuselect-menu-radius' },
|
|
14
14
|
{ label: 'padding', variable: '--menuselect-menu-padding', groupKey: 'menu-padding' },
|
|
15
|
-
{ label: 'padding-top', variable: '--menuselect-menu-padding-top', groupKey: 'menu-padding-top', hidden: true },
|
|
16
|
-
{ label: 'padding-right', variable: '--menuselect-menu-padding-right', groupKey: 'menu-padding-right', hidden: true },
|
|
17
|
-
{ label: 'padding-bottom', variable: '--menuselect-menu-padding-bottom', groupKey: 'menu-padding-bottom', hidden: true },
|
|
18
|
-
{ label: 'padding-left', variable: '--menuselect-menu-padding-left', groupKey: 'menu-padding-left', hidden: true },
|
|
19
15
|
{ label: 'item gap', groupKey: 'gap', variable: '--menuselect-menu-gap' },
|
|
20
16
|
{ label: 'shadow', groupKey: 'shadow', variable: '--menuselect-menu-shadow' },
|
|
21
17
|
{ label: 'item radius', groupKey: 'item-radius', variable: '--menuselect-item-radius' },
|
|
22
18
|
{ label: 'item padding', variable: '--menuselect-item-padding', groupKey: 'item-padding' },
|
|
23
|
-
{ label: 'item padding-top', variable: '--menuselect-item-padding-top', groupKey: 'item-padding-top', hidden: true },
|
|
24
|
-
{ label: 'item padding-right', variable: '--menuselect-item-padding-right', groupKey: 'item-padding-right', hidden: true },
|
|
25
|
-
{ label: 'item padding-bottom', variable: '--menuselect-item-padding-bottom', groupKey: 'item-padding-bottom', hidden: true },
|
|
26
|
-
{ label: 'item padding-left', variable: '--menuselect-item-padding-left', groupKey: 'item-padding-left', hidden: true },
|
|
27
19
|
],
|
|
28
20
|
'default item': [
|
|
29
21
|
{ label: 'surface color', groupKey: 'surface', variable: '--menuselect-default-surface' },
|
|
@@ -19,17 +19,9 @@
|
|
|
19
19
|
{ label: 'corner radius', groupKey: 'radius', variable: '--segmentedcontrol-bar-radius' },
|
|
20
20
|
{ label: 'option gap', groupKey: 'gap', variable: '--segmentedcontrol-bar-gap' },
|
|
21
21
|
{ label: 'padding', variable: '--segmentedcontrol-bar-padding', groupKey: 'bar-padding' },
|
|
22
|
-
{ label: 'padding-top', variable: '--segmentedcontrol-bar-padding-top', groupKey: 'bar-padding-top', hidden: true },
|
|
23
|
-
{ label: 'padding-right', variable: '--segmentedcontrol-bar-padding-right', groupKey: 'bar-padding-right', hidden: true },
|
|
24
|
-
{ label: 'padding-bottom', variable: '--segmentedcontrol-bar-padding-bottom', groupKey: 'bar-padding-bottom', hidden: true },
|
|
25
|
-
{ label: 'padding-left', variable: '--segmentedcontrol-bar-padding-left', groupKey: 'bar-padding-left', hidden: true },
|
|
26
22
|
],
|
|
27
23
|
'option base': [
|
|
28
24
|
{ label: 'padding', variable: '--segmentedcontrol-option-padding', groupKey: 'option-padding' },
|
|
29
|
-
{ label: 'padding-top', variable: '--segmentedcontrol-option-padding-top', groupKey: 'option-padding-top', hidden: true },
|
|
30
|
-
{ label: 'padding-right', variable: '--segmentedcontrol-option-padding-right', groupKey: 'option-padding-right', hidden: true },
|
|
31
|
-
{ label: 'padding-bottom', variable: '--segmentedcontrol-option-padding-bottom', groupKey: 'option-padding-bottom', hidden: true },
|
|
32
|
-
{ label: 'padding-left', variable: '--segmentedcontrol-option-padding-left', groupKey: 'option-padding-left', hidden: true },
|
|
33
25
|
{ label: 'icon gap', groupKey: 'option-gap', variable: '--segmentedcontrol-option-gap' },
|
|
34
26
|
{ label: 'icon size', groupKey: 'icon-size', variable: '--segmentedcontrol-option-icon-size' },
|
|
35
27
|
],
|
|
@@ -64,20 +56,12 @@
|
|
|
64
56
|
{ label: 'divider width', groupKey: 'small-thickness', variable: '--segmentedcontrol-divider-small-thickness' },
|
|
65
57
|
{ label: 'corner radius', groupKey: 'small-radius', variable: '--segmentedcontrol-bar-small-radius' },
|
|
66
58
|
{ label: 'padding', variable: '--segmentedcontrol-bar-small-padding', groupKey: 'bar-small-padding' },
|
|
67
|
-
{ label: 'padding-top', variable: '--segmentedcontrol-bar-small-padding-top', groupKey: 'bar-small-padding-top', hidden: true },
|
|
68
|
-
{ label: 'padding-right', variable: '--segmentedcontrol-bar-small-padding-right', groupKey: 'bar-small-padding-right', hidden: true },
|
|
69
|
-
{ label: 'padding-bottom', variable: '--segmentedcontrol-bar-small-padding-bottom', groupKey: 'bar-small-padding-bottom', hidden: true },
|
|
70
|
-
{ label: 'padding-left', variable: '--segmentedcontrol-bar-small-padding-left', groupKey: 'bar-small-padding-left', hidden: true },
|
|
71
59
|
],
|
|
72
60
|
'option base': [
|
|
73
61
|
{ label: 'icon size', groupKey: 'small-icon-size', variable: '--segmentedcontrol-option-small-icon-size' },
|
|
74
62
|
{ label: 'font size', groupKey: 'small-text-font-size', variable: '--segmentedcontrol-option-small-text-font-size' },
|
|
75
63
|
{ label: 'line height', groupKey: 'small-text-line-height', variable: '--segmentedcontrol-option-small-text-line-height' },
|
|
76
64
|
{ label: 'padding', variable: '--segmentedcontrol-option-small-padding', groupKey: 'option-small-padding' },
|
|
77
|
-
{ label: 'padding-top', variable: '--segmentedcontrol-option-small-padding-top', groupKey: 'option-small-padding-top', hidden: true },
|
|
78
|
-
{ label: 'padding-right', variable: '--segmentedcontrol-option-small-padding-right', groupKey: 'option-small-padding-right', hidden: true },
|
|
79
|
-
{ label: 'padding-bottom', variable: '--segmentedcontrol-option-small-padding-bottom', groupKey: 'option-small-padding-bottom', hidden: true },
|
|
80
|
-
{ label: 'padding-left', variable: '--segmentedcontrol-option-small-padding-left', groupKey: 'option-small-padding-left', hidden: true },
|
|
81
65
|
{ label: 'icon gap', groupKey: 'option-small-gap', variable: '--segmentedcontrol-option-small-gap' },
|
|
82
66
|
],
|
|
83
67
|
'selected option': [
|
|
@@ -359,6 +359,30 @@
|
|
|
359
359
|
|
|
360
360
|
/* Component aliases (production configs differing from defaults) */
|
|
361
361
|
:root:root {
|
|
362
|
+
/* button (my-button) */
|
|
363
|
+
--button-primary-text-font-size: var(--font-size-md);
|
|
364
|
+
--button-primary-text-font-weight: var(--font-weight-semibold);
|
|
365
|
+
--button-primary-radius: var(--radius-xl);
|
|
366
|
+
--button-secondary-text-font-size: var(--font-size-md);
|
|
367
|
+
--button-secondary-text-font-weight: var(--font-weight-semibold);
|
|
368
|
+
--button-secondary-radius: var(--radius-xl);
|
|
369
|
+
--button-outline-text-font-size: var(--font-size-md);
|
|
370
|
+
--button-outline-text-font-weight: var(--font-weight-semibold);
|
|
371
|
+
--button-outline-radius: var(--radius-xl);
|
|
372
|
+
--button-success-text-font-size: var(--font-size-md);
|
|
373
|
+
--button-success-text-font-weight: var(--font-weight-semibold);
|
|
374
|
+
--button-success-border-width: var(--border-width-1);
|
|
375
|
+
--button-success-radius: var(--radius-xl);
|
|
376
|
+
--button-danger-text-font-size: var(--font-size-md);
|
|
377
|
+
--button-danger-text-font-weight: var(--font-weight-semibold);
|
|
378
|
+
--button-danger-border-width: var(--border-width-1);
|
|
379
|
+
--button-danger-radius: var(--radius-xl);
|
|
380
|
+
--button-warning-text-font-size: var(--font-size-md);
|
|
381
|
+
--button-warning-text-font-weight: var(--font-weight-semibold);
|
|
382
|
+
--button-warning-border-width: var(--border-width-1);
|
|
383
|
+
--button-warning-radius: var(--radius-xl);
|
|
384
|
+
--button-small-text-font-size: var(--font-size-sm);
|
|
385
|
+
|
|
362
386
|
/* card (my-card) */
|
|
363
387
|
--card-default-surface: color-mix(in srgb, var(--surface-neutral-lower) 70%, transparent);
|
|
364
388
|
--card-default-header-surface: color-mix(in srgb, var(--surface-neutral-lowest) 80%, transparent);
|
|
@@ -76,6 +76,19 @@
|
|
|
76
76
|
expandedSections[path] = !expandedSections[path];
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
// Clicking a section label whose route is already current would otherwise be
|
|
80
|
+
// a no-op navigation. Make it a toggle in that case so the user can collapse
|
|
81
|
+
// the section they just opened without having to chase the chevron. The
|
|
82
|
+
// chevron's own onclick is unaffected — its event target isn't inside an <a>.
|
|
83
|
+
function maybeInterceptLabel(e: MouseEvent, section: SideNavSection) {
|
|
84
|
+
if (!section.hasIndexPage || currentPath !== section.path) return;
|
|
85
|
+
if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
|
|
86
|
+
const target = e.target as Element | null;
|
|
87
|
+
if (!target?.closest('a')) return;
|
|
88
|
+
e.preventDefault();
|
|
89
|
+
toggleSection(section.path);
|
|
90
|
+
}
|
|
91
|
+
|
|
79
92
|
function fireToggle() {
|
|
80
93
|
ontoggle?.();
|
|
81
94
|
dispatch('toggle');
|
|
@@ -164,10 +177,12 @@
|
|
|
164
177
|
<div class="sn-menu">
|
|
165
178
|
{#each sections as section (section.path)}
|
|
166
179
|
<div class="sn-section">
|
|
180
|
+
<!-- svelte-ignore a11y_click_events_have_key_events, a11y_no_noninteractive_element_interactions, a11y_no_static_element_interactions -->
|
|
167
181
|
<div
|
|
168
182
|
class="sn-section-header"
|
|
169
183
|
class:active={isSectionActive(section)}
|
|
170
184
|
class:force-hover={isSectionHover(section)}
|
|
185
|
+
onclick={(e) => maybeInterceptLabel(e, section)}
|
|
171
186
|
>
|
|
172
187
|
<CollapsibleSection
|
|
173
188
|
variant="chromeless"
|