@motion-proto/live-tokens 0.82.0 → 0.84.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.
Files changed (91) hide show
  1. package/.claude/skills/live-tokens-create-component/SKILL.md +16 -4
  2. package/.claude/skills/live-tokens-create-page/SKILL.md +19 -17
  3. package/.claude/skills/live-tokens-create-page/references/interaction-sources.md +3 -3
  4. package/.claude/skills/live-tokens-pick-component/SKILL.md +10 -83
  5. package/CHANGELOG.md +84 -0
  6. package/README.md +1 -1
  7. package/bin/cli.mjs +21 -8
  8. package/bin/lib/catalogue.mjs +140 -41
  9. package/bin/rules/componentStructure.mjs +12 -4
  10. package/dist-plugin/{chunk-REBHE3ZM.js → chunk-FD4FVDOC.js} +59 -9
  11. package/dist-plugin/{chunk-D4WRIKEZ.js → chunk-M6BWSS6C.js} +1 -1
  12. package/dist-plugin/{chunk-RFVYPNRO.js → chunk-V2OVSC5Z.js} +22 -1
  13. package/dist-plugin/index.cjs +85 -14
  14. package/dist-plugin/index.js +3 -3
  15. package/dist-plugin/migrateData/index.cjs +59 -9
  16. package/dist-plugin/migrateData/index.js +2 -2
  17. package/dist-plugin/setColors/index.cjs +59 -9
  18. package/dist-plugin/setColors/index.js +1 -1
  19. package/dist-plugin/setGeometry/index.cjs +63 -11
  20. package/dist-plugin/setGeometry/index.d.cts +1 -1
  21. package/dist-plugin/setGeometry/index.d.ts +1 -1
  22. package/dist-plugin/setGeometry/index.js +5 -3
  23. package/dist-plugin/tokensCssMigrations/index.cjs +22 -1
  24. package/dist-plugin/tokensCssMigrations/index.js +1 -1
  25. package/package.json +3 -1
  26. package/src/editor/component-editor/DialogEditor.svelte +2 -1
  27. package/src/editor/component-editor/ImageLightboxEditor.svelte +2 -1
  28. package/src/editor/component-editor/scaffolding/TokenLayout.svelte +4 -1
  29. package/src/editor/component-editor/scaffolding/types.ts +13 -8
  30. package/src/editor/core/components/aliasKinds.ts +5 -1
  31. package/src/editor/core/sketch/sketchLayer.ts +1 -1
  32. package/src/editor/core/themes/migrations/2026-09-20-imagelightbox-scrim.ts +28 -0
  33. package/src/editor/core/themes/migrations/2026-09-20-scrim-color-and-opacity.ts +45 -0
  34. package/src/editor/core/themes/migrations/index.ts +4 -0
  35. package/src/editor/docs/content/creating-components.md +3 -0
  36. package/src/editor/docs/content.generated.ts +1 -1
  37. package/src/editor/skill-atlas/SkillAtlas.svelte +65 -38
  38. package/src/editor/skill-atlas/SkillValue.svelte +202 -0
  39. package/src/editor/skill-atlas/evalResults.ts +46 -0
  40. package/src/editor/skill-atlas/skillSources.generated.ts +4 -4
  41. package/src/editor/skill-atlas/trees/create-component.ts +18 -18
  42. package/src/editor/skill-atlas/trees/create-page.ts +28 -32
  43. package/src/editor/skill-atlas/trees/pick-component.ts +66 -196
  44. package/src/editor/ui/UIVariantSelector.svelte +1 -1
  45. package/src/editor/ui/variantScales.ts +11 -0
  46. package/src/live-tokens/data/themes/autumn.json +6 -4
  47. package/src/live-tokens/data/themes/halloween.json +6 -4
  48. package/src/live-tokens/data/themes/midnight-study.json +6 -4
  49. package/src/live-tokens/data/themes/ocean.json +6 -4
  50. package/src/live-tokens/data/themes/royal-velvet.json +6 -4
  51. package/src/live-tokens/data/themes/sketchy.json +6 -4
  52. package/src/live-tokens/data/themes/spring-meadow.json +6 -4
  53. package/src/live-tokens/data/themes/sunset.json +6 -4
  54. package/src/system/components/Badge.svelte +5 -2
  55. package/src/system/components/Button.svelte +10 -2
  56. package/src/system/components/Callout.svelte +5 -2
  57. package/src/system/components/Card.svelte +8 -3
  58. package/src/system/components/CodeSnippet.svelte +6 -2
  59. package/src/system/components/CollapsibleSection.svelte +6 -2
  60. package/src/system/components/CornerBadge.svelte +5 -2
  61. package/src/system/components/Dialog.svelte +12 -4
  62. package/src/system/components/IconButton.svelte +5 -2
  63. package/src/system/components/Image.svelte +5 -2
  64. package/src/system/components/ImageLightbox.svelte +44 -4
  65. package/src/system/components/InlineEditActions.svelte +5 -2
  66. package/src/system/components/Input.svelte +6 -2
  67. package/src/system/components/MenuSelect.svelte +9 -2
  68. package/src/system/components/Notification.svelte +5 -2
  69. package/src/system/components/Panel.svelte +5 -2
  70. package/src/system/components/ProgressBar.svelte +5 -2
  71. package/src/system/components/RadioButton.svelte +5 -2
  72. package/src/system/components/SectionDivider.svelte +5 -2
  73. package/src/system/components/SegmentedControl.svelte +5 -2
  74. package/src/system/components/SideNavigation.svelte +5 -2
  75. package/src/system/components/Slider.svelte +6 -2
  76. package/src/system/components/TabBar.svelte +5 -2
  77. package/src/system/components/Table.svelte +4 -2
  78. package/src/system/components/Toggle.svelte +5 -2
  79. package/src/system/components/Tooltip.svelte +5 -2
  80. package/src/system/styles/tokens.css +12 -4
  81. package/src/testing-js/{chunk-ZMZQZ33J.js → chunk-WQJ6QB6Y.js} +8 -4
  82. package/src/testing-js/chunk-WQJ6QB6Y.js.map +1 -0
  83. package/src/testing-js/{chunk-Q3YIAAG3.js → chunk-XXABJNUU.js} +2 -2
  84. package/src/testing-js/component-behavior.contract.js +1 -1
  85. package/src/testing-js/component-editor.contract.js +1 -1
  86. package/src/testing-js/component-render.contract.js +1 -1
  87. package/src/testing-js/index.js +2 -2
  88. package/src/testing-js/page-compliance.contract.js +1 -1
  89. package/src/testing-js/vitest.js +2 -2
  90. package/src/testing-js/chunk-ZMZQZ33J.js.map +0 -1
  91. /package/src/testing-js/{chunk-Q3YIAAG3.js.map → chunk-XXABJNUU.js.map} +0 -0
@@ -2370,8 +2370,56 @@ var componentMigration_2026_09_13_sectiondividerSurface = {
2370
2370
  }
2371
2371
  };
2372
2372
 
2373
- // src/editor/core/themes/migrations/2026-09-13-cornerbadge-prefix.ts
2373
+ // src/editor/core/themes/migrations/2026-09-20-imagelightbox-scrim.ts
2374
2374
  var RENAMES7 = {
2375
+ "--imagelightbox-overlay-surface": "--imagelightbox-scrim-surface"
2376
+ };
2377
+ var componentMigration_2026_09_20_imagelightboxScrim = {
2378
+ id: "2026-09-20-imagelightbox-scrim",
2379
+ fromVersion: 35,
2380
+ toVersion: 36,
2381
+ appliesTo: "component-config",
2382
+ apply(rawVars, meta) {
2383
+ if (meta.component !== "imagelightbox") return { ...rawVars };
2384
+ const out = {};
2385
+ for (const [key, value] of Object.entries(rawVars)) {
2386
+ out[RENAMES7[key] ?? key] = value;
2387
+ }
2388
+ return out;
2389
+ }
2390
+ };
2391
+
2392
+ // src/editor/core/themes/migrations/2026-09-20-scrim-color-and-opacity.ts
2393
+ var STOPS = {
2394
+ "--scrim-low": "--scrim-opacity-low",
2395
+ "--scrim": "--scrim-opacity",
2396
+ "--scrim-high": "--scrim-opacity-high"
2397
+ };
2398
+ var SURFACE = /^--(imagelightbox|dialog)-scrim-surface$/;
2399
+ var componentMigration_2026_09_20_scrimColorAndOpacity = {
2400
+ id: "2026-09-20-scrim-color-and-opacity",
2401
+ fromVersion: 36,
2402
+ toVersion: 37,
2403
+ appliesTo: "component-config",
2404
+ apply(rawVars) {
2405
+ const out = {};
2406
+ for (const [key, value] of Object.entries(rawVars)) {
2407
+ const match = SURFACE.exec(key);
2408
+ if (!match) {
2409
+ out[key] = value;
2410
+ continue;
2411
+ }
2412
+ const stem = `--${match[1]}-scrim`;
2413
+ const stop = STOPS[value];
2414
+ out[`${stem}-color`] = stop ? "--scrim-color" : value;
2415
+ out[`${stem}-opacity`] = stop ?? "1";
2416
+ }
2417
+ return out;
2418
+ }
2419
+ };
2420
+
2421
+ // src/editor/core/themes/migrations/2026-09-13-cornerbadge-prefix.ts
2422
+ var RENAMES8 = {
2375
2423
  cornerbadge: {
2376
2424
  "--corner-badge-margin": "--cornerbadge-margin",
2377
2425
  "--corner-badge-outer-radius": "--cornerbadge-outer-radius",
@@ -2421,7 +2469,7 @@ var componentMigration_2026_09_13_cornerbadgePrefix = {
2421
2469
  toVersion: 32,
2422
2470
  appliesTo: "component-config",
2423
2471
  apply(rawVars, meta) {
2424
- const renames = meta.component ? RENAMES7[meta.component] : void 0;
2472
+ const renames = meta.component ? RENAMES8[meta.component] : void 0;
2425
2473
  if (!renames) return { ...rawVars };
2426
2474
  const out = {};
2427
2475
  for (const [key, value] of Object.entries(rawVars)) {
@@ -2432,7 +2480,7 @@ var componentMigration_2026_09_13_cornerbadgePrefix = {
2432
2480
  };
2433
2481
 
2434
2482
  // src/editor/core/themes/migrations/2026-09-13-toggle-label.ts
2435
- var RENAMES8 = {
2483
+ var RENAMES9 = {
2436
2484
  toggle: {
2437
2485
  "--toggle-label-text": "--toggle-label",
2438
2486
  "--toggle-disabled-label-text": "--toggle-disabled-label"
@@ -2444,7 +2492,7 @@ var componentMigration_2026_09_13_toggleLabel = {
2444
2492
  toVersion: 33,
2445
2493
  appliesTo: "component-config",
2446
2494
  apply(rawVars, meta) {
2447
- const renames = meta.component ? RENAMES8[meta.component] : void 0;
2495
+ const renames = meta.component ? RENAMES9[meta.component] : void 0;
2448
2496
  if (!renames) return { ...rawVars };
2449
2497
  const out = {};
2450
2498
  for (const [key, value] of Object.entries(rawVars)) {
@@ -2455,7 +2503,7 @@ var componentMigration_2026_09_13_toggleLabel = {
2455
2503
  };
2456
2504
 
2457
2505
  // src/editor/core/themes/migrations/2026-09-13-collapsiblesection-open.ts
2458
- var RENAMES9 = {
2506
+ var RENAMES10 = {
2459
2507
  collapsiblesection: {
2460
2508
  "--collapsiblesection-chromeless-expanded-padding": "--collapsiblesection-chromeless-open-padding",
2461
2509
  "--collapsiblesection-hairline-expanded-padding": "--collapsiblesection-hairline-open-padding",
@@ -2469,7 +2517,7 @@ var componentMigration_2026_09_13_collapsiblesectionOpen = {
2469
2517
  toVersion: 34,
2470
2518
  appliesTo: "component-config",
2471
2519
  apply(rawVars, meta) {
2472
- const renames = meta.component ? RENAMES9[meta.component] : void 0;
2520
+ const renames = meta.component ? RENAMES10[meta.component] : void 0;
2473
2521
  if (!renames) return { ...rawVars };
2474
2522
  const out = {};
2475
2523
  for (const [key, value] of Object.entries(rawVars)) {
@@ -2496,7 +2544,7 @@ var BADGE_SUFFIXES = [
2496
2544
  "icon-size"
2497
2545
  ];
2498
2546
  var CORNERBADGE_SUFFIXES = ["surface", "border", "text"];
2499
- var RENAMES10 = {
2547
+ var RENAMES11 = {
2500
2548
  badge: Object.fromEntries(
2501
2549
  BADGE_SUFFIXES.map((s) => [`--badge-primary-${s}`, `--badge-brand-${s}`])
2502
2550
  ),
@@ -2510,7 +2558,7 @@ var componentMigration_2026_09_13_badgeBrand = {
2510
2558
  toVersion: 35,
2511
2559
  appliesTo: "component-config",
2512
2560
  apply(rawVars, meta) {
2513
- const renames = meta.component ? RENAMES10[meta.component] : void 0;
2561
+ const renames = meta.component ? RENAMES11[meta.component] : void 0;
2514
2562
  if (!renames) return { ...rawVars };
2515
2563
  const out = {};
2516
2564
  for (const [key, value] of Object.entries(rawVars)) {
@@ -2564,7 +2612,9 @@ var MIGRATIONS = [
2564
2612
  componentMigration_2026_09_13_cornerbadgePrefix,
2565
2613
  componentMigration_2026_09_13_toggleLabel,
2566
2614
  componentMigration_2026_09_13_collapsiblesectionOpen,
2567
- componentMigration_2026_09_13_badgeBrand
2615
+ componentMigration_2026_09_13_badgeBrand,
2616
+ componentMigration_2026_09_20_imagelightboxScrim,
2617
+ componentMigration_2026_09_20_scrimColorAndOpacity
2568
2618
  ];
2569
2619
  function countFor(kind) {
2570
2620
  return MIGRATIONS.filter((m) => m.appliesTo === kind).length;
@@ -18,7 +18,7 @@ import {
18
18
  } from "../chunk-O6GQ6GBH.js";
19
19
  import {
20
20
  CURRENT_COMPONENT_SCHEMA_VERSION
21
- } from "../chunk-REBHE3ZM.js";
21
+ } from "../chunk-FD4FVDOC.js";
22
22
  import {
23
23
  cssColorToOklch,
24
24
  gamutClamp,
@@ -74,6 +74,9 @@ var KIND_RULES = [
74
74
  { kind: "dot-size", suffix: ["-dot-size"] },
75
75
  { kind: "blur", suffix: ["-blur"], prefix: ["--blur-"] },
76
76
  { kind: "scale", suffix: ["-scale"], prefix: ["--scale-"] },
77
+ // A strength from 0 to 1 that the component mixes into a colour where it
78
+ // paints. A palette picker here writes a colour into a number.
79
+ { kind: "opacity", suffix: ["-opacity"], prefix: ["--scrim-opacity"] },
77
80
  { kind: "shadow", suffix: ["-shadow"], prefix: ["--shadow-"] },
78
81
  { kind: "padding", suffix: ["-padding", "-margin"] },
79
82
  { kind: "gap", suffix: ["-gap"] },
@@ -95,8 +98,7 @@ var KIND_RULES = [
95
98
  "-indicator",
96
99
  "-thumb",
97
100
  "-color",
98
- "-tint",
99
- "-opacity"
101
+ "-tint"
100
102
  ],
101
103
  prefix: ["--surface-", "--tint", "--color-"]
102
104
  }
@@ -1519,8 +1521,56 @@ var componentMigration_2026_09_13_sectiondividerSurface = {
1519
1521
  }
1520
1522
  };
1521
1523
 
1522
- // src/editor/core/themes/migrations/2026-09-13-cornerbadge-prefix.ts
1524
+ // src/editor/core/themes/migrations/2026-09-20-imagelightbox-scrim.ts
1523
1525
  var RENAMES7 = {
1526
+ "--imagelightbox-overlay-surface": "--imagelightbox-scrim-surface"
1527
+ };
1528
+ var componentMigration_2026_09_20_imagelightboxScrim = {
1529
+ id: "2026-09-20-imagelightbox-scrim",
1530
+ fromVersion: 35,
1531
+ toVersion: 36,
1532
+ appliesTo: "component-config",
1533
+ apply(rawVars, meta) {
1534
+ if (meta.component !== "imagelightbox") return { ...rawVars };
1535
+ const out = {};
1536
+ for (const [key, value] of Object.entries(rawVars)) {
1537
+ out[RENAMES7[key] ?? key] = value;
1538
+ }
1539
+ return out;
1540
+ }
1541
+ };
1542
+
1543
+ // src/editor/core/themes/migrations/2026-09-20-scrim-color-and-opacity.ts
1544
+ var STOPS = {
1545
+ "--scrim-low": "--scrim-opacity-low",
1546
+ "--scrim": "--scrim-opacity",
1547
+ "--scrim-high": "--scrim-opacity-high"
1548
+ };
1549
+ var SURFACE = /^--(imagelightbox|dialog)-scrim-surface$/;
1550
+ var componentMigration_2026_09_20_scrimColorAndOpacity = {
1551
+ id: "2026-09-20-scrim-color-and-opacity",
1552
+ fromVersion: 36,
1553
+ toVersion: 37,
1554
+ appliesTo: "component-config",
1555
+ apply(rawVars) {
1556
+ const out = {};
1557
+ for (const [key, value] of Object.entries(rawVars)) {
1558
+ const match = SURFACE.exec(key);
1559
+ if (!match) {
1560
+ out[key] = value;
1561
+ continue;
1562
+ }
1563
+ const stem = `--${match[1]}-scrim`;
1564
+ const stop = STOPS[value];
1565
+ out[`${stem}-color`] = stop ? "--scrim-color" : value;
1566
+ out[`${stem}-opacity`] = stop ?? "1";
1567
+ }
1568
+ return out;
1569
+ }
1570
+ };
1571
+
1572
+ // src/editor/core/themes/migrations/2026-09-13-cornerbadge-prefix.ts
1573
+ var RENAMES8 = {
1524
1574
  cornerbadge: {
1525
1575
  "--corner-badge-margin": "--cornerbadge-margin",
1526
1576
  "--corner-badge-outer-radius": "--cornerbadge-outer-radius",
@@ -1570,7 +1620,7 @@ var componentMigration_2026_09_13_cornerbadgePrefix = {
1570
1620
  toVersion: 32,
1571
1621
  appliesTo: "component-config",
1572
1622
  apply(rawVars, meta) {
1573
- const renames = meta.component ? RENAMES7[meta.component] : void 0;
1623
+ const renames = meta.component ? RENAMES8[meta.component] : void 0;
1574
1624
  if (!renames) return { ...rawVars };
1575
1625
  const out = {};
1576
1626
  for (const [key, value] of Object.entries(rawVars)) {
@@ -1581,7 +1631,7 @@ var componentMigration_2026_09_13_cornerbadgePrefix = {
1581
1631
  };
1582
1632
 
1583
1633
  // src/editor/core/themes/migrations/2026-09-13-toggle-label.ts
1584
- var RENAMES8 = {
1634
+ var RENAMES9 = {
1585
1635
  toggle: {
1586
1636
  "--toggle-label-text": "--toggle-label",
1587
1637
  "--toggle-disabled-label-text": "--toggle-disabled-label"
@@ -1593,7 +1643,7 @@ var componentMigration_2026_09_13_toggleLabel = {
1593
1643
  toVersion: 33,
1594
1644
  appliesTo: "component-config",
1595
1645
  apply(rawVars, meta) {
1596
- const renames = meta.component ? RENAMES8[meta.component] : void 0;
1646
+ const renames = meta.component ? RENAMES9[meta.component] : void 0;
1597
1647
  if (!renames) return { ...rawVars };
1598
1648
  const out = {};
1599
1649
  for (const [key, value] of Object.entries(rawVars)) {
@@ -1604,7 +1654,7 @@ var componentMigration_2026_09_13_toggleLabel = {
1604
1654
  };
1605
1655
 
1606
1656
  // src/editor/core/themes/migrations/2026-09-13-collapsiblesection-open.ts
1607
- var RENAMES9 = {
1657
+ var RENAMES10 = {
1608
1658
  collapsiblesection: {
1609
1659
  "--collapsiblesection-chromeless-expanded-padding": "--collapsiblesection-chromeless-open-padding",
1610
1660
  "--collapsiblesection-hairline-expanded-padding": "--collapsiblesection-hairline-open-padding",
@@ -1618,7 +1668,7 @@ var componentMigration_2026_09_13_collapsiblesectionOpen = {
1618
1668
  toVersion: 34,
1619
1669
  appliesTo: "component-config",
1620
1670
  apply(rawVars, meta) {
1621
- const renames = meta.component ? RENAMES9[meta.component] : void 0;
1671
+ const renames = meta.component ? RENAMES10[meta.component] : void 0;
1622
1672
  if (!renames) return { ...rawVars };
1623
1673
  const out = {};
1624
1674
  for (const [key, value] of Object.entries(rawVars)) {
@@ -1645,7 +1695,7 @@ var BADGE_SUFFIXES = [
1645
1695
  "icon-size"
1646
1696
  ];
1647
1697
  var CORNERBADGE_SUFFIXES = ["surface", "border", "text"];
1648
- var RENAMES10 = {
1698
+ var RENAMES11 = {
1649
1699
  badge: Object.fromEntries(
1650
1700
  BADGE_SUFFIXES.map((s) => [`--badge-primary-${s}`, `--badge-brand-${s}`])
1651
1701
  ),
@@ -1659,7 +1709,7 @@ var componentMigration_2026_09_13_badgeBrand = {
1659
1709
  toVersion: 35,
1660
1710
  appliesTo: "component-config",
1661
1711
  apply(rawVars, meta) {
1662
- const renames = meta.component ? RENAMES10[meta.component] : void 0;
1712
+ const renames = meta.component ? RENAMES11[meta.component] : void 0;
1663
1713
  if (!renames) return { ...rawVars };
1664
1714
  const out = {};
1665
1715
  for (const [key, value] of Object.entries(rawVars)) {
@@ -1713,7 +1763,9 @@ var MIGRATIONS = [
1713
1763
  componentMigration_2026_09_13_cornerbadgePrefix,
1714
1764
  componentMigration_2026_09_13_toggleLabel,
1715
1765
  componentMigration_2026_09_13_collapsiblesectionOpen,
1716
- componentMigration_2026_09_13_badgeBrand
1766
+ componentMigration_2026_09_13_badgeBrand,
1767
+ componentMigration_2026_09_20_imagelightboxScrim,
1768
+ componentMigration_2026_09_20_scrimColorAndOpacity
1717
1769
  ];
1718
1770
  function countFor(kind) {
1719
1771
  return MIGRATIONS.filter((m) => m.appliesTo === kind).length;
@@ -37,7 +37,7 @@ interface AdjustResult {
37
37
  }
38
38
  declare function adjustAliases(configs: Record<string, ComponentConfig>, ops: readonly AdjustOp[], now: string): AdjustResult;
39
39
 
40
- type TokenKind = 'surface' | 'border' | 'border-width' | 'hairline-width' | 'indicator-width' | 'radius' | 'track-height' | 'hairline-inset' | 'dot-size' | 'length' | 'blur' | 'scale' | 'shadow' | 'font-family' | 'font-weight' | 'font-size' | 'line-height' | 'letter-spacing' | 'padding' | 'gap' | 'duration' | 'easing' | 'text-color';
40
+ type TokenKind = 'surface' | 'border' | 'border-width' | 'hairline-width' | 'indicator-width' | 'radius' | 'track-height' | 'hairline-inset' | 'dot-size' | 'length' | 'blur' | 'scale' | 'opacity' | 'shadow' | 'font-family' | 'font-weight' | 'font-size' | 'line-height' | 'letter-spacing' | 'padding' | 'gap' | 'duration' | 'easing' | 'text-color';
41
41
  /** Side-aware kind test. Per-side paddings (`--card-default-body-padding-top`)
42
42
  are written by UIPaddingSelector and never declared as editor tokens, so
43
43
  `rawKind` never meets one; the CLI does, and they belong with their parent. */
@@ -37,7 +37,7 @@ interface AdjustResult {
37
37
  }
38
38
  declare function adjustAliases(configs: Record<string, ComponentConfig>, ops: readonly AdjustOp[], now: string): AdjustResult;
39
39
 
40
- type TokenKind = 'surface' | 'border' | 'border-width' | 'hairline-width' | 'indicator-width' | 'radius' | 'track-height' | 'hairline-inset' | 'dot-size' | 'length' | 'blur' | 'scale' | 'shadow' | 'font-family' | 'font-weight' | 'font-size' | 'line-height' | 'letter-spacing' | 'padding' | 'gap' | 'duration' | 'easing' | 'text-color';
40
+ type TokenKind = 'surface' | 'border' | 'border-width' | 'hairline-width' | 'indicator-width' | 'radius' | 'track-height' | 'hairline-inset' | 'dot-size' | 'length' | 'blur' | 'scale' | 'opacity' | 'shadow' | 'font-family' | 'font-weight' | 'font-size' | 'line-height' | 'letter-spacing' | 'padding' | 'gap' | 'duration' | 'easing' | 'text-color';
41
41
  /** Side-aware kind test. Per-side paddings (`--card-default-body-padding-top`)
42
42
  are written by UIPaddingSelector and never declared as editor tokens, so
43
43
  `rawKind` never meets one; the CLI does, and they belong with their parent. */
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  CURRENT_COMPONENT_SCHEMA_VERSION
3
- } from "../chunk-REBHE3ZM.js";
3
+ } from "../chunk-FD4FVDOC.js";
4
4
  import {
5
5
  readLiveTokensConfig,
6
6
  resolveDataDirs
@@ -42,6 +42,9 @@ var KIND_RULES = [
42
42
  { kind: "dot-size", suffix: ["-dot-size"] },
43
43
  { kind: "blur", suffix: ["-blur"], prefix: ["--blur-"] },
44
44
  { kind: "scale", suffix: ["-scale"], prefix: ["--scale-"] },
45
+ // A strength from 0 to 1 that the component mixes into a colour where it
46
+ // paints. A palette picker here writes a colour into a number.
47
+ { kind: "opacity", suffix: ["-opacity"], prefix: ["--scrim-opacity"] },
45
48
  { kind: "shadow", suffix: ["-shadow"], prefix: ["--shadow-"] },
46
49
  { kind: "padding", suffix: ["-padding", "-margin"] },
47
50
  { kind: "gap", suffix: ["-gap"] },
@@ -63,8 +66,7 @@ var KIND_RULES = [
63
66
  "-indicator",
64
67
  "-thumb",
65
68
  "-color",
66
- "-tint",
67
- "-opacity"
69
+ "-tint"
68
70
  ],
69
71
  prefix: ["--surface-", "--tint", "--color-"]
70
72
  }
@@ -639,6 +639,26 @@ var tokensCssMigration_2026_09_01_tintScale = {
639
639
  }
640
640
  };
641
641
 
642
+ // vite-plugin/tokensCssMigrations/migrations/2026-09-20-scrim-color-and-opacity.ts
643
+ var ENTRIES2 = [
644
+ { name: "--scrim-color", value: "rgb(20, 3, 0)" },
645
+ { name: "--scrim-opacity-low", value: "0.38" },
646
+ { name: "--scrim-opacity", value: "0.51" },
647
+ { name: "--scrim-opacity-high", value: "0.64" }
648
+ ];
649
+ var tokensCssMigration_2026_09_20_scrimColorAndOpacity = {
650
+ id: "2026-09-20-scrim-color-and-opacity",
651
+ kind: "additive",
652
+ description: "Add --scrim-color and --scrim-opacity-*; a scrim's colour and strength are separate tokens",
653
+ apply(css) {
654
+ return ensureScale(css, {
655
+ entries: ENTRIES2,
656
+ sectionComment: "Scrim colour and strength, which each screen mixes where it paints",
657
+ anchorPrefixes: ["--scrim"]
658
+ });
659
+ }
660
+ };
661
+
642
662
  // vite-plugin/files/dataPaths.ts
643
663
  var import_fs = __toESM(require("fs"), 1);
644
664
  var import_path = __toESM(require("path"), 1);
@@ -691,7 +711,8 @@ var TOKENS_CSS_MIGRATIONS = [
691
711
  tokensCssMigration_2026_08_27_editorialSizeSteps,
692
712
  tokensCssMigration_2026_08_27_editorialLargeSteps,
693
713
  tokensCssMigration_2026_09_01_scrimRename,
694
- tokensCssMigration_2026_09_01_tintScale
714
+ tokensCssMigration_2026_09_01_tintScale,
715
+ tokensCssMigration_2026_09_20_scrimColorAndOpacity
695
716
  ];
696
717
  function runTokensCssMigrations(css) {
697
718
  return foldMigrations(css, () => true);
@@ -13,7 +13,7 @@ import {
13
13
  runTokensCssMigrations,
14
14
  semverBumpType,
15
15
  validateTokensCss
16
- } from "../chunk-RFVYPNRO.js";
16
+ } from "../chunk-V2OVSC5Z.js";
17
17
  import "../chunk-7TQQTHI6.js";
18
18
  import {
19
19
  readLiveTokensConfig
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@motion-proto/live-tokens",
3
- "version": "0.82.0",
3
+ "version": "0.84.0",
4
4
  "type": "module",
5
5
  "description": "Design token editor with live CSS variable editing. Svelte 5 + Vite 8.",
6
6
  "keywords": [
@@ -199,6 +199,8 @@
199
199
  "collapse:theme": "node scripts/collapse-theme-to-default.mjs",
200
200
  "check:smoke-install": "bash scripts/smoke-install.sh",
201
201
  "check:smoke-create": "bash scripts/smoke-create.sh",
202
+ "eval": "bash scripts/eval.sh",
203
+ "build:eval-project": "bash scripts/build-eval-project.sh",
202
204
  "check:smoke-component-tests": "bash scripts/smoke-component-tests.sh",
203
205
  "check:smoke-page-tests": "bash scripts/smoke-page-tests.sh",
204
206
  "prepublishOnly": "npm run check:no-style-imports && npm run check:no-tooling-imports && npm run check:slot-prose && npm run check:overlay-portal && npm run check:editor-font-isolation && npm run check:component-defaults && npm run check:pages && npm run check:production-is-default && npm run check:docs-content && npm run build:lib && npm run check:token-contract && npm run check:preset-themes && npm run check:skills && npm run check:cli-strings && npm run check:skill-sources && npm run check:skill-atlas && npm run check:smoke-install && npm run check:smoke-create && npm run check:smoke-component-tests && npm run check:smoke-page-tests"
@@ -16,7 +16,8 @@
16
16
  // Button styling lives in Button.svelte — the dialog only owns its own chrome.
17
17
  const frameStates: Record<string, Token[]> = {
18
18
  scrim: [
19
- { label: 'scrim color', groupKey: 'surface', variable: '--dialog-scrim-surface' },
19
+ { label: 'scrim color', groupKey: 'surface', variable: '--dialog-scrim-color' },
20
+ { label: 'scrim opacity', variable: '--dialog-scrim-opacity' },
20
21
  ],
21
22
  dialog: [
22
23
  { label: 'surface color', variable: '--dialog-surface' },
@@ -15,7 +15,8 @@
15
15
  { label: 'tile shadow', variable: '--imagelightbox-tile-shadow' },
16
16
  ],
17
17
  overlay: [
18
- { label: 'backdrop color', groupKey: 'surface', variable: '--imagelightbox-overlay-surface' },
18
+ { label: 'scrim color', groupKey: 'surface', variable: '--imagelightbox-scrim-color' },
19
+ { label: 'scrim opacity', variable: '--imagelightbox-scrim-opacity' },
19
20
  ],
20
21
  chrome: [
21
22
  { label: 'surface color', groupKey: 'surface', variable: '--imagelightbox-chrome-surface' },
@@ -9,7 +9,7 @@
9
9
  import UIPaddingSelector from '../../ui/UIPaddingSelector.svelte';
10
10
  import UILetterSpacingSelector from '../../ui/UILetterSpacingSelector.svelte';
11
11
  import UIEasingSelector from '../../ui/UIEasingSelector.svelte';
12
- import { BLUR, BORDER_WIDTH, DOT_SIZE, DURATION, RADIUS, SCALE, SHADOW, TRACK_HEIGHT, HAIRLINE_INSET } from '../../ui/variantScales';
12
+ import { BLUR, BORDER_WIDTH, DOT_SIZE, DURATION, RADIUS, SCALE, SCRIM_OPACITY, SHADOW, TRACK_HEIGHT, HAIRLINE_INSET } from '../../ui/variantScales';
13
13
  import {
14
14
  editorState,
15
15
  getComponentPropertySiblings,
@@ -80,6 +80,7 @@
80
80
  'easing',
81
81
  'blur',
82
82
  'scale',
83
+ 'opacity',
83
84
  'shadow',
84
85
  'text-color',
85
86
  'surface',
@@ -160,6 +161,7 @@
160
161
  'easing': { component: UIEasingSelector },
161
162
  'blur': { component: UIVariantSelector, extra: () => ({ ...BLUR }) },
162
163
  'scale': { component: UIVariantSelector, extra: () => ({ ...SCALE }) },
164
+ 'opacity': { component: UIVariantSelector, extra: () => ({ ...SCRIM_OPACITY }) },
163
165
  'shadow': { component: UIVariantSelector, extra: () => ({ ...SHADOW }) },
164
166
  'surface': { component: UIPaletteSelector, extra: paletteExtra },
165
167
  'border': { component: UIPaletteSelector, extra: paletteExtra },
@@ -190,6 +192,7 @@
190
192
  'easing',
191
193
  'blur',
192
194
  'scale',
195
+ 'opacity',
193
196
  'shadow',
194
197
  'surface',
195
198
  'border-width',
@@ -1,14 +1,19 @@
1
- /** A component's catalogue entry: what it is, what to use it for, what not
2
- to use it for, and what any guidance-bearing prop's values mean. Exported
3
- as `catalogue` from the runtime file's `<script module>` block — the
4
- Svelte compiler drops a leading HTML comment before it reaches the
5
- running editor, so this is the one form every reader (CLI, registry,
6
- consumer) can read. */
1
+ /** A component's catalogue entry: what it is, what to use it for, what to use
2
+ instead, the rules of use, and what any guidance-bearing prop's values
3
+ mean. Exported as `catalogue` from the runtime file's `<script module>`
4
+ block — the Svelte compiler drops a leading HTML comment before it
5
+ reaches the running editor, so this is the one form every reader (CLI,
6
+ registry, consumer) can read. */
7
7
  export type CatalogueEntry = {
8
8
  /** One sentence: what the component is. */
9
9
  description: string;
10
- useFor: string;
11
- notFor: string;
10
+ /** The condition that makes this component the right one. */
11
+ whenToUse: string;
12
+ /** Each row rules the component out. `use` is the component id
13
+ (`table`, never `Table`) that fits instead. */
14
+ whenNotToUse: Array<{ when: string; use?: string }>;
15
+ /** Rules of use, one sentence each. */
16
+ constraints?: string[];
12
17
  /** Keyed by prop name; the value explains that prop's values. */
13
18
  props?: Record<string, string>;
14
19
  };
@@ -11,6 +11,7 @@ export type TokenKind =
11
11
  | 'length'
12
12
  | 'blur'
13
13
  | 'scale'
14
+ | 'opacity'
14
15
  | 'shadow'
15
16
  | 'font-family'
16
17
  | 'font-weight'
@@ -59,6 +60,9 @@ export const KIND_RULES: ReadonlyArray<{
59
60
  { kind: 'dot-size', suffix: ['-dot-size'] },
60
61
  { kind: 'blur', suffix: ['-blur'], prefix: ['--blur-'] },
61
62
  { kind: 'scale', suffix: ['-scale'], prefix: ['--scale-'] },
63
+ // A strength from 0 to 1 that the component mixes into a colour where it
64
+ // paints. A palette picker here writes a colour into a number.
65
+ { kind: 'opacity', suffix: ['-opacity'], prefix: ['--scrim-opacity'] },
62
66
  { kind: 'shadow', suffix: ['-shadow'], prefix: ['--shadow-'] },
63
67
  { kind: 'padding', suffix: ['-padding', '-margin'] },
64
68
  { kind: 'gap', suffix: ['-gap'] },
@@ -73,7 +77,7 @@ export const KIND_RULES: ReadonlyArray<{
73
77
  // Fills. A tint is a wash over a surface, so it takes the surface picker: the
74
78
  // full palette with an alpha, not just the tint stops it defaults to.
75
79
  { kind: 'surface', suffix: ['-surface', '-fill', '-indicator',
76
- '-thumb', '-color', '-tint', '-opacity'],
80
+ '-thumb', '-color', '-tint'],
77
81
  prefix: ['--surface-', '--tint', '--color-'] },
78
82
  ];
79
83
 
@@ -186,7 +186,7 @@ const PART_SPECS: readonly PartSpec[] = [
186
186
  { sel: '.image-lightbox-thumb', stem: 'imagelightbox-tile', positioned: true, clips: true },
187
187
  // A fixed full-viewport scrim behind the open modal; no border of its own.
188
188
  {
189
- sel: '.image-lightbox-overlay', fill: 'var(--imagelightbox-overlay-surface)',
189
+ sel: '.image-lightbox-overlay', fill: 'color-mix(in srgb, var(--imagelightbox-scrim-color) calc(var(--imagelightbox-scrim-opacity) * 100%), transparent)',
190
190
  stroke: 'transparent', positioned: true, unmasked: true,
191
191
  },
192
192
  // Close and the two nav chevrons all carry this class; each is fixed and
@@ -0,0 +1,28 @@
1
+ import type { Migration } from './index';
2
+
3
+ /**
4
+ * One word for the layer that dims the page (2026-09-20).
5
+ *
6
+ * Dialog called it a scrim and read the `--scrim-*` scale; ImageLightbox called
7
+ * the same layer an overlay and mixed its own colour. The token scale settles
8
+ * the word, so the key reads `-scrim-surface`. The chrome tokens keep their own
9
+ * names: they paint the toolbar, not the layer behind it.
10
+ */
11
+ const RENAMES: Record<string, string> = {
12
+ '--imagelightbox-overlay-surface': '--imagelightbox-scrim-surface',
13
+ };
14
+
15
+ export const componentMigration_2026_09_20_imagelightboxScrim: Migration = {
16
+ id: '2026-09-20-imagelightbox-scrim',
17
+ fromVersion: 35,
18
+ toVersion: 36,
19
+ appliesTo: 'component-config',
20
+ apply(rawVars, meta) {
21
+ if (meta.component !== 'imagelightbox') return { ...rawVars };
22
+ const out: Record<string, string> = {};
23
+ for (const [key, value] of Object.entries(rawVars)) {
24
+ out[RENAMES[key] ?? key] = value;
25
+ }
26
+ return out;
27
+ },
28
+ };
@@ -0,0 +1,45 @@
1
+ import type { Migration } from './index';
2
+
3
+ /**
4
+ * A scrim's colour and its strength, apart (2026-09-20).
5
+ *
6
+ * `-scrim-surface` held one composed fill, so a theme that wanted a paler
7
+ * screen had to restate the colour to change the strength, and a light scrim
8
+ * meant hand-writing a `color-mix()`. The pair splits them: `-scrim-color`
9
+ * takes any colour, `-scrim-opacity` how much of it covers the page.
10
+ *
11
+ * The three `--scrim-*` stops still exist, composed from the two, so a value
12
+ * that named one maps to that stop's opacity and the scale's colour. Anything
13
+ * else was a hand-written fill: it becomes the colour, at full strength, which
14
+ * preserves what a reader saw when the old value was already opaque and
15
+ * otherwise leaves a value a person chose rather than guessing at its alpha.
16
+ */
17
+ const STOPS: Record<string, string> = {
18
+ '--scrim-low': '--scrim-opacity-low',
19
+ '--scrim': '--scrim-opacity',
20
+ '--scrim-high': '--scrim-opacity-high',
21
+ };
22
+
23
+ const SURFACE = /^--(imagelightbox|dialog)-scrim-surface$/;
24
+
25
+ export const componentMigration_2026_09_20_scrimColorAndOpacity: Migration = {
26
+ id: '2026-09-20-scrim-color-and-opacity',
27
+ fromVersion: 36,
28
+ toVersion: 37,
29
+ appliesTo: 'component-config',
30
+ apply(rawVars) {
31
+ const out: Record<string, string> = {};
32
+ for (const [key, value] of Object.entries(rawVars)) {
33
+ const match = SURFACE.exec(key);
34
+ if (!match) {
35
+ out[key] = value;
36
+ continue;
37
+ }
38
+ const stem = `--${match[1]}-scrim`;
39
+ const stop = STOPS[value];
40
+ out[`${stem}-color`] = stop ? '--scrim-color' : value;
41
+ out[`${stem}-opacity`] = stop ?? '1';
42
+ }
43
+ return out;
44
+ },
45
+ };
@@ -79,6 +79,8 @@ import { componentMigration_2026_09_13_selectedState } from './2026-09-13-select
79
79
  import { componentMigration_2026_09_13_hairline } from './2026-09-13-hairline';
80
80
  import { componentMigration_2026_09_13_indicator } from './2026-09-13-indicator';
81
81
  import { componentMigration_2026_09_13_sectiondividerSurface } from './2026-09-13-sectiondivider-surface';
82
+ import { componentMigration_2026_09_20_imagelightboxScrim } from './2026-09-20-imagelightbox-scrim';
83
+ import { componentMigration_2026_09_20_scrimColorAndOpacity } from './2026-09-20-scrim-color-and-opacity';
82
84
  import { componentMigration_2026_09_13_cornerbadgePrefix } from './2026-09-13-cornerbadge-prefix';
83
85
  import { componentMigration_2026_09_13_toggleLabel } from './2026-09-13-toggle-label';
84
86
  import { componentMigration_2026_09_13_collapsiblesectionOpen } from './2026-09-13-collapsiblesection-open';
@@ -132,6 +134,8 @@ export const MIGRATIONS: Migration[] = [
132
134
  componentMigration_2026_09_13_toggleLabel,
133
135
  componentMigration_2026_09_13_collapsiblesectionOpen,
134
136
  componentMigration_2026_09_13_badgeBrand,
137
+ componentMigration_2026_09_20_imagelightboxScrim,
138
+ componentMigration_2026_09_20_scrimColorAndOpacity,
135
139
  ];
136
140
 
137
141
  function countFor(kind: 'colors-and-type' | 'component-config'): number {
@@ -46,6 +46,9 @@ component in the editor and confirm everything works.
46
46
 
47
47
  - A runtime component whose editable properties default to your theme tokens.
48
48
  - An editor entry that appears under **Custom** in the `/live-tokens/components` view.
49
+ - A catalogue entry in the runtime file that says what the component is for and
50
+ what to use instead. `npx live-tokens components` prints it, and the skills
51
+ read it when they choose a component for a page.
49
52
  - The naming and wiring handled for you, so the component fits the system.
50
53
 
51
54
  Advanced authors who want to write a component by hand can read the naming and