@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.
- package/.claude/skills/live-tokens-create-component/SKILL.md +13 -2
- package/.claude/skills/live-tokens-create-component/references/sketch-mode.md +202 -0
- package/.claude/skills/live-tokens-pair-fonts/SKILL.md +2 -2
- package/.claude/skills/live-tokens-pick-component/SKILL.md +1 -1
- package/CHANGELOG.md +192 -0
- package/README.md +1 -1
- package/bin/cli.mjs +2 -1
- package/dist-plugin/adjust/index.cjs +1 -0
- package/dist-plugin/adjust/index.d.cts +2 -2
- package/dist-plugin/adjust/index.d.ts +2 -2
- package/dist-plugin/adjust/index.js +1 -1
- package/dist-plugin/{chunk-TKZBVIW5.js → chunk-E5QYON4L.js} +59 -2
- package/dist-plugin/{chunk-PB2JTK2H.js → chunk-LW4SR7AZ.js} +39 -6
- package/dist-plugin/{chunk-YR6GPXW2.js → chunk-XWXIMTWZ.js} +0 -5
- package/dist-plugin/{chunk-D3ZVKOR4.js → chunk-Y5CNFSSV.js} +1 -0
- package/dist-plugin/{dataPaths-DBN0RPuT.d.cts → dataPaths-CRfD1LdA.d.cts} +3 -0
- package/dist-plugin/{dataPaths-DBN0RPuT.d.ts → dataPaths-CRfD1LdA.d.ts} +3 -0
- package/dist-plugin/fontPairing/index.cjs +4 -2
- package/dist-plugin/fontPairing/index.d.cts +3 -3
- package/dist-plugin/fontPairing/index.d.ts +3 -3
- package/dist-plugin/fontPairing/index.js +4 -3
- package/dist-plugin/generateColorsAndType/index.cjs +22 -9
- package/dist-plugin/generateColorsAndType/index.d.cts +2 -2
- package/dist-plugin/generateColorsAndType/index.d.ts +2 -2
- package/dist-plugin/generateColorsAndType/index.js +8 -5
- package/dist-plugin/index.cjs +158 -9
- package/dist-plugin/index.d.cts +1 -1
- package/dist-plugin/index.d.ts +1 -1
- package/dist-plugin/index.js +71 -4
- package/dist-plugin/migrateData/index.cjs +1 -0
- package/dist-plugin/migrateData/index.d.cts +1 -1
- package/dist-plugin/migrateData/index.d.ts +1 -1
- package/dist-plugin/migrateData/index.js +1 -1
- package/dist-plugin/{themeTypes-BAqtv4XO.d.cts → themeTypes-DSV3Zisf.d.cts} +12 -1
- package/dist-plugin/{themeTypes-BAqtv4XO.d.ts → themeTypes-DSV3Zisf.d.ts} +12 -1
- package/dist-plugin/tokensCssMigrations/index.cjs +58 -1
- package/dist-plugin/tokensCssMigrations/index.d.cts +1 -1
- package/dist-plugin/tokensCssMigrations/index.d.ts +1 -1
- package/dist-plugin/tokensCssMigrations/index.js +3 -3
- package/package.json +3 -1
- package/src/editor/core/fonts/applyFontPairing.ts +3 -2
- package/src/editor/core/fonts/fontLoader.ts +1 -0
- package/src/editor/core/fonts/fontMigration.ts +31 -1
- package/src/editor/core/palettes/paletteDerivation.ts +9 -2
- package/src/editor/core/sketch/maskField.ts +385 -0
- package/src/editor/core/sketch/sketchLayer.ts +1106 -0
- package/src/editor/core/sketch/sketchPresetService.ts +65 -0
- package/src/editor/core/sketch/sketchPresets.ts +345 -0
- package/src/editor/core/sketch/sketchStore.ts +190 -0
- package/src/editor/core/store/editorPersistence.ts +28 -12
- package/src/editor/core/store/editorTypes.ts +4 -1
- package/src/editor/core/store/editorViewStore.ts +2 -2
- package/src/editor/core/store/gradientSource.ts +15 -1
- package/src/editor/core/themes/parsers/gradient.ts +62 -4
- package/src/editor/core/themes/slices/gradients.ts +75 -14
- package/src/editor/core/themes/themeTypes.ts +6 -1
- package/src/editor/docs/Docs.svelte +4 -3
- package/src/editor/docs/chapters.ts +1 -0
- package/src/editor/docs/content/01-overview.md +2 -1
- package/src/editor/docs/content/editing-tokens.md +5 -1
- package/src/editor/docs/content/sketch-mode.md +183 -0
- package/src/editor/docs/content.generated.ts +3 -2
- package/src/editor/overlay/LiveEditorOverlay.svelte +15 -0
- package/src/editor/pages/EditorShell.svelte +43 -0
- package/src/editor/ui/EditorViewSwitcher.svelte +30 -17
- package/src/editor/ui/FontStackEditor.svelte +3 -0
- package/src/editor/ui/GradientEditor.svelte +38 -1
- package/src/editor/ui/UIReveal.svelte +7 -1
- package/src/editor/ui/UISegmentedControl.svelte +4 -8
- package/src/editor/ui/sections/GradientsSection.svelte +47 -1
- package/src/editor/ui/sketch/SketchDial.svelte +124 -0
- package/src/editor/ui/sketch/SketchPreview.svelte +119 -0
- package/src/editor/ui/sketch/SketchRange.svelte +185 -0
- package/src/editor/ui/sketch/SketchTab.svelte +1264 -0
- package/src/live-tokens/data/colors-and-type/autumn.json +17 -0
- package/src/live-tokens/data/colors-and-type/default.json +17 -0
- package/src/live-tokens/data/colors-and-type/halloween.json +17 -0
- package/src/live-tokens/data/colors-and-type/midnight-study.json +17 -0
- package/src/live-tokens/data/colors-and-type/ocean.json +17 -0
- package/src/live-tokens/data/colors-and-type/royal-velvet.json +17 -0
- package/src/live-tokens/data/colors-and-type/sketchy.json +2520 -0
- package/src/live-tokens/data/colors-and-type/spring-meadow.json +17 -0
- package/src/live-tokens/data/colors-and-type/sunset.json +17 -0
- package/src/live-tokens/data/themes/autumn.json +17 -0
- package/src/live-tokens/data/themes/halloween.json +17 -0
- package/src/live-tokens/data/themes/midnight-study.json +17 -0
- package/src/live-tokens/data/themes/ocean.json +17 -0
- package/src/live-tokens/data/themes/royal-velvet.json +17 -0
- package/src/live-tokens/data/themes/sketchy.json +3984 -0
- package/src/live-tokens/data/themes/spring-meadow.json +17 -0
- package/src/live-tokens/data/themes/sunset.json +17 -0
- package/src/live-tokens/data/tokens.generated.css +1 -0
- package/src/system/components/Card.svelte +12 -1
- package/src/system/components/SectionDivider.svelte +4 -0
- 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>
|