@motion-proto/live-tokens 0.3.7 → 0.5.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/README.md +1 -1
- package/package.json +11 -9
- package/src/component-editor/BadgeEditor.svelte +24 -22
- package/src/component-editor/CalloutEditor.svelte +3 -3
- package/src/component-editor/CardEditor.svelte +25 -21
- package/src/component-editor/CollapsibleSectionEditor.svelte +27 -25
- package/src/component-editor/CornerBadgeEditor.svelte +37 -35
- package/src/component-editor/DialogEditor.svelte +26 -24
- package/src/component-editor/ImageEditor.svelte +11 -9
- package/src/component-editor/InlineEditActionsEditor.svelte +17 -15
- package/src/component-editor/NotificationEditor.svelte +32 -30
- package/src/component-editor/ProgressBarEditor.svelte +3 -3
- package/src/component-editor/RadioButtonEditor.svelte +31 -29
- package/src/component-editor/SectionDividerEditor.svelte +30 -28
- package/src/component-editor/SegmentedControlEditor.svelte +29 -25
- package/src/component-editor/StandardButtonsEditor.svelte +42 -38
- package/src/component-editor/TabBarEditor.svelte +20 -18
- package/src/component-editor/TableEditor.svelte +4 -4
- package/src/component-editor/TooltipEditor.svelte +11 -9
- package/src/component-editor/registry.ts +2 -2
- package/src/component-editor/scaffolding/AngleDial.svelte +20 -19
- package/src/component-editor/scaffolding/ComponentEditorBase.svelte +44 -20
- package/src/component-editor/scaffolding/ComponentFileManager.svelte +260 -37
- package/src/component-editor/scaffolding/ComponentFileMenu.svelte +41 -29
- package/src/component-editor/scaffolding/ComponentsTab.svelte +7 -3
- package/src/component-editor/scaffolding/CopyFromMenu.svelte +21 -12
- package/src/component-editor/scaffolding/DemoHeader.svelte +13 -4
- package/src/component-editor/scaffolding/DividerEditor.svelte +27 -14
- package/src/component-editor/scaffolding/FieldsetWrapper.svelte +10 -4
- package/src/component-editor/scaffolding/GradientCard.svelte +25 -20
- package/src/component-editor/scaffolding/LinkageChart.svelte +43 -34
- package/src/component-editor/scaffolding/LinkedBlock.svelte +24 -21
- package/src/component-editor/scaffolding/NonStylableConfig.svelte +6 -1
- package/src/component-editor/scaffolding/SaveAsDialog.svelte +39 -35
- package/src/component-editor/scaffolding/ShadowBackdrop.svelte +21 -9
- package/src/component-editor/scaffolding/ShadowBackdropControls.svelte +8 -3
- package/src/component-editor/scaffolding/StateBlock.svelte +30 -13
- package/src/component-editor/scaffolding/TokenLayout.svelte +46 -30
- package/src/component-editor/scaffolding/TypeEditor.svelte +52 -26
- package/src/component-editor/scaffolding/VariantGroup.svelte +81 -48
- package/src/component-editor/scaffolding/componentSectionType.ts +2 -2
- package/src/components/Badge.svelte +45 -26
- package/src/components/Button.svelte +44 -21
- package/src/components/Callout.svelte +17 -12
- package/src/components/Card.svelte +23 -11
- package/src/components/CollapsibleSection.svelte +56 -27
- package/src/components/CornerBadge.svelte +32 -18
- package/src/components/Dialog.svelte +55 -31
- package/src/components/Image.svelte +14 -5
- package/src/components/InlineEditActions.svelte +22 -10
- package/src/components/Notification.svelte +39 -19
- package/src/components/ProgressBar.svelte +27 -17
- package/src/components/RadioButton.svelte +27 -10
- package/src/components/SectionDivider.svelte +34 -26
- package/src/components/SegmentedControl.svelte +23 -9
- package/src/components/TabBar.svelte +23 -10
- package/src/components/Table.svelte +8 -3
- package/src/components/Tooltip.svelte +15 -5
- package/src/lib/ColumnsOverlay.svelte +3 -3
- package/src/lib/LiveEditorOverlay.svelte +73 -36
- package/src/pages/ComponentEditorPage.svelte +17 -13
- package/src/pages/EditorShell.svelte +24 -20
- package/src/styles/form-controls.css +2 -2
- package/src/styles/tokens.css +59 -81
- package/src/ui/BezierCurveEditor.svelte +59 -43
- package/src/ui/ColorEditPanel.svelte +71 -44
- package/src/ui/EditorViewSwitcher.svelte +9 -5
- package/src/ui/FontStackEditor.svelte +16 -15
- package/src/ui/GradientEditor.svelte +42 -33
- package/src/ui/GradientStopPicker.svelte +18 -29
- package/src/ui/PaletteEditor.svelte +238 -212
- package/src/ui/PresetFileManager.svelte +20 -18
- package/src/ui/ProjectFontsSection.svelte +30 -30
- package/src/ui/SurfacesTab.svelte +3 -3
- package/src/ui/TextTab.svelte +2 -2
- package/src/ui/ThemeFileManager.svelte +38 -35
- package/src/ui/Toggle.svelte +11 -9
- package/src/ui/UICopyPopover.svelte +19 -15
- package/src/ui/UIDialog.svelte +48 -30
- package/src/ui/UIFontFamilySelector.svelte +104 -78
- package/src/ui/UIFontSizeSelector.svelte +38 -20
- package/src/ui/UIFontWeightSelector.svelte +33 -13
- package/src/ui/UILineHeightSelector.svelte +33 -13
- package/src/ui/UILinkToggle.svelte +7 -6
- package/src/ui/UIOptionItem.svelte +21 -7
- package/src/ui/UIOptionList.svelte +9 -3
- package/src/ui/UIPaddingSelector.svelte +108 -82
- package/src/ui/UIPaletteSelector.svelte +186 -161
- package/src/ui/UIRadio.svelte +23 -8
- package/src/ui/UIRadioGroup.svelte +9 -8
- package/src/ui/UIRelinkConfirmPopover.svelte +26 -16
- package/src/ui/UITokenSelector.svelte +112 -68
- package/src/ui/UIVariantSelector.svelte +79 -57
- package/src/ui/VariablesTab.svelte +15 -15
- package/src/ui/palette/GradientStopEditor.svelte +45 -26
- package/src/ui/palette/OverridesPanel.svelte +85 -49
- package/src/ui/palette/PaletteBase.svelte +60 -32
- package/src/ui/palette/ScaleCurveEditor.svelte +25 -10
- package/src/ui/sections/ColumnsSection.svelte +13 -13
- package/src/ui/sections/GradientsSection.svelte +12 -9
- package/src/ui/sections/OverlaysSection.svelte +50 -47
- package/src/ui/sections/ShadowsSection.svelte +110 -104
- package/src/ui/sections/TokenScaleTable.svelte +38 -22
- package/src/ui/sections/tokenScales.ts +2 -2
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
// Bumped on breakpoint flips; passed to TokenScaleTable so it re-resolves.
|
|
22
22
|
// tokens.css declares responsive overrides at 768px and 480px.
|
|
23
|
-
let liveVersion = 0;
|
|
23
|
+
let liveVersion = $state(0);
|
|
24
24
|
const BREAKPOINTS = ['(max-width: 768px)', '(max-width: 480px)'] as const;
|
|
25
25
|
|
|
26
26
|
onMount(() => {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
};
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
-
let copiedVar: string | null = null;
|
|
37
|
+
let copiedVar: string | null = $state(null);
|
|
38
38
|
function copyVariable(v: string) {
|
|
39
39
|
navigator.clipboard.writeText(v);
|
|
40
40
|
copiedVar = v;
|
|
@@ -65,9 +65,9 @@
|
|
|
65
65
|
<section class="section" id="spacing">
|
|
66
66
|
<h2 class="section-title">Spacing & Borders</h2>
|
|
67
67
|
<h3 class="subsection-title">Spacing</h3>
|
|
68
|
-
<TokenScaleTable kind="spacing" vars={SPACING_VARS} {liveVersion} {copiedVar}
|
|
68
|
+
<TokenScaleTable kind="spacing" vars={SPACING_VARS} {liveVersion} {copiedVar} oncopy={copyVariable} />
|
|
69
69
|
<h3 class="subsection-title">Borders</h3>
|
|
70
|
-
<TokenScaleTable kind="border" vars={BORDER_WIDTH_VARS} {liveVersion} {copiedVar}
|
|
70
|
+
<TokenScaleTable kind="border" vars={BORDER_WIDTH_VARS} {liveVersion} {copiedVar} oncopy={copyVariable} />
|
|
71
71
|
</section>
|
|
72
72
|
|
|
73
73
|
<!-- Columns -->
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
<!-- Border Radius -->
|
|
77
77
|
<section class="section" id="border-radius">
|
|
78
78
|
<h2 class="section-title">Border Radius</h2>
|
|
79
|
-
<TokenScaleTable kind="radius" vars={RADIUS_VARS} {liveVersion} {copiedVar}
|
|
79
|
+
<TokenScaleTable kind="radius" vars={RADIUS_VARS} {liveVersion} {copiedVar} oncopy={copyVariable} />
|
|
80
80
|
</section>
|
|
81
81
|
|
|
82
82
|
<!-- Typography -->
|
|
@@ -92,17 +92,17 @@
|
|
|
92
92
|
|
|
93
93
|
<div class="typography-group">
|
|
94
94
|
<h3 class="group-title">Font Sizes</h3>
|
|
95
|
-
<TokenScaleTable kind="font-size" vars={FONT_SIZE_VARS} {liveVersion} {copiedVar}
|
|
95
|
+
<TokenScaleTable kind="font-size" vars={FONT_SIZE_VARS} {liveVersion} {copiedVar} oncopy={copyVariable} />
|
|
96
96
|
</div>
|
|
97
97
|
|
|
98
98
|
<div class="typography-group">
|
|
99
99
|
<h3 class="group-title">Font Weights</h3>
|
|
100
|
-
<TokenScaleTable kind="font-weight" vars={FONT_WEIGHT_VARS} {liveVersion} {copiedVar}
|
|
100
|
+
<TokenScaleTable kind="font-weight" vars={FONT_WEIGHT_VARS} {liveVersion} {copiedVar} oncopy={copyVariable} />
|
|
101
101
|
</div>
|
|
102
102
|
|
|
103
103
|
<div class="typography-group">
|
|
104
104
|
<h3 class="group-title">Line Heights</h3>
|
|
105
|
-
<TokenScaleTable kind="line-height" vars={LINE_HEIGHT_VARS} {liveVersion} {copiedVar}
|
|
105
|
+
<TokenScaleTable kind="line-height" vars={LINE_HEIGHT_VARS} {liveVersion} {copiedVar} oncopy={copyVariable} />
|
|
106
106
|
</div>
|
|
107
107
|
</div>
|
|
108
108
|
</section>
|
|
@@ -110,19 +110,19 @@
|
|
|
110
110
|
<!-- Icon Sizes -->
|
|
111
111
|
<section class="section" id="icon-sizes">
|
|
112
112
|
<h2 class="section-title">Icon Sizes</h2>
|
|
113
|
-
<TokenScaleTable kind="icon-size" vars={ICON_SIZE_VARS} {liveVersion} {copiedVar}
|
|
113
|
+
<TokenScaleTable kind="icon-size" vars={ICON_SIZE_VARS} {liveVersion} {copiedVar} oncopy={copyVariable} />
|
|
114
114
|
</section>
|
|
115
115
|
|
|
116
116
|
|
|
117
117
|
<!-- Shadows -->
|
|
118
|
-
<ShadowsSection {copiedVar}
|
|
118
|
+
<ShadowsSection {copiedVar} oncopy={copyVariable} />
|
|
119
119
|
|
|
120
120
|
|
|
121
121
|
<!-- Overlays -->
|
|
122
|
-
<OverlaysSection {copiedVar}
|
|
122
|
+
<OverlaysSection {copiedVar} oncopy={copyVariable} />
|
|
123
123
|
|
|
124
124
|
<!-- Gradients -->
|
|
125
|
-
<GradientsSection {copiedVar}
|
|
125
|
+
<GradientsSection {copiedVar} oncopy={copyVariable} />
|
|
126
126
|
|
|
127
127
|
<!-- Utility Tokens -->
|
|
128
128
|
<section class="section" id="utility-tokens">
|
|
@@ -130,17 +130,17 @@
|
|
|
130
130
|
<div class="utility-columns">
|
|
131
131
|
<div class="utility-group">
|
|
132
132
|
<h3 class="group-title">Durations</h3>
|
|
133
|
-
<TokenScaleTable kind="line-height" tokens={DURATION_TOKENS} {copiedVar}
|
|
133
|
+
<TokenScaleTable kind="line-height" tokens={DURATION_TOKENS} {copiedVar} oncopy={copyVariable} />
|
|
134
134
|
</div>
|
|
135
135
|
|
|
136
136
|
<div class="utility-group">
|
|
137
137
|
<h3 class="group-title">Z-Index Layers</h3>
|
|
138
|
-
<TokenScaleTable kind="line-height" tokens={Z_INDEX_TOKENS} {copiedVar}
|
|
138
|
+
<TokenScaleTable kind="line-height" tokens={Z_INDEX_TOKENS} {copiedVar} oncopy={copyVariable} />
|
|
139
139
|
</div>
|
|
140
140
|
|
|
141
141
|
<div class="utility-group">
|
|
142
142
|
<h3 class="group-title">Opacity</h3>
|
|
143
|
-
<TokenScaleTable kind="line-height" tokens={OPACITY_TOKENS} {copiedVar}
|
|
143
|
+
<TokenScaleTable kind="line-height" tokens={OPACITY_TOKENS} {copiedVar} oncopy={copyVariable} />
|
|
144
144
|
</div>
|
|
145
145
|
</div>
|
|
146
146
|
</section>
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { stopPropagation } from 'svelte/legacy';
|
|
3
|
+
|
|
2
4
|
import type { GradientStyle, GradientStop } from '../../lib/themeTypes';
|
|
3
5
|
import { beginSliderGesture } from '../../lib/editorStore';
|
|
4
6
|
|
|
@@ -16,19 +18,36 @@
|
|
|
16
18
|
|
|
17
19
|
interface PaletteStep { label: string; hex: string }
|
|
18
20
|
|
|
19
|
-
export let gradientStyle: GradientStyle;
|
|
20
|
-
export let gradientAngle: number;
|
|
21
|
-
export let gradientSize: 'page' | 'window';
|
|
22
|
-
export let gradientReverse: boolean;
|
|
23
|
-
export let gradientStops: GradientStop[];
|
|
24
|
-
export let gradientBarPreview: string;
|
|
25
|
-
export let paletteComputed: PaletteStep[];
|
|
26
21
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
22
|
+
interface Props {
|
|
23
|
+
gradientStyle: GradientStyle;
|
|
24
|
+
gradientAngle: number;
|
|
25
|
+
gradientSize: 'page' | 'window';
|
|
26
|
+
gradientReverse: boolean;
|
|
27
|
+
gradientStops: GradientStop[];
|
|
28
|
+
gradientBarPreview: string;
|
|
29
|
+
paletteComputed: PaletteStep[];
|
|
30
|
+
onSetGradientStyle: (style: GradientStyle) => void;
|
|
31
|
+
onSetGradientSize: (size: 'page' | 'window') => void;
|
|
32
|
+
onSetGradientAngle: (angle: number) => void;
|
|
33
|
+
onSetGradientReverse: (reverse: boolean) => void;
|
|
34
|
+
onSetGradientStops: (stops: GradientStop[]) => void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let {
|
|
38
|
+
gradientStyle,
|
|
39
|
+
gradientAngle,
|
|
40
|
+
gradientSize,
|
|
41
|
+
gradientReverse,
|
|
42
|
+
gradientStops,
|
|
43
|
+
gradientBarPreview,
|
|
44
|
+
paletteComputed,
|
|
45
|
+
onSetGradientStyle,
|
|
46
|
+
onSetGradientSize,
|
|
47
|
+
onSetGradientAngle,
|
|
48
|
+
onSetGradientReverse,
|
|
49
|
+
onSetGradientStops
|
|
50
|
+
}: Props = $props();
|
|
32
51
|
|
|
33
52
|
const gradientStyleOptions: { value: GradientStyle; icon: string; title: string }[] = [
|
|
34
53
|
{ value: 'linear', icon: '/', title: 'Linear' },
|
|
@@ -41,7 +60,7 @@
|
|
|
41
60
|
{ value: 'window', label: 'Window', title: 'Gradient stays fixed to the viewport' },
|
|
42
61
|
];
|
|
43
62
|
|
|
44
|
-
let selectedStopIndex = 0;
|
|
63
|
+
let selectedStopIndex = $state(0);
|
|
45
64
|
let draggingStopIndex: number | null = null;
|
|
46
65
|
|
|
47
66
|
function stopColor(stop: GradientStop): string {
|
|
@@ -152,7 +171,7 @@
|
|
|
152
171
|
class:active={gradientStyle === opt.value}
|
|
153
172
|
type="button"
|
|
154
173
|
title={opt.title}
|
|
155
|
-
|
|
174
|
+
onclick={() => onSetGradientStyle(opt.value)}
|
|
156
175
|
>{opt.icon}</button>
|
|
157
176
|
{/each}
|
|
158
177
|
</div>
|
|
@@ -166,7 +185,7 @@
|
|
|
166
185
|
min="0"
|
|
167
186
|
max="360"
|
|
168
187
|
value={gradientAngle}
|
|
169
|
-
|
|
188
|
+
oninput={onAngleInput}
|
|
170
189
|
/>
|
|
171
190
|
<span class="gradient-unit">deg</span>
|
|
172
191
|
<input
|
|
@@ -175,7 +194,7 @@
|
|
|
175
194
|
min="0"
|
|
176
195
|
max="360"
|
|
177
196
|
value={gradientAngle}
|
|
178
|
-
|
|
197
|
+
oninput={onAngleInput}
|
|
179
198
|
/>
|
|
180
199
|
</div>
|
|
181
200
|
|
|
@@ -188,7 +207,7 @@
|
|
|
188
207
|
class:active={gradientSize === opt.value}
|
|
189
208
|
type="button"
|
|
190
209
|
title={opt.title}
|
|
191
|
-
|
|
210
|
+
onclick={() => onSetGradientSize(opt.value)}
|
|
192
211
|
>{opt.label}</button>
|
|
193
212
|
{/each}
|
|
194
213
|
</div>
|
|
@@ -196,7 +215,7 @@
|
|
|
196
215
|
|
|
197
216
|
<div class="gradient-row">
|
|
198
217
|
<label class="gradient-checkbox-label">
|
|
199
|
-
<input type="checkbox" checked={gradientReverse}
|
|
218
|
+
<input type="checkbox" checked={gradientReverse} onchange={onReverseChange} />
|
|
200
219
|
Reverse
|
|
201
220
|
</label>
|
|
202
221
|
</div>
|
|
@@ -205,15 +224,15 @@
|
|
|
205
224
|
<div class="gradient-stop-bar-wrapper">
|
|
206
225
|
<div class="gradient-stop-handles">
|
|
207
226
|
{#each gradientStops as stop, i}
|
|
208
|
-
<!-- svelte-ignore
|
|
227
|
+
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
209
228
|
<div
|
|
210
229
|
class="gradient-stop-handle"
|
|
211
230
|
class:selected={selectedStopIndex === i}
|
|
212
231
|
style="left: {stop.position}%; --stop-color: {stopColor(stop)}"
|
|
213
|
-
|
|
232
|
+
onmousedown={stopPropagation((e) => handleStopHandleMouseDown(e as MouseEvent, i))}
|
|
214
233
|
role="button"
|
|
215
234
|
tabindex="0"
|
|
216
|
-
|
|
235
|
+
onkeydown={(e) => {
|
|
217
236
|
if (e.key === 'Delete' || e.key === 'Backspace') removeGradientStop(i);
|
|
218
237
|
}}
|
|
219
238
|
>
|
|
@@ -222,11 +241,11 @@
|
|
|
222
241
|
</div>
|
|
223
242
|
{/each}
|
|
224
243
|
</div>
|
|
225
|
-
<!-- svelte-ignore
|
|
244
|
+
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
226
245
|
<div
|
|
227
246
|
class="gradient-stop-bar"
|
|
228
247
|
style="background: {gradientBarPreview}"
|
|
229
|
-
|
|
248
|
+
onmousedown={handleStopBarMouseDown}
|
|
230
249
|
role="slider"
|
|
231
250
|
tabindex="0"
|
|
232
251
|
aria-label="Gradient stops"
|
|
@@ -243,7 +262,7 @@
|
|
|
243
262
|
<select
|
|
244
263
|
class="gradient-select"
|
|
245
264
|
value={gradientStops[selectedStopIndex].paletteLabel}
|
|
246
|
-
|
|
265
|
+
onchange={onStopColorChange}
|
|
247
266
|
>
|
|
248
267
|
{#each paletteComputed as ps}
|
|
249
268
|
<option value={ps.label}>{ps.label}</option>
|
|
@@ -257,7 +276,7 @@
|
|
|
257
276
|
min="0"
|
|
258
277
|
max="100"
|
|
259
278
|
value={gradientStops[selectedStopIndex].position}
|
|
260
|
-
|
|
279
|
+
onchange={onStopPositionChange}
|
|
261
280
|
/>
|
|
262
281
|
<span class="gradient-unit">%</span>
|
|
263
282
|
{#if gradientStops.length > 2}
|
|
@@ -265,7 +284,7 @@
|
|
|
265
284
|
class="stop-remove-btn"
|
|
266
285
|
type="button"
|
|
267
286
|
title="Remove stop"
|
|
268
|
-
|
|
287
|
+
onclick={() => removeGradientStop(selectedStopIndex)}
|
|
269
288
|
>×</button>
|
|
270
289
|
{/if}
|
|
271
290
|
</div>
|
|
@@ -36,37 +36,71 @@
|
|
|
36
36
|
|
|
37
37
|
interface PaletteStep { label: string; hex: string }
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
interface Props {
|
|
42
|
+
scale: Scale;
|
|
43
|
+
editorOpen: boolean;
|
|
44
|
+
snapped: boolean;
|
|
45
|
+
supportsSnap: boolean;
|
|
46
|
+
cssNamespace: string | null;
|
|
47
|
+
scaleCurves: Record<string, { lightness: CurveAnchor[]; saturation: CurveAnchor[] }>;
|
|
48
|
+
curveOffset: Record<string, number>;
|
|
49
|
+
defaultScaleCurves: Record<string, ScaleCurveDef>;
|
|
50
|
+
overrides: Record<string, string>;
|
|
51
|
+
editingKey: string | null;
|
|
52
|
+
snapPickerKey: string | null;
|
|
53
|
+
copiedKey: string | null;
|
|
54
|
+
copiedLabelKey: string | null;
|
|
55
|
+
paletteComputed: PaletteStep[];
|
|
56
|
+
derivedHexFor: (step: Step, scaleTitle: string) => string;
|
|
57
|
+
effectiveHexFor: (key: string, step: Step, scaleTitle: string) => string;
|
|
58
|
+
stepKeyFor: (scaleTitle: string, stepName: string) => string;
|
|
59
|
+
scaleCurveKeyFor: (scaleTitle: string, channel: Channel) => string;
|
|
60
|
+
onToggleSnap: (scale: Scale) => void;
|
|
61
|
+
onClearScaleOverrides: (scale: Scale) => void;
|
|
62
|
+
onToggleEditor: (scaleTitle: string) => void;
|
|
63
|
+
onResetOverride: (key: string) => void;
|
|
64
|
+
onOverrideClick: (key: string, step: Step, scaleTitle: string) => void;
|
|
65
|
+
onSnappedClick: (key: string) => void;
|
|
66
|
+
onSelectSnapValue: (key: string, paletteHex: string, scaleTitle: string) => void;
|
|
67
|
+
onCopyHex: (key: string, hex: string, event?: MouseEvent) => void;
|
|
68
|
+
onCopyVarName: (key: string, varName: string, event?: MouseEvent) => void;
|
|
69
|
+
onSetScaleCurve: (scaleTitle: string, channel: Channel, anchors: CurveAnchor[]) => void;
|
|
70
|
+
onOffsetChange: (key: string, value: number) => void;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
let {
|
|
74
|
+
scale,
|
|
75
|
+
editorOpen,
|
|
76
|
+
snapped,
|
|
77
|
+
supportsSnap,
|
|
78
|
+
cssNamespace,
|
|
79
|
+
scaleCurves,
|
|
80
|
+
curveOffset,
|
|
81
|
+
defaultScaleCurves,
|
|
82
|
+
overrides,
|
|
83
|
+
editingKey,
|
|
84
|
+
snapPickerKey,
|
|
85
|
+
copiedKey,
|
|
86
|
+
copiedLabelKey,
|
|
87
|
+
paletteComputed,
|
|
88
|
+
derivedHexFor,
|
|
89
|
+
effectiveHexFor,
|
|
90
|
+
stepKeyFor,
|
|
91
|
+
scaleCurveKeyFor,
|
|
92
|
+
onToggleSnap,
|
|
93
|
+
onClearScaleOverrides,
|
|
94
|
+
onToggleEditor,
|
|
95
|
+
onResetOverride,
|
|
96
|
+
onOverrideClick,
|
|
97
|
+
onSnappedClick,
|
|
98
|
+
onSelectSnapValue,
|
|
99
|
+
onCopyHex,
|
|
100
|
+
onCopyVarName,
|
|
101
|
+
onSetScaleCurve,
|
|
102
|
+
onOffsetChange
|
|
103
|
+
}: Props = $props();
|
|
70
104
|
|
|
71
105
|
interface CurveDescriptor {
|
|
72
106
|
key: string;
|
|
@@ -76,7 +110,7 @@
|
|
|
76
110
|
channel: Channel;
|
|
77
111
|
}
|
|
78
112
|
|
|
79
|
-
|
|
113
|
+
let curveDescriptors = $derived(((): CurveDescriptor[] => {
|
|
80
114
|
const lightnessCfg = scale.isText ? textLightnessCurveConfig : lightnessCurveConfig;
|
|
81
115
|
const sc = scaleCurves[scale.title];
|
|
82
116
|
const defs = defaultScaleCurves[scale.title];
|
|
@@ -85,7 +119,7 @@
|
|
|
85
119
|
{ key: scaleCurveKeyFor(scale.title, 'lightness'), anchors: sc.lightness, cfg: lightnessCfg, defaults: defs.lightness(), channel: 'lightness' },
|
|
86
120
|
{ key: scaleCurveKeyFor(scale.title, 'saturation'), anchors: sc.saturation, cfg: saturationCurveConfig, defaults: defs.saturation(), channel: 'saturation' },
|
|
87
121
|
];
|
|
88
|
-
})();
|
|
122
|
+
})());
|
|
89
123
|
</script>
|
|
90
124
|
|
|
91
125
|
<div class="scale-section">
|
|
@@ -96,14 +130,14 @@
|
|
|
96
130
|
class="edit-toggle"
|
|
97
131
|
class:active={snapped}
|
|
98
132
|
type="button"
|
|
99
|
-
|
|
133
|
+
onclick={() => onToggleSnap(scale)}
|
|
100
134
|
>{snapped ? 'Unsnap' : 'Snap All'}</button>
|
|
101
135
|
{/if}
|
|
102
|
-
<button class="edit-toggle" type="button"
|
|
136
|
+
<button class="edit-toggle" type="button" onclick={() => onClearScaleOverrides(scale)}>Clear Overrides</button>
|
|
103
137
|
<button
|
|
104
138
|
class="edit-toggle"
|
|
105
139
|
type="button"
|
|
106
|
-
|
|
140
|
+
onclick={() => onToggleEditor(scale.title)}
|
|
107
141
|
>{editorOpen ? 'Close' : 'Edit'}</button>
|
|
108
142
|
</div>
|
|
109
143
|
<div class="swatch-grid" style="--swatch-cols: {scale.steps.length}; --swatch-gap: var(--ui-space-8)">
|
|
@@ -112,37 +146,39 @@
|
|
|
112
146
|
{@const hex = effectiveHexFor(k, step, scale.title)}
|
|
113
147
|
{@const dHex = derivedHexFor(step, scale.title)}
|
|
114
148
|
<div class="step-column">
|
|
115
|
-
<button class="step-label copyable-label" class:copied={copiedLabelKey === k} type="button"
|
|
149
|
+
<button class="step-label copyable-label" class:copied={copiedLabelKey === k} type="button" onclick={(e) => { const v = scaleToCssVar(scale.title, step.name, cssNamespace); if (v) onCopyVarName(k, v, e); }}>
|
|
116
150
|
{copiedLabelKey === k ? 'copied!' : step.name}
|
|
117
151
|
</button>
|
|
118
152
|
{#if scale.isText}
|
|
153
|
+
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
119
154
|
<div
|
|
120
155
|
class="swatch derived text-swatch"
|
|
121
156
|
class:dimmed={k in overrides}
|
|
122
157
|
class:clickable={k in overrides}
|
|
123
|
-
|
|
158
|
+
onclick={() => onResetOverride(k)}
|
|
124
159
|
role={k in overrides ? 'button' : undefined}
|
|
125
160
|
tabindex={k in overrides ? 0 : undefined}
|
|
126
|
-
|
|
161
|
+
onkeydown={(e) => k in overrides && e.key === 'Enter' && onResetOverride(k)}
|
|
127
162
|
>
|
|
128
163
|
<span style="color: {dHex}">Ag</span>
|
|
129
164
|
</div>
|
|
130
|
-
<!-- svelte-ignore
|
|
165
|
+
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
131
166
|
<div
|
|
132
167
|
class="swatch override-slot text-swatch"
|
|
133
168
|
class:active={editingKey === k}
|
|
134
169
|
class:populated={k in overrides}
|
|
135
170
|
class:matching={k in overrides && overrides[k] === dHex}
|
|
136
|
-
|
|
171
|
+
onclick={() => onOverrideClick(k, step, scale.title)}
|
|
137
172
|
role="button"
|
|
138
173
|
tabindex="0"
|
|
139
|
-
|
|
174
|
+
onkeydown={(e) => e.key === 'Enter' && onOverrideClick(k, step, scale.title)}
|
|
140
175
|
>
|
|
141
176
|
{#if k in overrides}
|
|
142
177
|
<span style="color: {overrides[k]}">Ag</span>
|
|
143
178
|
{/if}
|
|
144
179
|
</div>
|
|
145
180
|
{:else}
|
|
181
|
+
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
146
182
|
<div
|
|
147
183
|
class="swatch derived"
|
|
148
184
|
class:border-preview={scale.title === 'Borders'}
|
|
@@ -151,23 +187,23 @@
|
|
|
151
187
|
style={scale.title === 'Borders'
|
|
152
188
|
? `border: 3px solid ${dHex}`
|
|
153
189
|
: `background: ${dHex}`}
|
|
154
|
-
|
|
190
|
+
onclick={() => onResetOverride(k)}
|
|
155
191
|
role={k in overrides ? 'button' : undefined}
|
|
156
192
|
tabindex={k in overrides ? 0 : undefined}
|
|
157
|
-
|
|
193
|
+
onkeydown={(e) => k in overrides && e.key === 'Enter' && onResetOverride(k)}
|
|
158
194
|
></div>
|
|
159
195
|
<div class="override-slot-wrapper">
|
|
160
|
-
<!-- svelte-ignore
|
|
196
|
+
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
161
197
|
<div
|
|
162
198
|
class="swatch override-slot"
|
|
163
199
|
class:border-preview={scale.title === 'Borders'}
|
|
164
200
|
class:active={editingKey === k || snapPickerKey === k}
|
|
165
201
|
class:populated={k in overrides}
|
|
166
202
|
class:matching={k in overrides && overrides[k] === dHex}
|
|
167
|
-
|
|
203
|
+
onclick={() => snapped ? onSnappedClick(k) : onOverrideClick(k, step, scale.title)}
|
|
168
204
|
role="button"
|
|
169
205
|
tabindex="0"
|
|
170
|
-
|
|
206
|
+
onkeydown={(e) => e.key === 'Enter' && (snapped ? onSnappedClick(k) : onOverrideClick(k, step, scale.title))}
|
|
171
207
|
>
|
|
172
208
|
{#if k in overrides}
|
|
173
209
|
{#if scale.title === 'Borders'}
|
|
@@ -190,7 +226,7 @@
|
|
|
190
226
|
class="snap-picker-item"
|
|
191
227
|
class:selected={overrides[k] === ps.hex}
|
|
192
228
|
type="button"
|
|
193
|
-
|
|
229
|
+
onclick={() => onSelectSnapValue(k, ps.hex, scale.title)}
|
|
194
230
|
>
|
|
195
231
|
<span class="snap-picker-swatch" style="background: {ps.hex}"></span>
|
|
196
232
|
<span class="snap-picker-label">{ps.label}</span>
|
|
@@ -204,7 +240,7 @@
|
|
|
204
240
|
class="step-hex"
|
|
205
241
|
class:copied={copiedKey === k}
|
|
206
242
|
type="button"
|
|
207
|
-
|
|
243
|
+
onclick={(e) => onCopyHex(k, hex, e)}
|
|
208
244
|
>{copiedKey === k ? 'copied!' : hex}</button>
|
|
209
245
|
</div>
|
|
210
246
|
{/each}
|
|
@@ -3,7 +3,11 @@
|
|
|
3
3
|
import Toggle from '../Toggle.svelte';
|
|
4
4
|
import { beginSliderGesture } from '../../lib/editorStore';
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
/**
|
|
7
11
|
* The header swatch + label + base-hex + (when active) the ColorEditPanel
|
|
8
12
|
* for editing the palette's base colour. In chromatic mode the user picks
|
|
9
13
|
* an arbitrary hex; in gray mode the user picks tint hue + chroma and the
|
|
@@ -13,51 +17,73 @@
|
|
|
13
17
|
* fires callbacks (`onStartEdit`, `onConfirm`, `onCancel`, etc.). The
|
|
14
18
|
* parent decides whether to apply the chromatic-vs-gray snapshot dance.
|
|
15
19
|
*/
|
|
20
|
+
label: string;
|
|
21
|
+
displayLabel?: string | null;
|
|
22
|
+
mode: 'chromatic' | 'gray';
|
|
23
|
+
baseColor: string;
|
|
24
|
+
gray500Hex: string;
|
|
25
|
+
tintHue: number;
|
|
26
|
+
tintChroma: number;
|
|
27
|
+
anchorToBase: boolean;
|
|
28
|
+
isEditingBase: boolean;
|
|
29
|
+
panelOpen: boolean;
|
|
30
|
+
editingColor: string | null;
|
|
31
|
+
editPanelTitle: string | null;
|
|
32
|
+
copiedKey: string | null;
|
|
33
|
+
onStartEdit: () => void;
|
|
34
|
+
onConfirm: () => void;
|
|
35
|
+
onCancel: () => void;
|
|
36
|
+
onColorChange: (hex: string) => void;
|
|
37
|
+
onTintChange: (hue: number, chroma: number) => void;
|
|
38
|
+
onAnchorToBaseChange: (next: boolean) => void;
|
|
39
|
+
onCopyBaseHex: (key: string, hex: string, event?: MouseEvent) => void;
|
|
40
|
+
}
|
|
16
41
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
let {
|
|
43
|
+
label,
|
|
44
|
+
displayLabel = null,
|
|
45
|
+
mode,
|
|
46
|
+
baseColor,
|
|
47
|
+
gray500Hex,
|
|
48
|
+
tintHue,
|
|
49
|
+
tintChroma,
|
|
50
|
+
anchorToBase,
|
|
51
|
+
isEditingBase,
|
|
52
|
+
panelOpen,
|
|
53
|
+
editingColor,
|
|
54
|
+
editPanelTitle,
|
|
55
|
+
copiedKey,
|
|
56
|
+
onStartEdit,
|
|
57
|
+
onConfirm,
|
|
58
|
+
onCancel,
|
|
59
|
+
onColorChange,
|
|
60
|
+
onTintChange,
|
|
61
|
+
onAnchorToBaseChange,
|
|
62
|
+
onCopyBaseHex
|
|
63
|
+
}: Props = $props();
|
|
64
|
+
|
|
65
|
+
let displayHex = $derived(mode === 'gray' ? gray500Hex : baseColor);
|
|
66
|
+
let copyKey = $derived(mode === 'gray' ? 'gray-500' : '__base__');
|
|
41
67
|
</script>
|
|
42
68
|
|
|
43
69
|
<div class="editor-top">
|
|
44
70
|
<div class="editor-primary">
|
|
45
|
-
<!-- svelte-ignore
|
|
71
|
+
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
46
72
|
<div
|
|
47
73
|
class="header-swatch"
|
|
48
74
|
class:active={isEditingBase}
|
|
49
75
|
style="background: {displayHex}"
|
|
50
|
-
|
|
76
|
+
onclick={onStartEdit}
|
|
51
77
|
role="button"
|
|
52
78
|
tabindex="0"
|
|
53
|
-
|
|
79
|
+
onkeydown={(e) => e.key === 'Enter' && onStartEdit()}
|
|
54
80
|
></div>
|
|
55
81
|
<div class="primary-info">
|
|
56
82
|
<span class="editor-label">{displayLabel ?? label}</span>
|
|
57
83
|
<button
|
|
58
84
|
class="base-hex clickable-hex"
|
|
59
85
|
type="button"
|
|
60
|
-
|
|
86
|
+
onclick={(e) => onCopyBaseHex(copyKey, displayHex, e)}
|
|
61
87
|
>{copiedKey === copyKey ? 'copied!' : displayHex}</button>
|
|
62
88
|
</div>
|
|
63
89
|
</div>
|
|
@@ -78,9 +104,11 @@
|
|
|
78
104
|
onRemoveOverride={() => {}}
|
|
79
105
|
onSliderStart={() => beginSliderGesture(`edit ${label} base`)}
|
|
80
106
|
>
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
107
|
+
{#snippet actions()}
|
|
108
|
+
<span class:hidden={mode !== 'chromatic'}>
|
|
109
|
+
<Toggle checked={anchorToBase} onchange={(v) => onAnchorToBaseChange(v ?? !anchorToBase)} label="Lock base color to position 500" />
|
|
110
|
+
</span>
|
|
111
|
+
{/snippet}
|
|
84
112
|
</ColorEditPanel>
|
|
85
113
|
{/if}
|
|
86
114
|
|