@motion-proto/live-tokens 0.84.0 → 0.86.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 (87) hide show
  1. package/.claude/skills/live-tokens-create-component/references/token-naming.md +0 -1
  2. package/CHANGELOG.md +85 -0
  3. package/README.md +1 -1
  4. package/dist-plugin/{chunk-V2OVSC5Z.js → chunk-GWMEYBZ2.js} +22 -1
  5. package/dist-plugin/{chunk-FD4FVDOC.js → chunk-ONYAIXCZ.js} +74 -1
  6. package/dist-plugin/{chunk-M6BWSS6C.js → chunk-W5VQV32K.js} +1 -1
  7. package/dist-plugin/index.cjs +101 -7
  8. package/dist-plugin/index.js +3 -3
  9. package/dist-plugin/migrateData/index.cjs +78 -5
  10. package/dist-plugin/migrateData/index.js +2 -2
  11. package/dist-plugin/setColors/index.cjs +74 -1
  12. package/dist-plugin/setColors/index.js +1 -1
  13. package/dist-plugin/setGeometry/index.cjs +74 -4
  14. package/dist-plugin/setGeometry/index.d.cts +1 -1
  15. package/dist-plugin/setGeometry/index.d.ts +1 -1
  16. package/dist-plugin/setGeometry/index.js +1 -4
  17. package/dist-plugin/tokensCssMigrations/index.cjs +22 -1
  18. package/dist-plugin/tokensCssMigrations/index.js +1 -1
  19. package/package.json +1 -1
  20. package/src/editor/component-editor/DialogEditor.svelte +1 -2
  21. package/src/editor/component-editor/ImageLightboxEditor.svelte +1 -2
  22. package/src/editor/component-editor/SlidePagerEditor.svelte +118 -0
  23. package/src/editor/component-editor/VideoFrameEditor.svelte +73 -0
  24. package/src/editor/component-editor/VideoLightboxEditor.svelte +95 -0
  25. package/src/editor/component-editor/registry.ts +40 -1
  26. package/src/editor/component-editor/scaffolding/TokenLayout.svelte +1 -4
  27. package/src/editor/core/components/aliasKinds.ts +0 -4
  28. package/src/editor/core/sketch/sketchLayer.ts +8 -1
  29. package/src/editor/core/store/editorPersistence.ts +46 -23
  30. package/src/editor/core/store/editorStore.ts +1 -5
  31. package/src/editor/core/store/editorTypes.ts +11 -7
  32. package/src/editor/core/themes/migrations/2026-09-21-scrim-surface.ts +56 -0
  33. package/src/editor/core/themes/migrations/2026-09-21-wash-color-and-opacity.ts +51 -0
  34. package/src/editor/core/themes/migrations/index.ts +4 -0
  35. package/src/editor/core/themes/slices/washes.ts +59 -77
  36. package/src/editor/overlay/LiveEditorOverlay.svelte +45 -52
  37. package/src/editor/pages/ComponentEditorPage.svelte +1 -1
  38. package/src/editor/skill-atlas/skillSources.generated.ts +1 -1
  39. package/src/editor/ui/ThemePanel.svelte +9 -53
  40. package/src/editor/ui/UIPaletteSelector.svelte +5 -1
  41. package/src/editor/ui/UIVariantSelector.svelte +1 -1
  42. package/src/editor/ui/sections/WashesSection.svelte +100 -99
  43. package/src/editor/ui/variantScales.ts +0 -11
  44. package/src/live-tokens/data/colors-and-type/autumn.json +9 -7
  45. package/src/live-tokens/data/colors-and-type/default.json +9 -7
  46. package/src/live-tokens/data/colors-and-type/halloween.json +9 -7
  47. package/src/live-tokens/data/colors-and-type/midnight-study.json +9 -7
  48. package/src/live-tokens/data/colors-and-type/ocean.json +9 -7
  49. package/src/live-tokens/data/colors-and-type/royal-velvet.json +9 -7
  50. package/src/live-tokens/data/colors-and-type/sketchy.json +9 -7
  51. package/src/live-tokens/data/colors-and-type/spring-meadow.json +9 -7
  52. package/src/live-tokens/data/colors-and-type/sunset.json +9 -7
  53. package/src/live-tokens/data/themes/autumn.json +98 -12
  54. package/src/live-tokens/data/themes/halloween.json +98 -12
  55. package/src/live-tokens/data/themes/midnight-study.json +98 -12
  56. package/src/live-tokens/data/themes/ocean.json +98 -12
  57. package/src/live-tokens/data/themes/royal-velvet.json +98 -12
  58. package/src/live-tokens/data/themes/sketchy.json +98 -12
  59. package/src/live-tokens/data/themes/spring-meadow.json +98 -12
  60. package/src/live-tokens/data/themes/sunset.json +98 -12
  61. package/src/live-tokens/data/tokens.generated.css +8 -6
  62. package/src/system/assets/slide-04.webp +0 -0
  63. package/src/system/assets/slide-05.webp +0 -0
  64. package/src/system/assets/slide-06.webp +0 -0
  65. package/src/system/assets/watch-navigation-poster.webp +0 -0
  66. package/src/system/assets/watch-navigation.mp4 +0 -0
  67. package/src/system/components/Dialog.svelte +2 -7
  68. package/src/system/components/ImageLightbox.svelte +27 -39
  69. package/src/system/components/SlidePager.svelte +516 -0
  70. package/src/system/components/VideoFrame.svelte +284 -0
  71. package/src/system/components/VideoLightbox.svelte +381 -0
  72. package/src/system/styles/tokens.css +13 -8
  73. package/src/testing-js/{chunk-WQJ6QB6Y.js → chunk-OHU5BHGZ.js} +347 -9
  74. package/src/testing-js/chunk-OHU5BHGZ.js.map +1 -0
  75. package/src/testing-js/{chunk-XXABJNUU.js → chunk-Y6R7Z7VK.js} +10 -6
  76. package/src/testing-js/chunk-Y6R7Z7VK.js.map +1 -0
  77. package/src/testing-js/component-behavior.contract.js +1 -1
  78. package/src/testing-js/component-editor.contract.js +1 -1
  79. package/src/testing-js/component-render.contract.js +1 -1
  80. package/src/testing-js/index.d.ts +2 -2
  81. package/src/testing-js/index.js +2 -2
  82. package/src/testing-js/page-compliance.contract.js +1 -1
  83. package/src/testing-js/{vitest-BMLIbDs2.d.ts → vitest-5vWtqwWe.d.ts} +2 -2
  84. package/src/testing-js/vitest.d.ts +1 -1
  85. package/src/testing-js/vitest.js +2 -2
  86. package/src/testing-js/chunk-WQJ6QB6Y.js.map +0 -1
  87. package/src/testing-js/chunk-XXABJNUU.js.map +0 -1
@@ -19,7 +19,6 @@ to that list, so the two cannot drift apart.
19
19
  | `-fill` | Inner fill (distinct from outer surface) |
20
20
  | `-color` | A hairline rule's colour, or a color no role word above names |
21
21
  | `-shadow` | Box-shadow |
22
- | `-opacity` | Opacity (0–1) |
23
22
  | `-blur` | Backdrop or filter blur radius |
24
23
  | `-tint` | A wash over the surface, aliasing a `--tint-*` stop |
25
24
  | `-indicator` | The colour of the bar or stripe that marks an item |
package/CHANGELOG.md CHANGED
@@ -1,5 +1,90 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.86.0 — Video and slides ship as components
4
+
5
+ ### Added
6
+
7
+ - **VideoLightbox.** A still that fades the page away and plays its clip in
8
+ the middle of the screen. A click anywhere, the close button, or Escape
9
+ closes it. Tile, scrim, and close-button chrome are editable, with a hover
10
+ state for the close button. Every shipped theme carries it, derived from
11
+ that theme's ImageLightbox so the two match.
12
+
13
+ - **VideoFrame.** It plays a clip in place from a poster frame, with a play
14
+ badge or no chrome at all, and falls back to the poster when the clip is
15
+ not served.
16
+
17
+ - **SlidePager.** It flips a deck of slides in place. Its full-screen view
18
+ pages through every slide with the same bar and the arrow keys, and has a
19
+ close button and Tab stops on its controls. Its chevrons are inline SVG, so
20
+ it needs no icon font.
21
+
22
+ Every shipped theme carries VideoFrame and SlidePager, with frame corners
23
+ and borders taken from that theme's ImageLightbox and Card. The catalogue
24
+ entries of the four media components point to each other.
25
+
26
+ ### Changed
27
+
28
+ - **Every ImageLightbox shows a close button.** A plain lightbox closed only
29
+ on a click, and nothing on screen said so. The close button now renders for
30
+ every lightbox and holds focus when the modal opens. An extended lightbox
31
+ also closes on a click to its unzoomed image; zoomed, a click still pans.
32
+
33
+ - **The editor overlay picks the active page from a dropdown.** The theme
34
+ panel's Components and Sketchstyle rows lose their Open buttons, since the
35
+ view switcher at the top of the panel already opens both. The font pairing
36
+ moves into the Colors & Type info box.
37
+
38
+ ### Fixed
39
+
40
+ - **`check-component --tests` collects only the installed package's
41
+ contracts.** `createVitestConfig` globbed the whole project, so a nested
42
+ project with its own copy of the package in `node_modules` added that
43
+ copy's contracts to the run, and they failed against this project's
44
+ registry. The default now scans the contract files' own directory, the way
45
+ `createPlaywrightConfig` already did.
46
+
47
+ ## 0.85.0 — A theme's scrims and tints are a colour and three strengths
48
+
49
+ ### Changed
50
+
51
+ - **The theme stores each wash family as a colour and three opacity stops.**
52
+ It writes `--scrim-color` with `--scrim-opacity-low`, `--scrim-opacity`, and
53
+ `--scrim-opacity-high`, and the same four for tints. It no longer writes the
54
+ composed `--scrim-*` and `--tint-*` fills. From 0.84.0 Dialog and
55
+ ImageLightbox read `--scrim-color` and `--scrim-opacity-*`, and themes never
56
+ set them, so a theme's scrim reached neither screen. The Washes section edits
57
+ one colour per family and a slider per stop. Migration
58
+ `2026-09-21-wash-color-and-opacity` splits the composed fills in a saved
59
+ theme. A fill that is not a `color-mix()` of one token stays as written.
60
+
61
+ - **Scrims default to 70%, 80%, and 90%.** They were 38%, 51%, and 64%. The
62
+ shipped themes use the new stops, and their ImageLightbox scrims read
63
+ `--scrim-high` instead of a hand-written fill. Tints stay at 5%, 10%, and 15%.
64
+
65
+ ### Changed (breaking)
66
+
67
+ - **Dialog and ImageLightbox each take one scrim fill again,
68
+ `-scrim-surface`, defaulting to `--scrim-high`.** The theme composes each
69
+ `--scrim-*` stop from its colour and strength, so a screen picks a stop the
70
+ way a hover picks a `--tint-*` stop. `-scrim-color` and `-scrim-opacity`
71
+ are gone. ImageLightbox's `scrim` prop takes any CSS fill, such as
72
+ `var(--scrim-low)`, and `scrimOpacity` is gone. Migration
73
+ `2026-09-21-scrim-surface` folds a saved pair into one value: the scale's
74
+ colour at one of its strengths becomes that stop, and any other pair becomes
75
+ the `color-mix()` the screen painted. The editor's `opacity` property kind
76
+ and its stop picker go with them, since no other property used them.
77
+
78
+ ### Added
79
+
80
+ - **`--tint-color` and `--tint-opacity-low`, `--tint-opacity`,
81
+ `--tint-opacity-high`.** tokens.css composes the three `--tint-*` stops from
82
+ them. The additive tokens-css migration `2026-09-21-tint-color-and-opacity`
83
+ inserts the four names into an existing `tokens.css`. The stops already in
84
+ that file keep their values; to have them follow `--tint-color`, write each
85
+ as `color-mix(in srgb, var(--tint-color) calc(var(--tint-opacity) * 100%), transparent)`
86
+ with its own opacity stop.
87
+
3
88
  ## 0.84.0 — A scrim's colour and strength are separate tokens
4
89
 
5
90
  ### Added
package/README.md CHANGED
@@ -11,7 +11,7 @@ The editor is dev-only. Production builds get plain CSS variables and the compon
11
11
  ## Features
12
12
 
13
13
  - **Live token editing.** Colors, typography, spacing, radii, shadows, motion, palettes, and gradients. Every input writes a CSS variable, so the page repaints with no reload and no build step.
14
- - **Live component editing.** 26 shipped Svelte components (Button, IconButton, Input, Card, Dialog, Badge, Callout, Table, Tooltip, Toggle, TabBar, SegmentedControl, RadioButton, MenuSelect, ProgressBar, CornerBadge, SectionDivider, CollapsibleSection, Notification, Image, ImageLightbox, CodeSnippet, SideNavigation, Panel, InlineEditActions, Slider) declare their design-token aliases in a `:global(:root)` block. Rewire an alias from the component's editor and it updates everywhere that component is used, on your real pages.
14
+ - **Live component editing.** 29 shipped Svelte components (Button, IconButton, Input, Card, Dialog, Badge, Callout, Table, Tooltip, Toggle, TabBar, SegmentedControl, RadioButton, MenuSelect, ProgressBar, CornerBadge, SectionDivider, CollapsibleSection, Notification, Image, ImageLightbox, VideoLightbox, VideoFrame, SlidePager, CodeSnippet, SideNavigation, Panel, InlineEditActions, Slider) declare their design-token aliases in a `:global(:root)` block. Rewire an alias from the component's editor and it updates everywhere that component is used, on your real pages.
15
15
  - **Four dev-only routes.** `/live-tokens/editor` for tokens, `/live-tokens/colors` for palettes, `/live-tokens/components` for per-component aliases, `/live-tokens/docs` for the user guide.
16
16
  - **Editor overlay.** Pins to the top right of every dev page and opens the editor in a side panel or floating window, so you edit on the page you are styling. Its "Page Source" button opens the current page's `.svelte` file in VS Code.
17
17
  - **Themes.** A theme is a whole look in one file: colors and type plus a config for every component, stored by value. Loading one changes a single pointer file, and nothing your site ships changes until you Adopt. Export a theme and import it into another project to restore the look in one step.
@@ -572,6 +572,26 @@ var tokensCssMigration_2026_09_20_scrimColorAndOpacity = {
572
572
  }
573
573
  };
574
574
 
575
+ // vite-plugin/tokensCssMigrations/migrations/2026-09-21-tint-color-and-opacity.ts
576
+ var ENTRIES3 = [
577
+ { name: "--tint-color", value: "rgb(255, 255, 255)" },
578
+ { name: "--tint-opacity-low", value: "0.05" },
579
+ { name: "--tint-opacity", value: "0.1" },
580
+ { name: "--tint-opacity-high", value: "0.15" }
581
+ ];
582
+ var tokensCssMigration_2026_09_21_tintColorAndOpacity = {
583
+ id: "2026-09-21-tint-color-and-opacity",
584
+ kind: "additive",
585
+ description: "Add --tint-color and --tint-opacity-*; a tint's colour and strength are separate tokens",
586
+ apply(css) {
587
+ return ensureScale(css, {
588
+ entries: ENTRIES3,
589
+ sectionComment: "Tint colour and strength, which the --tint-* stops compose",
590
+ anchorPrefixes: ["--tint"]
591
+ });
592
+ }
593
+ };
594
+
575
595
  // vite-plugin/tokensCssMigrations/index.ts
576
596
  var TOKENS_CSS_MIGRATIONS = [
577
597
  tokensCssMigration_2026_05_29_typographyScaleAdditions,
@@ -589,7 +609,8 @@ var TOKENS_CSS_MIGRATIONS = [
589
609
  tokensCssMigration_2026_08_27_editorialLargeSteps,
590
610
  tokensCssMigration_2026_09_01_scrimRename,
591
611
  tokensCssMigration_2026_09_01_tintScale,
592
- tokensCssMigration_2026_09_20_scrimColorAndOpacity
612
+ tokensCssMigration_2026_09_20_scrimColorAndOpacity,
613
+ tokensCssMigration_2026_09_21_tintColorAndOpacity
593
614
  ];
594
615
  function runTokensCssMigrations(css) {
595
616
  return foldMigrations(css, () => true);
@@ -1224,6 +1224,77 @@ var componentMigration_2026_09_20_scrimColorAndOpacity = {
1224
1224
  }
1225
1225
  };
1226
1226
 
1227
+ // src/editor/core/themes/migrations/2026-09-21-wash-color-and-opacity.ts
1228
+ var FAMILIES = ["scrim", "tint"];
1229
+ var COLOR_MIX_RE = /^color-mix\(in srgb,\s*var\((--[a-z0-9-]+)\)\s+(\d+(?:\.\d+)?)%,\s*transparent\)$/i;
1230
+ var PLAIN_VAR_RE = /^var\((--[a-z0-9-]+)\)$/i;
1231
+ function parseFill(raw) {
1232
+ const s = raw.trim();
1233
+ const mix = s.match(COLOR_MIX_RE);
1234
+ if (mix) return { color: mix[1], opacity: Math.min(100, Number(mix[2])) / 100 };
1235
+ const plain = s.match(PLAIN_VAR_RE);
1236
+ return plain ? { color: plain[1], opacity: 1 } : null;
1237
+ }
1238
+ var colorsAndTypeMigration_2026_09_21_washColorAndOpacity = {
1239
+ id: "2026-09-21-wash-color-and-opacity",
1240
+ fromVersion: 8,
1241
+ toVersion: 9,
1242
+ appliesTo: "colors-and-type",
1243
+ apply(rawVars) {
1244
+ const out = { ...rawVars };
1245
+ for (const family of FAMILIES) {
1246
+ let color = null;
1247
+ for (const suffix of ["", "-low", "-high"]) {
1248
+ const key = `--${family}${suffix}`;
1249
+ const parsed = out[key] === void 0 ? null : parseFill(out[key]);
1250
+ if (!parsed) continue;
1251
+ color ??= parsed.color;
1252
+ out[`--${family}-opacity${suffix}`] = String(parsed.opacity);
1253
+ delete out[key];
1254
+ }
1255
+ if (color) out[`--${family}-color`] = `var(${color})`;
1256
+ }
1257
+ return out;
1258
+ }
1259
+ };
1260
+
1261
+ // src/editor/core/themes/migrations/2026-09-21-scrim-surface.ts
1262
+ var STOPS2 = {
1263
+ "--scrim-opacity-low": "--scrim-low",
1264
+ "--scrim-opacity": "--scrim",
1265
+ "--scrim-opacity-high": "--scrim-high"
1266
+ };
1267
+ var PAIR = /^--(imagelightbox|dialog)-scrim-(color|opacity)$/;
1268
+ var ref = (value) => value.startsWith("--") ? `var(${value})` : value;
1269
+ function fill(color, opacity) {
1270
+ if (color === "--scrim-color" && STOPS2[opacity]) return STOPS2[opacity];
1271
+ if (opacity === "1") return color;
1272
+ const pct = Number.isFinite(Number(opacity)) ? `${Number(opacity) * 100}%` : `calc(${ref(opacity)} * 100%)`;
1273
+ return `color-mix(in srgb, ${ref(color)} ${pct}, transparent)`;
1274
+ }
1275
+ var componentMigration_2026_09_21_scrimSurface = {
1276
+ id: "2026-09-21-scrim-surface",
1277
+ fromVersion: 37,
1278
+ toVersion: 38,
1279
+ appliesTo: "component-config",
1280
+ apply(rawVars) {
1281
+ const out = {};
1282
+ const pairs = {};
1283
+ for (const [key, value] of Object.entries(rawVars)) {
1284
+ const match = PAIR.exec(key);
1285
+ if (!match) {
1286
+ out[key] = value;
1287
+ continue;
1288
+ }
1289
+ (pairs[match[1]] ??= {})[match[2]] = value;
1290
+ }
1291
+ for (const [id, { color = "--scrim-color", opacity = "--scrim-opacity-high" }] of Object.entries(pairs)) {
1292
+ out[`--${id}-scrim-surface`] = fill(color, opacity);
1293
+ }
1294
+ return out;
1295
+ }
1296
+ };
1297
+
1227
1298
  // src/editor/core/themes/migrations/2026-09-13-cornerbadge-prefix.ts
1228
1299
  var RENAMES8 = {
1229
1300
  cornerbadge: {
@@ -1420,7 +1491,9 @@ var MIGRATIONS = [
1420
1491
  componentMigration_2026_09_13_collapsiblesectionOpen,
1421
1492
  componentMigration_2026_09_13_badgeBrand,
1422
1493
  componentMigration_2026_09_20_imagelightboxScrim,
1423
- componentMigration_2026_09_20_scrimColorAndOpacity
1494
+ componentMigration_2026_09_20_scrimColorAndOpacity,
1495
+ colorsAndTypeMigration_2026_09_21_washColorAndOpacity,
1496
+ componentMigration_2026_09_21_scrimSurface
1424
1497
  ];
1425
1498
  function countFor(kind) {
1426
1499
  return MIGRATIONS.filter((m) => m.appliesTo === kind).length;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  CURRENT_COMPONENT_SCHEMA_VERSION,
3
3
  runMigrations
4
- } from "./chunk-FD4FVDOC.js";
4
+ } from "./chunk-ONYAIXCZ.js";
5
5
 
6
6
  // vite-plugin/files/versionedFileResourceServer.ts
7
7
  import fs from "fs";
@@ -2008,6 +2008,77 @@ var componentMigration_2026_09_20_scrimColorAndOpacity = {
2008
2008
  }
2009
2009
  };
2010
2010
 
2011
+ // src/editor/core/themes/migrations/2026-09-21-wash-color-and-opacity.ts
2012
+ var FAMILIES = ["scrim", "tint"];
2013
+ var COLOR_MIX_RE = /^color-mix\(in srgb,\s*var\((--[a-z0-9-]+)\)\s+(\d+(?:\.\d+)?)%,\s*transparent\)$/i;
2014
+ var PLAIN_VAR_RE = /^var\((--[a-z0-9-]+)\)$/i;
2015
+ function parseFill(raw) {
2016
+ const s = raw.trim();
2017
+ const mix = s.match(COLOR_MIX_RE);
2018
+ if (mix) return { color: mix[1], opacity: Math.min(100, Number(mix[2])) / 100 };
2019
+ const plain = s.match(PLAIN_VAR_RE);
2020
+ return plain ? { color: plain[1], opacity: 1 } : null;
2021
+ }
2022
+ var colorsAndTypeMigration_2026_09_21_washColorAndOpacity = {
2023
+ id: "2026-09-21-wash-color-and-opacity",
2024
+ fromVersion: 8,
2025
+ toVersion: 9,
2026
+ appliesTo: "colors-and-type",
2027
+ apply(rawVars) {
2028
+ const out = { ...rawVars };
2029
+ for (const family of FAMILIES) {
2030
+ let color = null;
2031
+ for (const suffix of ["", "-low", "-high"]) {
2032
+ const key = `--${family}${suffix}`;
2033
+ const parsed = out[key] === void 0 ? null : parseFill(out[key]);
2034
+ if (!parsed) continue;
2035
+ color ??= parsed.color;
2036
+ out[`--${family}-opacity${suffix}`] = String(parsed.opacity);
2037
+ delete out[key];
2038
+ }
2039
+ if (color) out[`--${family}-color`] = `var(${color})`;
2040
+ }
2041
+ return out;
2042
+ }
2043
+ };
2044
+
2045
+ // src/editor/core/themes/migrations/2026-09-21-scrim-surface.ts
2046
+ var STOPS2 = {
2047
+ "--scrim-opacity-low": "--scrim-low",
2048
+ "--scrim-opacity": "--scrim",
2049
+ "--scrim-opacity-high": "--scrim-high"
2050
+ };
2051
+ var PAIR = /^--(imagelightbox|dialog)-scrim-(color|opacity)$/;
2052
+ var ref = (value) => value.startsWith("--") ? `var(${value})` : value;
2053
+ function fill(color, opacity) {
2054
+ if (color === "--scrim-color" && STOPS2[opacity]) return STOPS2[opacity];
2055
+ if (opacity === "1") return color;
2056
+ const pct = Number.isFinite(Number(opacity)) ? `${Number(opacity) * 100}%` : `calc(${ref(opacity)} * 100%)`;
2057
+ return `color-mix(in srgb, ${ref(color)} ${pct}, transparent)`;
2058
+ }
2059
+ var componentMigration_2026_09_21_scrimSurface = {
2060
+ id: "2026-09-21-scrim-surface",
2061
+ fromVersion: 37,
2062
+ toVersion: 38,
2063
+ appliesTo: "component-config",
2064
+ apply(rawVars) {
2065
+ const out = {};
2066
+ const pairs = {};
2067
+ for (const [key, value] of Object.entries(rawVars)) {
2068
+ const match = PAIR.exec(key);
2069
+ if (!match) {
2070
+ out[key] = value;
2071
+ continue;
2072
+ }
2073
+ (pairs[match[1]] ??= {})[match[2]] = value;
2074
+ }
2075
+ for (const [id, { color = "--scrim-color", opacity = "--scrim-opacity-high" }] of Object.entries(pairs)) {
2076
+ out[`--${id}-scrim-surface`] = fill(color, opacity);
2077
+ }
2078
+ return out;
2079
+ }
2080
+ };
2081
+
2011
2082
  // src/editor/core/themes/migrations/2026-09-13-cornerbadge-prefix.ts
2012
2083
  var RENAMES8 = {
2013
2084
  cornerbadge: {
@@ -2204,7 +2275,9 @@ var MIGRATIONS = [
2204
2275
  componentMigration_2026_09_13_collapsiblesectionOpen,
2205
2276
  componentMigration_2026_09_13_badgeBrand,
2206
2277
  componentMigration_2026_09_20_imagelightboxScrim,
2207
- componentMigration_2026_09_20_scrimColorAndOpacity
2278
+ componentMigration_2026_09_20_scrimColorAndOpacity,
2279
+ colorsAndTypeMigration_2026_09_21_washColorAndOpacity,
2280
+ componentMigration_2026_09_21_scrimSurface
2208
2281
  ];
2209
2282
  function countFor(kind) {
2210
2283
  return MIGRATIONS.filter((m) => m.appliesTo === kind).length;
@@ -2551,7 +2624,7 @@ function migrateComponentConfig(component, aliasesIn, rawConfig, fileVersion) {
2551
2624
  config: configOut
2552
2625
  };
2553
2626
  }
2554
- var FAMILIES = ["canvas", "neutral", "alternate", "primary", "accent", "special"];
2627
+ var FAMILIES2 = ["canvas", "neutral", "alternate", "primary", "accent", "special"];
2555
2628
  var SIZE_VARIANTS = ["lg", "md", "sm"];
2556
2629
  function renameSectionDividerObjectSlots(objectPart) {
2557
2630
  const canvasSourceKeys = [
@@ -2569,7 +2642,7 @@ function renameSectionDividerObjectSlots(objectPart) {
2569
2642
  const out = {};
2570
2643
  for (const [key, value] of Object.entries(objectPart)) {
2571
2644
  let isFamilyGradient = false;
2572
- for (const f of FAMILIES) {
2645
+ for (const f of FAMILIES2) {
2573
2646
  if (key === `--sectiondivider-${f}-background` || key === `--sectiondivider-${f}-gradient` || key === `--sectiondivider-color-${f}-background`) {
2574
2647
  isFamilyGradient = true;
2575
2648
  break;
@@ -3933,6 +4006,26 @@ var tokensCssMigration_2026_09_20_scrimColorAndOpacity = {
3933
4006
  }
3934
4007
  };
3935
4008
 
4009
+ // vite-plugin/tokensCssMigrations/migrations/2026-09-21-tint-color-and-opacity.ts
4010
+ var ENTRIES3 = [
4011
+ { name: "--tint-color", value: "rgb(255, 255, 255)" },
4012
+ { name: "--tint-opacity-low", value: "0.05" },
4013
+ { name: "--tint-opacity", value: "0.1" },
4014
+ { name: "--tint-opacity-high", value: "0.15" }
4015
+ ];
4016
+ var tokensCssMigration_2026_09_21_tintColorAndOpacity = {
4017
+ id: "2026-09-21-tint-color-and-opacity",
4018
+ kind: "additive",
4019
+ description: "Add --tint-color and --tint-opacity-*; a tint's colour and strength are separate tokens",
4020
+ apply(css) {
4021
+ return ensureScale(css, {
4022
+ entries: ENTRIES3,
4023
+ sectionComment: "Tint colour and strength, which the --tint-* stops compose",
4024
+ anchorPrefixes: ["--tint"]
4025
+ });
4026
+ }
4027
+ };
4028
+
3936
4029
  // vite-plugin/tokensCssMigrations/index.ts
3937
4030
  var TOKENS_CSS_MIGRATIONS = [
3938
4031
  tokensCssMigration_2026_05_29_typographyScaleAdditions,
@@ -3950,7 +4043,8 @@ var TOKENS_CSS_MIGRATIONS = [
3950
4043
  tokensCssMigration_2026_08_27_editorialLargeSteps,
3951
4044
  tokensCssMigration_2026_09_01_scrimRename,
3952
4045
  tokensCssMigration_2026_09_01_tintScale,
3953
- tokensCssMigration_2026_09_20_scrimColorAndOpacity
4046
+ tokensCssMigration_2026_09_20_scrimColorAndOpacity,
4047
+ tokensCssMigration_2026_09_21_tintColorAndOpacity
3954
4048
  ];
3955
4049
  function runTokensCssMigrations(css) {
3956
4050
  return foldMigrations(css, () => true);
@@ -3981,9 +4075,9 @@ function validateTokensCss(input) {
3981
4075
  const body = extractGlobalRootBody(source);
3982
4076
  if (!body) continue;
3983
4077
  for (const t of collectDefinedTokens(body)) defined.add(t);
3984
- for (const ref of collectReferencedTokens(body)) {
3985
- let set = referencedBy.get(ref);
3986
- if (!set) referencedBy.set(ref, set = /* @__PURE__ */ new Set());
4078
+ for (const ref2 of collectReferencedTokens(body)) {
4079
+ let set = referencedBy.get(ref2);
4080
+ if (!set) referencedBy.set(ref2, set = /* @__PURE__ */ new Set());
3987
4081
  set.add(name);
3988
4082
  }
3989
4083
  }
@@ -5,7 +5,7 @@ import {
5
5
  nextAvailableName,
6
6
  normalizeTheme,
7
7
  versionedFileResourceServer
8
- } from "./chunk-M6BWSS6C.js";
8
+ } from "./chunk-W5VQV32K.js";
9
9
  import {
10
10
  formatGradientValue,
11
11
  palettesToVars,
@@ -16,14 +16,14 @@ import {
16
16
  } from "./chunk-O6GQ6GBH.js";
17
17
  import {
18
18
  CURRENT_COMPONENT_SCHEMA_VERSION
19
- } from "./chunk-FD4FVDOC.js";
19
+ } from "./chunk-ONYAIXCZ.js";
20
20
  import {
21
21
  TOKENS_CSS_MIGRATIONS,
22
22
  extractGlobalRootBody,
23
23
  runAdditiveTokensCssMigrations,
24
24
  runTokensCssMigrations,
25
25
  validateTokensCss
26
- } from "./chunk-V2OVSC5Z.js";
26
+ } from "./chunk-GWMEYBZ2.js";
27
27
  import {
28
28
  hexToOklch,
29
29
  oklchToRgb255,
@@ -1404,6 +1404,77 @@ var componentMigration_2026_09_20_scrimColorAndOpacity = {
1404
1404
  }
1405
1405
  };
1406
1406
 
1407
+ // src/editor/core/themes/migrations/2026-09-21-wash-color-and-opacity.ts
1408
+ var FAMILIES = ["scrim", "tint"];
1409
+ var COLOR_MIX_RE = /^color-mix\(in srgb,\s*var\((--[a-z0-9-]+)\)\s+(\d+(?:\.\d+)?)%,\s*transparent\)$/i;
1410
+ var PLAIN_VAR_RE = /^var\((--[a-z0-9-]+)\)$/i;
1411
+ function parseFill(raw) {
1412
+ const s = raw.trim();
1413
+ const mix = s.match(COLOR_MIX_RE);
1414
+ if (mix) return { color: mix[1], opacity: Math.min(100, Number(mix[2])) / 100 };
1415
+ const plain = s.match(PLAIN_VAR_RE);
1416
+ return plain ? { color: plain[1], opacity: 1 } : null;
1417
+ }
1418
+ var colorsAndTypeMigration_2026_09_21_washColorAndOpacity = {
1419
+ id: "2026-09-21-wash-color-and-opacity",
1420
+ fromVersion: 8,
1421
+ toVersion: 9,
1422
+ appliesTo: "colors-and-type",
1423
+ apply(rawVars) {
1424
+ const out = { ...rawVars };
1425
+ for (const family of FAMILIES) {
1426
+ let color = null;
1427
+ for (const suffix of ["", "-low", "-high"]) {
1428
+ const key = `--${family}${suffix}`;
1429
+ const parsed = out[key] === void 0 ? null : parseFill(out[key]);
1430
+ if (!parsed) continue;
1431
+ color ??= parsed.color;
1432
+ out[`--${family}-opacity${suffix}`] = String(parsed.opacity);
1433
+ delete out[key];
1434
+ }
1435
+ if (color) out[`--${family}-color`] = `var(${color})`;
1436
+ }
1437
+ return out;
1438
+ }
1439
+ };
1440
+
1441
+ // src/editor/core/themes/migrations/2026-09-21-scrim-surface.ts
1442
+ var STOPS2 = {
1443
+ "--scrim-opacity-low": "--scrim-low",
1444
+ "--scrim-opacity": "--scrim",
1445
+ "--scrim-opacity-high": "--scrim-high"
1446
+ };
1447
+ var PAIR = /^--(imagelightbox|dialog)-scrim-(color|opacity)$/;
1448
+ var ref = (value) => value.startsWith("--") ? `var(${value})` : value;
1449
+ function fill(color, opacity) {
1450
+ if (color === "--scrim-color" && STOPS2[opacity]) return STOPS2[opacity];
1451
+ if (opacity === "1") return color;
1452
+ const pct = Number.isFinite(Number(opacity)) ? `${Number(opacity) * 100}%` : `calc(${ref(opacity)} * 100%)`;
1453
+ return `color-mix(in srgb, ${ref(color)} ${pct}, transparent)`;
1454
+ }
1455
+ var componentMigration_2026_09_21_scrimSurface = {
1456
+ id: "2026-09-21-scrim-surface",
1457
+ fromVersion: 37,
1458
+ toVersion: 38,
1459
+ appliesTo: "component-config",
1460
+ apply(rawVars) {
1461
+ const out = {};
1462
+ const pairs = {};
1463
+ for (const [key, value] of Object.entries(rawVars)) {
1464
+ const match = PAIR.exec(key);
1465
+ if (!match) {
1466
+ out[key] = value;
1467
+ continue;
1468
+ }
1469
+ (pairs[match[1]] ??= {})[match[2]] = value;
1470
+ }
1471
+ for (const [id, { color = "--scrim-color", opacity = "--scrim-opacity-high" }] of Object.entries(pairs)) {
1472
+ out[`--${id}-scrim-surface`] = fill(color, opacity);
1473
+ }
1474
+ return out;
1475
+ }
1476
+ };
1477
+
1407
1478
  // src/editor/core/themes/migrations/2026-09-13-cornerbadge-prefix.ts
1408
1479
  var RENAMES8 = {
1409
1480
  cornerbadge: {
@@ -1600,7 +1671,9 @@ var MIGRATIONS = [
1600
1671
  componentMigration_2026_09_13_collapsiblesectionOpen,
1601
1672
  componentMigration_2026_09_13_badgeBrand,
1602
1673
  componentMigration_2026_09_20_imagelightboxScrim,
1603
- componentMigration_2026_09_20_scrimColorAndOpacity
1674
+ componentMigration_2026_09_20_scrimColorAndOpacity,
1675
+ colorsAndTypeMigration_2026_09_21_washColorAndOpacity,
1676
+ componentMigration_2026_09_21_scrimSurface
1604
1677
  ];
1605
1678
  function countFor(kind) {
1606
1679
  return MIGRATIONS.filter((m) => m.appliesTo === kind).length;
@@ -1639,7 +1712,7 @@ function migrateComponentConfig(component, aliasesIn, rawConfig, fileVersion) {
1639
1712
  config: configOut
1640
1713
  };
1641
1714
  }
1642
- var FAMILIES = ["canvas", "neutral", "alternate", "primary", "accent", "special"];
1715
+ var FAMILIES2 = ["canvas", "neutral", "alternate", "primary", "accent", "special"];
1643
1716
  var SIZE_VARIANTS = ["lg", "md", "sm"];
1644
1717
  function renameSectionDividerObjectSlots(objectPart) {
1645
1718
  const canvasSourceKeys = [
@@ -1657,7 +1730,7 @@ function renameSectionDividerObjectSlots(objectPart) {
1657
1730
  const out = {};
1658
1731
  for (const [key, value] of Object.entries(objectPart)) {
1659
1732
  let isFamilyGradient = false;
1660
- for (const f of FAMILIES) {
1733
+ for (const f of FAMILIES2) {
1661
1734
  if (key === `--sectiondivider-${f}-background` || key === `--sectiondivider-${f}-gradient` || key === `--sectiondivider-color-${f}-background`) {
1662
1735
  isFamilyGradient = true;
1663
1736
  break;
@@ -2590,9 +2663,9 @@ function migrateData(opts) {
2590
2663
  }
2591
2664
  const { theme, migrated, dropped } = normalizeTheme(raw, resolvers);
2592
2665
  themes.push({ slug, theme });
2593
- for (const ref of dropped) {
2666
+ for (const ref2 of dropped) {
2594
2667
  droppedRefs.push(
2595
- `theme "${slug}": the reference ${ref} resolved to nothing, so it carries the shipped default instead`
2668
+ `theme "${slug}": the reference ${ref2} resolved to nothing, so it carries the shipped default instead`
2596
2669
  );
2597
2670
  }
2598
2671
  if (migrated && import_fs3.default.existsSync(themesRes.filePath(slug))) {
@@ -7,10 +7,10 @@ import {
7
7
  normalizeTheme,
8
8
  planLegacyRenames,
9
9
  versionedFileResourceServer
10
- } from "../chunk-M6BWSS6C.js";
10
+ } from "../chunk-W5VQV32K.js";
11
11
  import {
12
12
  CURRENT_COMPONENT_SCHEMA_VERSION
13
- } from "../chunk-FD4FVDOC.js";
13
+ } from "../chunk-ONYAIXCZ.js";
14
14
  import {
15
15
  readLiveTokensConfig,
16
16
  resolveDataDirs
@@ -2418,6 +2418,77 @@ var componentMigration_2026_09_20_scrimColorAndOpacity = {
2418
2418
  }
2419
2419
  };
2420
2420
 
2421
+ // src/editor/core/themes/migrations/2026-09-21-wash-color-and-opacity.ts
2422
+ var FAMILIES = ["scrim", "tint"];
2423
+ var COLOR_MIX_RE = /^color-mix\(in srgb,\s*var\((--[a-z0-9-]+)\)\s+(\d+(?:\.\d+)?)%,\s*transparent\)$/i;
2424
+ var PLAIN_VAR_RE = /^var\((--[a-z0-9-]+)\)$/i;
2425
+ function parseFill(raw) {
2426
+ const s = raw.trim();
2427
+ const mix = s.match(COLOR_MIX_RE);
2428
+ if (mix) return { color: mix[1], opacity: Math.min(100, Number(mix[2])) / 100 };
2429
+ const plain = s.match(PLAIN_VAR_RE);
2430
+ return plain ? { color: plain[1], opacity: 1 } : null;
2431
+ }
2432
+ var colorsAndTypeMigration_2026_09_21_washColorAndOpacity = {
2433
+ id: "2026-09-21-wash-color-and-opacity",
2434
+ fromVersion: 8,
2435
+ toVersion: 9,
2436
+ appliesTo: "colors-and-type",
2437
+ apply(rawVars) {
2438
+ const out = { ...rawVars };
2439
+ for (const family of FAMILIES) {
2440
+ let color = null;
2441
+ for (const suffix of ["", "-low", "-high"]) {
2442
+ const key = `--${family}${suffix}`;
2443
+ const parsed = out[key] === void 0 ? null : parseFill(out[key]);
2444
+ if (!parsed) continue;
2445
+ color ??= parsed.color;
2446
+ out[`--${family}-opacity${suffix}`] = String(parsed.opacity);
2447
+ delete out[key];
2448
+ }
2449
+ if (color) out[`--${family}-color`] = `var(${color})`;
2450
+ }
2451
+ return out;
2452
+ }
2453
+ };
2454
+
2455
+ // src/editor/core/themes/migrations/2026-09-21-scrim-surface.ts
2456
+ var STOPS2 = {
2457
+ "--scrim-opacity-low": "--scrim-low",
2458
+ "--scrim-opacity": "--scrim",
2459
+ "--scrim-opacity-high": "--scrim-high"
2460
+ };
2461
+ var PAIR = /^--(imagelightbox|dialog)-scrim-(color|opacity)$/;
2462
+ var ref = (value) => value.startsWith("--") ? `var(${value})` : value;
2463
+ function fill(color, opacity) {
2464
+ if (color === "--scrim-color" && STOPS2[opacity]) return STOPS2[opacity];
2465
+ if (opacity === "1") return color;
2466
+ const pct = Number.isFinite(Number(opacity)) ? `${Number(opacity) * 100}%` : `calc(${ref(opacity)} * 100%)`;
2467
+ return `color-mix(in srgb, ${ref(color)} ${pct}, transparent)`;
2468
+ }
2469
+ var componentMigration_2026_09_21_scrimSurface = {
2470
+ id: "2026-09-21-scrim-surface",
2471
+ fromVersion: 37,
2472
+ toVersion: 38,
2473
+ appliesTo: "component-config",
2474
+ apply(rawVars) {
2475
+ const out = {};
2476
+ const pairs = {};
2477
+ for (const [key, value] of Object.entries(rawVars)) {
2478
+ const match = PAIR.exec(key);
2479
+ if (!match) {
2480
+ out[key] = value;
2481
+ continue;
2482
+ }
2483
+ (pairs[match[1]] ??= {})[match[2]] = value;
2484
+ }
2485
+ for (const [id, { color = "--scrim-color", opacity = "--scrim-opacity-high" }] of Object.entries(pairs)) {
2486
+ out[`--${id}-scrim-surface`] = fill(color, opacity);
2487
+ }
2488
+ return out;
2489
+ }
2490
+ };
2491
+
2421
2492
  // src/editor/core/themes/migrations/2026-09-13-cornerbadge-prefix.ts
2422
2493
  var RENAMES8 = {
2423
2494
  cornerbadge: {
@@ -2614,7 +2685,9 @@ var MIGRATIONS = [
2614
2685
  componentMigration_2026_09_13_collapsiblesectionOpen,
2615
2686
  componentMigration_2026_09_13_badgeBrand,
2616
2687
  componentMigration_2026_09_20_imagelightboxScrim,
2617
- componentMigration_2026_09_20_scrimColorAndOpacity
2688
+ componentMigration_2026_09_20_scrimColorAndOpacity,
2689
+ colorsAndTypeMigration_2026_09_21_washColorAndOpacity,
2690
+ componentMigration_2026_09_21_scrimSurface
2618
2691
  ];
2619
2692
  function countFor(kind) {
2620
2693
  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-FD4FVDOC.js";
21
+ } from "../chunk-ONYAIXCZ.js";
22
22
  import {
23
23
  cssColorToOklch,
24
24
  gamutClamp,