@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
@@ -0,0 +1,119 @@
1
+ <script lang="ts">
2
+ import Button from '../../../system/components/Button.svelte';
3
+ import Card from '../../../system/components/Card.svelte';
4
+ import Input from '../../../system/components/Input.svelte';
5
+ import Badge from '../../../system/components/Badge.svelte';
6
+ import Callout from '../../../system/components/Callout.svelte';
7
+ import Toggle from '../../../system/components/Toggle.svelte';
8
+ import { setSketchScope } from '../../core/sketch/sketchLayer';
9
+ import type { SketchSettings } from '../../core/sketch/sketchPresets';
10
+
11
+ interface Props {
12
+ settings: SketchSettings;
13
+ enabled: boolean;
14
+ }
15
+
16
+ let { settings, enabled }: Props = $props();
17
+
18
+ let stage = $state<HTMLDivElement | undefined>(undefined);
19
+
20
+ // The scope attribute goes on this container rather than the editor document
21
+ // root, so the editor's own chrome never picks the effect up.
22
+ $effect(() => {
23
+ setSketchScope(stage ?? null, enabled ? settings : null);
24
+ });
25
+ </script>
26
+
27
+ <div class="stage" bind:this={stage}>
28
+ <section class="item">
29
+ <h4>Buttons</h4>
30
+ <div class="cluster">
31
+ <Button variant="primary">Primary</Button>
32
+ <Button variant="secondary">Secondary</Button>
33
+ <Button variant="outline">Outline</Button>
34
+ <Button variant="danger">Danger</Button>
35
+ </div>
36
+ </section>
37
+
38
+ <section class="item">
39
+ <h4>Cards</h4>
40
+ <div class="cluster">
41
+ <Card title="Rough draft">
42
+ <p>Fill and outline displace on different noise seeds, so they disagree at the edges.</p>
43
+ </Card>
44
+ <Card title="Second card">
45
+ <p>Same size and same preset. A different seed keeps the silhouette from repeating.</p>
46
+ </Card>
47
+ </div>
48
+ </section>
49
+
50
+ <section class="item">
51
+ <h4>Badges</h4>
52
+ <div class="cluster">
53
+ <Badge variant="info">Info</Badge>
54
+ <Badge variant="success">Success</Badge>
55
+ <Badge variant="warning">Warning</Badge>
56
+ <Badge variant="danger">Danger</Badge>
57
+ </div>
58
+ </section>
59
+
60
+ <section class="item">
61
+ <h4>Form</h4>
62
+ <div class="cluster stack">
63
+ <Input label="Name" placeholder="Ada Lovelace" hint="Helper text stays crisp" />
64
+ <Toggle label="Enabled" checked />
65
+ </div>
66
+ </section>
67
+
68
+ <section class="item">
69
+ <h4>Callouts</h4>
70
+ <div class="cluster stack">
71
+ <Callout variant="info" label="Note">Body text is never filtered, so it stays fully legible.</Callout>
72
+ <Callout variant="warning" label="Careful">Only the fill and outline layers move.</Callout>
73
+ </div>
74
+ </section>
75
+ </div>
76
+
77
+ <style>
78
+ .stage {
79
+ display: flex;
80
+ flex-direction: column;
81
+ gap: var(--ui-space-24);
82
+ padding: var(--ui-space-24);
83
+ background: var(--surface-neutral-lowest);
84
+ border: 1px solid var(--ui-border-low);
85
+ border-radius: var(--ui-radius-md);
86
+ }
87
+
88
+ .item {
89
+ display: flex;
90
+ flex-direction: column;
91
+ gap: var(--ui-space-10);
92
+ }
93
+
94
+ h4 {
95
+ margin: 0;
96
+ font-family: var(--ui-font-sans);
97
+ font-size: var(--ui-font-size-xs);
98
+ font-weight: var(--ui-font-weight-semibold);
99
+ letter-spacing: 0.08em;
100
+ text-transform: uppercase;
101
+ color: var(--ui-text-muted);
102
+ }
103
+
104
+ .cluster {
105
+ display: flex;
106
+ flex-wrap: wrap;
107
+ gap: var(--ui-space-16);
108
+ align-items: flex-start;
109
+ }
110
+
111
+ .cluster.stack {
112
+ flex-direction: column;
113
+ max-width: 28rem;
114
+ }
115
+
116
+ .cluster :global(.card) {
117
+ max-width: 20rem;
118
+ }
119
+ </style>
@@ -0,0 +1,185 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ label: string;
4
+ low: number;
5
+ high: number;
6
+ min: number;
7
+ max: number;
8
+ step: number;
9
+ /** Closest the two handles may sit, in the same units as the values. */
10
+ gap: number;
11
+ readout: string;
12
+ hint: string;
13
+ onchange: (low: number, high: number) => void;
14
+ }
15
+
16
+ let { label, low, high, min, max, step, gap, readout, hint, onchange }: Props = $props();
17
+
18
+ /** Handles never cross and never meet: whichever one moved keeps its value and
19
+ pushes the other along, so a drag to the far end walks the pair rather than
20
+ stopping dead. */
21
+ function setLow(v: number) {
22
+ const next = Math.min(Math.max(v, min), max - gap);
23
+ onchange(next, Math.max(high, next + gap));
24
+ }
25
+
26
+ function setHigh(v: number) {
27
+ const next = Math.max(Math.min(v, max), min + gap);
28
+ onchange(Math.min(low, next - gap), next);
29
+ }
30
+
31
+ /** The thumb's centre travels between half a thumb in from each end, so the
32
+ band has to be inset the same way or it drifts out from under the handles
33
+ towards the middle of the track. */
34
+ const at = (v: number) =>
35
+ `calc(var(--thumb) / 2 + (100% - var(--thumb)) * ${(v - min) / (max - min)})`;
36
+ </script>
37
+
38
+ <div
39
+ class="dial"
40
+ data-hint={hint}
41
+ style:--low={at(low)}
42
+ style:--high={at(high)}
43
+ style:--mid={at((low + high) / 2)}
44
+ >
45
+ <span class="dial-label">{label}</span>
46
+ <span class="dial-value">{readout}</span>
47
+ <div class="track">
48
+ <input
49
+ class="lo" type="range" {min} {max} {step} value={low}
50
+ aria-label="{label} minimum"
51
+ oninput={(e) => setLow(+e.currentTarget.value)}
52
+ />
53
+ <input
54
+ class="hi" type="range" {min} {max} {step} value={high}
55
+ aria-label="{label} maximum"
56
+ oninput={(e) => setHigh(+e.currentTarget.value)}
57
+ />
58
+ </div>
59
+ </div>
60
+
61
+ <style>
62
+ .dial {
63
+ /* Declared here, not on the track: the three positions below are set on
64
+ this element and each one measures itself against the thumb, and a custom
65
+ property resolves the ones it names against the element declaring it, not
66
+ against the element it lands on. Left on the track, every position
67
+ computed invalid and the whole control collapsed to its defaults. */
68
+ --thumb: var(--ui-space-16);
69
+ position: relative;
70
+ display: grid;
71
+ grid-template-columns: 1fr auto;
72
+ gap: 0 var(--ui-space-12);
73
+ align-items: baseline;
74
+ }
75
+
76
+ .dial-label {
77
+ font-size: var(--ui-font-size-md);
78
+ color: var(--ui-text-primary);
79
+ }
80
+
81
+ .dial-value {
82
+ font-size: var(--ui-font-size-md);
83
+ font-family: var(--ui-font-mono);
84
+ color: var(--ui-text-primary);
85
+ }
86
+
87
+ /* The track is painted here rather than by either input: two of them stacked
88
+ would each draw their own, and the one on top would cover the band. */
89
+ .track {
90
+ position: relative;
91
+ grid-column: 1 / -1;
92
+ height: var(--thumb);
93
+ margin-top: var(--ui-space-2);
94
+ background:
95
+ linear-gradient(
96
+ to right,
97
+ var(--ui-border-high) var(--low),
98
+ var(--ui-text-primary) var(--low),
99
+ var(--ui-text-primary) var(--high),
100
+ var(--ui-border-high) var(--high)
101
+ )
102
+ center / 100% 4px no-repeat;
103
+ }
104
+
105
+ input[type='range'] {
106
+ position: absolute;
107
+ inset: 0;
108
+ width: 100%;
109
+ height: 100%;
110
+ -webkit-appearance: none;
111
+ appearance: none;
112
+ background: none;
113
+ cursor: ew-resize;
114
+ }
115
+
116
+ /* Each input owns the side of the track its handle is on, so a press anywhere
117
+ lands on the one whose handle is nearer and the browser does the rest:
118
+ jump to the press, then drag. Stacking them whole instead would give every
119
+ press to whichever sat on top, and the handle underneath could only ever be
120
+ moved by keyboard.
121
+
122
+ The split runs half a thumb past the midpoint on each side rather than
123
+ through it, so neither handle is ever cut in half at the boundary. Where
124
+ the two overlap the press goes to the upper one, which is why the handles
125
+ are held a gap apart. */
126
+ .lo {
127
+ clip-path: inset(0 calc(100% - var(--mid) - var(--thumb) / 2) 0 0);
128
+ }
129
+
130
+ .hi {
131
+ clip-path: inset(0 0 0 calc(var(--mid) - var(--thumb) / 2));
132
+ }
133
+
134
+ input[type='range']::-webkit-slider-thumb {
135
+ -webkit-appearance: none;
136
+ width: var(--thumb);
137
+ height: var(--thumb);
138
+ border-radius: var(--ui-radius-full);
139
+ background: var(--ui-text-primary);
140
+ box-shadow: var(--ui-shadow-sm);
141
+ }
142
+
143
+ input[type='range']::-moz-range-thumb {
144
+ width: var(--thumb);
145
+ height: var(--thumb);
146
+ border: none;
147
+ border-radius: var(--ui-radius-full);
148
+ background: var(--ui-text-primary);
149
+ box-shadow: var(--ui-shadow-sm);
150
+ }
151
+
152
+ /* On the handle, not the input: the input is clipped to its own half, which
153
+ would cut a ring drawn round its box, and with two of them the ring has to
154
+ say which one has the keyboard. */
155
+ input[type='range']:focus-visible {
156
+ outline: none;
157
+ }
158
+
159
+ input[type='range']:focus-visible::-webkit-slider-thumb {
160
+ box-shadow: 0 0 0 2px var(--ui-highlight);
161
+ }
162
+
163
+ input[type='range']:focus-visible::-moz-range-thumb {
164
+ box-shadow: 0 0 0 2px var(--ui-highlight);
165
+ }
166
+
167
+ /* Absolutely positioned so a hint never reflows the stack of dials under it. */
168
+ .dial:hover::after {
169
+ content: attr(data-hint);
170
+ position: absolute;
171
+ top: calc(100% + var(--ui-space-2));
172
+ left: 0;
173
+ right: 0;
174
+ z-index: 2;
175
+ padding: var(--ui-space-8) var(--ui-space-10);
176
+ background: var(--ui-surface-high);
177
+ border: 1px solid var(--ui-border-low);
178
+ border-radius: var(--ui-radius-md);
179
+ box-shadow: var(--ui-shadow-md);
180
+ color: var(--ui-text-secondary);
181
+ font-size: var(--ui-font-size-sm);
182
+ line-height: var(--ui-line-height-relaxed);
183
+ pointer-events: none;
184
+ }
185
+ </style>