@motion-proto/live-tokens 0.3.9 → 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/package.json +9 -8
- 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 +57 -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
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { run, stopPropagation, createBubbler } from 'svelte/legacy';
|
|
3
|
+
|
|
4
|
+
const bubble = createBubbler();
|
|
2
5
|
import { onMount, onDestroy, tick } from 'svelte';
|
|
3
6
|
import { hexToOklch, oklchToHex, gamutClamp } from '../lib/oklch';
|
|
4
7
|
import { type CurveAnchor, makeAnchor, sampleCurve, lightnessCurveConfig, saturationCurveConfig, textLightnessCurveConfig } from './curveEngine';
|
|
@@ -17,45 +20,24 @@
|
|
|
17
20
|
/** Mid-gray fallback used when no base colour or computed gray-500 is available. */
|
|
18
21
|
const GRAY_FALLBACK = '#808080';
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
interface Props {
|
|
24
|
+
label: string;
|
|
25
|
+
displayLabel?: string | null;
|
|
26
|
+
initialColor?: string;
|
|
27
|
+
mode?: 'chromatic' | 'gray';
|
|
28
|
+
cssNamespace?: string | null;
|
|
29
|
+
emptySelector?: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let {
|
|
33
|
+
label,
|
|
34
|
+
displayLabel = null,
|
|
35
|
+
initialColor = GRAY_FALLBACK,
|
|
36
|
+
mode = 'chromatic',
|
|
37
|
+
cssNamespace = null,
|
|
38
|
+
emptySelector = false
|
|
39
|
+
}: Props = $props();
|
|
26
40
|
|
|
27
|
-
// --- Store-sourced config (single source of truth) ---
|
|
28
|
-
//
|
|
29
|
-
// All persistent palette state lives in `$editorState.palettes[label]`.
|
|
30
|
-
// Local `$:` derivations below pull named fields with defaults; every
|
|
31
|
-
// handler writes via `edit()` / `patchPalette()` so the store is the only
|
|
32
|
-
// writer. No `let` mirrors, no round-trip sync reactives.
|
|
33
|
-
//
|
|
34
|
-
// The defaults fall back only when palettes[label] is undefined (brand-new
|
|
35
|
-
// install, never seeded). Production seeds via themeInit → seedPalettesFromTheme.
|
|
36
|
-
$: paletteConfig = $editorState.palettes[label];
|
|
37
|
-
$: baseColor = paletteConfig?.baseColor ?? initialColor;
|
|
38
|
-
$: tintHue = paletteConfig?.tintHue ?? 240;
|
|
39
|
-
$: tintChroma = paletteConfig?.tintChroma ?? DEFAULT_TINT_CHROMA;
|
|
40
|
-
$: lightnessCurve = paletteConfig?.lightnessCurve ?? DEFAULT_PALETTE_LIGHTNESS();
|
|
41
|
-
$: saturationCurve = paletteConfig?.saturationCurve ?? DEFAULT_PALETTE_SATURATION();
|
|
42
|
-
$: grayLightnessCurve = paletteConfig?.grayLightnessCurve ?? DEFAULT_GRAY_LIGHTNESS();
|
|
43
|
-
$: graySaturationCurve = paletteConfig?.graySaturationCurve ?? DEFAULT_GRAY_SATURATION();
|
|
44
|
-
$: scaleCurves = paletteConfig?.scaleCurves ?? defaultScaleCurvesObject();
|
|
45
|
-
$: curveOffset = paletteConfig?.curveOffset ?? { lightness: 0, saturation: 0 };
|
|
46
|
-
$: overrides = paletteConfig?.overrides ?? {};
|
|
47
|
-
$: snappedScales = new Set(paletteConfig?.snappedScales ?? []);
|
|
48
|
-
$: anchorToBase = paletteConfig?.anchorToBase ?? true;
|
|
49
|
-
$: emptyMode = paletteConfig?.emptyMode ?? 'solid';
|
|
50
|
-
$: emptyStep = paletteConfig?.emptyStep ?? '850';
|
|
51
|
-
$: gradientStyle = paletteConfig?.gradientStyle ?? 'linear';
|
|
52
|
-
$: gradientAngle = paletteConfig?.gradientAngle ?? 180;
|
|
53
|
-
$: gradientReverse = paletteConfig?.gradientReverse ?? false;
|
|
54
|
-
$: gradientStops = paletteConfig?.gradientStops ?? [
|
|
55
|
-
{ position: 0, paletteLabel: '800' },
|
|
56
|
-
{ position: 100, paletteLabel: '950' },
|
|
57
|
-
];
|
|
58
|
-
$: gradientSize = paletteConfig?.gradientSize ?? 'page';
|
|
59
41
|
|
|
60
42
|
function defaultPaletteConfig(): PaletteConfig {
|
|
61
43
|
return {
|
|
@@ -97,8 +79,8 @@
|
|
|
97
79
|
}
|
|
98
80
|
|
|
99
81
|
// --- Transient UI state (not persisted; not in PaletteConfig) ---
|
|
100
|
-
let lockedLightnessIdx: number | null = null;
|
|
101
|
-
let lockedSaturationIdx: number | null = null;
|
|
82
|
+
let lockedLightnessIdx: number | null = $state(null);
|
|
83
|
+
let lockedSaturationIdx: number | null = $state(null);
|
|
102
84
|
|
|
103
85
|
// Handle for the open palette edit scope: a clipping scope (clipUndoFloor:
|
|
104
86
|
// true) bracketing one panel-open → confirm/cancel cycle. Held at component
|
|
@@ -111,9 +93,9 @@
|
|
|
111
93
|
return ps ? ps.effective : '#000000';
|
|
112
94
|
}
|
|
113
95
|
|
|
114
|
-
let gradientColorStops = '';
|
|
115
|
-
let gradientCssValue = '';
|
|
116
|
-
let gradientBarPreview = '';
|
|
96
|
+
let gradientColorStops = $state('');
|
|
97
|
+
let gradientCssValue = $state('');
|
|
98
|
+
let gradientBarPreview = $state('');
|
|
117
99
|
|
|
118
100
|
function onEmptyModeChange(e: Event) {
|
|
119
101
|
edit('emptyMode', (e.currentTarget as HTMLInputElement).checked ? 'gradient' : 'solid');
|
|
@@ -142,11 +124,11 @@
|
|
|
142
124
|
{ label: '950', hue: 229, saturation: 34, lightness: 3 },
|
|
143
125
|
];
|
|
144
126
|
|
|
145
|
-
let grayEditorOpen = false;
|
|
146
|
-
let showDerived = false;
|
|
127
|
+
let grayEditorOpen = $state(false);
|
|
128
|
+
let showDerived = $state(false);
|
|
147
129
|
|
|
148
130
|
// --- Palette curve editors (lightness + saturation) ---
|
|
149
|
-
let paletteEditorOpen = false;
|
|
131
|
+
let paletteEditorOpen = $state(false);
|
|
150
132
|
|
|
151
133
|
// Default curve anchors (used for initial state and reset)
|
|
152
134
|
const DEFAULT_PALETTE_LIGHTNESS = () => [makeAnchor(0, 95, 5), makeAnchor(100, 8, 5)];
|
|
@@ -179,15 +161,8 @@
|
|
|
179
161
|
// (`editingKey`, `editingSnapshot`, `editingDraft`, `snapshotTintHue`,
|
|
180
162
|
// `snapshotTintChroma`). The compatibility `$:` derivations below preserve
|
|
181
163
|
// existing read sites while writes go through `editing = { kind: ... }`.
|
|
182
|
-
let editing: EditingState = idleState;
|
|
164
|
+
let editing: EditingState = $state(idleState);
|
|
183
165
|
|
|
184
|
-
// Read-side compat: existing `editingKey === ...` etc. comparisons keep
|
|
185
|
-
// working. New code should narrow on `editing.kind` directly.
|
|
186
|
-
$: editingKey = editing.kind === 'idle' ? null : editing.kind === 'editingBase' ? BASE_KEY : editing.stepKey;
|
|
187
|
-
$: editingDraft = editing.kind === 'editingStep' ? editing.draft : null;
|
|
188
|
-
$: editingSnapshot = editing.kind === 'idle' ? null : editing.kind === 'editingBase' ? editing.snapshotHex : editing.snapshot;
|
|
189
|
-
$: snapshotTintHue = editing.kind === 'editingBase' ? editing.snapshotTintHue : null;
|
|
190
|
-
$: snapshotTintChroma = editing.kind === 'editingBase' ? editing.snapshotTintChroma : null;
|
|
191
166
|
|
|
192
167
|
function computeGrayColor(index: number, hue: number, chroma: number = tintChroma): string {
|
|
193
168
|
const xPos = grayStepToX(index);
|
|
@@ -206,30 +181,8 @@
|
|
|
206
181
|
return `gray-${label}`;
|
|
207
182
|
}
|
|
208
183
|
|
|
209
|
-
// Reactive map of computed gray colors
|
|
210
|
-
$: grayComputed = (() => {
|
|
211
|
-
const _gl = grayLightnessCurve, _gs = graySaturationCurve, _co = curveOffset, _tc = tintChroma, _th = tintHue;
|
|
212
|
-
return graySteps.map((step, index) => ({
|
|
213
|
-
step,
|
|
214
|
-
index,
|
|
215
|
-
key: grayStepKey(step.label),
|
|
216
|
-
hex: computeGrayColor(index, _th, _tc),
|
|
217
|
-
}));
|
|
218
|
-
})();
|
|
219
184
|
|
|
220
|
-
$: grayEffective = (() => {
|
|
221
|
-
const _ed = editingDraft, _ek = editingKey, _ov = overrides;
|
|
222
|
-
return grayComputed.map(g => ({
|
|
223
|
-
...g,
|
|
224
|
-
effective: (_ek === g.key && _ed !== null) ? _ed : (g.key in _ov) ? _ov[g.key] : g.hex,
|
|
225
|
-
}));
|
|
226
|
-
})();
|
|
227
185
|
|
|
228
|
-
// Gray-500 hex — always the computed (curve-derived) value so derived
|
|
229
|
-
// scales (surfaces, borders, text) update in realtime when tint changes.
|
|
230
|
-
$: gray500Hex = mode === 'gray'
|
|
231
|
-
? (grayComputed.find(g => g.step.label === '500')?.hex ?? GRAY_FALLBACK)
|
|
232
|
-
: baseColor;
|
|
233
186
|
|
|
234
187
|
|
|
235
188
|
// --- Chromatic palette steps ---
|
|
@@ -313,34 +266,7 @@
|
|
|
313
266
|
}
|
|
314
267
|
}
|
|
315
268
|
|
|
316
|
-
// Derive locked anchor indices from curve shape — no writes to state.
|
|
317
|
-
$: {
|
|
318
|
-
if (anchorToBase) {
|
|
319
|
-
const x500 = stepIndexToX(4);
|
|
320
|
-
const lIdx = lightnessCurve.findIndex(a => Math.abs(a.x - x500) < 0.5);
|
|
321
|
-
lockedLightnessIdx = lIdx >= 0 ? lIdx : null;
|
|
322
|
-
const sIdx = saturationCurve.findIndex(a => Math.abs(a.x - x500) < 0.5);
|
|
323
|
-
lockedSaturationIdx = sIdx >= 0 ? sIdx : null;
|
|
324
|
-
} else {
|
|
325
|
-
lockedLightnessIdx = null;
|
|
326
|
-
lockedSaturationIdx = null;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
269
|
|
|
330
|
-
/**
|
|
331
|
-
* Keep the locked lightness anchor y in sync with baseColor. Idempotent —
|
|
332
|
-
* only writes when the curve's anchor y differs from the baseColor-derived
|
|
333
|
-
* target. During a baseColor drag (inside a slider transaction) this
|
|
334
|
-
* additional curve edit merges into the same history entry. On undo/redo
|
|
335
|
-
* the curve already has the correct y (they're saved together), so this
|
|
336
|
-
* is a no-op.
|
|
337
|
-
*/
|
|
338
|
-
$: if (anchorToBase && lockedLightnessIdx !== null && baseColor) {
|
|
339
|
-
const targetY = hexToOklch(baseColor).l * 100;
|
|
340
|
-
if (lightnessCurve[lockedLightnessIdx] && Math.abs(lightnessCurve[lockedLightnessIdx].y - targetY) > 0.01) {
|
|
341
|
-
edit('lightnessCurve', lightnessCurve.map((a, i) => i === lockedLightnessIdx ? { ...a, y: targetY } : a));
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
270
|
|
|
345
271
|
function computePaletteColor(index: number, base: string): string {
|
|
346
272
|
const { c: baseC, h } = hexToOklch(base);
|
|
@@ -354,39 +280,7 @@
|
|
|
354
280
|
return oklchToHex(clamped.l, clamped.c, clamped.h);
|
|
355
281
|
}
|
|
356
282
|
|
|
357
|
-
$: paletteComputed = (() => {
|
|
358
|
-
const _bc = baseColor, _lc = lightnessCurve, _sc = saturationCurve, _co = curveOffset, _ed = editingDraft, _ek = editingKey, _ov = overrides, _ab = anchorToBase;
|
|
359
|
-
return paletteStepLightness.map((ps, index) => {
|
|
360
|
-
const k = paletteStepKey(ps.label);
|
|
361
|
-
const hex = computePaletteColor(index, baseColor);
|
|
362
|
-
const effective = (_ek === k && _ed !== null) ? _ed : (k in _ov) ? _ov[k] : hex;
|
|
363
|
-
return {
|
|
364
|
-
label: ps.label,
|
|
365
|
-
lightness: ps.lightness,
|
|
366
|
-
index,
|
|
367
|
-
key: k,
|
|
368
|
-
hex,
|
|
369
|
-
effective,
|
|
370
|
-
};
|
|
371
|
-
});
|
|
372
|
-
})();
|
|
373
283
|
|
|
374
|
-
// Gradient reactives — must follow paletteComputed
|
|
375
|
-
$: {
|
|
376
|
-
const pc = paletteComputed;
|
|
377
|
-
const sorted = [...gradientStops].sort((a, b) => gradientReverse ? b.position - a.position : a.position - b.position);
|
|
378
|
-
gradientColorStops = sorted.map(s => `${stopColor(s, pc)} ${s.position}%`).join(', ');
|
|
379
|
-
gradientBarPreview = `linear-gradient(to right, ${gradientColorStops})`;
|
|
380
|
-
if (emptySelector && emptyMode === 'gradient') {
|
|
381
|
-
switch (gradientStyle) {
|
|
382
|
-
case 'radial': gradientCssValue = `radial-gradient(circle, ${gradientColorStops})`; break;
|
|
383
|
-
case 'conic': gradientCssValue = `conic-gradient(from ${gradientAngle}deg, ${gradientColorStops})`; break;
|
|
384
|
-
default: gradientCssValue = `linear-gradient(${gradientAngle}deg, ${gradientColorStops})`;
|
|
385
|
-
}
|
|
386
|
-
} else {
|
|
387
|
-
gradientCssValue = '';
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
284
|
|
|
391
285
|
function startBaseEdit() {
|
|
392
286
|
if (editing.kind === 'editingBase') { confirmEdit(); return; }
|
|
@@ -460,13 +354,6 @@
|
|
|
460
354
|
}
|
|
461
355
|
];
|
|
462
356
|
|
|
463
|
-
// Scales to render in gray mode (varies by namespace)
|
|
464
|
-
$: grayScales = mode === 'gray' ? scales.filter(scale => {
|
|
465
|
-
if (scale.title === 'Surfaces') return true;
|
|
466
|
-
if (scale.title === 'Borders') return true;
|
|
467
|
-
if (scale.title === 'Text') return true;
|
|
468
|
-
return false;
|
|
469
|
-
}) : [];
|
|
470
357
|
|
|
471
358
|
// --- Per-scale curve state (Surfaces & Borders) ---
|
|
472
359
|
|
|
@@ -485,7 +372,7 @@
|
|
|
485
372
|
},
|
|
486
373
|
};
|
|
487
374
|
|
|
488
|
-
let scaleEditorOpen: Record<string, boolean> = { Surfaces: false, Borders: false, Text: false };
|
|
375
|
+
let scaleEditorOpen: Record<string, boolean> = $state({ Surfaces: false, Borders: false, Text: false });
|
|
489
376
|
|
|
490
377
|
function toggleScaleEditor(title: string) {
|
|
491
378
|
scaleEditorOpen[title] = !scaleEditorOpen[title];
|
|
@@ -516,58 +403,16 @@
|
|
|
516
403
|
return `${scaleTitle}-${stepName}`;
|
|
517
404
|
}
|
|
518
405
|
|
|
519
|
-
$: curveVersion = JSON.stringify(scaleCurves) + JSON.stringify(curveOffset) + gray500Hex;
|
|
520
406
|
|
|
521
407
|
function derivedHex(step: Step, base: string, scaleTitle: string, _version?: string): string {
|
|
522
408
|
return computeDerivedColor(step, base, configForScale(scaleTitle), scaleTitle);
|
|
523
409
|
}
|
|
524
410
|
|
|
525
|
-
/**
|
|
526
|
-
* Closure factories used by `<OverridesPanel>` so the panel doesn't have to
|
|
527
|
-
* know about `baseColor` / `gray500Hex` / `curveVersion`. These keep
|
|
528
|
-
* reactivity intact (the parent's `$:` blocks still drive re-render).
|
|
529
|
-
*
|
|
530
|
-
* Note: `effectiveColor` itself always uses `gray500Hex` for non-override
|
|
531
|
-
* derivation (pre-existing); the chromatic vs gray distinction here is
|
|
532
|
-
* only for the `derivedHex` (the "Ag" preview / border-color base).
|
|
533
|
-
*/
|
|
534
|
-
$: derivedHexForBase = (step: Step, scaleTitle: string) => derivedHex(step, baseColor, scaleTitle, curveVersion);
|
|
535
|
-
$: derivedHexForGray = (step: Step, scaleTitle: string) => derivedHex(step, gray500Hex, scaleTitle, curveVersion);
|
|
536
|
-
$: effectiveHexAny = (k: string, step: Step, scaleTitle: string) => effectiveColor(k, step, scaleTitle, curveVersion);
|
|
537
411
|
|
|
538
|
-
// --- Reactive editing state ---
|
|
539
412
|
|
|
540
|
-
$: isEditingBase = isBaseEdit(editing);
|
|
541
413
|
|
|
542
|
-
$: editingColor = isEditingBase
|
|
543
|
-
? (mode === 'gray' ? gray500Hex : baseColor)
|
|
544
|
-
: editingDraft;
|
|
545
414
|
|
|
546
|
-
$: editingStepInfo = (() => {
|
|
547
|
-
if (!editingKey || isEditingBase) return null;
|
|
548
|
-
if (mode === 'gray') {
|
|
549
|
-
const gs = graySteps.find(s => grayStepKey(s.label) === editingKey);
|
|
550
|
-
if (gs) return { scale: 'Gray', step: gs.label };
|
|
551
|
-
}
|
|
552
|
-
const ps = paletteStepLightness.find(p => paletteStepKey(p.label) === editingKey);
|
|
553
|
-
if (ps) return { scale: 'Palette', step: ps.label };
|
|
554
|
-
for (const scale of scales) {
|
|
555
|
-
for (const step of scale.steps) {
|
|
556
|
-
if (stepKey(scale.title, step.name) === editingKey) {
|
|
557
|
-
return { scale: scale.title, step: step.name };
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
return null;
|
|
562
|
-
})();
|
|
563
415
|
|
|
564
|
-
$: panelOpen = editingKey !== null && (isEditingBase || (editingDraft !== null && editingStepInfo !== null));
|
|
565
|
-
|
|
566
|
-
$: editPanelTitle = isEditingBase
|
|
567
|
-
? 'Base Color'
|
|
568
|
-
: editingStepInfo
|
|
569
|
-
? `${editingStepInfo.scale} \u203A ${editingStepInfo.step}`
|
|
570
|
-
: null;
|
|
571
416
|
|
|
572
417
|
// --- Compute derived color via OKLCH ---
|
|
573
418
|
|
|
@@ -740,7 +585,7 @@
|
|
|
740
585
|
return `linear-gradient(to right, ${points.join(', ')})`;
|
|
741
586
|
}
|
|
742
587
|
|
|
743
|
-
let copiedKey: string | null = null;
|
|
588
|
+
let copiedKey: string | null = $state(null);
|
|
744
589
|
function copyHex(k: string, hex: string, event?: MouseEvent) {
|
|
745
590
|
navigator.clipboard.writeText(hex);
|
|
746
591
|
copiedKey = k;
|
|
@@ -748,7 +593,7 @@
|
|
|
748
593
|
setTimeout(() => { copiedKey = null; }, 1500);
|
|
749
594
|
}
|
|
750
595
|
|
|
751
|
-
let copiedLabelKey: string | null = null;
|
|
596
|
+
let copiedLabelKey: string | null = $state(null);
|
|
752
597
|
function copyVarName(k: string, varName: string, event?: MouseEvent) {
|
|
753
598
|
navigator.clipboard.writeText(varName);
|
|
754
599
|
copiedLabelKey = k;
|
|
@@ -840,7 +685,7 @@
|
|
|
840
685
|
}
|
|
841
686
|
}
|
|
842
687
|
|
|
843
|
-
let snapPickerKey: string | null = null;
|
|
688
|
+
let snapPickerKey: string | null = $state(null);
|
|
844
689
|
|
|
845
690
|
function handleDocClick(e: MouseEvent) {
|
|
846
691
|
if (!snapPickerKey) return;
|
|
@@ -881,7 +726,6 @@
|
|
|
881
726
|
if (changed) edit('overrides', next);
|
|
882
727
|
}
|
|
883
728
|
|
|
884
|
-
$: baseColor, scaleCurves, lightnessCurve, saturationCurve, curveOffset, snappedScales, resnapScales();
|
|
885
729
|
|
|
886
730
|
// CSS-var emission lives in `paletteDerivation` → `editorRenderer`; the store
|
|
887
731
|
// is the single source of truth for palette config and the renderer
|
|
@@ -899,6 +743,188 @@
|
|
|
899
743
|
}
|
|
900
744
|
|
|
901
745
|
|
|
746
|
+
// --- Store-sourced config (single source of truth) ---
|
|
747
|
+
//
|
|
748
|
+
// All persistent palette state lives in `$editorState.palettes[label]`.
|
|
749
|
+
// Local `$:` derivations below pull named fields with defaults; every
|
|
750
|
+
// handler writes via `edit()` / `patchPalette()` so the store is the only
|
|
751
|
+
// writer. No `let` mirrors, no round-trip sync reactives.
|
|
752
|
+
//
|
|
753
|
+
// The defaults fall back only when palettes[label] is undefined (brand-new
|
|
754
|
+
// install, never seeded). Production seeds via themeInit → seedPalettesFromTheme.
|
|
755
|
+
let paletteConfig = $derived($editorState.palettes[label]);
|
|
756
|
+
let baseColor = $derived(paletteConfig?.baseColor ?? initialColor);
|
|
757
|
+
let tintHue = $derived(paletteConfig?.tintHue ?? 240);
|
|
758
|
+
let tintChroma = $derived(paletteConfig?.tintChroma ?? DEFAULT_TINT_CHROMA);
|
|
759
|
+
let lightnessCurve = $derived(paletteConfig?.lightnessCurve ?? DEFAULT_PALETTE_LIGHTNESS());
|
|
760
|
+
let saturationCurve = $derived(paletteConfig?.saturationCurve ?? DEFAULT_PALETTE_SATURATION());
|
|
761
|
+
let grayLightnessCurve = $derived(paletteConfig?.grayLightnessCurve ?? DEFAULT_GRAY_LIGHTNESS());
|
|
762
|
+
let graySaturationCurve = $derived(paletteConfig?.graySaturationCurve ?? DEFAULT_GRAY_SATURATION());
|
|
763
|
+
let scaleCurves = $derived(paletteConfig?.scaleCurves ?? defaultScaleCurvesObject());
|
|
764
|
+
let curveOffset = $derived(paletteConfig?.curveOffset ?? { lightness: 0, saturation: 0 });
|
|
765
|
+
let overrides = $derived(paletteConfig?.overrides ?? {});
|
|
766
|
+
let snappedScales = $derived(new Set(paletteConfig?.snappedScales ?? []));
|
|
767
|
+
let anchorToBase = $derived(paletteConfig?.anchorToBase ?? true);
|
|
768
|
+
let emptyMode = $derived(paletteConfig?.emptyMode ?? 'solid');
|
|
769
|
+
let emptyStep = $derived(paletteConfig?.emptyStep ?? '850');
|
|
770
|
+
let gradientStyle = $derived(paletteConfig?.gradientStyle ?? 'linear');
|
|
771
|
+
let gradientAngle = $derived(paletteConfig?.gradientAngle ?? 180);
|
|
772
|
+
let gradientReverse = $derived(paletteConfig?.gradientReverse ?? false);
|
|
773
|
+
let gradientStops = $derived(paletteConfig?.gradientStops ?? [
|
|
774
|
+
{ position: 0, paletteLabel: '800' },
|
|
775
|
+
{ position: 100, paletteLabel: '950' },
|
|
776
|
+
]);
|
|
777
|
+
let gradientSize = $derived(paletteConfig?.gradientSize ?? 'page');
|
|
778
|
+
// Read-side compat: existing `editingKey === ...` etc. comparisons keep
|
|
779
|
+
// working. New code should narrow on `editing.kind` directly.
|
|
780
|
+
let editingKey = $derived(editing.kind === 'idle' ? null : editing.kind === 'editingBase' ? BASE_KEY : editing.stepKey);
|
|
781
|
+
let editingDraft = $derived(editing.kind === 'editingStep' ? editing.draft : null);
|
|
782
|
+
let editingSnapshot = $derived(editing.kind === 'idle' ? null : editing.kind === 'editingBase' ? editing.snapshotHex : editing.snapshot);
|
|
783
|
+
let snapshotTintHue = $derived(editing.kind === 'editingBase' ? editing.snapshotTintHue : null);
|
|
784
|
+
let snapshotTintChroma = $derived(editing.kind === 'editingBase' ? editing.snapshotTintChroma : null);
|
|
785
|
+
// Reactive map of computed gray colors
|
|
786
|
+
let grayComputed = $derived((() => {
|
|
787
|
+
const _gl = grayLightnessCurve, _gs = graySaturationCurve, _co = curveOffset, _tc = tintChroma, _th = tintHue;
|
|
788
|
+
return graySteps.map((step, index) => ({
|
|
789
|
+
step,
|
|
790
|
+
index,
|
|
791
|
+
key: grayStepKey(step.label),
|
|
792
|
+
hex: computeGrayColor(index, _th, _tc),
|
|
793
|
+
}));
|
|
794
|
+
})());
|
|
795
|
+
let grayEffective = $derived((() => {
|
|
796
|
+
const _ed = editingDraft, _ek = editingKey, _ov = overrides;
|
|
797
|
+
return grayComputed.map(g => ({
|
|
798
|
+
...g,
|
|
799
|
+
effective: (_ek === g.key && _ed !== null) ? _ed : (g.key in _ov) ? _ov[g.key] : g.hex,
|
|
800
|
+
}));
|
|
801
|
+
})());
|
|
802
|
+
// Gray-500 hex — always the computed (curve-derived) value so derived
|
|
803
|
+
// scales (surfaces, borders, text) update in realtime when tint changes.
|
|
804
|
+
let gray500Hex = $derived(mode === 'gray'
|
|
805
|
+
? (grayComputed.find(g => g.step.label === '500')?.hex ?? GRAY_FALLBACK)
|
|
806
|
+
: baseColor);
|
|
807
|
+
// Derive locked anchor indices from curve shape — no writes to state.
|
|
808
|
+
run(() => {
|
|
809
|
+
if (anchorToBase) {
|
|
810
|
+
const x500 = stepIndexToX(4);
|
|
811
|
+
const lIdx = lightnessCurve.findIndex(a => Math.abs(a.x - x500) < 0.5);
|
|
812
|
+
lockedLightnessIdx = lIdx >= 0 ? lIdx : null;
|
|
813
|
+
const sIdx = saturationCurve.findIndex(a => Math.abs(a.x - x500) < 0.5);
|
|
814
|
+
lockedSaturationIdx = sIdx >= 0 ? sIdx : null;
|
|
815
|
+
} else {
|
|
816
|
+
lockedLightnessIdx = null;
|
|
817
|
+
lockedSaturationIdx = null;
|
|
818
|
+
}
|
|
819
|
+
});
|
|
820
|
+
/**
|
|
821
|
+
* Keep the locked lightness anchor y in sync with baseColor. Idempotent —
|
|
822
|
+
* only writes when the curve's anchor y differs from the baseColor-derived
|
|
823
|
+
* target. During a baseColor drag (inside a slider transaction) this
|
|
824
|
+
* additional curve edit merges into the same history entry. On undo/redo
|
|
825
|
+
* the curve already has the correct y (they're saved together), so this
|
|
826
|
+
* is a no-op.
|
|
827
|
+
*/
|
|
828
|
+
run(() => {
|
|
829
|
+
if (anchorToBase && lockedLightnessIdx !== null && baseColor) {
|
|
830
|
+
const targetY = hexToOklch(baseColor).l * 100;
|
|
831
|
+
if (lightnessCurve[lockedLightnessIdx] && Math.abs(lightnessCurve[lockedLightnessIdx].y - targetY) > 0.01) {
|
|
832
|
+
edit('lightnessCurve', lightnessCurve.map((a, i) => i === lockedLightnessIdx ? { ...a, y: targetY } : a));
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
});
|
|
836
|
+
let paletteComputed = $derived((() => {
|
|
837
|
+
const _bc = baseColor, _lc = lightnessCurve, _sc = saturationCurve, _co = curveOffset, _ed = editingDraft, _ek = editingKey, _ov = overrides, _ab = anchorToBase;
|
|
838
|
+
return paletteStepLightness.map((ps, index) => {
|
|
839
|
+
const k = paletteStepKey(ps.label);
|
|
840
|
+
const hex = computePaletteColor(index, baseColor);
|
|
841
|
+
const effective = (_ek === k && _ed !== null) ? _ed : (k in _ov) ? _ov[k] : hex;
|
|
842
|
+
return {
|
|
843
|
+
label: ps.label,
|
|
844
|
+
lightness: ps.lightness,
|
|
845
|
+
index,
|
|
846
|
+
key: k,
|
|
847
|
+
hex,
|
|
848
|
+
effective,
|
|
849
|
+
};
|
|
850
|
+
});
|
|
851
|
+
})());
|
|
852
|
+
// Gradient reactives — must follow paletteComputed
|
|
853
|
+
run(() => {
|
|
854
|
+
const pc = paletteComputed;
|
|
855
|
+
const sorted = [...gradientStops].sort((a, b) => gradientReverse ? b.position - a.position : a.position - b.position);
|
|
856
|
+
gradientColorStops = sorted.map(s => `${stopColor(s, pc)} ${s.position}%`).join(', ');
|
|
857
|
+
gradientBarPreview = `linear-gradient(to right, ${gradientColorStops})`;
|
|
858
|
+
if (emptySelector && emptyMode === 'gradient') {
|
|
859
|
+
switch (gradientStyle) {
|
|
860
|
+
case 'radial': gradientCssValue = `radial-gradient(circle, ${gradientColorStops})`; break;
|
|
861
|
+
case 'conic': gradientCssValue = `conic-gradient(from ${gradientAngle}deg, ${gradientColorStops})`; break;
|
|
862
|
+
default: gradientCssValue = `linear-gradient(${gradientAngle}deg, ${gradientColorStops})`;
|
|
863
|
+
}
|
|
864
|
+
} else {
|
|
865
|
+
gradientCssValue = '';
|
|
866
|
+
}
|
|
867
|
+
});
|
|
868
|
+
// Scales to render in gray mode (varies by namespace)
|
|
869
|
+
let grayScales = $derived(mode === 'gray' ? scales.filter(scale => {
|
|
870
|
+
if (scale.title === 'Surfaces') return true;
|
|
871
|
+
if (scale.title === 'Borders') return true;
|
|
872
|
+
if (scale.title === 'Text') return true;
|
|
873
|
+
return false;
|
|
874
|
+
}) : []);
|
|
875
|
+
let curveVersion = $derived(JSON.stringify(scaleCurves) + JSON.stringify(curveOffset) + gray500Hex);
|
|
876
|
+
/**
|
|
877
|
+
* Closure factories used by `<OverridesPanel>` so the panel doesn't have to
|
|
878
|
+
* know about `baseColor` / `gray500Hex` / `curveVersion`. These keep
|
|
879
|
+
* reactivity intact (the parent's `$:` blocks still drive re-render).
|
|
880
|
+
*
|
|
881
|
+
* Note: `effectiveColor` itself always uses `gray500Hex` for non-override
|
|
882
|
+
* derivation (pre-existing); the chromatic vs gray distinction here is
|
|
883
|
+
* only for the `derivedHex` (the "Ag" preview / border-color base).
|
|
884
|
+
*/
|
|
885
|
+
let derivedHexForBase = $derived((step: Step, scaleTitle: string) => derivedHex(step, baseColor, scaleTitle, curveVersion));
|
|
886
|
+
let derivedHexForGray = $derived((step: Step, scaleTitle: string) => derivedHex(step, gray500Hex, scaleTitle, curveVersion));
|
|
887
|
+
let effectiveHexAny = $derived((k: string, step: Step, scaleTitle: string) => effectiveColor(k, step, scaleTitle, curveVersion));
|
|
888
|
+
// --- Reactive editing state ---
|
|
889
|
+
|
|
890
|
+
let isEditingBase = $derived(isBaseEdit(editing));
|
|
891
|
+
let editingColor = $derived(isEditingBase
|
|
892
|
+
? (mode === 'gray' ? gray500Hex : baseColor)
|
|
893
|
+
: editingDraft);
|
|
894
|
+
let editingStepInfo = $derived((() => {
|
|
895
|
+
if (!editingKey || isEditingBase) return null;
|
|
896
|
+
if (mode === 'gray') {
|
|
897
|
+
const gs = graySteps.find(s => grayStepKey(s.label) === editingKey);
|
|
898
|
+
if (gs) return { scale: 'Gray', step: gs.label };
|
|
899
|
+
}
|
|
900
|
+
const ps = paletteStepLightness.find(p => paletteStepKey(p.label) === editingKey);
|
|
901
|
+
if (ps) return { scale: 'Palette', step: ps.label };
|
|
902
|
+
for (const scale of scales) {
|
|
903
|
+
for (const step of scale.steps) {
|
|
904
|
+
if (stepKey(scale.title, step.name) === editingKey) {
|
|
905
|
+
return { scale: scale.title, step: step.name };
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
return null;
|
|
910
|
+
})());
|
|
911
|
+
let panelOpen = $derived(editingKey !== null && (isEditingBase || (editingDraft !== null && editingStepInfo !== null)));
|
|
912
|
+
let editPanelTitle = $derived(isEditingBase
|
|
913
|
+
? 'Base Color'
|
|
914
|
+
: editingStepInfo
|
|
915
|
+
? `${editingStepInfo.scale} \u203A ${editingStepInfo.step}`
|
|
916
|
+
: null);
|
|
917
|
+
$effect(() => {
|
|
918
|
+
// Re-snap whenever any of the inputs change. Touch each so the effect
|
|
919
|
+
// tracks them explicitly (resnapScales() reads them indirectly).
|
|
920
|
+
void baseColor;
|
|
921
|
+
void scaleCurves;
|
|
922
|
+
void lightnessCurve;
|
|
923
|
+
void saturationCurve;
|
|
924
|
+
void curveOffset;
|
|
925
|
+
void snappedScales;
|
|
926
|
+
resnapScales();
|
|
927
|
+
});
|
|
902
928
|
</script>
|
|
903
929
|
|
|
904
930
|
<div class="palette-editor" style="--editor-base: {mode === 'gray' ? gray500Hex : baseColor}">
|
|
@@ -936,40 +962,40 @@
|
|
|
936
962
|
<input
|
|
937
963
|
type="checkbox"
|
|
938
964
|
checked={emptyMode === 'gradient'}
|
|
939
|
-
|
|
965
|
+
onchange={onEmptyModeChange}
|
|
940
966
|
/>
|
|
941
967
|
<span>Gradient</span>
|
|
942
968
|
</label>
|
|
943
969
|
{/if}
|
|
944
|
-
<button class="edit-toggle" type="button"
|
|
970
|
+
<button class="edit-toggle" type="button" onclick={clearPaletteOverrides}>Clear Overrides</button>
|
|
945
971
|
<button
|
|
946
972
|
class="edit-toggle"
|
|
947
973
|
type="button"
|
|
948
|
-
|
|
974
|
+
onclick={() => paletteEditorOpen = !paletteEditorOpen}
|
|
949
975
|
>{paletteEditorOpen ? 'Close' : 'Edit'}</button>
|
|
950
976
|
</div>
|
|
951
977
|
<div class="swatch-grid" style="--swatch-cols: {paletteStepLightness.length + 2}">
|
|
952
978
|
<div class="step-column">
|
|
953
|
-
<button class="step-label copyable-label" class:copied={copiedLabelKey === 'palette-white'} type="button"
|
|
979
|
+
<button class="step-label copyable-label" class:copied={copiedLabelKey === 'palette-white'} type="button" onclick={(e) => copyVarName('palette-white', `--color-${cssNamespace}-white`, e)}>
|
|
954
980
|
{copiedLabelKey === 'palette-white' ? 'copied!' : 'white'}
|
|
955
981
|
</button>
|
|
956
982
|
<div class="swatch gray-swatch bookend" style="background: #ffffff"></div>
|
|
957
983
|
</div>
|
|
958
984
|
{#each paletteComputed as ps}
|
|
959
985
|
<div class="step-column">
|
|
960
|
-
<button class="step-label copyable-label" class:copied={copiedLabelKey === ps.key} type="button"
|
|
986
|
+
<button class="step-label copyable-label" class:copied={copiedLabelKey === ps.key} type="button" onclick={(e) => copyVarName(ps.key, `--color-${cssNamespace}-${ps.label}`, e)}>
|
|
961
987
|
{copiedLabelKey === ps.key ? 'copied!' : ps.label}
|
|
962
988
|
</button>
|
|
963
|
-
<!-- svelte-ignore
|
|
989
|
+
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
964
990
|
<div
|
|
965
991
|
class="swatch gray-swatch"
|
|
966
992
|
class:active={editingKey === ps.key}
|
|
967
993
|
class:overridden={ps.key in overrides}
|
|
968
994
|
style="background: {ps.effective}"
|
|
969
|
-
|
|
995
|
+
onclick={() => handlePaletteClick({ label: ps.label, lightness: ps.lightness, index: ps.index })}
|
|
970
996
|
role="button"
|
|
971
997
|
tabindex="0"
|
|
972
|
-
|
|
998
|
+
onkeydown={(e) => e.key === 'Enter' && handlePaletteClick({ label: ps.label, lightness: ps.lightness, index: ps.index })}
|
|
973
999
|
>
|
|
974
1000
|
{#if ps.key in overrides}
|
|
975
1001
|
<span class="override-dot" title="Palette override"></span>
|
|
@@ -979,8 +1005,8 @@
|
|
|
979
1005
|
type="checkbox"
|
|
980
1006
|
class="empty-check"
|
|
981
1007
|
checked={emptyStep === ps.label}
|
|
982
|
-
|
|
983
|
-
|
|
1008
|
+
onclick={stopPropagation(() => edit('emptyStep', ps.label))}
|
|
1009
|
+
onkeydown={stopPropagation(bubble('keydown'))}
|
|
984
1010
|
title="Page background"
|
|
985
1011
|
/>
|
|
986
1012
|
{/if}
|
|
@@ -989,12 +1015,12 @@
|
|
|
989
1015
|
class="step-hex"
|
|
990
1016
|
class:copied={copiedKey === ps.key}
|
|
991
1017
|
type="button"
|
|
992
|
-
|
|
1018
|
+
onclick={(e) => copyHex(ps.key, ps.effective, e)}
|
|
993
1019
|
>{copiedKey === ps.key ? 'copied!' : ps.effective}</button>
|
|
994
1020
|
</div>
|
|
995
1021
|
{/each}
|
|
996
1022
|
<div class="step-column">
|
|
997
|
-
<button class="step-label copyable-label" class:copied={copiedLabelKey === 'palette-black'} type="button"
|
|
1023
|
+
<button class="step-label copyable-label" class:copied={copiedLabelKey === 'palette-black'} type="button" onclick={(e) => copyVarName('palette-black', `--color-${cssNamespace}-black`, e)}>
|
|
998
1024
|
{copiedLabelKey === 'palette-black' ? 'copied!' : 'black'}
|
|
999
1025
|
</button>
|
|
1000
1026
|
<div class="swatch gray-swatch bookend" style="background: #000000"></div>
|
|
@@ -1047,7 +1073,7 @@
|
|
|
1047
1073
|
|
|
1048
1074
|
</div>
|
|
1049
1075
|
|
|
1050
|
-
<button class="derived-toggle" type="button"
|
|
1076
|
+
<button class="derived-toggle" type="button" onclick={() => showDerived = !showDerived}>
|
|
1051
1077
|
<i class="fas" class:fa-chevron-right={!showDerived} class:fa-chevron-down={showDerived}></i>
|
|
1052
1078
|
<span>Text, Surfaces & Borders</span>
|
|
1053
1079
|
</button>
|
|
@@ -1133,35 +1159,35 @@
|
|
|
1133
1159
|
<div class="scale-section">
|
|
1134
1160
|
<div class="scale-header">
|
|
1135
1161
|
<h4 class="scale-title">{displayLabel ?? label}</h4>
|
|
1136
|
-
<button class="edit-toggle" type="button"
|
|
1162
|
+
<button class="edit-toggle" type="button" onclick={clearPaletteOverrides}>Clear Overrides</button>
|
|
1137
1163
|
<button
|
|
1138
1164
|
class="edit-toggle"
|
|
1139
1165
|
type="button"
|
|
1140
|
-
|
|
1166
|
+
onclick={() => grayEditorOpen = !grayEditorOpen}
|
|
1141
1167
|
>{grayEditorOpen ? 'Close' : 'Edit'}</button>
|
|
1142
1168
|
</div>
|
|
1143
1169
|
<div class="swatch-grid" style="--swatch-cols: {graySteps.length + 2}">
|
|
1144
1170
|
<div class="step-column">
|
|
1145
|
-
<button class="step-label copyable-label" class:copied={copiedLabelKey === 'gray-white'} type="button"
|
|
1171
|
+
<button class="step-label copyable-label" class:copied={copiedLabelKey === 'gray-white'} type="button" onclick={(e) => copyVarName('gray-white', `--color-${cssNamespace}-white`, e)}>
|
|
1146
1172
|
{copiedLabelKey === 'gray-white' ? 'copied!' : 'white'}
|
|
1147
1173
|
</button>
|
|
1148
1174
|
<div class="swatch gray-swatch bookend" style="background: #ffffff"></div>
|
|
1149
1175
|
</div>
|
|
1150
1176
|
{#each grayEffective as g}
|
|
1151
1177
|
<div class="step-column">
|
|
1152
|
-
<button class="step-label copyable-label" class:copied={copiedLabelKey === g.key} type="button"
|
|
1178
|
+
<button class="step-label copyable-label" class:copied={copiedLabelKey === g.key} type="button" onclick={(e) => copyVarName(g.key, `--color-${cssNamespace}-${g.step.label}`, e)}>
|
|
1153
1179
|
{copiedLabelKey === g.key ? 'copied!' : g.step.label}
|
|
1154
1180
|
</button>
|
|
1155
|
-
<!-- svelte-ignore
|
|
1181
|
+
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
1156
1182
|
<div
|
|
1157
1183
|
class="swatch gray-swatch"
|
|
1158
1184
|
class:active={editingKey === g.key}
|
|
1159
1185
|
class:overridden={g.key in overrides}
|
|
1160
1186
|
style="background: {g.effective}"
|
|
1161
|
-
|
|
1187
|
+
onclick={() => handleGrayClick(g.step, g.index)}
|
|
1162
1188
|
role="button"
|
|
1163
1189
|
tabindex="0"
|
|
1164
|
-
|
|
1190
|
+
onkeydown={(e) => e.key === 'Enter' && handleGrayClick(g.step, g.index)}
|
|
1165
1191
|
>
|
|
1166
1192
|
{#if g.key in overrides}
|
|
1167
1193
|
<span class="override-dot" title="Palette override"></span>
|
|
@@ -1171,12 +1197,12 @@
|
|
|
1171
1197
|
class="step-hex"
|
|
1172
1198
|
class:copied={copiedKey === g.key}
|
|
1173
1199
|
type="button"
|
|
1174
|
-
|
|
1200
|
+
onclick={(e) => copyHex(g.key, g.effective, e)}
|
|
1175
1201
|
>{copiedKey === g.key ? 'copied!' : g.effective}</button>
|
|
1176
1202
|
</div>
|
|
1177
1203
|
{/each}
|
|
1178
1204
|
<div class="step-column">
|
|
1179
|
-
<button class="step-label copyable-label" class:copied={copiedLabelKey === 'gray-black'} type="button"
|
|
1205
|
+
<button class="step-label copyable-label" class:copied={copiedLabelKey === 'gray-black'} type="button" onclick={(e) => copyVarName('gray-black', `--color-${cssNamespace}-black`, e)}>
|
|
1180
1206
|
{copiedLabelKey === 'gray-black' ? 'copied!' : 'black'}
|
|
1181
1207
|
</button>
|
|
1182
1208
|
<div class="swatch gray-swatch bookend" style="background: #000000"></div>
|
|
@@ -1209,7 +1235,7 @@
|
|
|
1209
1235
|
</div>
|
|
1210
1236
|
</div>
|
|
1211
1237
|
|
|
1212
|
-
<button class="derived-toggle" type="button"
|
|
1238
|
+
<button class="derived-toggle" type="button" onclick={() => showDerived = !showDerived}>
|
|
1213
1239
|
<i class="fas" class:fa-chevron-right={!showDerived} class:fa-chevron-down={showDerived}></i>
|
|
1214
1240
|
<span>Text, Surfaces & Borders</span>
|
|
1215
1241
|
</button>
|