@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.
- package/.claude/skills/live-tokens-create-component/references/token-naming.md +0 -1
- package/CHANGELOG.md +85 -0
- package/README.md +1 -1
- package/dist-plugin/{chunk-V2OVSC5Z.js → chunk-GWMEYBZ2.js} +22 -1
- package/dist-plugin/{chunk-FD4FVDOC.js → chunk-ONYAIXCZ.js} +74 -1
- package/dist-plugin/{chunk-M6BWSS6C.js → chunk-W5VQV32K.js} +1 -1
- package/dist-plugin/index.cjs +101 -7
- package/dist-plugin/index.js +3 -3
- package/dist-plugin/migrateData/index.cjs +78 -5
- package/dist-plugin/migrateData/index.js +2 -2
- package/dist-plugin/setColors/index.cjs +74 -1
- package/dist-plugin/setColors/index.js +1 -1
- package/dist-plugin/setGeometry/index.cjs +74 -4
- package/dist-plugin/setGeometry/index.d.cts +1 -1
- package/dist-plugin/setGeometry/index.d.ts +1 -1
- package/dist-plugin/setGeometry/index.js +1 -4
- package/dist-plugin/tokensCssMigrations/index.cjs +22 -1
- package/dist-plugin/tokensCssMigrations/index.js +1 -1
- package/package.json +1 -1
- package/src/editor/component-editor/DialogEditor.svelte +1 -2
- package/src/editor/component-editor/ImageLightboxEditor.svelte +1 -2
- package/src/editor/component-editor/SlidePagerEditor.svelte +118 -0
- package/src/editor/component-editor/VideoFrameEditor.svelte +73 -0
- package/src/editor/component-editor/VideoLightboxEditor.svelte +95 -0
- package/src/editor/component-editor/registry.ts +40 -1
- package/src/editor/component-editor/scaffolding/TokenLayout.svelte +1 -4
- package/src/editor/core/components/aliasKinds.ts +0 -4
- package/src/editor/core/sketch/sketchLayer.ts +8 -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-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 +4 -0
- package/src/editor/core/themes/slices/washes.ts +59 -77
- package/src/editor/overlay/LiveEditorOverlay.svelte +45 -52
- package/src/editor/pages/ComponentEditorPage.svelte +1 -1
- package/src/editor/skill-atlas/skillSources.generated.ts +1 -1
- package/src/editor/ui/ThemePanel.svelte +9 -53
- package/src/editor/ui/UIPaletteSelector.svelte +5 -1
- package/src/editor/ui/UIVariantSelector.svelte +1 -1
- package/src/editor/ui/sections/WashesSection.svelte +100 -99
- package/src/editor/ui/variantScales.ts +0 -11
- 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 +98 -12
- package/src/live-tokens/data/themes/halloween.json +98 -12
- package/src/live-tokens/data/themes/midnight-study.json +98 -12
- package/src/live-tokens/data/themes/ocean.json +98 -12
- package/src/live-tokens/data/themes/royal-velvet.json +98 -12
- package/src/live-tokens/data/themes/sketchy.json +98 -12
- package/src/live-tokens/data/themes/spring-meadow.json +98 -12
- package/src/live-tokens/data/themes/sunset.json +98 -12
- package/src/live-tokens/data/tokens.generated.css +8 -6
- package/src/system/assets/slide-04.webp +0 -0
- package/src/system/assets/slide-05.webp +0 -0
- package/src/system/assets/slide-06.webp +0 -0
- package/src/system/assets/watch-navigation-poster.webp +0 -0
- package/src/system/assets/watch-navigation.mp4 +0 -0
- package/src/system/components/Dialog.svelte +2 -7
- package/src/system/components/ImageLightbox.svelte +27 -39
- package/src/system/components/SlidePager.svelte +516 -0
- package/src/system/components/VideoFrame.svelte +284 -0
- package/src/system/components/VideoLightbox.svelte +381 -0
- package/src/system/styles/tokens.css +13 -8
- package/src/testing-js/{chunk-WQJ6QB6Y.js → chunk-OHU5BHGZ.js} +347 -9
- package/src/testing-js/chunk-OHU5BHGZ.js.map +1 -0
- package/src/testing-js/{chunk-XXABJNUU.js → chunk-Y6R7Z7VK.js} +10 -6
- package/src/testing-js/chunk-Y6R7Z7VK.js.map +1 -0
- package/src/testing-js/component-behavior.contract.js +1 -1
- package/src/testing-js/component-editor.contract.js +1 -1
- package/src/testing-js/component-render.contract.js +1 -1
- package/src/testing-js/index.d.ts +2 -2
- package/src/testing-js/index.js +2 -2
- package/src/testing-js/page-compliance.contract.js +1 -1
- package/src/testing-js/{vitest-BMLIbDs2.d.ts → vitest-5vWtqwWe.d.ts} +2 -2
- package/src/testing-js/vitest.d.ts +1 -1
- package/src/testing-js/vitest.js +2 -2
- package/src/testing-js/chunk-WQJ6QB6Y.js.map +0 -1
- package/src/testing-js/chunk-XXABJNUU.js.map +0 -1
|
@@ -74,9 +74,6 @@ 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"] },
|
|
80
77
|
{ kind: "shadow", suffix: ["-shadow"], prefix: ["--shadow-"] },
|
|
81
78
|
{ kind: "padding", suffix: ["-padding", "-margin"] },
|
|
82
79
|
{ kind: "gap", suffix: ["-gap"] },
|
|
@@ -1569,6 +1566,77 @@ var componentMigration_2026_09_20_scrimColorAndOpacity = {
|
|
|
1569
1566
|
}
|
|
1570
1567
|
};
|
|
1571
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
|
+
|
|
1572
1640
|
// src/editor/core/themes/migrations/2026-09-13-cornerbadge-prefix.ts
|
|
1573
1641
|
var RENAMES8 = {
|
|
1574
1642
|
cornerbadge: {
|
|
@@ -1765,7 +1833,9 @@ var MIGRATIONS = [
|
|
|
1765
1833
|
componentMigration_2026_09_13_collapsiblesectionOpen,
|
|
1766
1834
|
componentMigration_2026_09_13_badgeBrand,
|
|
1767
1835
|
componentMigration_2026_09_20_imagelightboxScrim,
|
|
1768
|
-
componentMigration_2026_09_20_scrimColorAndOpacity
|
|
1836
|
+
componentMigration_2026_09_20_scrimColorAndOpacity,
|
|
1837
|
+
colorsAndTypeMigration_2026_09_21_washColorAndOpacity,
|
|
1838
|
+
componentMigration_2026_09_21_scrimSurface
|
|
1769
1839
|
];
|
|
1770
1840
|
function countFor(kind) {
|
|
1771
1841
|
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' | '
|
|
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';
|
|
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' | '
|
|
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';
|
|
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-
|
|
3
|
+
} from "../chunk-ONYAIXCZ.js";
|
|
4
4
|
import {
|
|
5
5
|
readLiveTokensConfig,
|
|
6
6
|
resolveDataDirs
|
|
@@ -42,9 +42,6 @@ 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"] },
|
|
48
45
|
{ kind: "shadow", suffix: ["-shadow"], prefix: ["--shadow-"] },
|
|
49
46
|
{ kind: "padding", suffix: ["-padding", "-margin"] },
|
|
50
47
|
{ kind: "gap", suffix: ["-gap"] },
|
|
@@ -659,6 +659,26 @@ var tokensCssMigration_2026_09_20_scrimColorAndOpacity = {
|
|
|
659
659
|
}
|
|
660
660
|
};
|
|
661
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
|
+
|
|
662
682
|
// vite-plugin/files/dataPaths.ts
|
|
663
683
|
var import_fs = __toESM(require("fs"), 1);
|
|
664
684
|
var import_path = __toESM(require("path"), 1);
|
|
@@ -712,7 +732,8 @@ var TOKENS_CSS_MIGRATIONS = [
|
|
|
712
732
|
tokensCssMigration_2026_08_27_editorialLargeSteps,
|
|
713
733
|
tokensCssMigration_2026_09_01_scrimRename,
|
|
714
734
|
tokensCssMigration_2026_09_01_tintScale,
|
|
715
|
-
tokensCssMigration_2026_09_20_scrimColorAndOpacity
|
|
735
|
+
tokensCssMigration_2026_09_20_scrimColorAndOpacity,
|
|
736
|
+
tokensCssMigration_2026_09_21_tintColorAndOpacity
|
|
716
737
|
];
|
|
717
738
|
function runTokensCssMigrations(css) {
|
|
718
739
|
return foldMigrations(css, () => true);
|
package/package.json
CHANGED
|
@@ -16,8 +16,7 @@
|
|
|
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-
|
|
20
|
-
{ label: 'scrim opacity', variable: '--dialog-scrim-opacity' },
|
|
19
|
+
{ label: 'scrim color', groupKey: 'surface', variable: '--dialog-scrim-surface' },
|
|
21
20
|
],
|
|
22
21
|
dialog: [
|
|
23
22
|
{ label: 'surface color', variable: '--dialog-surface' },
|
|
@@ -15,8 +15,7 @@
|
|
|
15
15
|
{ label: 'tile shadow', variable: '--imagelightbox-tile-shadow' },
|
|
16
16
|
],
|
|
17
17
|
overlay: [
|
|
18
|
-
{ label: 'scrim color', groupKey: 'surface', variable: '--imagelightbox-scrim-
|
|
19
|
-
{ label: 'scrim opacity', variable: '--imagelightbox-scrim-opacity' },
|
|
18
|
+
{ label: 'scrim color', groupKey: 'surface', variable: '--imagelightbox-scrim-surface' },
|
|
20
19
|
],
|
|
21
20
|
chrome: [
|
|
22
21
|
{ label: 'surface color', groupKey: 'surface', variable: '--imagelightbox-chrome-surface' },
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
import type { Token } from './scaffolding/types';
|
|
3
|
+
|
|
4
|
+
export const component = 'slidepager';
|
|
5
|
+
|
|
6
|
+
// Single variant: the default carries the frame, the bar, the counter and
|
|
7
|
+
// the control's resting look. Hover and disabled layer on the control alone.
|
|
8
|
+
const states: Record<string, Token[]> = {
|
|
9
|
+
default: [
|
|
10
|
+
{ label: 'surface color', element: 'frame', variable: '--slidepager-frame-surface' },
|
|
11
|
+
{ label: 'border color', element: 'frame', variable: '--slidepager-frame-border' },
|
|
12
|
+
{ label: 'border width', canBeLinked: true, element: 'frame', variable: '--slidepager-frame-border-width' },
|
|
13
|
+
{ label: 'corner radius', canBeLinked: true, element: 'frame', variable: '--slidepager-frame-radius' },
|
|
14
|
+
{ label: 'shadow', element: 'frame', variable: '--slidepager-frame-shadow' },
|
|
15
|
+
{ label: 'gap', canBeLinked: true, element: 'bar', variable: '--slidepager-bar-gap' },
|
|
16
|
+
{ label: 'padding', canBeLinked: true, element: 'bar', variable: '--slidepager-bar-padding' },
|
|
17
|
+
{ label: 'surface color', element: 'control', variable: '--slidepager-control-surface' },
|
|
18
|
+
{ label: 'border color', element: 'control', variable: '--slidepager-control-border' },
|
|
19
|
+
{ label: 'border width', canBeLinked: true, element: 'control', variable: '--slidepager-control-border-width' },
|
|
20
|
+
{ label: 'corner radius', canBeLinked: true, element: 'control', variable: '--slidepager-control-radius' },
|
|
21
|
+
{ label: 'size', canBeLinked: true, element: 'control', variable: '--slidepager-control-size' },
|
|
22
|
+
{ label: 'icon color', element: 'control', variable: '--slidepager-control-icon' },
|
|
23
|
+
{ label: 'icon size', canBeLinked: true, element: 'control', variable: '--slidepager-control-icon-size' },
|
|
24
|
+
{ label: 'text color', element: 'counter', variable: '--slidepager-counter-text' },
|
|
25
|
+
{ label: 'font family', element: 'counter', variable: '--slidepager-counter-font-family' },
|
|
26
|
+
{ label: 'font size', element: 'counter', variable: '--slidepager-counter-font-size' },
|
|
27
|
+
{ label: 'font weight', element: 'counter', variable: '--slidepager-counter-font-weight' },
|
|
28
|
+
{ label: 'line height', element: 'counter', variable: '--slidepager-counter-line-height' },
|
|
29
|
+
{ label: 'letter spacing', element: 'counter', variable: '--slidepager-counter-letter-spacing' },
|
|
30
|
+
{ label: 'scrim color', element: 'overlay', variable: '--slidepager-scrim-surface' },
|
|
31
|
+
{ label: 'padding', canBeLinked: true, element: 'overlay', variable: '--slidepager-overlay-padding' },
|
|
32
|
+
{ label: 'close button margin', canBeLinked: true, element: 'overlay', variable: '--slidepager-close-margin' },
|
|
33
|
+
{ label: 'fade duration', element: 'overlay', variable: '--slidepager-overlay-duration' },
|
|
34
|
+
{ label: 'fade easing', element: 'overlay', variable: '--slidepager-overlay-easing' }
|
|
35
|
+
],
|
|
36
|
+
hover: [
|
|
37
|
+
{ label: 'surface color', element: 'control', variable: '--slidepager-control-hover-surface' },
|
|
38
|
+
{ label: 'border color', element: 'control', variable: '--slidepager-control-hover-border' },
|
|
39
|
+
{ label: 'icon color', element: 'control', variable: '--slidepager-control-hover-icon' }
|
|
40
|
+
],
|
|
41
|
+
disabled: [
|
|
42
|
+
{ label: 'surface color', element: 'control', variable: '--slidepager-control-disabled-surface' },
|
|
43
|
+
{ label: 'border color', element: 'control', variable: '--slidepager-control-disabled-border' },
|
|
44
|
+
{ label: 'icon color', element: 'control', variable: '--slidepager-control-disabled-icon' }
|
|
45
|
+
]
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const allTokens: Token[] = Object.values(states).flat();
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
<script lang="ts">
|
|
52
|
+
import SlidePager, { type SlidePage } from '../../system/components/SlidePager.svelte';
|
|
53
|
+
import VariantGroup from './scaffolding/VariantGroup.svelte';
|
|
54
|
+
import ComponentEditorBase from './scaffolding/ComponentEditorBase.svelte';
|
|
55
|
+
import page04 from '../../system/assets/slide-04.webp';
|
|
56
|
+
import page05 from '../../system/assets/slide-05.webp';
|
|
57
|
+
import page06 from '../../system/assets/slide-06.webp';
|
|
58
|
+
|
|
59
|
+
const demoSlides: SlidePage[] = [
|
|
60
|
+
{ src: page04, alt: 'Types of disabilities: visual, auditory, motor, cognitive', width: 960, height: 540 },
|
|
61
|
+
{ src: page05, alt: 'Permanent, temporary, or situational', width: 960, height: 540 },
|
|
62
|
+
{ src: page06, alt: 'Non-apparent disabilities', width: 960, height: 540 }
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
// The control's two states are forced on both chevrons at once, so the strip
|
|
66
|
+
// shows each one without a pointer and without landing on an end slide.
|
|
67
|
+
function forceClass(activeState: string) {
|
|
68
|
+
if (activeState === 'hover') return 'force-hover';
|
|
69
|
+
if (activeState === 'disabled') return 'force-disabled';
|
|
70
|
+
return '';
|
|
71
|
+
}
|
|
72
|
+
</script>
|
|
73
|
+
|
|
74
|
+
<ComponentEditorBase
|
|
75
|
+
{component}
|
|
76
|
+
title="Slide Pager"
|
|
77
|
+
description="A deck of slides the reader flips through in place, one at a time. Clicking the frame opens a full-screen read that pages through every slide, with the same bar and a close button. The open preview shows it in place."
|
|
78
|
+
tokens={allTokens}
|
|
79
|
+
>
|
|
80
|
+
<VariantGroup
|
|
81
|
+
name="slidepager"
|
|
82
|
+
title="Slide Pager"
|
|
83
|
+
{states}
|
|
84
|
+
{component}
|
|
85
|
+
elementOrder={['frame', 'bar', 'control', 'counter', 'overlay']}
|
|
86
|
+
>
|
|
87
|
+
{#snippet children({ activeState }: { activeState: string })}
|
|
88
|
+
<div class="slidepager-demo">
|
|
89
|
+
<div class="slidepager-demo-inline">
|
|
90
|
+
<SlidePager slides={demoSlides} index={1} class={forceClass(activeState)} />
|
|
91
|
+
</div>
|
|
92
|
+
<div class="slidepager-demo-open">
|
|
93
|
+
<SlidePager slides={demoSlides} index={1} inline class={forceClass(activeState)} />
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
{/snippet}
|
|
97
|
+
</VariantGroup>
|
|
98
|
+
</ComponentEditorBase>
|
|
99
|
+
|
|
100
|
+
<style>
|
|
101
|
+
.slidepager-demo {
|
|
102
|
+
display: flex;
|
|
103
|
+
flex-wrap: wrap;
|
|
104
|
+
align-items: flex-start;
|
|
105
|
+
gap: var(--ui-space-32);
|
|
106
|
+
width: 100%;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.slidepager-demo-inline {
|
|
110
|
+
flex: 1 1 22rem;
|
|
111
|
+
max-width: 32rem;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.slidepager-demo-open {
|
|
115
|
+
flex: 1 1 16rem;
|
|
116
|
+
max-width: 22rem;
|
|
117
|
+
}
|
|
118
|
+
</style>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
import type { Token } from './scaffolding/types';
|
|
3
|
+
|
|
4
|
+
export const component = 'videoframe';
|
|
5
|
+
|
|
6
|
+
const states: Record<string, Token[]> = {
|
|
7
|
+
default: [
|
|
8
|
+
{ label: 'surface color', element: 'frame', variable: '--videoframe-frame-surface' },
|
|
9
|
+
{ label: 'clip surface color', element: 'frame', variable: '--videoframe-clip-surface' },
|
|
10
|
+
{ label: 'border color', element: 'frame', variable: '--videoframe-frame-border' },
|
|
11
|
+
{ label: 'border width', canBeLinked: true, element: 'frame', variable: '--videoframe-frame-border-width' },
|
|
12
|
+
{ label: 'corner radius', canBeLinked: true, element: 'frame', variable: '--videoframe-frame-radius' },
|
|
13
|
+
{ label: 'surface color', element: 'badge', variable: '--videoframe-badge-default-surface' },
|
|
14
|
+
{ label: 'border color', element: 'badge', variable: '--videoframe-badge-default-border' },
|
|
15
|
+
{ label: 'border width', canBeLinked: true, element: 'badge', variable: '--videoframe-badge-default-border-width' },
|
|
16
|
+
{ label: 'size', canBeLinked: true, element: 'badge', variable: '--videoframe-badge-default-size' },
|
|
17
|
+
{ label: 'icon color', element: 'badge', variable: '--videoframe-badge-default-icon' },
|
|
18
|
+
{ label: 'icon size', canBeLinked: true, element: 'badge', variable: '--videoframe-badge-default-icon-size' },
|
|
19
|
+
{ label: 'hover duration', element: 'badge', variable: '--videoframe-badge-duration' },
|
|
20
|
+
{ label: 'hover easing', element: 'badge', variable: '--videoframe-badge-easing' }
|
|
21
|
+
],
|
|
22
|
+
hover: [
|
|
23
|
+
{ label: 'surface color', element: 'badge', variable: '--videoframe-badge-hover-surface' },
|
|
24
|
+
{ label: 'border color', element: 'badge', variable: '--videoframe-badge-hover-border' },
|
|
25
|
+
{ label: 'icon color', element: 'badge', variable: '--videoframe-badge-hover-icon' }
|
|
26
|
+
]
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const allTokens: Token[] = Object.values(states).flat();
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<script lang="ts">
|
|
33
|
+
import VideoFrame from '../../system/components/VideoFrame.svelte';
|
|
34
|
+
import VariantGroup from './scaffolding/VariantGroup.svelte';
|
|
35
|
+
import ComponentEditorBase from './scaffolding/ComponentEditorBase.svelte';
|
|
36
|
+
import clipUrl from '../../system/assets/watch-navigation.mp4';
|
|
37
|
+
import posterUrl from '../../system/assets/watch-navigation-poster.webp';
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<ComponentEditorBase
|
|
41
|
+
{component}
|
|
42
|
+
title="Video Frame"
|
|
43
|
+
description="A poster frame that plays its clip in place when clicked."
|
|
44
|
+
tokens={allTokens}
|
|
45
|
+
>
|
|
46
|
+
<VariantGroup
|
|
47
|
+
name="videoframe"
|
|
48
|
+
title="Video Frame"
|
|
49
|
+
{states}
|
|
50
|
+
{component}
|
|
51
|
+
elementOrder={['frame', 'badge']}
|
|
52
|
+
>
|
|
53
|
+
{#snippet children({ activeState }: { activeState: string })}
|
|
54
|
+
<div class="videoframe-demo">
|
|
55
|
+
<VideoFrame
|
|
56
|
+
src={clipUrl}
|
|
57
|
+
poster={posterUrl}
|
|
58
|
+
alt="Navigation running on a smartwatch"
|
|
59
|
+
width={480}
|
|
60
|
+
height={552}
|
|
61
|
+
class={activeState === 'hover' ? 'force-hover' : ''}
|
|
62
|
+
/>
|
|
63
|
+
</div>
|
|
64
|
+
{/snippet}
|
|
65
|
+
</VariantGroup>
|
|
66
|
+
</ComponentEditorBase>
|
|
67
|
+
|
|
68
|
+
<style>
|
|
69
|
+
.videoframe-demo {
|
|
70
|
+
width: 100%;
|
|
71
|
+
max-width: 14rem;
|
|
72
|
+
}
|
|
73
|
+
</style>
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
import type { Token } from './scaffolding/types';
|
|
3
|
+
|
|
4
|
+
export const component = 'videolightbox';
|
|
5
|
+
|
|
6
|
+
const states: Record<string, Token[]> = {
|
|
7
|
+
default: [
|
|
8
|
+
{ label: 'surface color', element: 'tile', variable: '--videolightbox-tile-surface' },
|
|
9
|
+
{ label: 'border color', element: 'tile', variable: '--videolightbox-tile-border' },
|
|
10
|
+
{ label: 'border width', canBeLinked: true, element: 'tile', variable: '--videolightbox-tile-border-width' },
|
|
11
|
+
{ label: 'corner radius', canBeLinked: true, element: 'tile', variable: '--videolightbox-tile-radius' },
|
|
12
|
+
{ label: 'shadow', element: 'tile', variable: '--videolightbox-tile-shadow' },
|
|
13
|
+
{ label: 'scrim color', element: 'overlay', variable: '--videolightbox-scrim-surface' },
|
|
14
|
+
{ label: 'padding', canBeLinked: true, element: 'overlay', variable: '--videolightbox-overlay-padding' },
|
|
15
|
+
{ label: 'fade duration', element: 'overlay', variable: '--videolightbox-overlay-duration' },
|
|
16
|
+
{ label: 'fade easing', element: 'overlay', variable: '--videolightbox-overlay-easing' },
|
|
17
|
+
{ label: 'surface color', element: 'close', variable: '--videolightbox-chrome-surface' },
|
|
18
|
+
{ label: 'border color', element: 'close', variable: '--videolightbox-chrome-border' },
|
|
19
|
+
{ label: 'border width', canBeLinked: true, element: 'close', variable: '--videolightbox-chrome-border-width' },
|
|
20
|
+
{ label: 'corner radius', canBeLinked: true, element: 'close', variable: '--videolightbox-chrome-radius' },
|
|
21
|
+
{ label: 'icon color', element: 'close', variable: '--videolightbox-chrome-icon' },
|
|
22
|
+
],
|
|
23
|
+
hover: [
|
|
24
|
+
{ label: 'surface color', element: 'close', variable: '--videolightbox-chrome-hover-surface' },
|
|
25
|
+
],
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const allTokens: Token[] = Object.values(states).flat();
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<script lang="ts">
|
|
32
|
+
import VideoLightbox from '../../system/components/VideoLightbox.svelte';
|
|
33
|
+
import VariantGroup from './scaffolding/VariantGroup.svelte';
|
|
34
|
+
import ComponentEditorBase from './scaffolding/ComponentEditorBase.svelte';
|
|
35
|
+
import clipUrl from '../../system/assets/watch-navigation.mp4';
|
|
36
|
+
import posterUrl from '../../system/assets/watch-navigation-poster.webp';
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<ComponentEditorBase
|
|
40
|
+
{component}
|
|
41
|
+
title="Video Lightbox"
|
|
42
|
+
description="A small still that fades the page away and plays its clip in the middle of the screen. Click anywhere, the close button, or Escape to close it. The open preview beside the tile shows the overlay and close button in place."
|
|
43
|
+
tokens={allTokens}
|
|
44
|
+
>
|
|
45
|
+
<VariantGroup
|
|
46
|
+
name="videolightbox"
|
|
47
|
+
title="Video Lightbox"
|
|
48
|
+
{states}
|
|
49
|
+
{component}
|
|
50
|
+
elementOrder={['tile', 'overlay', 'close']}
|
|
51
|
+
>
|
|
52
|
+
{#snippet children({ activeState })}
|
|
53
|
+
<div class="videolightbox-demo">
|
|
54
|
+
<div class="videolightbox-demo-tile">
|
|
55
|
+
<VideoLightbox
|
|
56
|
+
src={clipUrl}
|
|
57
|
+
poster={posterUrl}
|
|
58
|
+
alt="Navigation running on a smartwatch"
|
|
59
|
+
width={480}
|
|
60
|
+
height={552}
|
|
61
|
+
/>
|
|
62
|
+
</div>
|
|
63
|
+
<div class="videolightbox-demo-open">
|
|
64
|
+
<VideoLightbox
|
|
65
|
+
src={clipUrl}
|
|
66
|
+
poster={posterUrl}
|
|
67
|
+
width={480}
|
|
68
|
+
height={552}
|
|
69
|
+
inline
|
|
70
|
+
class={activeState === 'hover' ? 'force-hover' : ''}
|
|
71
|
+
/>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
{/snippet}
|
|
75
|
+
</VariantGroup>
|
|
76
|
+
</ComponentEditorBase>
|
|
77
|
+
|
|
78
|
+
<style>
|
|
79
|
+
.videolightbox-demo {
|
|
80
|
+
display: flex;
|
|
81
|
+
flex-wrap: wrap;
|
|
82
|
+
align-items: center;
|
|
83
|
+
gap: var(--ui-space-32);
|
|
84
|
+
width: 100%;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.videolightbox-demo-tile {
|
|
88
|
+
width: 8rem;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.videolightbox-demo-open {
|
|
92
|
+
flex: 1 1 18rem;
|
|
93
|
+
max-width: 28rem;
|
|
94
|
+
}
|
|
95
|
+
</style>
|
|
@@ -24,6 +24,12 @@ import ImageEditor, { allTokens as imageTokens, intrinsics as imageIntrinsics }
|
|
|
24
24
|
import { catalogue as imageCatalogue } from '../../system/components/Image.svelte';
|
|
25
25
|
import ImageLightboxEditor, { allTokens as imageLightboxTokens } from './ImageLightboxEditor.svelte';
|
|
26
26
|
import { catalogue as imageLightboxCatalogue } from '../../system/components/ImageLightbox.svelte';
|
|
27
|
+
import VideoLightboxEditor, { allTokens as videoLightboxTokens } from './VideoLightboxEditor.svelte';
|
|
28
|
+
import VideoFrameEditor, { allTokens as videoFrameTokens } from './VideoFrameEditor.svelte';
|
|
29
|
+
import { catalogue as videoFrameCatalogue } from '../../system/components/VideoFrame.svelte';
|
|
30
|
+
import SlidePagerEditor, { allTokens as slidePagerTokens } from './SlidePagerEditor.svelte';
|
|
31
|
+
import { catalogue as slidePagerCatalogue } from '../../system/components/SlidePager.svelte';
|
|
32
|
+
import { catalogue as videoLightboxCatalogue } from '../../system/components/VideoLightbox.svelte';
|
|
27
33
|
import InlineEditActionsEditor, { allTokens as inlineEditActionsTokens } from './InlineEditActionsEditor.svelte';
|
|
28
34
|
import { catalogue as inlineEditActionsCatalogue } from '../../system/components/InlineEditActions.svelte';
|
|
29
35
|
import InputEditor, { allTokens as inputTokens } from './InputEditor.svelte';
|
|
@@ -81,7 +87,10 @@ type BuiltInComponentId =
|
|
|
81
87
|
| 'tabbar'
|
|
82
88
|
| 'toggle'
|
|
83
89
|
| 'tooltip'
|
|
84
|
-
| 'progressbar'
|
|
90
|
+
| 'progressbar'
|
|
91
|
+
| 'videolightbox'
|
|
92
|
+
| 'videoframe'
|
|
93
|
+
| 'slidepager';
|
|
85
94
|
|
|
86
95
|
/**
|
|
87
96
|
* Public component id type. Widened to `string` because consumers can register
|
|
@@ -255,6 +264,36 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
|
|
|
255
264
|
catalogue: imageLightboxCatalogue,
|
|
256
265
|
origin: 'system',
|
|
257
266
|
},
|
|
267
|
+
videolightbox: {
|
|
268
|
+
id: 'videolightbox',
|
|
269
|
+
label: 'Video Lightbox',
|
|
270
|
+
icon: 'fas fa-circle-play',
|
|
271
|
+
sourceFile: 'src/system/components/VideoLightbox.svelte',
|
|
272
|
+
editorComponent: VideoLightboxEditor,
|
|
273
|
+
schema: videoLightboxTokens,
|
|
274
|
+
catalogue: videoLightboxCatalogue,
|
|
275
|
+
origin: 'system',
|
|
276
|
+
},
|
|
277
|
+
videoframe: {
|
|
278
|
+
id: 'videoframe',
|
|
279
|
+
label: 'Video Frame',
|
|
280
|
+
icon: 'fas fa-film',
|
|
281
|
+
sourceFile: 'src/system/components/VideoFrame.svelte',
|
|
282
|
+
editorComponent: VideoFrameEditor,
|
|
283
|
+
schema: videoFrameTokens,
|
|
284
|
+
catalogue: videoFrameCatalogue,
|
|
285
|
+
origin: 'system',
|
|
286
|
+
},
|
|
287
|
+
slidepager: {
|
|
288
|
+
id: 'slidepager',
|
|
289
|
+
label: 'Slide Pager',
|
|
290
|
+
icon: 'fas fa-images',
|
|
291
|
+
sourceFile: 'src/system/components/SlidePager.svelte',
|
|
292
|
+
editorComponent: SlidePagerEditor,
|
|
293
|
+
schema: slidePagerTokens,
|
|
294
|
+
catalogue: slidePagerCatalogue,
|
|
295
|
+
origin: 'system',
|
|
296
|
+
},
|
|
258
297
|
inlineeditactions: {
|
|
259
298
|
id: 'inlineeditactions',
|
|
260
299
|
label: 'Inline Edit Actions',
|
|
@@ -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,
|
|
12
|
+
import { BLUR, BORDER_WIDTH, DOT_SIZE, DURATION, RADIUS, SCALE, SHADOW, TRACK_HEIGHT, HAIRLINE_INSET } from '../../ui/variantScales';
|
|
13
13
|
import {
|
|
14
14
|
editorState,
|
|
15
15
|
getComponentPropertySiblings,
|
|
@@ -80,7 +80,6 @@
|
|
|
80
80
|
'easing',
|
|
81
81
|
'blur',
|
|
82
82
|
'scale',
|
|
83
|
-
'opacity',
|
|
84
83
|
'shadow',
|
|
85
84
|
'text-color',
|
|
86
85
|
'surface',
|
|
@@ -161,7 +160,6 @@
|
|
|
161
160
|
'easing': { component: UIEasingSelector },
|
|
162
161
|
'blur': { component: UIVariantSelector, extra: () => ({ ...BLUR }) },
|
|
163
162
|
'scale': { component: UIVariantSelector, extra: () => ({ ...SCALE }) },
|
|
164
|
-
'opacity': { component: UIVariantSelector, extra: () => ({ ...SCRIM_OPACITY }) },
|
|
165
163
|
'shadow': { component: UIVariantSelector, extra: () => ({ ...SHADOW }) },
|
|
166
164
|
'surface': { component: UIPaletteSelector, extra: paletteExtra },
|
|
167
165
|
'border': { component: UIPaletteSelector, extra: paletteExtra },
|
|
@@ -192,7 +190,6 @@
|
|
|
192
190
|
'easing',
|
|
193
191
|
'blur',
|
|
194
192
|
'scale',
|
|
195
|
-
'opacity',
|
|
196
193
|
'shadow',
|
|
197
194
|
'surface',
|
|
198
195
|
'border-width',
|
|
@@ -11,7 +11,6 @@ export type TokenKind =
|
|
|
11
11
|
| 'length'
|
|
12
12
|
| 'blur'
|
|
13
13
|
| 'scale'
|
|
14
|
-
| 'opacity'
|
|
15
14
|
| 'shadow'
|
|
16
15
|
| 'font-family'
|
|
17
16
|
| 'font-weight'
|
|
@@ -60,9 +59,6 @@ export const KIND_RULES: ReadonlyArray<{
|
|
|
60
59
|
{ kind: 'dot-size', suffix: ['-dot-size'] },
|
|
61
60
|
{ kind: 'blur', suffix: ['-blur'], prefix: ['--blur-'] },
|
|
62
61
|
{ 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'] },
|
|
66
62
|
{ kind: 'shadow', suffix: ['-shadow'], prefix: ['--shadow-'] },
|
|
67
63
|
{ kind: 'padding', suffix: ['-padding', '-margin'] },
|
|
68
64
|
{ kind: 'gap', suffix: ['-gap'] },
|
|
@@ -186,12 +186,19 @@ 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: '
|
|
189
|
+
sel: '.image-lightbox-overlay', fill: 'var(--imagelightbox-scrim-surface)',
|
|
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
|
|
193
193
|
// floats over the photo rather than a scrim of its own.
|
|
194
194
|
{ sel: '.image-lightbox-chrome', stem: 'imagelightbox-chrome', positioned: true, unmasked: true },
|
|
195
|
+
// The trigger inside clips the still, so the tile itself stays unclipped.
|
|
196
|
+
{ sel: '.videolightbox', stem: 'videolightbox-tile' },
|
|
197
|
+
{
|
|
198
|
+
sel: '.videolightbox-modal', fill: 'var(--videolightbox-scrim-surface)',
|
|
199
|
+
stroke: 'transparent', positioned: true, unmasked: true,
|
|
200
|
+
},
|
|
201
|
+
{ sel: '.videolightbox-close', stem: 'videolightbox-chrome', positioned: true, unmasked: true },
|
|
195
202
|
|
|
196
203
|
// Status blocks
|
|
197
204
|
...STATUS_VARIANTS.map((v) => ({ sel: `.callout-${v}`, stem: `callout-${v}` })),
|