@motion-proto/live-tokens 0.83.0 → 0.85.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-create-component/references/token-naming.md +0 -1
- package/CHANGELOG.md +72 -0
- package/dist-plugin/{chunk-RFVYPNRO.js → chunk-GWMEYBZ2.js} +43 -1
- package/dist-plugin/{chunk-6JKUYCPL.js → chunk-ONYAIXCZ.js} +104 -1
- package/dist-plugin/{chunk-LBZISJPG.js → chunk-W5VQV32K.js} +1 -1
- package/dist-plugin/index.cjs +152 -7
- package/dist-plugin/index.js +3 -3
- package/dist-plugin/migrateData/index.cjs +108 -5
- package/dist-plugin/migrateData/index.js +2 -2
- package/dist-plugin/setColors/index.cjs +104 -1
- package/dist-plugin/setColors/index.js +1 -1
- package/dist-plugin/setGeometry/index.cjs +105 -3
- package/dist-plugin/setGeometry/index.js +2 -3
- package/dist-plugin/tokensCssMigrations/index.cjs +43 -1
- package/dist-plugin/tokensCssMigrations/index.js +1 -1
- package/package.json +1 -1
- package/src/editor/core/components/aliasKinds.ts +1 -1
- package/src/editor/core/store/editorPersistence.ts +46 -23
- package/src/editor/core/store/editorStore.ts +1 -5
- package/src/editor/core/store/editorTypes.ts +11 -7
- package/src/editor/core/themes/migrations/2026-09-20-scrim-color-and-opacity.ts +45 -0
- package/src/editor/core/themes/migrations/2026-09-21-scrim-surface.ts +56 -0
- package/src/editor/core/themes/migrations/2026-09-21-wash-color-and-opacity.ts +51 -0
- package/src/editor/core/themes/migrations/index.ts +6 -0
- package/src/editor/core/themes/slices/washes.ts +59 -77
- package/src/editor/skill-atlas/skillSources.generated.ts +1 -1
- package/src/editor/ui/UIPaletteSelector.svelte +5 -1
- package/src/editor/ui/sections/WashesSection.svelte +100 -99
- package/src/live-tokens/data/colors-and-type/autumn.json +9 -7
- package/src/live-tokens/data/colors-and-type/default.json +9 -7
- package/src/live-tokens/data/colors-and-type/halloween.json +9 -7
- package/src/live-tokens/data/colors-and-type/midnight-study.json +9 -7
- package/src/live-tokens/data/colors-and-type/ocean.json +9 -7
- package/src/live-tokens/data/colors-and-type/royal-velvet.json +9 -7
- package/src/live-tokens/data/colors-and-type/sketchy.json +9 -7
- package/src/live-tokens/data/colors-and-type/spring-meadow.json +9 -7
- package/src/live-tokens/data/colors-and-type/sunset.json +9 -7
- package/src/live-tokens/data/themes/autumn.json +11 -9
- package/src/live-tokens/data/themes/halloween.json +11 -9
- package/src/live-tokens/data/themes/midnight-study.json +11 -9
- package/src/live-tokens/data/themes/ocean.json +11 -9
- package/src/live-tokens/data/themes/royal-velvet.json +11 -9
- package/src/live-tokens/data/themes/sketchy.json +11 -9
- package/src/live-tokens/data/themes/spring-meadow.json +11 -9
- package/src/live-tokens/data/themes/sunset.json +11 -9
- package/src/live-tokens/data/tokens.generated.css +8 -6
- package/src/system/components/ImageLightbox.svelte +5 -19
- package/src/system/styles/tokens.css +22 -9
|
@@ -2389,6 +2389,106 @@ var componentMigration_2026_09_20_imagelightboxScrim = {
|
|
|
2389
2389
|
}
|
|
2390
2390
|
};
|
|
2391
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-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
|
+
|
|
2392
2492
|
// src/editor/core/themes/migrations/2026-09-13-cornerbadge-prefix.ts
|
|
2393
2493
|
var RENAMES8 = {
|
|
2394
2494
|
cornerbadge: {
|
|
@@ -2584,7 +2684,10 @@ var MIGRATIONS = [
|
|
|
2584
2684
|
componentMigration_2026_09_13_toggleLabel,
|
|
2585
2685
|
componentMigration_2026_09_13_collapsiblesectionOpen,
|
|
2586
2686
|
componentMigration_2026_09_13_badgeBrand,
|
|
2587
|
-
componentMigration_2026_09_20_imagelightboxScrim
|
|
2687
|
+
componentMigration_2026_09_20_imagelightboxScrim,
|
|
2688
|
+
componentMigration_2026_09_20_scrimColorAndOpacity,
|
|
2689
|
+
colorsAndTypeMigration_2026_09_21_washColorAndOpacity,
|
|
2690
|
+
componentMigration_2026_09_21_scrimSurface
|
|
2588
2691
|
];
|
|
2589
2692
|
function countFor(kind) {
|
|
2590
2693
|
return MIGRATIONS.filter((m) => m.appliesTo === kind).length;
|
|
@@ -95,8 +95,7 @@ var KIND_RULES = [
|
|
|
95
95
|
"-indicator",
|
|
96
96
|
"-thumb",
|
|
97
97
|
"-color",
|
|
98
|
-
"-tint"
|
|
99
|
-
"-opacity"
|
|
98
|
+
"-tint"
|
|
100
99
|
],
|
|
101
100
|
prefix: ["--surface-", "--tint", "--color-"]
|
|
102
101
|
}
|
|
@@ -1538,6 +1537,106 @@ var componentMigration_2026_09_20_imagelightboxScrim = {
|
|
|
1538
1537
|
}
|
|
1539
1538
|
};
|
|
1540
1539
|
|
|
1540
|
+
// src/editor/core/themes/migrations/2026-09-20-scrim-color-and-opacity.ts
|
|
1541
|
+
var STOPS = {
|
|
1542
|
+
"--scrim-low": "--scrim-opacity-low",
|
|
1543
|
+
"--scrim": "--scrim-opacity",
|
|
1544
|
+
"--scrim-high": "--scrim-opacity-high"
|
|
1545
|
+
};
|
|
1546
|
+
var SURFACE = /^--(imagelightbox|dialog)-scrim-surface$/;
|
|
1547
|
+
var componentMigration_2026_09_20_scrimColorAndOpacity = {
|
|
1548
|
+
id: "2026-09-20-scrim-color-and-opacity",
|
|
1549
|
+
fromVersion: 36,
|
|
1550
|
+
toVersion: 37,
|
|
1551
|
+
appliesTo: "component-config",
|
|
1552
|
+
apply(rawVars) {
|
|
1553
|
+
const out = {};
|
|
1554
|
+
for (const [key, value] of Object.entries(rawVars)) {
|
|
1555
|
+
const match = SURFACE.exec(key);
|
|
1556
|
+
if (!match) {
|
|
1557
|
+
out[key] = value;
|
|
1558
|
+
continue;
|
|
1559
|
+
}
|
|
1560
|
+
const stem = `--${match[1]}-scrim`;
|
|
1561
|
+
const stop = STOPS[value];
|
|
1562
|
+
out[`${stem}-color`] = stop ? "--scrim-color" : value;
|
|
1563
|
+
out[`${stem}-opacity`] = stop ?? "1";
|
|
1564
|
+
}
|
|
1565
|
+
return out;
|
|
1566
|
+
}
|
|
1567
|
+
};
|
|
1568
|
+
|
|
1569
|
+
// src/editor/core/themes/migrations/2026-09-21-wash-color-and-opacity.ts
|
|
1570
|
+
var FAMILIES = ["scrim", "tint"];
|
|
1571
|
+
var COLOR_MIX_RE = /^color-mix\(in srgb,\s*var\((--[a-z0-9-]+)\)\s+(\d+(?:\.\d+)?)%,\s*transparent\)$/i;
|
|
1572
|
+
var PLAIN_VAR_RE = /^var\((--[a-z0-9-]+)\)$/i;
|
|
1573
|
+
function parseFill(raw) {
|
|
1574
|
+
const s = raw.trim();
|
|
1575
|
+
const mix = s.match(COLOR_MIX_RE);
|
|
1576
|
+
if (mix) return { color: mix[1], opacity: Math.min(100, Number(mix[2])) / 100 };
|
|
1577
|
+
const plain = s.match(PLAIN_VAR_RE);
|
|
1578
|
+
return plain ? { color: plain[1], opacity: 1 } : null;
|
|
1579
|
+
}
|
|
1580
|
+
var colorsAndTypeMigration_2026_09_21_washColorAndOpacity = {
|
|
1581
|
+
id: "2026-09-21-wash-color-and-opacity",
|
|
1582
|
+
fromVersion: 8,
|
|
1583
|
+
toVersion: 9,
|
|
1584
|
+
appliesTo: "colors-and-type",
|
|
1585
|
+
apply(rawVars) {
|
|
1586
|
+
const out = { ...rawVars };
|
|
1587
|
+
for (const family of FAMILIES) {
|
|
1588
|
+
let color = null;
|
|
1589
|
+
for (const suffix of ["", "-low", "-high"]) {
|
|
1590
|
+
const key = `--${family}${suffix}`;
|
|
1591
|
+
const parsed = out[key] === void 0 ? null : parseFill(out[key]);
|
|
1592
|
+
if (!parsed) continue;
|
|
1593
|
+
color ??= parsed.color;
|
|
1594
|
+
out[`--${family}-opacity${suffix}`] = String(parsed.opacity);
|
|
1595
|
+
delete out[key];
|
|
1596
|
+
}
|
|
1597
|
+
if (color) out[`--${family}-color`] = `var(${color})`;
|
|
1598
|
+
}
|
|
1599
|
+
return out;
|
|
1600
|
+
}
|
|
1601
|
+
};
|
|
1602
|
+
|
|
1603
|
+
// src/editor/core/themes/migrations/2026-09-21-scrim-surface.ts
|
|
1604
|
+
var STOPS2 = {
|
|
1605
|
+
"--scrim-opacity-low": "--scrim-low",
|
|
1606
|
+
"--scrim-opacity": "--scrim",
|
|
1607
|
+
"--scrim-opacity-high": "--scrim-high"
|
|
1608
|
+
};
|
|
1609
|
+
var PAIR = /^--(imagelightbox|dialog)-scrim-(color|opacity)$/;
|
|
1610
|
+
var ref = (value) => value.startsWith("--") ? `var(${value})` : value;
|
|
1611
|
+
function fill(color, opacity) {
|
|
1612
|
+
if (color === "--scrim-color" && STOPS2[opacity]) return STOPS2[opacity];
|
|
1613
|
+
if (opacity === "1") return color;
|
|
1614
|
+
const pct = Number.isFinite(Number(opacity)) ? `${Number(opacity) * 100}%` : `calc(${ref(opacity)} * 100%)`;
|
|
1615
|
+
return `color-mix(in srgb, ${ref(color)} ${pct}, transparent)`;
|
|
1616
|
+
}
|
|
1617
|
+
var componentMigration_2026_09_21_scrimSurface = {
|
|
1618
|
+
id: "2026-09-21-scrim-surface",
|
|
1619
|
+
fromVersion: 37,
|
|
1620
|
+
toVersion: 38,
|
|
1621
|
+
appliesTo: "component-config",
|
|
1622
|
+
apply(rawVars) {
|
|
1623
|
+
const out = {};
|
|
1624
|
+
const pairs = {};
|
|
1625
|
+
for (const [key, value] of Object.entries(rawVars)) {
|
|
1626
|
+
const match = PAIR.exec(key);
|
|
1627
|
+
if (!match) {
|
|
1628
|
+
out[key] = value;
|
|
1629
|
+
continue;
|
|
1630
|
+
}
|
|
1631
|
+
(pairs[match[1]] ??= {})[match[2]] = value;
|
|
1632
|
+
}
|
|
1633
|
+
for (const [id, { color = "--scrim-color", opacity = "--scrim-opacity-high" }] of Object.entries(pairs)) {
|
|
1634
|
+
out[`--${id}-scrim-surface`] = fill(color, opacity);
|
|
1635
|
+
}
|
|
1636
|
+
return out;
|
|
1637
|
+
}
|
|
1638
|
+
};
|
|
1639
|
+
|
|
1541
1640
|
// src/editor/core/themes/migrations/2026-09-13-cornerbadge-prefix.ts
|
|
1542
1641
|
var RENAMES8 = {
|
|
1543
1642
|
cornerbadge: {
|
|
@@ -1733,7 +1832,10 @@ var MIGRATIONS = [
|
|
|
1733
1832
|
componentMigration_2026_09_13_toggleLabel,
|
|
1734
1833
|
componentMigration_2026_09_13_collapsiblesectionOpen,
|
|
1735
1834
|
componentMigration_2026_09_13_badgeBrand,
|
|
1736
|
-
componentMigration_2026_09_20_imagelightboxScrim
|
|
1835
|
+
componentMigration_2026_09_20_imagelightboxScrim,
|
|
1836
|
+
componentMigration_2026_09_20_scrimColorAndOpacity,
|
|
1837
|
+
colorsAndTypeMigration_2026_09_21_washColorAndOpacity,
|
|
1838
|
+
componentMigration_2026_09_21_scrimSurface
|
|
1737
1839
|
];
|
|
1738
1840
|
function countFor(kind) {
|
|
1739
1841
|
return MIGRATIONS.filter((m) => m.appliesTo === kind).length;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CURRENT_COMPONENT_SCHEMA_VERSION
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-ONYAIXCZ.js";
|
|
4
4
|
import {
|
|
5
5
|
readLiveTokensConfig,
|
|
6
6
|
resolveDataDirs
|
|
@@ -63,8 +63,7 @@ var KIND_RULES = [
|
|
|
63
63
|
"-indicator",
|
|
64
64
|
"-thumb",
|
|
65
65
|
"-color",
|
|
66
|
-
"-tint"
|
|
67
|
-
"-opacity"
|
|
66
|
+
"-tint"
|
|
68
67
|
],
|
|
69
68
|
prefix: ["--surface-", "--tint", "--color-"]
|
|
70
69
|
}
|
|
@@ -639,6 +639,46 @@ 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
|
+
|
|
662
|
+
// vite-plugin/tokensCssMigrations/migrations/2026-09-21-tint-color-and-opacity.ts
|
|
663
|
+
var ENTRIES3 = [
|
|
664
|
+
{ name: "--tint-color", value: "rgb(255, 255, 255)" },
|
|
665
|
+
{ name: "--tint-opacity-low", value: "0.05" },
|
|
666
|
+
{ name: "--tint-opacity", value: "0.1" },
|
|
667
|
+
{ name: "--tint-opacity-high", value: "0.15" }
|
|
668
|
+
];
|
|
669
|
+
var tokensCssMigration_2026_09_21_tintColorAndOpacity = {
|
|
670
|
+
id: "2026-09-21-tint-color-and-opacity",
|
|
671
|
+
kind: "additive",
|
|
672
|
+
description: "Add --tint-color and --tint-opacity-*; a tint's colour and strength are separate tokens",
|
|
673
|
+
apply(css) {
|
|
674
|
+
return ensureScale(css, {
|
|
675
|
+
entries: ENTRIES3,
|
|
676
|
+
sectionComment: "Tint colour and strength, which the --tint-* stops compose",
|
|
677
|
+
anchorPrefixes: ["--tint"]
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
};
|
|
681
|
+
|
|
642
682
|
// vite-plugin/files/dataPaths.ts
|
|
643
683
|
var import_fs = __toESM(require("fs"), 1);
|
|
644
684
|
var import_path = __toESM(require("path"), 1);
|
|
@@ -691,7 +731,9 @@ var TOKENS_CSS_MIGRATIONS = [
|
|
|
691
731
|
tokensCssMigration_2026_08_27_editorialSizeSteps,
|
|
692
732
|
tokensCssMigration_2026_08_27_editorialLargeSteps,
|
|
693
733
|
tokensCssMigration_2026_09_01_scrimRename,
|
|
694
|
-
tokensCssMigration_2026_09_01_tintScale
|
|
734
|
+
tokensCssMigration_2026_09_01_tintScale,
|
|
735
|
+
tokensCssMigration_2026_09_20_scrimColorAndOpacity,
|
|
736
|
+
tokensCssMigration_2026_09_21_tintColorAndOpacity
|
|
695
737
|
];
|
|
696
738
|
function runTokensCssMigrations(css) {
|
|
697
739
|
return foldMigrations(css, () => true);
|
package/package.json
CHANGED
|
@@ -73,7 +73,7 @@ export const KIND_RULES: ReadonlyArray<{
|
|
|
73
73
|
// Fills. A tint is a wash over a surface, so it takes the surface picker: the
|
|
74
74
|
// full palette with an alpha, not just the tint stops it defaults to.
|
|
75
75
|
{ kind: 'surface', suffix: ['-surface', '-fill', '-indicator',
|
|
76
|
-
'-thumb', '-color', '-tint'
|
|
76
|
+
'-thumb', '-color', '-tint'],
|
|
77
77
|
prefix: ['--surface-', '--tint', '--color-'] },
|
|
78
78
|
];
|
|
79
79
|
|
|
@@ -14,13 +14,13 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { get } from 'svelte/store';
|
|
17
|
-
import type { EditorState } from './editorTypes';
|
|
17
|
+
import type { EditorState, WashScale } from './editorTypes';
|
|
18
18
|
import { storageKey } from './editorConfig';
|
|
19
19
|
import { store } from './editorCore';
|
|
20
20
|
import { quietGet, quietSet } from '../storage/storage';
|
|
21
21
|
import { isGradientSlot, makeDefaultGradients } from '../themes/slices/gradients';
|
|
22
22
|
import { seedShadowsFromDom } from '../themes/slices/shadows';
|
|
23
|
-
import {
|
|
23
|
+
import { makeDefaultWashScale, type WashFamily } from '../themes/slices/washes';
|
|
24
24
|
import { sanitizeHarmonyAxes } from '../palettes/colorHarmony';
|
|
25
25
|
import {
|
|
26
26
|
renameBackgroundPaletteKey,
|
|
@@ -78,34 +78,57 @@ function migrateGradients(state: EditorState): EditorState {
|
|
|
78
78
|
// calls `Object.entries(slice.config)` unconditionally, so backfill the
|
|
79
79
|
// required fields and drop any non-object slice before the state reaches the
|
|
80
80
|
// renderer. Spread preserves optional fields like `unlinked`.
|
|
81
|
-
//
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
// `
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
'--overlay-
|
|
90
|
-
'--
|
|
91
|
-
'--
|
|
92
|
-
'--
|
|
81
|
+
// A persisted washes slice can predate two reshapes. Before the scrim and tint
|
|
82
|
+
// renames it was `overlays: { tokens, hoverTokens }`; until 0.85.0 each family
|
|
83
|
+
// was a list of `{variable, alias, opacity}` stops, each carrying its own
|
|
84
|
+
// colour. `hydrate` shallow-merges, so an older build's `washes` arrives whole
|
|
85
|
+
// in that shape, and `washesToVars` reads `color` and `stops` unconditionally.
|
|
86
|
+
// Reshape here: the family takes the base stop's colour, and each stop its
|
|
87
|
+
// opacity under the new variable.
|
|
88
|
+
const LEGACY_STOP_OPACITY_VARS: Record<string, string> = {
|
|
89
|
+
'--overlay-low': '--scrim-opacity-low',
|
|
90
|
+
'--overlay': '--scrim-opacity',
|
|
91
|
+
'--overlay-high': '--scrim-opacity-high',
|
|
92
|
+
'--scrim-low': '--scrim-opacity-low',
|
|
93
|
+
'--scrim': '--scrim-opacity',
|
|
94
|
+
'--scrim-high': '--scrim-opacity-high',
|
|
95
|
+
'--hover-low': '--tint-opacity-low',
|
|
96
|
+
'--hover': '--tint-opacity',
|
|
97
|
+
'--hover-high': '--tint-opacity-high',
|
|
98
|
+
'--tint-low': '--tint-opacity-low',
|
|
99
|
+
'--tint': '--tint-opacity',
|
|
100
|
+
'--tint-high': '--tint-opacity-high',
|
|
93
101
|
};
|
|
94
102
|
|
|
95
103
|
type LegacyWashes = {
|
|
104
|
+
scrim?: unknown;
|
|
105
|
+
tint?: unknown;
|
|
96
106
|
scrims?: unknown;
|
|
97
107
|
tints?: unknown;
|
|
98
108
|
hoverTokens?: unknown;
|
|
99
109
|
tokens?: unknown;
|
|
100
110
|
};
|
|
101
111
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
.
|
|
108
|
-
|
|
112
|
+
type LegacyStop = { variable: string; alias?: unknown; opacity?: unknown };
|
|
113
|
+
|
|
114
|
+
function isScale(raw: unknown): raw is WashScale {
|
|
115
|
+
return !!raw && typeof raw === 'object'
|
|
116
|
+
&& typeof (raw as WashScale).color === 'string'
|
|
117
|
+
&& Array.isArray((raw as WashScale).stops);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function washScale(current: unknown, legacyList: unknown, family: WashFamily): WashScale {
|
|
121
|
+
if (isScale(current)) return current;
|
|
122
|
+
const scale = makeDefaultWashScale(family);
|
|
123
|
+
if (!Array.isArray(legacyList)) return scale;
|
|
124
|
+
const stops = legacyList.filter((t): t is LegacyStop => !!t && typeof t === 'object' && 'variable' in t);
|
|
125
|
+
const base = stops.find((t) => LEGACY_STOP_OPACITY_VARS[t.variable] === `--${family}-opacity`) ?? stops[0];
|
|
126
|
+
if (typeof base?.alias === 'string') scale.color = base.alias;
|
|
127
|
+
for (const t of stops) {
|
|
128
|
+
const stop = scale.stops.find((s) => s.variable === LEGACY_STOP_OPACITY_VARS[t.variable]);
|
|
129
|
+
if (stop && typeof t.opacity === 'number') stop.opacity = t.opacity;
|
|
130
|
+
}
|
|
131
|
+
return scale;
|
|
109
132
|
}
|
|
110
133
|
|
|
111
134
|
export function normalizeWashes(state: EditorState): EditorState {
|
|
@@ -113,8 +136,8 @@ export function normalizeWashes(state: EditorState): EditorState {
|
|
|
113
136
|
const legacy = ((state as unknown as { overlays?: LegacyWashes }).overlays ?? {}) as LegacyWashes;
|
|
114
137
|
const next = { ...state } as EditorState & { overlays?: unknown };
|
|
115
138
|
next.washes = {
|
|
116
|
-
|
|
117
|
-
|
|
139
|
+
scrim: washScale(washes.scrim, washes.scrims ?? legacy.tokens, 'scrim'),
|
|
140
|
+
tint: washScale(washes.tint, washes.tints ?? washes.hoverTokens ?? legacy.hoverTokens, 'tint'),
|
|
118
141
|
};
|
|
119
142
|
delete next.overlays;
|
|
120
143
|
return next;
|
|
@@ -152,12 +152,8 @@ export {
|
|
|
152
152
|
export {
|
|
153
153
|
washesToVars,
|
|
154
154
|
WASH_VAR_NAMES,
|
|
155
|
-
applyWashVarsToState,
|
|
156
155
|
makeDefaultWashesState,
|
|
157
|
-
|
|
158
|
-
makeDefaultTintTokens,
|
|
159
|
-
washTokenToCss,
|
|
160
|
-
parseWashCss,
|
|
156
|
+
makeDefaultWashScale,
|
|
161
157
|
} from '../themes/slices/washes';
|
|
162
158
|
|
|
163
159
|
export {
|
|
@@ -23,16 +23,20 @@ export interface ShadowOverrideFlags {
|
|
|
23
23
|
distance: boolean; blur: boolean; size: boolean;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
/**
|
|
27
|
-
|
|
28
|
-
* is behind them; tints shade the surface they sit on. */
|
|
29
|
-
export interface WashToken {
|
|
26
|
+
/** One opacity stop of a wash family, emitted as a bare number. */
|
|
27
|
+
export interface WashStop {
|
|
30
28
|
variable: string;
|
|
31
29
|
label: string;
|
|
32
|
-
alias: string;
|
|
33
30
|
opacity: number;
|
|
34
31
|
}
|
|
35
32
|
|
|
33
|
+
/** A wash family: one aliased colour and its opacity stops. Scrims dim what is
|
|
34
|
+
* behind them; tints shade the surface they sit on. */
|
|
35
|
+
export interface WashScale {
|
|
36
|
+
color: string;
|
|
37
|
+
stops: WashStop[];
|
|
38
|
+
}
|
|
39
|
+
|
|
36
40
|
export interface ColumnsState {
|
|
37
41
|
count: number;
|
|
38
42
|
maxWidth: number;
|
|
@@ -113,8 +117,8 @@ export interface EditorState {
|
|
|
113
117
|
overrides: Record<string, ShadowOverrideFlags>;
|
|
114
118
|
};
|
|
115
119
|
washes: {
|
|
116
|
-
|
|
117
|
-
|
|
120
|
+
scrim: WashScale;
|
|
121
|
+
tint: WashScale;
|
|
118
122
|
};
|
|
119
123
|
columns: ColumnsState;
|
|
120
124
|
components: Record<string, ComponentSlice>;
|
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Migration } from './index';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A screen's scrim is one fill again (2026-09-21).
|
|
5
|
+
*
|
|
6
|
+
* From 0.84.0 Dialog and ImageLightbox read `-scrim-color` and
|
|
7
|
+
* `-scrim-opacity` and mixed them where they painted. The theme now composes
|
|
8
|
+
* `--scrim-low`, `--scrim`, and `--scrim-high` from its own colour and
|
|
9
|
+
* strengths, so a screen picks one of those stops as `-scrim-surface`, the way
|
|
10
|
+
* a hover picks a `--tint-*` stop.
|
|
11
|
+
*
|
|
12
|
+
* The scale's colour at one of its strengths becomes that stop. Any other pair
|
|
13
|
+
* becomes the `color-mix()` the screen used to paint, so the page looks the
|
|
14
|
+
* same.
|
|
15
|
+
*/
|
|
16
|
+
const STOPS: Record<string, string> = {
|
|
17
|
+
'--scrim-opacity-low': '--scrim-low',
|
|
18
|
+
'--scrim-opacity': '--scrim',
|
|
19
|
+
'--scrim-opacity-high': '--scrim-high',
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const PAIR = /^--(imagelightbox|dialog)-scrim-(color|opacity)$/;
|
|
23
|
+
|
|
24
|
+
const ref = (value: string) => (value.startsWith('--') ? `var(${value})` : value);
|
|
25
|
+
|
|
26
|
+
function fill(color: string, opacity: string): string {
|
|
27
|
+
if (color === '--scrim-color' && STOPS[opacity]) return STOPS[opacity];
|
|
28
|
+
if (opacity === '1') return color;
|
|
29
|
+
const pct = Number.isFinite(Number(opacity))
|
|
30
|
+
? `${Number(opacity) * 100}%`
|
|
31
|
+
: `calc(${ref(opacity)} * 100%)`;
|
|
32
|
+
return `color-mix(in srgb, ${ref(color)} ${pct}, transparent)`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const componentMigration_2026_09_21_scrimSurface: Migration = {
|
|
36
|
+
id: '2026-09-21-scrim-surface',
|
|
37
|
+
fromVersion: 37,
|
|
38
|
+
toVersion: 38,
|
|
39
|
+
appliesTo: 'component-config',
|
|
40
|
+
apply(rawVars) {
|
|
41
|
+
const out: Record<string, string> = {};
|
|
42
|
+
const pairs: Record<string, { color?: string; opacity?: string }> = {};
|
|
43
|
+
for (const [key, value] of Object.entries(rawVars)) {
|
|
44
|
+
const match = PAIR.exec(key);
|
|
45
|
+
if (!match) {
|
|
46
|
+
out[key] = value;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
(pairs[match[1]] ??= {})[match[2] as 'color' | 'opacity'] = value;
|
|
50
|
+
}
|
|
51
|
+
for (const [id, { color = '--scrim-color', opacity = '--scrim-opacity-high' }] of Object.entries(pairs)) {
|
|
52
|
+
out[`--${id}-scrim-surface`] = fill(color, opacity);
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
55
|
+
},
|
|
56
|
+
};
|