@motion-proto/live-tokens 0.1.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 (68) hide show
  1. package/README.md +41 -0
  2. package/dist-plugin/index.cjs +444 -0
  3. package/dist-plugin/index.d.cts +12 -0
  4. package/dist-plugin/index.d.ts +12 -0
  5. package/dist-plugin/index.js +407 -0
  6. package/package.json +86 -0
  7. package/src/components/Badge.svelte +82 -0
  8. package/src/components/Button.svelte +333 -0
  9. package/src/components/Card.svelte +83 -0
  10. package/src/components/CollapsibleSection.svelte +82 -0
  11. package/src/components/DetailNav.svelte +78 -0
  12. package/src/components/Dialog.svelte +269 -0
  13. package/src/components/InlineEditActions.svelte +73 -0
  14. package/src/components/Notification.svelte +308 -0
  15. package/src/components/ProgressBar.svelte +99 -0
  16. package/src/components/RadioButton.svelte +87 -0
  17. package/src/components/SectionDivider.svelte +121 -0
  18. package/src/components/TabBar.svelte +92 -0
  19. package/src/components/Toggle.svelte +86 -0
  20. package/src/components/Tooltip.svelte +64 -0
  21. package/src/lib/ColumnsOverlay.svelte +120 -0
  22. package/src/lib/LiveEditorOverlay.svelte +467 -0
  23. package/src/lib/columnsOverlay.ts +26 -0
  24. package/src/lib/cssVarSync.ts +72 -0
  25. package/src/lib/editorConfig.ts +9 -0
  26. package/src/lib/editorConfigStore.ts +14 -0
  27. package/src/lib/index.ts +51 -0
  28. package/src/lib/oklch.ts +129 -0
  29. package/src/lib/pageSource.ts +6 -0
  30. package/src/lib/tokenInit.ts +29 -0
  31. package/src/lib/tokenService.ts +144 -0
  32. package/src/lib/tokenTypes.ts +45 -0
  33. package/src/pages/Admin.svelte +100 -0
  34. package/src/pages/ShowcasePage.svelte +146 -0
  35. package/src/showcase/BackupBrowser.svelte +617 -0
  36. package/src/showcase/BezierCurveEditor.svelte +648 -0
  37. package/src/showcase/ColorEditPanel.svelte +498 -0
  38. package/src/showcase/ComponentsTab.svelte +107 -0
  39. package/src/showcase/EditorDialog.svelte +137 -0
  40. package/src/showcase/PaletteEditor.svelte +2579 -0
  41. package/src/showcase/PaletteSelector.svelte +627 -0
  42. package/src/showcase/SurfacesTab.svelte +409 -0
  43. package/src/showcase/TextTab.svelte +205 -0
  44. package/src/showcase/TokenFileManager.svelte +683 -0
  45. package/src/showcase/TokenMap.svelte +54 -0
  46. package/src/showcase/VariablesTab.svelte +2657 -0
  47. package/src/showcase/VisualsTab.svelte +233 -0
  48. package/src/showcase/curveEngine.ts +190 -0
  49. package/src/showcase/demos/BadgeDemo.svelte +58 -0
  50. package/src/showcase/demos/CardDemo.svelte +52 -0
  51. package/src/showcase/demos/ChoiceButtonsDemo.svelte +194 -0
  52. package/src/showcase/demos/CollapsibleSectionDemo.svelte +56 -0
  53. package/src/showcase/demos/DialogDemo.svelte +42 -0
  54. package/src/showcase/demos/InlineEditActionsDemo.svelte +27 -0
  55. package/src/showcase/demos/NotificationDemo.svelte +149 -0
  56. package/src/showcase/demos/ProgressBarDemo.svelte +56 -0
  57. package/src/showcase/demos/RadioButtonDemo.svelte +58 -0
  58. package/src/showcase/demos/SectionDividerDemo.svelte +79 -0
  59. package/src/showcase/demos/StandardButtonsDemo.svelte +457 -0
  60. package/src/showcase/demos/TabBarDemo.svelte +60 -0
  61. package/src/showcase/demos/TooltipDemo.svelte +54 -0
  62. package/src/showcase/editor.css +93 -0
  63. package/src/showcase/index.ts +17 -0
  64. package/src/styles/fonts/Domine/Domine-VariableFont_wght.ttf +0 -0
  65. package/src/styles/fonts/Domine/OFL.txt +97 -0
  66. package/src/styles/fonts/Domine/README.txt +66 -0
  67. package/src/styles/fonts.css +18 -0
  68. package/src/styles/form-controls.css +190 -0
@@ -0,0 +1,498 @@
1
+ <script lang="ts">
2
+ import { hexToOklch, oklchToHex, gamutClamp } from '../lib/oklch';
3
+ import InlineEditActions from '../components/InlineEditActions.svelte';
4
+ import Button from '../components/Button.svelte';
5
+
6
+ export let color: string;
7
+ export let title: string | null = null;
8
+ export let showRemoveOverride: boolean = false;
9
+ export let onColorChange: (hex: string) => void = () => {};
10
+ export let onConfirm: () => void = () => {};
11
+ export let onCancel: () => void = () => {};
12
+ export let onRemoveOverride: () => void = () => {};
13
+
14
+ // Hue-chroma mode props (for neutral/gray base editing)
15
+ export let mode: 'hsl' | 'hue-chroma' = 'hsl';
16
+ export let hue: number = 0;
17
+ export let chroma: number = 0.04;
18
+ export let onHueChromaChange: (hue: number, chroma: number) => void = () => {};
19
+
20
+ const hasEyeDropper = typeof window !== 'undefined' && 'EyeDropper' in window;
21
+ const PREVIEW_LIGHTNESS = 0.55;
22
+ const CHROMA_MAX = 0.15;
23
+
24
+ // --- HSL helpers (used in hsl mode) ---
25
+
26
+ function hexToHsl(hex: string): [number, number, number] {
27
+ const r = parseInt(hex.slice(1, 3), 16) / 255;
28
+ const g = parseInt(hex.slice(3, 5), 16) / 255;
29
+ const b = parseInt(hex.slice(5, 7), 16) / 255;
30
+ const max = Math.max(r, g, b), min = Math.min(r, g, b);
31
+ let h = 0, s = 0;
32
+ const l = (max + min) / 2;
33
+ if (max !== min) {
34
+ const d = max - min;
35
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
36
+ if (max === r) h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
37
+ else if (max === g) h = ((b - r) / d + 2) / 6;
38
+ else h = ((r - g) / d + 4) / 6;
39
+ }
40
+ return [Math.round(h * 360), Math.round(s * 100), Math.round(l * 100)];
41
+ }
42
+
43
+ function hslToHex(h: number, s: number, l: number): string {
44
+ s /= 100; l /= 100;
45
+ const a = s * Math.min(l, 1 - l);
46
+ const f = (n: number) => {
47
+ const k = (n + h / 30) % 12;
48
+ const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
49
+ return Math.round(255 * color).toString(16).padStart(2, '0');
50
+ };
51
+ return `#${f(0)}${f(8)}${f(4)}`;
52
+ }
53
+
54
+ // --- HSL mode reactives ---
55
+
56
+ $: hsl = hexToHsl(color);
57
+
58
+ function hueGrad(s: number, l: number): string {
59
+ return `linear-gradient(to right, ${
60
+ [0, 60, 120, 180, 240, 300, 360].map(h => `hsl(${h},${s}%,${l}%)`).join(',')
61
+ })`;
62
+ }
63
+
64
+ function satGrad(h: number, l: number): string {
65
+ return `linear-gradient(to right, hsl(${h},0%,${l}%), hsl(${h},100%,${l}%))`;
66
+ }
67
+
68
+ function lightGrad(h: number, s: number): string {
69
+ return `linear-gradient(to right, hsl(${h},${s}%,0%), hsl(${h},${s}%,50%), hsl(${h},${s}%,100%))`;
70
+ }
71
+
72
+ function updateHsl(component: 0 | 1 | 2, value: number) {
73
+ const current = hexToHsl(color);
74
+ current[component] = value;
75
+ onColorChange(hslToHex(current[0], current[1], current[2]));
76
+ }
77
+
78
+ // --- Hue-chroma mode reactives ---
79
+
80
+ $: previewHex = mode === 'hue-chroma'
81
+ ? (() => { const c = gamutClamp(PREVIEW_LIGHTNESS, chroma, hue); return oklchToHex(c.l, c.c, c.h); })()
82
+ : color;
83
+
84
+ $: hueGradient = (() => {
85
+ const _c = chroma;
86
+ const displayChroma = Math.max(_c, CHROMA_MAX);
87
+ const stops = Array.from({ length: 13 }, (_, i) => {
88
+ const h = (i / 12) * 360;
89
+ const c = gamutClamp(PREVIEW_LIGHTNESS, displayChroma, h);
90
+ return oklchToHex(c.l, c.c, c.h);
91
+ });
92
+ return `linear-gradient(to right, ${stops.join(',')})`;
93
+ })();
94
+
95
+ $: chromaGradient = (() => {
96
+ const _h = hue;
97
+ const stops = Array.from({ length: 8 }, (_, i) => {
98
+ const c = (i / 7) * CHROMA_MAX;
99
+ const clamped = gamutClamp(PREVIEW_LIGHTNESS, c, _h);
100
+ return oklchToHex(clamped.l, clamped.c, clamped.h);
101
+ });
102
+ return `linear-gradient(to right, ${stops.join(',')})`;
103
+ })();
104
+
105
+ // --- Shared ---
106
+
107
+ async function pickScreenColor() {
108
+ if (!hasEyeDropper) return;
109
+ try {
110
+ const dropper = new (window as any).EyeDropper();
111
+ const result = await dropper.open();
112
+ const hex = result.sRGBHex.toLowerCase();
113
+ if (mode === 'hue-chroma') {
114
+ const oklch = hexToOklch(hex);
115
+ onHueChromaChange(Math.round(oklch.h), Math.round(oklch.c * 1000) / 1000);
116
+ } else {
117
+ onColorChange(hex);
118
+ }
119
+ } catch {
120
+ // user cancelled the eyedropper
121
+ }
122
+ }
123
+
124
+ let hexEditing = false;
125
+ let hexDraft = '';
126
+
127
+ function startHexEdit() {
128
+ hexDraft = previewHex;
129
+ hexEditing = true;
130
+ }
131
+
132
+ function autoFocus(node: HTMLElement) { node.focus(); }
133
+
134
+ function commitHex() {
135
+ const v = hexDraft.startsWith('#') ? hexDraft : `#${hexDraft}`;
136
+ if (/^#[0-9a-f]{6}$/i.test(v)) {
137
+ const hex = v.toLowerCase();
138
+ if (mode === 'hue-chroma') {
139
+ const oklch = hexToOklch(hex);
140
+ onHueChromaChange(Math.round(oklch.h), Math.round(oklch.c * 1000) / 1000);
141
+ } else {
142
+ onColorChange(hex);
143
+ }
144
+ }
145
+ hexEditing = false;
146
+ }
147
+
148
+ function handleHexKeydown(e: KeyboardEvent) {
149
+ if (e.key === 'Enter') commitHex();
150
+ if (e.key === 'Escape') hexEditing = false;
151
+ }
152
+ </script>
153
+
154
+ <div class="hsl-panel">
155
+ <div class="hsl-panel-header">
156
+ <div class="hsl-preview" style="background: {previewHex}"></div>
157
+ {#if hasEyeDropper}
158
+ <button
159
+ class="eyedropper-btn"
160
+ type="button"
161
+ title="Pick color from screen"
162
+ on:click={pickScreenColor}
163
+ ><i class="fas fa-eye-dropper"></i></button>
164
+ {/if}
165
+ {#if title}
166
+ <span class="hsl-panel-title">{title}</span>
167
+ {/if}
168
+ {#if hexEditing}
169
+ <input
170
+ class="hsl-hex-input"
171
+ type="text"
172
+ bind:value={hexDraft}
173
+ on:keydown={handleHexKeydown}
174
+ on:blur={commitHex}
175
+ maxlength="7"
176
+ use:autoFocus
177
+ />
178
+ {:else}
179
+ <button class="hsl-hex" on:click={startHexEdit} title="Click to edit hex">{previewHex}</button>
180
+ {/if}
181
+ {#if mode === 'hue-chroma'}
182
+ <code class="hsl-values">oklch({PREVIEW_LIGHTNESS}, {chroma.toFixed(3)}, {hue})</code>
183
+ {:else}
184
+ <code class="hsl-values">hsl({hsl[0]}, {hsl[1]}%, {hsl[2]}%)</code>
185
+ {/if}
186
+ <slot name="actions" />
187
+ <div class="hsl-panel-actions">
188
+ {#if showRemoveOverride}
189
+ <Button
190
+ variant="danger"
191
+ size="small"
192
+ icon="fas fa-trash"
193
+ on:click={onRemoveOverride}
194
+ >Remove override</Button>
195
+ {/if}
196
+ <InlineEditActions
197
+ onSave={onConfirm}
198
+ onCancel={onCancel}
199
+ saveTitle="Apply changes"
200
+ cancelTitle="Discard changes"
201
+ />
202
+ </div>
203
+ </div>
204
+ <div class="hsl-sliders">
205
+ {#if mode === 'hue-chroma'}
206
+ <div class="hsl-slider-row">
207
+ <span class="hsl-slider-label">H</span>
208
+ <div class="slider-track" style="background: {hueGradient}">
209
+ <input type="range" min="0" max="360" value={hue}
210
+ on:input={(e) => onHueChromaChange(+e.currentTarget.value, chroma)} />
211
+ </div>
212
+ <input
213
+ class="hsl-slider-input"
214
+ type="number"
215
+ min="0"
216
+ max="360"
217
+ value={hue}
218
+ on:change={(e) => onHueChromaChange(Math.min(360, Math.max(0, +e.currentTarget.value)), chroma)}
219
+ /><span class="hsl-slider-unit">&deg;</span>
220
+ </div>
221
+ <div class="hsl-slider-row">
222
+ <span class="hsl-slider-label">C</span>
223
+ <div class="slider-track" style="background: {chromaGradient}">
224
+ <input type="range" min="0" max={CHROMA_MAX} step="0.001" value={chroma}
225
+ on:input={(e) => onHueChromaChange(hue, +e.currentTarget.value)} />
226
+ </div>
227
+ <input
228
+ class="hsl-slider-input chroma-input"
229
+ type="number"
230
+ min="0"
231
+ max={CHROMA_MAX}
232
+ step="0.001"
233
+ value={chroma.toFixed(3)}
234
+ on:change={(e) => onHueChromaChange(hue, Math.min(CHROMA_MAX, Math.max(0, +e.currentTarget.value)))}
235
+ />
236
+ </div>
237
+ {:else}
238
+ <div class="hsl-slider-row">
239
+ <span class="hsl-slider-label">H</span>
240
+ <div class="slider-track" style="background: {hueGrad(hsl[1], hsl[2])}">
241
+ <input type="range" min="0" max="360" value={hsl[0]}
242
+ on:input={(e) => updateHsl(0, +e.currentTarget.value)} />
243
+ </div>
244
+ <input
245
+ class="hsl-slider-input"
246
+ type="number"
247
+ min="0"
248
+ max="360"
249
+ value={hsl[0]}
250
+ on:change={(e) => updateHsl(0, Math.min(360, Math.max(0, +e.currentTarget.value)))}
251
+ /><span class="hsl-slider-unit">&deg;</span>
252
+ </div>
253
+ <div class="hsl-slider-row">
254
+ <span class="hsl-slider-label">S</span>
255
+ <div class="slider-track" style="background: {satGrad(hsl[0], hsl[2])}">
256
+ <input type="range" min="0" max="100" value={hsl[1]}
257
+ on:input={(e) => updateHsl(1, +e.currentTarget.value)} />
258
+ </div>
259
+ <input
260
+ class="hsl-slider-input"
261
+ type="number"
262
+ min="0"
263
+ max="100"
264
+ value={hsl[1]}
265
+ on:change={(e) => updateHsl(1, Math.min(100, Math.max(0, +e.currentTarget.value)))}
266
+ /><span class="hsl-slider-unit">%</span>
267
+ </div>
268
+ <div class="hsl-slider-row">
269
+ <span class="hsl-slider-label">L</span>
270
+ <div class="slider-track" style="background: {lightGrad(hsl[0], hsl[1])}">
271
+ <input type="range" min="0" max="100" value={hsl[2]}
272
+ on:input={(e) => updateHsl(2, +e.currentTarget.value)} />
273
+ </div>
274
+ <input
275
+ class="hsl-slider-input"
276
+ type="number"
277
+ min="0"
278
+ max="100"
279
+ value={hsl[2]}
280
+ on:change={(e) => updateHsl(2, Math.min(100, Math.max(0, +e.currentTarget.value)))}
281
+ /><span class="hsl-slider-unit">%</span>
282
+ </div>
283
+ {/if}
284
+ </div>
285
+ </div>
286
+
287
+ <style>
288
+ .hsl-panel {
289
+ display: flex;
290
+ flex-direction: column;
291
+ gap: var(--space-12);
292
+ padding: var(--space-12);
293
+ background: var(--ui-surface-lowest);
294
+ border: 1px solid var(--ui-border-subtle);
295
+ border-radius: var(--radius-md);
296
+ }
297
+
298
+ .hsl-panel-header {
299
+ display: flex;
300
+ align-items: center;
301
+ gap: var(--space-8);
302
+ flex-wrap: wrap;
303
+ }
304
+
305
+ .hsl-preview {
306
+ width: 1.5rem;
307
+ height: 1.5rem;
308
+ border-radius: var(--radius-sm);
309
+ border: 1px solid var(--ui-border-faint);
310
+ flex-shrink: 0;
311
+ }
312
+
313
+ .eyedropper-btn {
314
+ display: inline-flex;
315
+ align-items: center;
316
+ justify-content: center;
317
+ width: 1.5rem;
318
+ height: 1.5rem;
319
+ padding: 0;
320
+ border: 1px solid var(--ui-border-default);
321
+ border-radius: var(--radius-sm);
322
+ background: var(--ui-hover);
323
+ color: var(--ui-text-secondary);
324
+ cursor: pointer;
325
+ font-size: var(--font-md);
326
+ flex-shrink: 0;
327
+
328
+ &:hover {
329
+ background: var(--ui-hover-high);
330
+ color: var(--ui-text-primary);
331
+ border-color: var(--ui-border-strong);
332
+ }
333
+ }
334
+
335
+ .hsl-panel-title {
336
+ font-size: var(--font-md);
337
+ font-weight: var(--font-weight-semibold);
338
+ color: var(--ui-text-secondary);
339
+ }
340
+
341
+ .hsl-hex {
342
+ font-size: var(--font-md);
343
+ color: var(--ui-text-accent);
344
+ font-family: var(--ui-font-mono);
345
+ background: none;
346
+ border: 1px solid transparent;
347
+ border-radius: var(--radius-sm);
348
+ padding: var(--space-2) var(--space-4);
349
+ cursor: pointer;
350
+ transition: all var(--transition-fast);
351
+ }
352
+
353
+ .hsl-hex:hover {
354
+ border-color: var(--ui-border-default);
355
+ background: var(--ui-surface-low);
356
+ }
357
+
358
+ .hsl-hex-input {
359
+ font-size: var(--font-md);
360
+ color: var(--ui-text-accent);
361
+ font-family: var(--ui-font-mono);
362
+ background: var(--ui-surface-low);
363
+ border: 1px solid var(--ui-border-strong);
364
+ border-radius: var(--radius-sm);
365
+ padding: var(--space-2) var(--space-4);
366
+ width: 5.5rem;
367
+ outline: none;
368
+ }
369
+
370
+ .hsl-values {
371
+ font-size: var(--font-md);
372
+ color: var(--ui-text-tertiary);
373
+ font-family: var(--ui-font-mono);
374
+ }
375
+
376
+ .hsl-panel-actions {
377
+ display: flex;
378
+ align-items: center;
379
+ gap: var(--space-6);
380
+ margin-left: auto;
381
+ flex-wrap: wrap;
382
+ }
383
+
384
+ .hsl-sliders {
385
+ display: flex;
386
+ flex-direction: column;
387
+ gap: var(--space-6);
388
+ }
389
+
390
+ .hsl-slider-row {
391
+ display: flex;
392
+ align-items: center;
393
+ gap: var(--space-8);
394
+ }
395
+
396
+ .hsl-slider-label {
397
+ font-size: var(--font-md);
398
+ font-weight: var(--font-weight-semibold);
399
+ color: var(--ui-text-tertiary);
400
+ width: 2.5rem;
401
+ text-align: right;
402
+ flex-shrink: 0;
403
+ }
404
+
405
+ .slider-track {
406
+ position: relative;
407
+ height: 1.25rem;
408
+ border-radius: var(--radius-md);
409
+ border: 1px solid var(--ui-border-faint);
410
+ flex: 1;
411
+ min-width: 6rem;
412
+ }
413
+
414
+ .slider-track input[type="range"] {
415
+ -webkit-appearance: none;
416
+ appearance: none;
417
+ position: absolute;
418
+ inset: 0;
419
+ width: 100%;
420
+ height: 100%;
421
+ margin: 0;
422
+ background: transparent;
423
+ cursor: pointer;
424
+ border-radius: var(--radius-md);
425
+ }
426
+
427
+ .slider-track input[type="range"]::-webkit-slider-thumb {
428
+ -webkit-appearance: none;
429
+ width: 0.5rem;
430
+ height: 1.25rem;
431
+ border-radius: var(--radius-sm);
432
+ background: white;
433
+ border: 2px solid rgba(0, 0, 0, 0.3);
434
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
435
+ cursor: pointer;
436
+ }
437
+
438
+ .slider-track input[type="range"]::-moz-range-thumb {
439
+ width: 0.5rem;
440
+ height: 1.25rem;
441
+ border-radius: var(--radius-sm);
442
+ background: white;
443
+ border: 2px solid rgba(0, 0, 0, 0.3);
444
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
445
+ cursor: pointer;
446
+ }
447
+
448
+ .slider-track input[type="range"]::-moz-range-track {
449
+ background: transparent;
450
+ border: none;
451
+ }
452
+
453
+ .slider-track input[type="range"]:focus {
454
+ outline: none;
455
+ }
456
+
457
+ .slider-track input[type="range"]:focus-visible {
458
+ outline: 2px solid var(--ui-border-medium);
459
+ outline-offset: 2px;
460
+ }
461
+
462
+ .hsl-slider-input {
463
+ font-size: var(--font-md);
464
+ color: var(--ui-text-primary);
465
+ font-family: var(--ui-font-mono);
466
+ width: 2.5rem;
467
+ text-align: right;
468
+ flex-shrink: 0;
469
+ background: var(--ui-surface-lowest);
470
+ border: 1px solid var(--ui-border-subtle);
471
+ border-radius: var(--radius-sm);
472
+ padding: var(--space-2) var(--space-4);
473
+ -moz-appearance: textfield;
474
+ }
475
+
476
+ .hsl-slider-input.chroma-input {
477
+ width: 3.5rem;
478
+ }
479
+
480
+ .hsl-slider-input::-webkit-inner-spin-button,
481
+ .hsl-slider-input::-webkit-outer-spin-button {
482
+ -webkit-appearance: none;
483
+ margin: 0;
484
+ }
485
+
486
+ .hsl-slider-input:focus {
487
+ outline: none;
488
+ border-color: var(--ui-border-medium);
489
+ }
490
+
491
+ .hsl-slider-unit {
492
+ font-size: var(--font-md);
493
+ color: var(--ui-text-muted);
494
+ font-family: var(--ui-font-mono);
495
+ width: 0.75rem;
496
+ flex-shrink: 0;
497
+ }
498
+ </style>
@@ -0,0 +1,107 @@
1
+ <script lang="ts" context="module">
2
+ import type { ComponentType } from 'svelte';
3
+ import ChoiceButtonsDemo from './demos/ChoiceButtonsDemo.svelte';
4
+ import StandardButtonsDemo from './demos/StandardButtonsDemo.svelte';
5
+ import NotificationDemo from './demos/NotificationDemo.svelte';
6
+ import DialogDemo from './demos/DialogDemo.svelte';
7
+ import RadioButtonDemo from './demos/RadioButtonDemo.svelte';
8
+ import CardDemo from './demos/CardDemo.svelte';
9
+ import BadgeDemo from './demos/BadgeDemo.svelte';
10
+ import InlineEditActionsDemo from './demos/InlineEditActionsDemo.svelte';
11
+ import SectionDividerDemo from './demos/SectionDividerDemo.svelte';
12
+ import CollapsibleSectionDemo from './demos/CollapsibleSectionDemo.svelte';
13
+ import TabBarDemo from './demos/TabBarDemo.svelte';
14
+ import TooltipDemo from './demos/TooltipDemo.svelte';
15
+ import ProgressBarDemo from './demos/ProgressBarDemo.svelte';
16
+
17
+ export type ComponentSection = {
18
+ id: string;
19
+ label: string;
20
+ component: ComponentType;
21
+ props?: Record<string, unknown>;
22
+ };
23
+
24
+ export const defaultSections: ComponentSection[] = [
25
+ { id: 'choiceButtons', label: 'Choice Sets', component: ChoiceButtonsDemo },
26
+ { id: 'standardButtons', label: 'Button', component: StandardButtonsDemo },
27
+ { id: 'notifications', label: 'Notification', component: NotificationDemo },
28
+ { id: 'dialog', label: 'Dialog', component: DialogDemo },
29
+ { id: 'radioButtons', label: 'Radio Button', component: RadioButtonDemo },
30
+ { id: 'cards', label: 'Card', component: CardDemo },
31
+ { id: 'traitBadges', label: 'Trait Badge', component: BadgeDemo },
32
+ { id: 'inlineEdit', label: 'Inline Edit Actions', component: InlineEditActionsDemo },
33
+ { id: 'sectionDivider', label: 'Section Divider', component: SectionDividerDemo },
34
+ { id: 'collapsible', label: 'Collapsible Section', component: CollapsibleSectionDemo },
35
+ { id: 'tabBar', label: 'Tab Bar', component: TabBarDemo },
36
+ { id: 'tooltip', label: 'Tooltip', component: TooltipDemo },
37
+ { id: 'progressBar', label: 'Progress Bar', component: ProgressBarDemo },
38
+ ];
39
+ </script>
40
+
41
+ <script lang="ts">
42
+ export let sections: ComponentSection[] = defaultSections;
43
+ export let selectedComponent: string = sections[0]?.id ?? '';
44
+ </script>
45
+
46
+ <div class="components-container">
47
+ {#each sections as section (section.id)}
48
+ {#if selectedComponent === section.id}
49
+ <svelte:component this={section.component} {...(section.props ?? {})} />
50
+ {/if}
51
+ {/each}
52
+ </div>
53
+
54
+ <style>
55
+ @import '../styles/variables.css';
56
+
57
+ .components-container {
58
+ display: flex;
59
+ flex-direction: column;
60
+ min-width: 0;
61
+ }
62
+
63
+ /* Shared demo chrome — used by every demo wrapper in ./demos/. */
64
+ :global(.components-container .demo-block) {
65
+ display: flex;
66
+ flex-direction: column;
67
+ gap: var(--space-16);
68
+ min-width: 0;
69
+ }
70
+
71
+ :global(.components-container .component-title) {
72
+ font-size: var(--font-xl);
73
+ font-weight: var(--font-weight-semibold);
74
+ color: var(--ui-text-primary);
75
+ margin: 0;
76
+ padding-bottom: var(--space-8);
77
+ border-bottom: 1px solid var(--ui-border-subtle);
78
+ }
79
+
80
+ :global(.components-container .demo-description) {
81
+ font-size: var(--font-sm);
82
+ color: var(--ui-text-tertiary);
83
+ margin: 0;
84
+ }
85
+
86
+ :global(.components-container .demo-description code) {
87
+ font-size: var(--font-xs);
88
+ color: var(--ui-text-accent);
89
+ background: var(--ui-surface-lowest);
90
+ padding: var(--space-2) var(--space-4);
91
+ border-radius: var(--radius-sm);
92
+ font-family: var(--ui-font-mono);
93
+ }
94
+
95
+ :global(.components-container .demo-section) {
96
+ display: flex;
97
+ flex-direction: column;
98
+ gap: var(--space-8);
99
+ }
100
+
101
+ :global(.components-container .demo-subtitle) {
102
+ font-size: var(--font-sm);
103
+ font-weight: var(--font-weight-medium);
104
+ color: var(--ui-text-secondary);
105
+ margin: 0;
106
+ }
107
+ </style>