@motion-proto/live-tokens 0.56.1 → 0.58.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 (95) hide show
  1. package/.claude/skills/live-tokens-create-component/SKILL.md +13 -2
  2. package/.claude/skills/live-tokens-create-component/references/sketch-mode.md +202 -0
  3. package/.claude/skills/live-tokens-pair-fonts/SKILL.md +2 -2
  4. package/.claude/skills/live-tokens-pick-component/SKILL.md +1 -1
  5. package/CHANGELOG.md +192 -0
  6. package/README.md +1 -1
  7. package/bin/cli.mjs +2 -1
  8. package/dist-plugin/adjust/index.cjs +1 -0
  9. package/dist-plugin/adjust/index.d.cts +2 -2
  10. package/dist-plugin/adjust/index.d.ts +2 -2
  11. package/dist-plugin/adjust/index.js +1 -1
  12. package/dist-plugin/{chunk-TKZBVIW5.js → chunk-E5QYON4L.js} +59 -2
  13. package/dist-plugin/{chunk-PB2JTK2H.js → chunk-LW4SR7AZ.js} +39 -6
  14. package/dist-plugin/{chunk-YR6GPXW2.js → chunk-XWXIMTWZ.js} +0 -5
  15. package/dist-plugin/{chunk-D3ZVKOR4.js → chunk-Y5CNFSSV.js} +1 -0
  16. package/dist-plugin/{dataPaths-DBN0RPuT.d.cts → dataPaths-CRfD1LdA.d.cts} +3 -0
  17. package/dist-plugin/{dataPaths-DBN0RPuT.d.ts → dataPaths-CRfD1LdA.d.ts} +3 -0
  18. package/dist-plugin/fontPairing/index.cjs +4 -2
  19. package/dist-plugin/fontPairing/index.d.cts +3 -3
  20. package/dist-plugin/fontPairing/index.d.ts +3 -3
  21. package/dist-plugin/fontPairing/index.js +4 -3
  22. package/dist-plugin/generateColorsAndType/index.cjs +22 -9
  23. package/dist-plugin/generateColorsAndType/index.d.cts +2 -2
  24. package/dist-plugin/generateColorsAndType/index.d.ts +2 -2
  25. package/dist-plugin/generateColorsAndType/index.js +8 -5
  26. package/dist-plugin/index.cjs +158 -9
  27. package/dist-plugin/index.d.cts +1 -1
  28. package/dist-plugin/index.d.ts +1 -1
  29. package/dist-plugin/index.js +71 -4
  30. package/dist-plugin/migrateData/index.cjs +1 -0
  31. package/dist-plugin/migrateData/index.d.cts +1 -1
  32. package/dist-plugin/migrateData/index.d.ts +1 -1
  33. package/dist-plugin/migrateData/index.js +1 -1
  34. package/dist-plugin/{themeTypes-BAqtv4XO.d.cts → themeTypes-DSV3Zisf.d.cts} +12 -1
  35. package/dist-plugin/{themeTypes-BAqtv4XO.d.ts → themeTypes-DSV3Zisf.d.ts} +12 -1
  36. package/dist-plugin/tokensCssMigrations/index.cjs +58 -1
  37. package/dist-plugin/tokensCssMigrations/index.d.cts +1 -1
  38. package/dist-plugin/tokensCssMigrations/index.d.ts +1 -1
  39. package/dist-plugin/tokensCssMigrations/index.js +3 -3
  40. package/package.json +3 -1
  41. package/src/editor/core/fonts/applyFontPairing.ts +3 -2
  42. package/src/editor/core/fonts/fontLoader.ts +1 -0
  43. package/src/editor/core/fonts/fontMigration.ts +31 -1
  44. package/src/editor/core/palettes/paletteDerivation.ts +9 -2
  45. package/src/editor/core/sketch/maskField.ts +385 -0
  46. package/src/editor/core/sketch/sketchLayer.ts +1106 -0
  47. package/src/editor/core/sketch/sketchPresetService.ts +65 -0
  48. package/src/editor/core/sketch/sketchPresets.ts +345 -0
  49. package/src/editor/core/sketch/sketchStore.ts +190 -0
  50. package/src/editor/core/store/editorPersistence.ts +28 -12
  51. package/src/editor/core/store/editorTypes.ts +4 -1
  52. package/src/editor/core/store/editorViewStore.ts +2 -2
  53. package/src/editor/core/store/gradientSource.ts +15 -1
  54. package/src/editor/core/themes/parsers/gradient.ts +62 -4
  55. package/src/editor/core/themes/slices/gradients.ts +75 -14
  56. package/src/editor/core/themes/themeTypes.ts +6 -1
  57. package/src/editor/docs/Docs.svelte +4 -3
  58. package/src/editor/docs/chapters.ts +1 -0
  59. package/src/editor/docs/content/01-overview.md +2 -1
  60. package/src/editor/docs/content/editing-tokens.md +5 -1
  61. package/src/editor/docs/content/sketch-mode.md +183 -0
  62. package/src/editor/docs/content.generated.ts +3 -2
  63. package/src/editor/overlay/LiveEditorOverlay.svelte +15 -0
  64. package/src/editor/pages/EditorShell.svelte +43 -0
  65. package/src/editor/ui/EditorViewSwitcher.svelte +30 -17
  66. package/src/editor/ui/FontStackEditor.svelte +3 -0
  67. package/src/editor/ui/GradientEditor.svelte +38 -1
  68. package/src/editor/ui/UIReveal.svelte +7 -1
  69. package/src/editor/ui/UISegmentedControl.svelte +4 -8
  70. package/src/editor/ui/sections/GradientsSection.svelte +47 -1
  71. package/src/editor/ui/sketch/SketchDial.svelte +124 -0
  72. package/src/editor/ui/sketch/SketchPreview.svelte +119 -0
  73. package/src/editor/ui/sketch/SketchRange.svelte +185 -0
  74. package/src/editor/ui/sketch/SketchTab.svelte +1264 -0
  75. package/src/live-tokens/data/colors-and-type/autumn.json +17 -0
  76. package/src/live-tokens/data/colors-and-type/default.json +17 -0
  77. package/src/live-tokens/data/colors-and-type/halloween.json +17 -0
  78. package/src/live-tokens/data/colors-and-type/midnight-study.json +17 -0
  79. package/src/live-tokens/data/colors-and-type/ocean.json +17 -0
  80. package/src/live-tokens/data/colors-and-type/royal-velvet.json +17 -0
  81. package/src/live-tokens/data/colors-and-type/sketchy.json +2520 -0
  82. package/src/live-tokens/data/colors-and-type/spring-meadow.json +17 -0
  83. package/src/live-tokens/data/colors-and-type/sunset.json +17 -0
  84. package/src/live-tokens/data/themes/autumn.json +17 -0
  85. package/src/live-tokens/data/themes/halloween.json +17 -0
  86. package/src/live-tokens/data/themes/midnight-study.json +17 -0
  87. package/src/live-tokens/data/themes/ocean.json +17 -0
  88. package/src/live-tokens/data/themes/royal-velvet.json +17 -0
  89. package/src/live-tokens/data/themes/sketchy.json +3984 -0
  90. package/src/live-tokens/data/themes/spring-meadow.json +17 -0
  91. package/src/live-tokens/data/themes/sunset.json +17 -0
  92. package/src/live-tokens/data/tokens.generated.css +1 -0
  93. package/src/system/components/Card.svelte +12 -1
  94. package/src/system/components/SectionDivider.svelte +4 -0
  95. package/src/system/styles/tokens.css +15 -2
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  cssColorToOklch,
3
3
  gamutClamp,
4
- oklchToCssClamped
5
- } from "./chunk-YR6GPXW2.js";
4
+ oklchToCss
5
+ } from "./chunk-XWXIMTWZ.js";
6
6
 
7
7
  // src/editor/core/storage/files/versionedFileResourceClient.ts
8
8
  function sanitizeFileName(name) {
@@ -21,6 +21,30 @@ function formatColorOpacity(name, opacity) {
21
21
  }
22
22
 
23
23
  // src/editor/core/themes/parsers/gradient.ts
24
+ var LINEAR_DIRECTIONS = [
25
+ "to top",
26
+ "to top right",
27
+ "to right",
28
+ "to bottom right",
29
+ "to bottom",
30
+ "to bottom left",
31
+ "to left",
32
+ "to top left"
33
+ ];
34
+ var DIRECTION_ANGLES = {
35
+ "to top": 0,
36
+ "to top right": 45,
37
+ "to right": 90,
38
+ "to bottom right": 135,
39
+ "to bottom": 180,
40
+ "to bottom left": 225,
41
+ "to left": 270,
42
+ "to top left": 315
43
+ };
44
+ function parseDirection(raw) {
45
+ const norm = raw.trim().toLowerCase().replace(/\s+/g, " ");
46
+ return LINEAR_DIRECTIONS.includes(norm) ? norm : null;
47
+ }
24
48
  var RADIAL_BASE_PX = 100;
25
49
  function formatStopColor(s) {
26
50
  const opacity = s.opacity ?? 100;
@@ -48,11 +72,15 @@ function formatGradientValue(v) {
48
72
  return first ? formatStopColor(first) : "transparent";
49
73
  }
50
74
  const stops = formatGradientStops(v.stops);
51
- if (v.type === "linear") return `linear-gradient(${v.angle}deg, ${stops})`;
75
+ if (v.type === "linear") {
76
+ return `linear-gradient(${v.direction ?? `${v.angle}deg`}, ${stops})`;
77
+ }
52
78
  return `radial-gradient(${formatRadialShape(v)} at ${v.centerX ?? 50}% 50%, ${stops})`;
53
79
  }
54
80
  var NUM = String.raw`-?\d+(?:\.\d+)?`;
55
- var LINEAR_RE = new RegExp(String.raw`^linear-gradient\(\s*(${NUM})deg\s*,\s*(.+)\)$`, "i");
81
+ var HEADING = String.raw`${NUM}deg|to\s+\w+(?:\s+\w+)?`;
82
+ var LINEAR_RE = new RegExp(String.raw`^linear-gradient\(\s*(${HEADING})\s*,\s*(.+)\)$`, "i");
83
+ var DEG_RE = new RegExp(String.raw`^(${NUM})deg$`, "i");
56
84
  var RADIAL_RE = new RegExp(
57
85
  String.raw`^radial-gradient\(\s*(circle|circle\s+${NUM}px|ellipse\s+${NUM}px\s+${NUM}px)\s+at\s+(${NUM})%\s+50%\s*,\s*(.+)\)$`,
58
86
  "i"
@@ -111,8 +139,12 @@ function parseGradientValue(value) {
111
139
  const css = value.trim();
112
140
  const linear = css.match(LINEAR_RE);
113
141
  if (linear) {
142
+ const deg = linear[1].match(DEG_RE);
143
+ const direction = deg ? null : parseDirection(linear[1]);
144
+ if (!deg && !direction) return null;
114
145
  const stops2 = parseStops(linear[2]);
115
- return stops2 && { type: "linear", angle: parseFloat(linear[1]), stops: stops2 };
146
+ if (!stops2) return null;
147
+ return deg ? { type: "linear", angle: parseFloat(deg[1]), stops: stops2 } : { type: "linear", angle: 0, direction, stops: stops2 };
116
148
  }
117
149
  const radial = css.match(RADIAL_RE);
118
150
  if (!radial) return null;
@@ -307,7 +339,7 @@ function scaleStepToX(step, scale) {
307
339
  return scale.steps.length > 1 ? idx / (scale.steps.length - 1) * 100 : 50;
308
340
  }
309
341
  function serializeDerivedValue(value) {
310
- return value.kind === "raw" ? value.css : oklchToCssClamped(value.l, value.c, value.h);
342
+ return value.kind === "raw" ? value.css : oklchToCss(value.l, value.c, value.h);
311
343
  }
312
344
  function computePaletteOklch(index, base, lightnessCurve, saturationCurve, curveOffset, hueCurve) {
313
345
  const { c: baseC } = base;
@@ -587,6 +619,7 @@ function reconcilePalettesFromCssVars(palettes, cssVars) {
587
619
 
588
620
  export {
589
621
  parseColorOpacity,
622
+ DIRECTION_ANGLES,
590
623
  formatGradientValue,
591
624
  parseGradientValue,
592
625
  sanitizeFileName,
@@ -99,10 +99,6 @@ function oklchToCss(l, c, h) {
99
99
  const cs = trim(c, 4);
100
100
  return `oklch(${trim(l, 4)} ${cs} ${cs === "0" ? "0" : trim(h, 2)})`;
101
101
  }
102
- function oklchToCssClamped(l, c, h) {
103
- const g = gamutClamp(l, c, h);
104
- return oklchToCss(g.l, g.c, g.h);
105
- }
106
102
  var OKLCH_RE = /^oklch\(\s*([\d.]+)(%?)\s+([\d.]+)(%?)\s+([\d.]+)(?:deg)?\s*\)$/i;
107
103
  var HEX6_RE = /^#[0-9a-f]{6}$/i;
108
104
  function parseOklchCss(value) {
@@ -124,6 +120,5 @@ export {
124
120
  oklchToHexClamped,
125
121
  gamutClamp,
126
122
  oklchToCss,
127
- oklchToCssClamped,
128
123
  cssColorToOklch
129
124
  };
@@ -42,6 +42,7 @@ function resolveDataDirs(opts = {}) {
42
42
  colorsAndTypeDir: opts.colorsAndTypeDir ? path.resolve(opts.colorsAndTypeDir) : fileConfig.colorsAndTypeDir ? path.resolve(fileConfig.colorsAndTypeDir) : sub("colors-and-type"),
43
43
  componentConfigsDir: opts.componentConfigsDir ? path.resolve(opts.componentConfigsDir) : fileConfig.componentConfigsDir ? path.resolve(fileConfig.componentConfigsDir) : sub("component-configs"),
44
44
  themesDir: opts.themesDir ? path.resolve(opts.themesDir) : fileConfig.themesDir ? path.resolve(fileConfig.themesDir) : sub("themes"),
45
+ sketchPresetsDir: sub("sketch-presets"),
45
46
  legacyManifestsDir: fileConfig.manifestsDir ? path.resolve(fileConfig.manifestsDir) : void 0
46
47
  };
47
48
  }
@@ -28,6 +28,9 @@ interface ResolvedDataDirs {
28
28
  colorsAndTypeDir: string;
29
29
  componentConfigsDir: string;
30
30
  themesDir: string;
31
+ /** No per-folder config override: sketch presets are a draft-look artifact
32
+ * with no reason to live apart from the rest of the data tree. */
33
+ sketchPresetsDir: string;
31
34
  /** Absolute path of the retired `manifestsDir` key, when the config sets it.
32
35
  * Only the pre-0.48 layout detector and the migration read it. */
33
36
  legacyManifestsDir?: string;
@@ -28,6 +28,9 @@ interface ResolvedDataDirs {
28
28
  colorsAndTypeDir: string;
29
29
  componentConfigsDir: string;
30
30
  themesDir: string;
31
+ /** No per-folder config override: sketch presets are a draft-look artifact
32
+ * with no reason to live apart from the rest of the data tree. */
33
+ sketchPresetsDir: string;
31
34
  /** Absolute path of the retired `manifestsDir` key, when the config sets it.
32
35
  * Only the pre-0.48 layout detector and the migration read it. */
33
36
  legacyManifestsDir?: string;
@@ -143,12 +143,13 @@ function fontPairingLabel(stacks, sources) {
143
143
  }
144
144
 
145
145
  // src/editor/core/fonts/applyFontPairing.ts
146
- var SLOT_ORDER = ["display", "body", "serif", "mono"];
146
+ var SLOT_ORDER = ["display", "body", "serif", "mono", "editorial"];
147
147
  var SLOT_VARIABLES = {
148
148
  display: "--font-display",
149
149
  body: "--font-sans",
150
150
  serif: "--font-serif",
151
- mono: "--font-mono"
151
+ mono: "--font-mono",
152
+ editorial: "--font-editorial"
152
153
  };
153
154
  function slugifyFamily(name) {
154
155
  return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
@@ -391,6 +392,7 @@ function resolveDataDirs(opts = {}) {
391
392
  colorsAndTypeDir: opts.colorsAndTypeDir ? import_path.default.resolve(opts.colorsAndTypeDir) : fileConfig.colorsAndTypeDir ? import_path.default.resolve(fileConfig.colorsAndTypeDir) : sub("colors-and-type"),
392
393
  componentConfigsDir: opts.componentConfigsDir ? import_path.default.resolve(opts.componentConfigsDir) : fileConfig.componentConfigsDir ? import_path.default.resolve(fileConfig.componentConfigsDir) : sub("component-configs"),
393
394
  themesDir: opts.themesDir ? import_path.default.resolve(opts.themesDir) : fileConfig.themesDir ? import_path.default.resolve(fileConfig.themesDir) : sub("themes"),
395
+ sketchPresetsDir: sub("sketch-presets"),
394
396
  legacyManifestsDir: fileConfig.manifestsDir ? import_path.default.resolve(fileConfig.manifestsDir) : void 0
395
397
  };
396
398
  }
@@ -1,7 +1,7 @@
1
- import { c as FontStackVariable, C as ColorsAndType, b as FontStack, F as FontSource } from '../themeTypes-BAqtv4XO.cjs';
2
- export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-DBN0RPuT.cjs';
1
+ import { c as FontStackVariable, C as ColorsAndType, b as FontStack, F as FontSource } from '../themeTypes-DSV3Zisf.cjs';
2
+ export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-CRfD1LdA.cjs';
3
3
 
4
- type PairingSlot = 'display' | 'body' | 'serif' | 'mono';
4
+ type PairingSlot = 'display' | 'body' | 'serif' | 'mono' | 'editorial';
5
5
  interface PairingFace {
6
6
  name: string;
7
7
  url: string;
@@ -1,7 +1,7 @@
1
- import { c as FontStackVariable, C as ColorsAndType, b as FontStack, F as FontSource } from '../themeTypes-BAqtv4XO.js';
2
- export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-DBN0RPuT.js';
1
+ import { c as FontStackVariable, C as ColorsAndType, b as FontStack, F as FontSource } from '../themeTypes-DSV3Zisf.js';
2
+ export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-CRfD1LdA.js';
3
3
 
4
- type PairingSlot = 'display' | 'body' | 'serif' | 'mono';
4
+ type PairingSlot = 'display' | 'body' | 'serif' | 'mono' | 'editorial';
5
5
  interface PairingFace {
6
6
  name: string;
7
7
  url: string;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  readLiveTokensConfig,
3
3
  resolveDataDirs
4
- } from "../chunk-D3ZVKOR4.js";
4
+ } from "../chunk-Y5CNFSSV.js";
5
5
 
6
6
  // src/editor/core/fonts/fontParse.ts
7
7
  function parseGoogleFontsUrl(url2) {
@@ -101,12 +101,13 @@ function fontPairingLabel(stacks, sources) {
101
101
  }
102
102
 
103
103
  // src/editor/core/fonts/applyFontPairing.ts
104
- var SLOT_ORDER = ["display", "body", "serif", "mono"];
104
+ var SLOT_ORDER = ["display", "body", "serif", "mono", "editorial"];
105
105
  var SLOT_VARIABLES = {
106
106
  display: "--font-display",
107
107
  body: "--font-sans",
108
108
  serif: "--font-serif",
109
- mono: "--font-mono"
109
+ mono: "--font-mono",
110
+ editorial: "--font-editorial"
110
111
  };
111
112
  function slugifyFamily(name) {
112
113
  return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
@@ -139,10 +139,6 @@ function oklchToCss(l, c, h) {
139
139
  const cs = trim(c, 4);
140
140
  return `oklch(${trim(l, 4)} ${cs} ${cs === "0" ? "0" : trim(h, 2)})`;
141
141
  }
142
- function oklchToCssClamped(l, c, h) {
143
- const g = gamutClamp(l, c, h);
144
- return oklchToCss(g.l, g.c, g.h);
145
- }
146
142
  var OKLCH_RE = /^oklch\(\s*([\d.]+)(%?)\s+([\d.]+)(%?)\s+([\d.]+)(?:deg)?\s*\)$/i;
147
143
  var HEX6_RE = /^#[0-9a-f]{6}$/i;
148
144
  function parseOklchCss(value) {
@@ -336,7 +332,7 @@ function scaleStepToX(step, scale) {
336
332
  return scale.steps.length > 1 ? idx / (scale.steps.length - 1) * 100 : 50;
337
333
  }
338
334
  function serializeDerivedValue(value) {
339
- return value.kind === "raw" ? value.css : oklchToCssClamped(value.l, value.c, value.h);
335
+ return value.kind === "raw" ? value.css : oklchToCss(value.l, value.c, value.h);
340
336
  }
341
337
  function computePaletteOklch(index, base, lightnessCurve, saturationCurve, curveOffset, hueCurve) {
342
338
  const { c: baseC } = base;
@@ -609,6 +605,16 @@ function formatColorOpacity(name, opacity) {
609
605
  }
610
606
 
611
607
  // src/editor/core/themes/parsers/gradient.ts
608
+ var DIRECTION_ANGLES = {
609
+ "to top": 0,
610
+ "to top right": 45,
611
+ "to right": 90,
612
+ "to bottom right": 135,
613
+ "to bottom": 180,
614
+ "to bottom left": 225,
615
+ "to left": 270,
616
+ "to top left": 315
617
+ };
612
618
  var RADIAL_BASE_PX = 100;
613
619
  function formatStopColor(s) {
614
620
  const opacity = s.opacity ?? 100;
@@ -636,11 +642,15 @@ function formatGradientValue(v) {
636
642
  return first ? formatStopColor(first) : "transparent";
637
643
  }
638
644
  const stops = formatGradientStops(v.stops);
639
- if (v.type === "linear") return `linear-gradient(${v.angle}deg, ${stops})`;
645
+ if (v.type === "linear") {
646
+ return `linear-gradient(${v.direction ?? `${v.angle}deg`}, ${stops})`;
647
+ }
640
648
  return `radial-gradient(${formatRadialShape(v)} at ${v.centerX ?? 50}% 50%, ${stops})`;
641
649
  }
642
650
  var NUM = String.raw`-?\d+(?:\.\d+)?`;
643
- var LINEAR_RE = new RegExp(String.raw`^linear-gradient\(\s*(${NUM})deg\s*,\s*(.+)\)$`, "i");
651
+ var HEADING = String.raw`${NUM}deg|to\s+\w+(?:\s+\w+)?`;
652
+ var LINEAR_RE = new RegExp(String.raw`^linear-gradient\(\s*(${HEADING})\s*,\s*(.+)\)$`, "i");
653
+ var DEG_RE = new RegExp(String.raw`^(${NUM})deg$`, "i");
644
654
  var RADIAL_RE = new RegExp(
645
655
  String.raw`^radial-gradient\(\s*(circle|circle\s+${NUM}px|ellipse\s+${NUM}px\s+${NUM}px)\s+at\s+(${NUM})%\s+50%\s*,\s*(.+)\)$`,
646
656
  "i"
@@ -655,7 +665,8 @@ function makeDefaultGradients() {
655
665
  {
656
666
  variable: "--gradient-1",
657
667
  type: "linear",
658
- angle: 90,
668
+ angle: DIRECTION_ANGLES["to right"],
669
+ direction: "to right",
659
670
  stops: [
660
671
  { position: 0, color: "--color-brand-500" },
661
672
  { position: 100, color: "--color-accent-500" }
@@ -673,7 +684,8 @@ function makeDefaultGradients() {
673
684
  {
674
685
  variable: "--gradient-3",
675
686
  type: "linear",
676
- angle: 90,
687
+ angle: DIRECTION_ANGLES["to right"],
688
+ direction: "to right",
677
689
  stops: [
678
690
  { position: 0, color: "--color-success-500" },
679
691
  { position: 100, color: "--color-info-500" }
@@ -1914,6 +1926,7 @@ function resolveDataDirs(opts = {}) {
1914
1926
  colorsAndTypeDir: opts.colorsAndTypeDir ? import_path.default.resolve(opts.colorsAndTypeDir) : fileConfig.colorsAndTypeDir ? import_path.default.resolve(fileConfig.colorsAndTypeDir) : sub("colors-and-type"),
1915
1927
  componentConfigsDir: opts.componentConfigsDir ? import_path.default.resolve(opts.componentConfigsDir) : fileConfig.componentConfigsDir ? import_path.default.resolve(fileConfig.componentConfigsDir) : sub("component-configs"),
1916
1928
  themesDir: opts.themesDir ? import_path.default.resolve(opts.themesDir) : fileConfig.themesDir ? import_path.default.resolve(fileConfig.themesDir) : sub("themes"),
1929
+ sketchPresetsDir: sub("sketch-presets"),
1917
1930
  legacyManifestsDir: fileConfig.manifestsDir ? import_path.default.resolve(fileConfig.manifestsDir) : void 0
1918
1931
  };
1919
1932
  }
@@ -1,5 +1,5 @@
1
- import { F as FontSource, b as FontStack, G as GradientDiskToken, O as Oklch, H as HarmonyMode, C as ColorsAndType } from '../themeTypes-BAqtv4XO.cjs';
2
- export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-DBN0RPuT.cjs';
1
+ import { F as FontSource, b as FontStack, G as GradientDiskToken, O as Oklch, H as HarmonyMode, C as ColorsAndType } from '../themeTypes-DSV3Zisf.cjs';
2
+ export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-CRfD1LdA.cjs';
3
3
  export { C as CURRENT_COMPONENT_SCHEMA_VERSION } from '../index-4N-Orzzi.cjs';
4
4
 
5
5
  /**
@@ -1,5 +1,5 @@
1
- import { F as FontSource, b as FontStack, G as GradientDiskToken, O as Oklch, H as HarmonyMode, C as ColorsAndType } from '../themeTypes-BAqtv4XO.js';
2
- export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-DBN0RPuT.js';
1
+ import { F as FontSource, b as FontStack, G as GradientDiskToken, O as Oklch, H as HarmonyMode, C as ColorsAndType } from '../themeTypes-DSV3Zisf.js';
2
+ export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-CRfD1LdA.js';
3
3
  export { C as CURRENT_COMPONENT_SCHEMA_VERSION } from '../index-4N-Orzzi.js';
4
4
 
5
5
  /**
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  DEFAULT_PALETTE_LIGHTNESS,
3
3
  DEFAULT_PALETTE_SATURATION,
4
+ DIRECTION_ANGLES,
4
5
  PALETTE_SPECS,
5
6
  PALETTE_STEPS,
6
7
  SCALES,
@@ -14,7 +15,7 @@ import {
14
15
  scaleToCssVar,
15
16
  setCurveAnchor,
16
17
  syncBaseAnchor
17
- } from "../chunk-PB2JTK2H.js";
18
+ } from "../chunk-LW4SR7AZ.js";
18
19
  import {
19
20
  CURRENT_COLORS_AND_TYPE_SCHEMA_VERSION,
20
21
  CURRENT_COMPONENT_SCHEMA_VERSION
@@ -25,11 +26,11 @@ import {
25
26
  hexToOklch,
26
27
  oklchToHex,
27
28
  oklchToHexClamped
28
- } from "../chunk-YR6GPXW2.js";
29
+ } from "../chunk-XWXIMTWZ.js";
29
30
  import {
30
31
  readLiveTokensConfig,
31
32
  resolveDataDirs
32
- } from "../chunk-D3ZVKOR4.js";
33
+ } from "../chunk-Y5CNFSSV.js";
33
34
 
34
35
  // src/editor/core/store/editorCore.ts
35
36
  import { writable, derived, get } from "svelte/store";
@@ -50,7 +51,8 @@ function makeDefaultGradients() {
50
51
  {
51
52
  variable: "--gradient-1",
52
53
  type: "linear",
53
- angle: 90,
54
+ angle: DIRECTION_ANGLES["to right"],
55
+ direction: "to right",
54
56
  stops: [
55
57
  { position: 0, color: "--color-brand-500" },
56
58
  { position: 100, color: "--color-accent-500" }
@@ -68,7 +70,8 @@ function makeDefaultGradients() {
68
70
  {
69
71
  variable: "--gradient-3",
70
72
  type: "linear",
71
- angle: 90,
73
+ angle: DIRECTION_ANGLES["to right"],
74
+ direction: "to right",
72
75
  stops: [
73
76
  { position: 0, color: "--color-success-500" },
74
77
  { position: 100, color: "--color-info-500" }
@@ -64,6 +64,20 @@ function formatColorOpacity(name, opacity) {
64
64
  }
65
65
 
66
66
  // src/editor/core/themes/parsers/gradient.ts
67
+ var LINEAR_DIRECTIONS = [
68
+ "to top",
69
+ "to top right",
70
+ "to right",
71
+ "to bottom right",
72
+ "to bottom",
73
+ "to bottom left",
74
+ "to left",
75
+ "to top left"
76
+ ];
77
+ function parseDirection(raw) {
78
+ const norm = raw.trim().toLowerCase().replace(/\s+/g, " ");
79
+ return LINEAR_DIRECTIONS.includes(norm) ? norm : null;
80
+ }
67
81
  var RADIAL_BASE_PX = 100;
68
82
  function formatStopColor(s) {
69
83
  const opacity = s.opacity ?? 100;
@@ -91,11 +105,15 @@ function formatGradientValue(v) {
91
105
  return first ? formatStopColor(first) : "transparent";
92
106
  }
93
107
  const stops = formatGradientStops(v.stops);
94
- if (v.type === "linear") return `linear-gradient(${v.angle}deg, ${stops})`;
108
+ if (v.type === "linear") {
109
+ return `linear-gradient(${v.direction ?? `${v.angle}deg`}, ${stops})`;
110
+ }
95
111
  return `radial-gradient(${formatRadialShape(v)} at ${v.centerX ?? 50}% 50%, ${stops})`;
96
112
  }
97
113
  var NUM = String.raw`-?\d+(?:\.\d+)?`;
98
- var LINEAR_RE = new RegExp(String.raw`^linear-gradient\(\s*(${NUM})deg\s*,\s*(.+)\)$`, "i");
114
+ var HEADING = String.raw`${NUM}deg|to\s+\w+(?:\s+\w+)?`;
115
+ var LINEAR_RE = new RegExp(String.raw`^linear-gradient\(\s*(${HEADING})\s*,\s*(.+)\)$`, "i");
116
+ var DEG_RE = new RegExp(String.raw`^(${NUM})deg$`, "i");
99
117
  var RADIAL_RE = new RegExp(
100
118
  String.raw`^radial-gradient\(\s*(circle|circle\s+${NUM}px|ellipse\s+${NUM}px\s+${NUM}px)\s+at\s+(${NUM})%\s+50%\s*,\s*(.+)\)$`,
101
119
  "i"
@@ -154,8 +172,12 @@ function parseGradientValue(value) {
154
172
  const css = value.trim();
155
173
  const linear = css.match(LINEAR_RE);
156
174
  if (linear) {
175
+ const deg = linear[1].match(DEG_RE);
176
+ const direction = deg ? null : parseDirection(linear[1]);
177
+ if (!deg && !direction) return null;
157
178
  const stops2 = parseStops(linear[2]);
158
- return stops2 && { type: "linear", angle: parseFloat(linear[1]), stops: stops2 };
179
+ if (!stops2) return null;
180
+ return deg ? { type: "linear", angle: parseFloat(deg[1]), stops: stops2 } : { type: "linear", angle: 0, direction, stops: stops2 };
159
181
  }
160
182
  const radial = css.match(RADIAL_RE);
161
183
  if (!radial) return null;
@@ -259,10 +281,6 @@ function oklchToCss(l, c, h) {
259
281
  const cs = trim(c, 4);
260
282
  return `oklch(${trim(l, 4)} ${cs} ${cs === "0" ? "0" : trim(h, 2)})`;
261
283
  }
262
- function oklchToCssClamped(l, c, h) {
263
- const g = gamutClamp(l, c, h);
264
- return oklchToCss(g.l, g.c, g.h);
265
- }
266
284
  var OKLCH_RE = /^oklch\(\s*([\d.]+)(%?)\s+([\d.]+)(%?)\s+([\d.]+)(?:deg)?\s*\)$/i;
267
285
  var HEX6_RE = /^#[0-9a-f]{6}$/i;
268
286
  function parseOklchCss(value) {
@@ -456,7 +474,7 @@ function scaleStepToX(step, scale) {
456
474
  return scale.steps.length > 1 ? idx / (scale.steps.length - 1) * 100 : 50;
457
475
  }
458
476
  function serializeDerivedValue(value) {
459
- return value.kind === "raw" ? value.css : oklchToCssClamped(value.l, value.c, value.h);
477
+ return value.kind === "raw" ? value.css : oklchToCss(value.l, value.c, value.h);
460
478
  }
461
479
  function computePaletteOklch(index, base, lightnessCurve, saturationCurve, curveOffset, hueCurve) {
462
480
  const { c: baseC } = base;
@@ -1977,6 +1995,7 @@ function resolveDataDirs(opts = {}) {
1977
1995
  colorsAndTypeDir: opts.colorsAndTypeDir ? import_path2.default.resolve(opts.colorsAndTypeDir) : fileConfig.colorsAndTypeDir ? import_path2.default.resolve(fileConfig.colorsAndTypeDir) : sub("colors-and-type"),
1978
1996
  componentConfigsDir: opts.componentConfigsDir ? import_path2.default.resolve(opts.componentConfigsDir) : fileConfig.componentConfigsDir ? import_path2.default.resolve(fileConfig.componentConfigsDir) : sub("component-configs"),
1979
1997
  themesDir: opts.themesDir ? import_path2.default.resolve(opts.themesDir) : fileConfig.themesDir ? import_path2.default.resolve(fileConfig.themesDir) : sub("themes"),
1998
+ sketchPresetsDir: sub("sketch-presets"),
1980
1999
  legacyManifestsDir: fileConfig.manifestsDir ? import_path2.default.resolve(fileConfig.manifestsDir) : void 0
1981
2000
  };
1982
2001
  }
@@ -2040,11 +2059,17 @@ function detectLegacyLayout(input) {
2040
2059
  // vite-plugin/tokensCssMigrations/cssTokenOps.ts
2041
2060
  var DECL_RE = /(^|[\s;{])(--[a-z0-9-]+)\s*:/gi;
2042
2061
  var REF_RE = /var\(\s*(--[a-z0-9-]+)/gi;
2062
+ var DECL_VALUE_RE = /(^|[\s;{])(--[a-z0-9-]+)\s*:([^;}]*)/gi;
2043
2063
  function collectDefinedTokens(css) {
2044
2064
  const out = /* @__PURE__ */ new Set();
2045
2065
  for (const m of css.matchAll(DECL_RE)) out.add(m[2]);
2046
2066
  return out;
2047
2067
  }
2068
+ function collectTokenValues(css) {
2069
+ const out = /* @__PURE__ */ new Map();
2070
+ for (const m of css.matchAll(DECL_VALUE_RE)) out.set(m[2], m[3].trim());
2071
+ return out;
2072
+ }
2048
2073
  function collectReferencedTokens(css) {
2049
2074
  const out = /* @__PURE__ */ new Set();
2050
2075
  for (const m of css.matchAll(REF_RE)) out.add(m[1]);
@@ -2392,6 +2417,61 @@ var tokensCssMigration_2026_08_19_oklchColorValues = {
2392
2417
  }
2393
2418
  };
2394
2419
 
2420
+ // vite-plugin/tokensCssMigrations/migrations/2026-08-25-editorial-type-role.ts
2421
+ var STACK = [{ name: "--font-editorial", value: "var(--font-sans)" }];
2422
+ var BUNDLE2 = [
2423
+ { name: "--editorial-font-family", value: "var(--font-editorial)" },
2424
+ { name: "--editorial-font-size", value: "var(--font-size-md)" },
2425
+ { name: "--editorial-font-weight", value: "var(--font-weight-normal)" },
2426
+ { name: "--editorial-line-height", value: "var(--line-height-normal)" },
2427
+ { name: "--editorial-letter-spacing", value: "var(--letter-spacing-normal)" }
2428
+ ];
2429
+ var tokensCssMigration_2026_08_25_editorialTypeRole = {
2430
+ id: "2026-08-25-editorial-type-role",
2431
+ kind: "additive",
2432
+ description: "Add the editorial type role (--font-editorial and the --editorial-* bundle)",
2433
+ apply(css) {
2434
+ const withStack = ensureScale(css, {
2435
+ anchorPrefixes: ["--font-mono", "--font-serif", "--font-sans", "--font-display"],
2436
+ entries: STACK
2437
+ });
2438
+ return ensureScale(withStack, {
2439
+ sectionComment: "Editorial \u2014 the long-reading role, body face until repointed",
2440
+ anchorPrefixes: [
2441
+ "--eyebrow-",
2442
+ "--code-",
2443
+ "--body-",
2444
+ "--heading-",
2445
+ "--letter-spacing-",
2446
+ "--line-height-",
2447
+ "--font-weight-",
2448
+ "--font-size-",
2449
+ "--font-"
2450
+ ],
2451
+ entries: BUNDLE2
2452
+ });
2453
+ }
2454
+ };
2455
+
2456
+ // vite-plugin/tokensCssMigrations/migrations/2026-08-26-gradient-stops.ts
2457
+ var STOPS_RE = /^(?:linear|radial)-gradient\(\s*[^,]+,\s*(.+)\)$/i;
2458
+ var tokensCssMigration_2026_08_26_gradientStops = {
2459
+ id: "2026-08-26-gradient-stops",
2460
+ kind: "additive",
2461
+ description: "Add --gradient-N-stops companions to the gradient slots",
2462
+ apply(css) {
2463
+ const values = collectTokenValues(css);
2464
+ const entries = [];
2465
+ for (const [name, value] of values) {
2466
+ if (!/^--gradient-\d+$/.test(name)) continue;
2467
+ const stops = value.match(STOPS_RE);
2468
+ if (stops) entries.push({ name: `${name}-stops`, value: stops[1].trim() });
2469
+ }
2470
+ if (entries.length === 0) return css;
2471
+ return ensureScale(css, { anchorPrefixes: ["--gradient-"], entries });
2472
+ }
2473
+ };
2474
+
2395
2475
  // vite-plugin/tokensCssMigrations/index.ts
2396
2476
  var TOKENS_CSS_MIGRATIONS = [
2397
2477
  tokensCssMigration_2026_05_29_typographyScaleAdditions,
@@ -2401,7 +2481,9 @@ var TOKENS_CSS_MIGRATIONS = [
2401
2481
  tokensCssMigration_2026_06_04_easingColorAndTypescaleAdditions,
2402
2482
  tokensCssMigration_2026_07_20_lineHeightRename,
2403
2483
  tokensCssMigration_2026_07_20_semanticTextStyles,
2404
- tokensCssMigration_2026_08_19_oklchColorValues
2484
+ tokensCssMigration_2026_08_19_oklchColorValues,
2485
+ tokensCssMigration_2026_08_25_editorialTypeRole,
2486
+ tokensCssMigration_2026_08_26_gradientStops
2405
2487
  ];
2406
2488
  function runTokensCssMigrations(css) {
2407
2489
  return foldMigrations(css, () => true);
@@ -2502,6 +2584,7 @@ function themeFileApi(opts) {
2502
2584
  const COLORS_AND_TYPE_DIR = dataDirs.colorsAndTypeDir;
2503
2585
  const COMPONENT_CONFIGS_DIR = dataDirs.componentConfigsDir;
2504
2586
  const THEMES_DIR = dataDirs.themesDir;
2587
+ const SKETCH_PRESETS_DIR = dataDirs.sketchPresetsDir;
2505
2588
  const CSS_PATH = import_path4.default.resolve(opts.tokensCssPath);
2506
2589
  const GENERATED_CSS_PATH = opts.tokensGeneratedCssPath ? import_path4.default.resolve(opts.tokensGeneratedCssPath) : import_path4.default.join(dataDirs.dataDir, "tokens.generated.css");
2507
2590
  const FONTS_CSS_PATH = opts.fontsCssPath ? import_path4.default.resolve(opts.fontsCssPath) : import_path4.default.join(import_path4.default.dirname(CSS_PATH), "fonts.css");
@@ -2559,6 +2642,7 @@ function themeFileApi(opts) {
2559
2642
  dir: THEMES_DIR,
2560
2643
  packageDir: packageThemesDir
2561
2644
  });
2645
+ const sketchPresetsResource = versionedFileResourceServer({ dir: SKETCH_PRESETS_DIR });
2562
2646
  function ensureColorsAndTypeDir() {
2563
2647
  colorsAndTypeResource.ensureDir();
2564
2648
  }
@@ -3124,6 +3208,8 @@ ${lines.join("\n")}
3124
3208
  const THEME_EXPORT_REGEX = new RegExp(`^${escapedBase}/themes/([a-z0-9\\-_]+)/export$`);
3125
3209
  const THEME_IMPORT_ROUTE = `${API_BASE}/themes/import`;
3126
3210
  const THEME_BY_NAME_REGEX = new RegExp(`^${escapedBase}/themes/([a-z0-9\\-_]+)$`);
3211
+ const SKETCH_PRESETS_ROUTE = `${API_BASE}/sketch-presets`;
3212
+ const SKETCH_PRESET_BY_NAME_REGEX = new RegExp(`^${escapedBase}/sketch-presets/([a-z0-9\\-_]+)$`);
3127
3213
  const PRODUCTION_ROUTE = `${API_BASE}/production`;
3128
3214
  async function handleListColorsAndType(_ctx) {
3129
3215
  const files = colorsAndTypeResource.listNames().map((fileName) => {
@@ -3655,6 +3741,61 @@ ${lines.join("\n")}
3655
3741
  }
3656
3742
  });
3657
3743
  }
3744
+ async function handleListSketchPresets({ res }) {
3745
+ const files = sketchPresetsResource.listNames().map((fileName) => {
3746
+ let data = null;
3747
+ try {
3748
+ data = sketchPresetsResource.readJson(fileName);
3749
+ } catch {
3750
+ }
3751
+ return {
3752
+ name: data?.name || fileName,
3753
+ fileName,
3754
+ updatedAt: data?.updatedAt || ""
3755
+ };
3756
+ });
3757
+ jsonResponse(res, 200, { files });
3758
+ }
3759
+ async function handleSketchPresetByName({ params, req, res }) {
3760
+ const [fileName] = params;
3761
+ if (rejectReservedName(res, fileName)) return;
3762
+ const filePath = sketchPresetsResource.filePath(fileName);
3763
+ if (req.method === "GET") {
3764
+ const raw = sketchPresetsResource.readJson(fileName);
3765
+ if (!raw) {
3766
+ jsonResponse(res, 404, { error: "Not found" });
3767
+ return;
3768
+ }
3769
+ jsonResponse(res, 200, { ...raw, _fileName: fileName });
3770
+ return;
3771
+ }
3772
+ if (req.method === "PUT") {
3773
+ const body = JSON.parse(await readBody(req));
3774
+ if (!body || typeof body !== "object" || !body.settings || typeof body.settings !== "object") {
3775
+ jsonResponse(res, 400, { error: "A sketch preset needs a settings object" });
3776
+ return;
3777
+ }
3778
+ body.name = String(body.name || fileName);
3779
+ body.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
3780
+ if (import_fs4.default.existsSync(filePath)) {
3781
+ try {
3782
+ const existing = JSON.parse(import_fs4.default.readFileSync(filePath, "utf-8"));
3783
+ if (existing.createdAt) body.createdAt = existing.createdAt;
3784
+ } catch {
3785
+ }
3786
+ }
3787
+ if (!body.createdAt) body.createdAt = body.updatedAt;
3788
+ sketchPresetsResource.ensureDir();
3789
+ import_fs4.default.writeFileSync(filePath, JSON.stringify(body, null, 2));
3790
+ jsonResponse(res, 200, { ok: true, fileName });
3791
+ return;
3792
+ }
3793
+ if (req.method === "DELETE") {
3794
+ if (import_fs4.default.existsSync(filePath)) import_fs4.default.unlinkSync(filePath);
3795
+ jsonResponse(res, 200, { ok: true });
3796
+ return;
3797
+ }
3798
+ }
3658
3799
  function methodNotAllowed({ res }) {
3659
3800
  jsonResponse(res, 405, { error: "Method not allowed" });
3660
3801
  }
@@ -3731,6 +3872,14 @@ ${lines.join("\n")}
3731
3872
  { method: "PUT", pattern: THEME_BY_NAME_REGEX, handler: handleThemeByName },
3732
3873
  { method: "DELETE", pattern: THEME_BY_NAME_REGEX, handler: handleThemeByName },
3733
3874
  // Production — the whole-look adopt door
3875
+ { method: "GET", pattern: SKETCH_PRESETS_ROUTE, handler: handleListSketchPresets },
3876
+ { method: "PUT", pattern: SKETCH_PRESETS_ROUTE, handler: methodNotAllowed },
3877
+ { method: "POST", pattern: SKETCH_PRESETS_ROUTE, handler: methodNotAllowed },
3878
+ { method: "DELETE", pattern: SKETCH_PRESETS_ROUTE, handler: methodNotAllowed },
3879
+ { method: "GET", pattern: SKETCH_PRESET_BY_NAME_REGEX, handler: handleSketchPresetByName },
3880
+ { method: "PUT", pattern: SKETCH_PRESET_BY_NAME_REGEX, handler: handleSketchPresetByName },
3881
+ { method: "DELETE", pattern: SKETCH_PRESET_BY_NAME_REGEX, handler: handleSketchPresetByName },
3882
+ { method: "POST", pattern: SKETCH_PRESET_BY_NAME_REGEX, handler: methodNotAllowed },
3734
3883
  { method: "PUT", pattern: PRODUCTION_ROUTE, handler: handleAdoptLook },
3735
3884
  { method: "GET", pattern: PRODUCTION_ROUTE, handler: methodNotAllowed },
3736
3885
  { method: "POST", pattern: PRODUCTION_ROUTE, handler: methodNotAllowed },
@@ -1,6 +1,6 @@
1
1
  import { Plugin } from 'vite';
2
2
  export { ComponentSource, MissingToken, RunResult, TOKENS_CSS_MIGRATIONS, TokensCssMigration, ValidateInput, runTokensCssMigrations, validateTokensCss } from './tokensCssMigrations/index.cjs';
3
- import './dataPaths-DBN0RPuT.cjs';
3
+ import './dataPaths-CRfD1LdA.cjs';
4
4
 
5
5
  interface ThemeFileApiOptions {
6
6
  tokensCssPath: string;
@@ -1,6 +1,6 @@
1
1
  import { Plugin } from 'vite';
2
2
  export { ComponentSource, MissingToken, RunResult, TOKENS_CSS_MIGRATIONS, TokensCssMigration, ValidateInput, runTokensCssMigrations, validateTokensCss } from './tokensCssMigrations/index.js';
3
- import './dataPaths-DBN0RPuT.js';
3
+ import './dataPaths-CRfD1LdA.js';
4
4
 
5
5
  interface ThemeFileApiOptions {
6
6
  tokensCssPath: string;