@dryui/theme-wizard 4.0.0 → 5.0.1

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 (47) hide show
  1. package/package.json +5 -5
  2. package/dist/actions.d.ts +0 -4
  3. package/dist/actions.js +0 -9
  4. package/dist/components/AlphaSlider.svelte +0 -13
  5. package/dist/components/AlphaSlider.svelte.d.ts +0 -9
  6. package/dist/components/ContrastBadge.svelte +0 -22
  7. package/dist/components/ContrastBadge.svelte.d.ts +0 -8
  8. package/dist/components/HsbPicker.svelte +0 -304
  9. package/dist/components/HsbPicker.svelte.d.ts +0 -9
  10. package/dist/components/StepIndicator.svelte +0 -87
  11. package/dist/components/StepIndicator.svelte.d.ts +0 -7
  12. package/dist/components/TokenPreview.svelte +0 -55
  13. package/dist/components/TokenPreview.svelte.d.ts +0 -8
  14. package/dist/components/WizardShell.svelte +0 -140
  15. package/dist/components/WizardShell.svelte.d.ts +0 -15
  16. package/dist/engine/derivation.d.ts +0 -282
  17. package/dist/engine/derivation.js +0 -1445
  18. package/dist/engine/derivation.test.d.ts +0 -1
  19. package/dist/engine/derivation.test.js +0 -956
  20. package/dist/engine/export-css.d.ts +0 -32
  21. package/dist/engine/export-css.js +0 -90
  22. package/dist/engine/export-css.test.d.ts +0 -1
  23. package/dist/engine/export-css.test.js +0 -78
  24. package/dist/engine/index.d.ts +0 -10
  25. package/dist/engine/index.js +0 -6
  26. package/dist/engine/palette.d.ts +0 -16
  27. package/dist/engine/palette.js +0 -44
  28. package/dist/engine/presets.d.ts +0 -13
  29. package/dist/engine/presets.js +0 -124
  30. package/dist/engine/url-codec.d.ts +0 -53
  31. package/dist/engine/url-codec.js +0 -243
  32. package/dist/engine/url-codec.test.d.ts +0 -1
  33. package/dist/engine/url-codec.test.js +0 -137
  34. package/dist/index.d.ts +0 -15
  35. package/dist/index.js +0 -19
  36. package/dist/state.svelte.d.ts +0 -104
  37. package/dist/state.svelte.js +0 -574
  38. package/dist/steps/BrandColor.svelte +0 -216
  39. package/dist/steps/BrandColor.svelte.d.ts +0 -6
  40. package/dist/steps/Personality.svelte +0 -319
  41. package/dist/steps/Personality.svelte.d.ts +0 -3
  42. package/dist/steps/PreviewExport.svelte +0 -115
  43. package/dist/steps/PreviewExport.svelte.d.ts +0 -9
  44. package/dist/steps/Shape.svelte +0 -121
  45. package/dist/steps/Shape.svelte.d.ts +0 -18
  46. package/dist/steps/Typography.svelte +0 -115
  47. package/dist/steps/Typography.svelte.d.ts +0 -18
@@ -1,574 +0,0 @@
1
- import { untrack } from 'svelte';
2
- import { generateTheme } from './engine/derivation.js';
3
- import { PRESETS } from './engine/presets.js';
4
- function fmtRem(value) {
5
- return `${parseFloat(value.toFixed(4))}rem`;
6
- }
7
- const STORAGE_KEY = 'dryui-theme-wizard';
8
- const DEFAULTS = {
9
- currentStep: 1,
10
- personality: 'structured',
11
- brandHsb: { h: 230, s: 65, b: 85 },
12
- neutralMode: 'monochromatic',
13
- statusHues: { error: 0, warning: 40, success: 145, info: 210 },
14
- darkBgOverrides: {},
15
- fastTrack: false,
16
- typography: {
17
- fontPreset: 'System',
18
- scale: 'default'
19
- },
20
- shape: {
21
- radiusPreset: 'soft',
22
- radiusScale: 1,
23
- density: 'default'
24
- },
25
- shadows: {
26
- preset: 'elevated',
27
- intensity: 1,
28
- tintBrand: true
29
- }
30
- };
31
- function loadPersistedState() {
32
- if (typeof sessionStorage === 'undefined')
33
- return DEFAULTS;
34
- try {
35
- const raw = sessionStorage.getItem(STORAGE_KEY);
36
- if (!raw)
37
- return DEFAULTS;
38
- const saved = JSON.parse(raw);
39
- return { ...DEFAULTS, ...saved };
40
- }
41
- catch {
42
- return DEFAULTS;
43
- }
44
- }
45
- let persistTimer;
46
- function persistState() {
47
- if (typeof sessionStorage === 'undefined')
48
- return;
49
- clearTimeout(persistTimer);
50
- persistTimer = setTimeout(() => {
51
- untrack(() => {
52
- try {
53
- const { personality, brandHsb, neutralMode, statusHues, darkBgOverrides, typography, shape, shadows } = wizardState;
54
- const tokens = {
55
- light: getAllTokens('light'),
56
- dark: getAllTokens('dark')
57
- };
58
- sessionStorage.setItem(STORAGE_KEY, JSON.stringify({
59
- personality,
60
- brandHsb,
61
- neutralMode,
62
- statusHues,
63
- darkBgOverrides,
64
- typography,
65
- shape,
66
- shadows,
67
- tokens
68
- }));
69
- }
70
- catch {
71
- // storage full or unavailable — ignore
72
- }
73
- });
74
- }, 300);
75
- }
76
- const initial = loadPersistedState();
77
- export const wizardState = $state({
78
- currentStep: initial.currentStep,
79
- personality: initial.personality,
80
- brandHsb: initial.brandHsb,
81
- neutralMode: initial.neutralMode,
82
- statusHues: initial.statusHues,
83
- darkBgOverrides: initial.darkBgOverrides,
84
- fastTrack: initial.fastTrack,
85
- typography: initial.typography,
86
- shape: initial.shape,
87
- shadows: initial.shadows
88
- });
89
- // ─── Derived theme ────────────────────────────────────────────────────────────
90
- const derivedTheme = $derived.by(() => {
91
- return {
92
- value: generateTheme(wizardState.brandHsb, {
93
- neutralMode: wizardState.neutralMode,
94
- statusHues: wizardState.statusHues,
95
- darkBg: wizardState.darkBgOverrides
96
- })
97
- };
98
- });
99
- export function getDerivedTheme() {
100
- return derivedTheme.value;
101
- }
102
- // ─── Exported functions ───────────────────────────────────────────────────────
103
- /** Update the brand color (h: 0-360, s/b: 0-100). */
104
- export function setBrandHsb(h, s, b) {
105
- wizardState.brandHsb = { h, s, b };
106
- persistState();
107
- }
108
- /** Update a single status tone's hue. */
109
- export function setStatusHue(tone, hue) {
110
- wizardState.statusHues[tone] = hue;
111
- persistState();
112
- }
113
- /** Update the neutral palette mode. */
114
- export function setNeutralMode(mode) {
115
- wizardState.neutralMode = mode;
116
- persistState();
117
- }
118
- function resetStyleStateToDefaults() {
119
- wizardState.neutralMode = DEFAULTS.neutralMode;
120
- wizardState.statusHues = { ...DEFAULTS.statusHues };
121
- wizardState.darkBgOverrides = { ...DEFAULTS.darkBgOverrides };
122
- wizardState.typography = { ...DEFAULTS.typography };
123
- wizardState.shape = { ...DEFAULTS.shape };
124
- wizardState.shadows = { ...DEFAULTS.shadows };
125
- }
126
- /** Set the personality (chrome level) and apply cross-step defaults. */
127
- function applyPersonalityDefaults(p) {
128
- wizardState.personality = p;
129
- // Cross-step defaults
130
- const PERSONALITY_SHADOW = {
131
- minimal: 'flat',
132
- clean: 'flat',
133
- structured: 'elevated',
134
- rich: 'deep'
135
- };
136
- const PERSONALITY_RADIUS = {
137
- minimal: 'soft',
138
- clean: 'soft',
139
- structured: 'soft',
140
- rich: 'rounded'
141
- };
142
- wizardState.shadows.preset = PERSONALITY_SHADOW[p];
143
- wizardState.shape.radiusPreset = PERSONALITY_RADIUS[p];
144
- }
145
- /** Set the personality (chrome level) and apply cross-step defaults. */
146
- export function setPersonality(p) {
147
- resetStyleStateToDefaults();
148
- applyPersonalityDefaults(p);
149
- persistState();
150
- }
151
- /** Override a dark background level. */
152
- export function setDarkBg(level, value) {
153
- wizardState.darkBgOverrides[level] = value;
154
- persistState();
155
- }
156
- /** Navigate to a specific step (1–5). */
157
- export function setStep(n) {
158
- wizardState.currentStep = Math.max(1, Math.min(5, n));
159
- }
160
- /** Advance to the next step. */
161
- export function goNextStep() {
162
- setStep(wizardState.currentStep + 1);
163
- }
164
- /** Go back to the previous step. */
165
- export function goPrevStep() {
166
- setStep(wizardState.currentStep - 1);
167
- }
168
- /** Enable fast-track mode and jump to the final step. */
169
- export function activateFastTrack() {
170
- wizardState.fastTrack = true;
171
- setStep(5);
172
- }
173
- /** Apply a named preset from the PRESETS array. */
174
- export function applyPreset(name) {
175
- const preset = PRESETS.find((p) => p.name.toLowerCase() === name.toLowerCase());
176
- if (!preset) {
177
- throw new Error(`Unknown preset: "${name}"`);
178
- }
179
- wizardState.brandHsb = { ...preset.brandInput };
180
- persistState();
181
- }
182
- /**
183
- * Return a CSS custom property string for live preview injection.
184
- *
185
- * @param mode - 'light' | 'dark'
186
- * @returns e.g. `--dry-color-brand: hsl(230, 75%, 60%); ...`
187
- */
188
- export function getStyleString(mode) {
189
- return Object.entries(getAllTokens(mode))
190
- .map(([name, value]) => `${name}: ${value}`)
191
- .join('; ');
192
- }
193
- /** Update the font preset name. */
194
- export function setFontPreset(preset) {
195
- wizardState.typography.fontPreset = preset;
196
- persistState();
197
- }
198
- /** Update the type scale. */
199
- export function setTypeScale(scale) {
200
- wizardState.typography.scale = scale;
201
- persistState();
202
- }
203
- /** Reset all wizard state to defaults. */
204
- export function resetToDefaults() {
205
- wizardState.currentStep = DEFAULTS.currentStep;
206
- wizardState.personality = DEFAULTS.personality;
207
- wizardState.brandHsb = { ...DEFAULTS.brandHsb };
208
- resetStyleStateToDefaults();
209
- wizardState.fastTrack = DEFAULTS.fastTrack;
210
- if (typeof sessionStorage !== 'undefined') {
211
- sessionStorage.removeItem(STORAGE_KEY);
212
- }
213
- }
214
- /** Apply a full wizard recipe, using personality defaults before explicit overrides. */
215
- export function applyRecipe(recipe) {
216
- wizardState.currentStep = DEFAULTS.currentStep;
217
- wizardState.brandHsb = { ...recipe.brand };
218
- resetStyleStateToDefaults();
219
- wizardState.neutralMode = recipe.neutralMode ?? DEFAULTS.neutralMode;
220
- wizardState.statusHues = { ...DEFAULTS.statusHues, ...recipe.statusHues };
221
- wizardState.fastTrack = false;
222
- wizardState.typography = recipe.typography
223
- ? { ...recipe.typography }
224
- : { ...DEFAULTS.typography };
225
- applyPersonalityDefaults(recipe.personality ?? DEFAULTS.personality);
226
- if (recipe.shape) {
227
- wizardState.shape = { ...recipe.shape };
228
- }
229
- if (recipe.shadows) {
230
- wizardState.shadows = { ...recipe.shadows };
231
- }
232
- persistState();
233
- }
234
- // ─── Shape & spacing ─────────────────────────────────────────────────────────
235
- export function setRadiusPreset(preset) {
236
- wizardState.shape.radiusPreset = preset;
237
- wizardState.shape.radiusScale = 1;
238
- persistState();
239
- }
240
- export function setRadiusScale(scale) {
241
- wizardState.shape.radiusScale = scale;
242
- persistState();
243
- }
244
- export function setDensity(density) {
245
- wizardState.shape.density = density;
246
- persistState();
247
- }
248
- export const RADIUS_PRESETS = {
249
- sharp: { sm: 0, md: 2, lg: 2, xl: 4, '2xl': 4, full: 9999 },
250
- soft: { sm: 4, md: 8, lg: 8, xl: 12, '2xl': 16, full: 9999 },
251
- rounded: { sm: 8, md: 12, lg: 16, xl: 20, '2xl': 24, full: 9999 },
252
- pill: { sm: 9999, md: 9999, lg: 16, xl: 20, '2xl': 24, full: 9999 }
253
- };
254
- const DENSITY_FACTORS = {
255
- compact: 0.85,
256
- default: 1,
257
- spacious: 1.15
258
- };
259
- // ─── Shadows & elevation ────────────────────────────────────────────────────
260
- export function setShadowPreset(preset) {
261
- wizardState.shadows.preset = preset;
262
- persistState();
263
- }
264
- export function setShadowIntensity(intensity) {
265
- wizardState.shadows.intensity = intensity;
266
- persistState();
267
- }
268
- export function setShadowTint(tint) {
269
- wizardState.shadows.tintBrand = tint;
270
- persistState();
271
- }
272
- const SHADOW_DEFS = {
273
- flat: {
274
- raised: [],
275
- overlay: []
276
- },
277
- subtle: {
278
- raised: [
279
- { y: 1, blur: 3, lightA: 0.06, darkA: 0.5 },
280
- { y: 1, blur: 2, lightA: 0.04, darkA: 0.35 }
281
- ],
282
- overlay: [
283
- { y: 4, blur: 16, lightA: 0.1, darkA: 0.6 },
284
- { y: 2, blur: 6, lightA: 0.06, darkA: 0.4 }
285
- ]
286
- },
287
- elevated: {
288
- raised: [
289
- { y: 2, blur: 6, lightA: 0.1, darkA: 0.65 },
290
- { y: 1, blur: 3, lightA: 0.07, darkA: 0.45 }
291
- ],
292
- overlay: [
293
- { y: 8, blur: 28, lightA: 0.14, darkA: 0.7 },
294
- { y: 3, blur: 10, lightA: 0.1, darkA: 0.5 }
295
- ]
296
- },
297
- deep: {
298
- raised: [
299
- { y: 4, blur: 14, lightA: 0.16, darkA: 0.8 },
300
- { y: 2, blur: 5, lightA: 0.1, darkA: 0.55 }
301
- ],
302
- overlay: [
303
- { y: 16, blur: 48, lightA: 0.22, darkA: 0.85 },
304
- { y: 6, blur: 18, lightA: 0.14, darkA: 0.6 }
305
- ]
306
- }
307
- };
308
- function buildShadowValue(layers, mode, hue, sat, lightness, intensity) {
309
- if (layers.length === 0)
310
- return 'none';
311
- return layers
312
- .map((l) => {
313
- const a = (mode === 'light' ? l.lightA : l.darkA) * intensity;
314
- return `0 ${l.y}px ${l.blur}px hsla(${hue}, ${sat}%, ${lightness}%, ${Math.min(a, 1).toFixed(3)})`;
315
- })
316
- .join(', ');
317
- }
318
- export function getShadowTokens(shadowPreset = wizardState.shadows.preset, shadowIntensity = wizardState.shadows.intensity, tintBrand = wizardState.shadows.tintBrand, brandHue = wizardState.brandHsb.h) {
319
- const H = Math.round(brandHue);
320
- const hue = tintBrand ? H : 0;
321
- const def = SHADOW_DEFS[shadowPreset];
322
- return {
323
- light: {
324
- '--dry-shadow-raised': buildShadowValue(def.raised, 'light', hue, 20, 20, shadowIntensity),
325
- '--dry-shadow-overlay': buildShadowValue(def.overlay, 'light', hue, 20, 20, shadowIntensity)
326
- },
327
- dark: {
328
- '--dry-shadow-raised': buildShadowValue(def.raised, 'dark', hue, 15, 2, shadowIntensity),
329
- '--dry-shadow-overlay': buildShadowValue(def.overlay, 'dark', hue, 15, 2, shadowIntensity)
330
- }
331
- };
332
- }
333
- const SPACE_SCALE = [
334
- ['0_5', 0.125],
335
- ['1', 0.25],
336
- ['1_5', 0.375],
337
- ['2', 0.5],
338
- ['2_5', 0.625],
339
- ['3', 0.75],
340
- ['3_5', 0.875],
341
- ['4', 1],
342
- ['5', 1.25],
343
- ['6', 1.5],
344
- ['7', 1.75],
345
- ['8', 2],
346
- ['9', 2.25],
347
- ['10', 2.5],
348
- ['11', 2.75],
349
- ['12', 3],
350
- ['14', 3.5],
351
- ['16', 4],
352
- ['20', 5],
353
- ['24', 6],
354
- ['32', 8]
355
- ];
356
- export function getShapeTokens(radiusPreset = wizardState.shape.radiusPreset, radiusScale = wizardState.shape.radiusScale, densityPreset = wizardState.shape.density) {
357
- const preset = RADIUS_PRESETS[radiusPreset];
358
- const scale = radiusScale;
359
- const density = DENSITY_FACTORS[densityPreset];
360
- const tokens = {};
361
- for (const [key, base] of Object.entries(preset)) {
362
- let px;
363
- if (base >= 9999) {
364
- px = scale >= 1 ? 9999 : Math.round(24 * scale);
365
- }
366
- else {
367
- px = Math.round(base * scale);
368
- }
369
- tokens[`--dry-radius-${key}`] = `${px}px`;
370
- }
371
- for (const [key, rem] of SPACE_SCALE) {
372
- tokens[`--dry-space-${key}`] = fmtRem(rem * density);
373
- }
374
- return tokens;
375
- }
376
- // ─── Personality / chrome ───────────────────────────────────────────────────
377
- const PERSONALITY_TOKENS = {
378
- minimal: {
379
- // Surface role
380
- '--dry-surface-bg': 'transparent',
381
- '--dry-surface-border': 'transparent',
382
- '--dry-surface-shadow': 'none',
383
- '--dry-surface-radius': '0',
384
- '--dry-surface-padding': 'var(--dry-space-4)',
385
- // Chrome role
386
- '--dry-chrome-bg': 'transparent',
387
- '--dry-chrome-border': 'transparent',
388
- '--dry-chrome-shadow': 'none',
389
- // Overlay role
390
- '--dry-overlay-bg': 'var(--dry-color-bg-overlay)',
391
- '--dry-overlay-border': 'var(--dry-color-stroke-weak)',
392
- '--dry-overlay-shadow': 'var(--dry-shadow-sm)',
393
- '--dry-overlay-radius': 'var(--dry-radius-lg)',
394
- // Control role
395
- '--dry-control-bg': 'transparent',
396
- '--dry-control-border': 'var(--dry-color-stroke-weak)',
397
- '--dry-control-radius': 'var(--dry-radius-sm)',
398
- // Page role
399
- '--dry-page-bg': 'transparent',
400
- '--dry-page-border': 'transparent',
401
- '--dry-page-shadow': 'none',
402
- '--dry-page-radius': '0'
403
- },
404
- clean: {
405
- // Surface role
406
- '--dry-surface-bg': 'var(--dry-color-bg-raised)',
407
- '--dry-surface-border': 'transparent',
408
- '--dry-surface-shadow': 'none',
409
- '--dry-surface-radius': 'var(--dry-radius-lg)',
410
- '--dry-surface-padding': 'var(--dry-space-6)',
411
- // Chrome role
412
- '--dry-chrome-bg': 'transparent',
413
- '--dry-chrome-border': 'var(--dry-color-stroke-weak)',
414
- '--dry-chrome-shadow': 'none',
415
- // Overlay role
416
- '--dry-overlay-bg': 'var(--dry-color-bg-overlay)',
417
- '--dry-overlay-border': 'var(--dry-color-stroke-weak)',
418
- '--dry-overlay-shadow': 'var(--dry-shadow-md)',
419
- '--dry-overlay-radius': 'var(--dry-radius-lg)',
420
- // Control role
421
- '--dry-control-bg': 'var(--dry-color-bg-raised)',
422
- '--dry-control-border': 'var(--dry-color-stroke-strong)',
423
- '--dry-control-radius': 'var(--dry-radius-md)',
424
- // Page role
425
- '--dry-page-bg': 'transparent',
426
- '--dry-page-border': 'transparent',
427
- '--dry-page-shadow': 'none',
428
- '--dry-page-radius': 'var(--dry-radius-lg)'
429
- },
430
- structured: {
431
- // Surface role
432
- '--dry-surface-bg': 'var(--dry-color-bg-raised)',
433
- '--dry-surface-border': 'var(--dry-color-stroke-weak)',
434
- '--dry-surface-shadow': 'var(--dry-shadow-raised)',
435
- '--dry-surface-radius': 'var(--dry-radius-xl)',
436
- '--dry-surface-padding': 'var(--dry-space-8)',
437
- // Chrome role
438
- '--dry-chrome-bg': 'var(--dry-color-bg-raised)',
439
- '--dry-chrome-border': 'var(--dry-color-stroke-weak)',
440
- '--dry-chrome-shadow': 'var(--dry-shadow-sm)',
441
- // Overlay role
442
- '--dry-overlay-bg': 'var(--dry-color-bg-overlay)',
443
- '--dry-overlay-border': 'var(--dry-color-stroke-weak)',
444
- '--dry-overlay-shadow': 'var(--dry-shadow-lg)',
445
- '--dry-overlay-radius': 'var(--dry-radius-xl)',
446
- // Control role
447
- '--dry-control-bg': 'var(--dry-color-bg-raised)',
448
- '--dry-control-border': 'var(--dry-color-stroke-strong)',
449
- '--dry-control-radius': 'var(--dry-radius-md)',
450
- // Page role
451
- '--dry-page-bg': 'var(--dry-color-bg-overlay)',
452
- '--dry-page-border': 'var(--dry-color-stroke-weak)',
453
- '--dry-page-shadow': 'var(--dry-shadow-sm)',
454
- '--dry-page-radius': 'var(--dry-radius-xl)'
455
- },
456
- rich: {
457
- // Surface role
458
- '--dry-surface-bg': 'var(--dry-color-bg-overlay)',
459
- '--dry-surface-border': 'var(--dry-color-stroke-weak)',
460
- '--dry-surface-shadow': 'var(--dry-shadow-overlay)',
461
- '--dry-surface-radius': 'var(--dry-radius-2xl)',
462
- '--dry-surface-padding': 'var(--dry-space-10)',
463
- // Chrome role
464
- '--dry-chrome-bg': 'var(--dry-color-bg-overlay)',
465
- '--dry-chrome-border': 'var(--dry-color-stroke-weak)',
466
- '--dry-chrome-shadow': 'var(--dry-shadow-overlay)',
467
- // Overlay role
468
- '--dry-overlay-bg': 'var(--dry-color-bg-overlay)',
469
- '--dry-overlay-border': 'var(--dry-color-stroke-weak)',
470
- '--dry-overlay-shadow': 'var(--dry-shadow-overlay)',
471
- '--dry-overlay-radius': 'var(--dry-radius-2xl)',
472
- // Control role
473
- '--dry-control-bg': 'var(--dry-color-bg-raised)',
474
- '--dry-control-border': 'var(--dry-color-stroke-strong)',
475
- '--dry-control-radius': 'var(--dry-radius-lg)',
476
- // Page role
477
- '--dry-page-bg': 'var(--dry-color-bg-raised)',
478
- '--dry-page-border': 'var(--dry-color-stroke-weak)',
479
- '--dry-page-shadow': 'var(--dry-shadow-overlay)',
480
- '--dry-page-radius': 'var(--dry-radius-2xl)'
481
- }
482
- };
483
- export function getPersonalityTokens() {
484
- return PERSONALITY_TOKENS[wizardState.personality];
485
- }
486
- // ─── Typography tokens ──────────────────────────────────────────────────────
487
- export const FONT_STACKS = {
488
- System: 'ui-sans-serif, system-ui, -apple-system, sans-serif',
489
- Humanist: 'Seravek, "Gill Sans Nova", Ubuntu, Calibri, "DejaVu Sans", sans-serif',
490
- Geometric: 'Avenir, Montserrat, Corbel, "URW Gothic", source-sans-pro, sans-serif',
491
- Classical: 'Optima, Candara, "Noto Sans", source-sans-pro, sans-serif',
492
- Serif: 'Charter, "Bitstream Charter", "Sitka Text", Cambria, serif',
493
- Mono: 'ui-monospace, "SF Mono", Menlo, Consolas, monospace'
494
- };
495
- const TYPE_BASE = {
496
- display: { size: 3.5, leading: 4 },
497
- 'heading-1': { size: 2.5, leading: 3 },
498
- 'heading-2': { size: 2, leading: 2.5 },
499
- 'heading-3': { size: 1.5, leading: 2 },
500
- 'heading-4': { size: 1.25, leading: 1.75 },
501
- small: { size: 1, leading: 1.5 },
502
- tiny: { size: 0.875, leading: 1.25 }
503
- };
504
- const TYPE_SCALE_FACTORS = {
505
- compact: 0.9,
506
- default: 1,
507
- spacious: 1.1
508
- };
509
- export function getTypographyTokens(fontPreset = wizardState.typography.fontPreset, scale = wizardState.typography.scale) {
510
- const factor = TYPE_SCALE_FACTORS[scale];
511
- const tokens = {
512
- '--dry-font-sans': FONT_STACKS[fontPreset]
513
- };
514
- for (const [name, { size, leading }] of Object.entries(TYPE_BASE)) {
515
- tokens[`--dry-type-${name}-size`] = fmtRem(size * factor);
516
- tokens[`--dry-type-${name}-leading`] = fmtRem(leading * factor);
517
- }
518
- return tokens;
519
- }
520
- /** Return all tokens (color + shape + shadow + personality + typography) merged for a given mode. */
521
- export function getAllTokens(mode = 'light') {
522
- const m = mode;
523
- const theme = derivedTheme.value;
524
- const colorTokens = m === 'dark' ? theme.dark : theme.light;
525
- const shapeTokens = getShapeTokens();
526
- const shadows = getShadowTokens();
527
- const shadowTokens = shadows[m];
528
- const personalityTokens = getPersonalityTokens();
529
- const typographyTokens = getTypographyTokens();
530
- return {
531
- ...colorTokens,
532
- ...shapeTokens,
533
- ...shadowTokens,
534
- ...personalityTokens,
535
- ...typographyTokens
536
- };
537
- }
538
- /** Return only tokens that the user has changed from defaults. */
539
- export function getOverrideTokens(mode = 'light') {
540
- const all = getAllTokens(mode);
541
- const m = mode;
542
- const base = getDefaultAllTokens(m);
543
- const overrides = {};
544
- for (const k in all) {
545
- if (all[k] !== base[k]) {
546
- overrides[k] = all[k];
547
- }
548
- }
549
- return overrides;
550
- }
551
- /** getAllTokens computed with DEFAULTS — cached per mode. */
552
- function getDefaultAllTokens(mode) {
553
- return (defaultAllTokensCache[mode] ??= computeDefaultAllTokens(mode));
554
- }
555
- const defaultAllTokensCache = {};
556
- function computeDefaultAllTokens(mode) {
557
- const theme = generateTheme(DEFAULTS.brandHsb, {
558
- neutralMode: DEFAULTS.neutralMode,
559
- statusHues: DEFAULTS.statusHues,
560
- darkBg: DEFAULTS.darkBgOverrides
561
- });
562
- const colorTokens = mode === 'dark' ? theme.dark : theme.light;
563
- const shapeTokens = getShapeTokens(DEFAULTS.shape.radiusPreset, DEFAULTS.shape.radiusScale, DEFAULTS.shape.density);
564
- const shadowTokens = getShadowTokens(DEFAULTS.shadows.preset, DEFAULTS.shadows.intensity, DEFAULTS.shadows.tintBrand, DEFAULTS.brandHsb.h)[mode];
565
- const personalityTokens = PERSONALITY_TOKENS[DEFAULTS.personality];
566
- const typographyTokens = getTypographyTokens(DEFAULTS.typography.fontPreset, DEFAULTS.typography.scale);
567
- return {
568
- ...colorTokens,
569
- ...shapeTokens,
570
- ...shadowTokens,
571
- ...personalityTokens,
572
- ...typographyTokens
573
- };
574
- }