@shalomormsby/ui 0.0.5

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.
@@ -0,0 +1,736 @@
1
+ "use client";
2
+ "use strict";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/providers.ts
22
+ var providers_exports = {};
23
+ __export(providers_exports, {
24
+ ThemeProvider: () => ThemeProvider
25
+ });
26
+ module.exports = __toCommonJS(providers_exports);
27
+
28
+ // src/providers/ThemeProvider.tsx
29
+ var import_react = require("react");
30
+
31
+ // src/lib/store/theme.ts
32
+ var import_zustand = require("zustand");
33
+ var import_middleware = require("zustand/middleware");
34
+ var useThemeStore = (0, import_zustand.create)()(
35
+ (0, import_middleware.persist)(
36
+ (set, get) => ({
37
+ // Defaults
38
+ theme: "volt",
39
+ mode: "dark",
40
+ // Actions
41
+ setTheme: (theme) => set({ theme }),
42
+ setMode: (mode) => set({ mode }),
43
+ toggleMode: () => set((state) => ({ mode: state.mode === "light" ? "dark" : "light" })),
44
+ // Computed
45
+ get themeConfig() {
46
+ const state = get();
47
+ return { name: state.theme, mode: state.mode };
48
+ }
49
+ }),
50
+ {
51
+ name: "ecosystem-theme",
52
+ // Only persist theme and mode
53
+ partialize: (state) => ({
54
+ theme: state.theme,
55
+ mode: state.mode
56
+ })
57
+ }
58
+ )
59
+ );
60
+
61
+ // src/lib/store/customizer.ts
62
+ var import_zustand2 = require("zustand");
63
+ var import_middleware2 = require("zustand/middleware");
64
+ var import_tokens = require("@sage/tokens");
65
+
66
+ // src/lib/colors.ts
67
+ var colorTokens = {
68
+ // Background colors
69
+ background: "var(--color-background)",
70
+ backgroundSecondary: "var(--color-background-secondary)",
71
+ backgroundTertiary: "var(--color-background-tertiary)",
72
+ surface: "var(--color-surface)",
73
+ // Foreground/Text colors
74
+ foreground: "var(--color-foreground)",
75
+ foregroundSecondary: "var(--color-foreground-secondary)",
76
+ foregroundTertiary: "var(--color-foreground-tertiary)",
77
+ textPrimary: "var(--color-text-primary)",
78
+ textSecondary: "var(--color-text-secondary)",
79
+ textMuted: "var(--color-text-muted)",
80
+ // Brand colors
81
+ primary: "var(--color-primary)",
82
+ primaryForeground: "var(--color-primary-foreground)",
83
+ secondary: "var(--color-secondary)",
84
+ secondaryForeground: "var(--color-secondary-foreground)",
85
+ accent: "var(--color-accent)",
86
+ accentForeground: "var(--color-accent-foreground)",
87
+ // Semantic colors
88
+ success: "var(--color-success)",
89
+ successForeground: "var(--color-success-foreground)",
90
+ warning: "var(--color-warning)",
91
+ warningForeground: "var(--color-warning-foreground)",
92
+ error: "var(--color-error)",
93
+ errorForeground: "var(--color-error-foreground)",
94
+ info: "var(--color-info)",
95
+ infoForeground: "var(--color-info-foreground)",
96
+ // Borders
97
+ border: "var(--color-border)",
98
+ borderSubtle: "var(--color-border-subtle)",
99
+ // Interactive states
100
+ hover: "var(--color-hover)",
101
+ active: "var(--color-active)",
102
+ focus: "var(--color-focus)",
103
+ // Links
104
+ link: "var(--color-link)",
105
+ linkHover: "var(--color-link-hover)",
106
+ linkHoverForeground: "var(--color-link-hover-foreground)"
107
+ };
108
+ var semanticColors = {
109
+ /**
110
+ * Status colors for indicating states
111
+ */
112
+ status: {
113
+ success: {
114
+ bg: colorTokens.success,
115
+ fg: colorTokens.successForeground
116
+ },
117
+ warning: {
118
+ bg: colorTokens.warning,
119
+ fg: colorTokens.warningForeground
120
+ },
121
+ error: {
122
+ bg: colorTokens.error,
123
+ fg: colorTokens.errorForeground
124
+ },
125
+ info: {
126
+ bg: colorTokens.info,
127
+ fg: colorTokens.infoForeground
128
+ }
129
+ },
130
+ /**
131
+ * Brand colors for primary UI elements
132
+ */
133
+ brand: {
134
+ primary: {
135
+ bg: colorTokens.primary,
136
+ fg: colorTokens.primaryForeground
137
+ },
138
+ secondary: {
139
+ bg: colorTokens.secondary,
140
+ fg: colorTokens.secondaryForeground
141
+ },
142
+ accent: {
143
+ bg: colorTokens.accent,
144
+ fg: colorTokens.accentForeground
145
+ }
146
+ },
147
+ /**
148
+ * Interactive state colors
149
+ */
150
+ interactive: {
151
+ default: {
152
+ bg: colorTokens.background,
153
+ fg: colorTokens.foreground
154
+ },
155
+ hover: {
156
+ bg: colorTokens.hover,
157
+ fg: colorTokens.foreground
158
+ },
159
+ active: {
160
+ bg: colorTokens.active,
161
+ fg: colorTokens.foreground
162
+ },
163
+ focus: {
164
+ border: colorTokens.focus
165
+ }
166
+ }
167
+ };
168
+ function hexToRgb(hex) {
169
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
170
+ return result ? {
171
+ r: parseInt(result[1], 16),
172
+ g: parseInt(result[2], 16),
173
+ b: parseInt(result[3], 16)
174
+ } : null;
175
+ }
176
+ function getLuminance(r, g, b) {
177
+ const [rs, gs, bs] = [r, g, b].map((c) => {
178
+ const srgb = c / 255;
179
+ return srgb <= 0.03928 ? srgb / 12.92 : Math.pow((srgb + 0.055) / 1.055, 2.4);
180
+ });
181
+ return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
182
+ }
183
+ function getContrastRatio(hex1, hex2) {
184
+ const rgb1 = hexToRgb(hex1);
185
+ const rgb2 = hexToRgb(hex2);
186
+ if (!rgb1 || !rgb2) return 0;
187
+ const lum1 = getLuminance(rgb1.r, rgb1.g, rgb1.b);
188
+ const lum2 = getLuminance(rgb2.r, rgb2.g, rgb2.b);
189
+ const lighter = Math.max(lum1, lum2);
190
+ const darker = Math.min(lum1, lum2);
191
+ return (lighter + 0.05) / (darker + 0.05);
192
+ }
193
+ function hexToHSL(hex) {
194
+ const rgb = hexToRgb(hex);
195
+ if (!rgb) return { h: 0, s: 0, l: 0 };
196
+ const r = rgb.r / 255;
197
+ const g = rgb.g / 255;
198
+ const b = rgb.b / 255;
199
+ const max = Math.max(r, g, b);
200
+ const min = Math.min(r, g, b);
201
+ let h = 0, s = 0, l = (max + min) / 2;
202
+ if (max !== min) {
203
+ const d = max - min;
204
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
205
+ switch (max) {
206
+ case r:
207
+ h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
208
+ break;
209
+ case g:
210
+ h = ((b - r) / d + 2) / 6;
211
+ break;
212
+ case b:
213
+ h = ((r - g) / d + 4) / 6;
214
+ break;
215
+ }
216
+ }
217
+ return {
218
+ h: Math.round(h * 360),
219
+ s: Math.round(s * 100),
220
+ l: Math.round(l * 100)
221
+ };
222
+ }
223
+ function hslToHex(h, s, l) {
224
+ h = h / 360;
225
+ s = s / 100;
226
+ l = l / 100;
227
+ let r, g, b;
228
+ if (s === 0) {
229
+ r = g = b = l;
230
+ } else {
231
+ const hue2rgb = (p2, q2, t) => {
232
+ if (t < 0) t += 1;
233
+ if (t > 1) t -= 1;
234
+ if (t < 1 / 6) return p2 + (q2 - p2) * 6 * t;
235
+ if (t < 1 / 2) return q2;
236
+ if (t < 2 / 3) return p2 + (q2 - p2) * (2 / 3 - t) * 6;
237
+ return p2;
238
+ };
239
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
240
+ const p = 2 * l - q;
241
+ r = hue2rgb(p, q, h + 1 / 3);
242
+ g = hue2rgb(p, q, h);
243
+ b = hue2rgb(p, q, h - 1 / 3);
244
+ }
245
+ const toHex = (x) => {
246
+ const hex = Math.round(x * 255).toString(16);
247
+ return hex.length === 1 ? "0" + hex : hex;
248
+ };
249
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
250
+ }
251
+ function getOptimalForeground(bgHex, whiteHex = "#ffffff", blackHex = "#000000") {
252
+ const whiteRatio = getContrastRatio(bgHex, whiteHex);
253
+ const blackRatio = getContrastRatio(bgHex, blackHex);
254
+ return whiteRatio > blackRatio ? whiteHex : blackHex;
255
+ }
256
+ function generateColorScale(baseHex) {
257
+ const hsl = hexToHSL(baseHex);
258
+ return {
259
+ 50: hslToHex(hsl.h, Math.max(hsl.s - 10, 20), 95),
260
+ 100: hslToHex(hsl.h, Math.max(hsl.s - 5, 30), 90),
261
+ 200: hslToHex(hsl.h, hsl.s, 80),
262
+ 300: hslToHex(hsl.h, hsl.s, 70),
263
+ 400: hslToHex(hsl.h, hsl.s, 60),
264
+ 500: baseHex,
265
+ // Base color
266
+ 600: hslToHex(hsl.h, Math.min(hsl.s + 5, 100), 45),
267
+ 700: hslToHex(hsl.h, Math.min(hsl.s + 10, 100), 35),
268
+ 800: hslToHex(hsl.h, Math.min(hsl.s + 15, 100), 25),
269
+ 900: hslToHex(hsl.h, Math.min(hsl.s + 20, 100), 15)
270
+ };
271
+ }
272
+
273
+ // src/lib/store/customizer.ts
274
+ var useCustomizer = (0, import_zustand2.create)()(
275
+ (0, import_middleware2.persist)(
276
+ (set, get) => ({
277
+ motion: 5,
278
+ prefersReducedMotion: false,
279
+ customizationMode: "simple",
280
+ customColors: {},
281
+ savedPalettes: [],
282
+ customFontThemes: {},
283
+ savedFontThemes: [],
284
+ setMotion: (level) => set({ motion: level }),
285
+ setPrefersReducedMotion: (value) => set({ prefersReducedMotion: value }),
286
+ setCustomizationMode: (mode) => set({ customizationMode: mode }),
287
+ setCustomPrimaryColor: (theme, mode, hexColor) => {
288
+ const state = get();
289
+ const currentPalette = state.customColors[theme]?.[mode];
290
+ const scale = generateColorScale(hexColor);
291
+ const primaryForeground = getOptimalForeground(hexColor);
292
+ const derivedTokens = (0, import_tokens.computeDerivedTokens)("--color-primary", hexColor, mode);
293
+ const isSimple = state.customizationMode === "simple";
294
+ const palette = {
295
+ primary: hexColor,
296
+ primaryForeground,
297
+ secondary: isSimple ? void 0 : currentPalette?.secondary,
298
+ secondaryForeground: isSimple ? void 0 : currentPalette?.secondaryForeground,
299
+ accent: isSimple ? void 0 : currentPalette?.accent,
300
+ accentForeground: isSimple ? void 0 : currentPalette?.accentForeground,
301
+ scale,
302
+ derivedTokens
303
+ };
304
+ set((state2) => ({
305
+ customColors: {
306
+ ...state2.customColors,
307
+ [theme]: {
308
+ ...state2.customColors[theme],
309
+ [mode]: palette
310
+ }
311
+ }
312
+ }));
313
+ },
314
+ setCustomSecondaryColor: (theme, mode, hexColor) => {
315
+ const state = get();
316
+ const currentPalette = state.customColors[theme]?.[mode];
317
+ if (!currentPalette) return;
318
+ const secondaryForeground = getOptimalForeground(hexColor);
319
+ const derivedTokens = (0, import_tokens.computeDerivedTokens)("--color-secondary", hexColor, mode);
320
+ set((state2) => ({
321
+ customColors: {
322
+ ...state2.customColors,
323
+ [theme]: {
324
+ ...state2.customColors[theme],
325
+ [mode]: {
326
+ ...currentPalette,
327
+ secondary: hexColor,
328
+ secondaryForeground,
329
+ derivedTokens: {
330
+ ...currentPalette.derivedTokens,
331
+ ...derivedTokens
332
+ }
333
+ }
334
+ }
335
+ }
336
+ }));
337
+ },
338
+ setCustomAccentColor: (theme, mode, hexColor) => {
339
+ const state = get();
340
+ const currentPalette = state.customColors[theme]?.[mode];
341
+ if (!currentPalette) return;
342
+ const accentForeground = getOptimalForeground(hexColor);
343
+ const derivedTokens = (0, import_tokens.computeDerivedTokens)("--color-accent", hexColor, mode);
344
+ set((state2) => ({
345
+ customColors: {
346
+ ...state2.customColors,
347
+ [theme]: {
348
+ ...state2.customColors[theme],
349
+ [mode]: {
350
+ ...currentPalette,
351
+ accent: hexColor,
352
+ accentForeground,
353
+ derivedTokens: {
354
+ ...currentPalette.derivedTokens,
355
+ ...derivedTokens
356
+ }
357
+ }
358
+ }
359
+ }
360
+ }));
361
+ },
362
+ applyColorPalette: (theme, mode, colors) => {
363
+ const scale = generateColorScale(colors.primary);
364
+ const primaryForeground = getOptimalForeground(colors.primary);
365
+ let derivedTokens = (0, import_tokens.computeDerivedTokens)("--color-primary", colors.primary, mode);
366
+ let secondary = colors.secondary;
367
+ let secondaryForeground = secondary ? getOptimalForeground(secondary) : void 0;
368
+ if (secondary) {
369
+ const secondaryDerived = (0, import_tokens.computeDerivedTokens)("--color-secondary", secondary, mode);
370
+ derivedTokens = { ...derivedTokens, ...secondaryDerived };
371
+ }
372
+ let accent = colors.accent;
373
+ let accentForeground = accent ? getOptimalForeground(accent) : void 0;
374
+ if (accent) {
375
+ const accentDerived = (0, import_tokens.computeDerivedTokens)("--color-accent", accent, mode);
376
+ derivedTokens = { ...derivedTokens, ...accentDerived };
377
+ }
378
+ const palette = {
379
+ name: colors.name,
380
+ description: colors.description,
381
+ primary: colors.primary,
382
+ primaryForeground,
383
+ secondary,
384
+ secondaryForeground,
385
+ accent,
386
+ accentForeground,
387
+ scale,
388
+ derivedTokens
389
+ };
390
+ set((state) => ({
391
+ customColors: {
392
+ ...state.customColors,
393
+ [theme]: {
394
+ ...state.customColors[theme],
395
+ [mode]: palette
396
+ }
397
+ }
398
+ }));
399
+ },
400
+ resetCustomColors: (theme, mode) => {
401
+ if (mode) {
402
+ set((state) => ({
403
+ customColors: {
404
+ ...state.customColors,
405
+ [theme]: {
406
+ ...state.customColors[theme],
407
+ [mode]: void 0
408
+ }
409
+ }
410
+ }));
411
+ } else {
412
+ set((state) => {
413
+ const { [theme]: _, ...rest } = state.customColors;
414
+ return { customColors: rest };
415
+ });
416
+ }
417
+ },
418
+ getActiveColorPalette: (theme, mode) => {
419
+ return get().customColors[theme]?.[mode] || null;
420
+ },
421
+ // Saved palette management
422
+ savePalette: (paletteData) => {
423
+ const id = `custom-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
424
+ const newPalette = {
425
+ ...paletteData,
426
+ id,
427
+ category: "custom",
428
+ createdAt: Date.now()
429
+ };
430
+ set((state) => ({
431
+ savedPalettes: [...state.savedPalettes, newPalette]
432
+ }));
433
+ },
434
+ updatePalette: (id, updates) => {
435
+ set((state) => ({
436
+ savedPalettes: state.savedPalettes.map(
437
+ (p) => p.id === id ? { ...p, ...updates } : p
438
+ )
439
+ }));
440
+ },
441
+ renamePalette: (id, newName) => {
442
+ set((state) => ({
443
+ savedPalettes: state.savedPalettes.map(
444
+ (p) => p.id === id ? { ...p, name: newName } : p
445
+ )
446
+ }));
447
+ },
448
+ deletePalette: (id) => {
449
+ set((state) => ({
450
+ savedPalettes: state.savedPalettes.filter((p) => p.id !== id)
451
+ }));
452
+ },
453
+ reorderPalettes: (palettes) => {
454
+ set({ savedPalettes: palettes });
455
+ },
456
+ getSavedPalettes: () => {
457
+ return get().savedPalettes;
458
+ },
459
+ // Font theme management
460
+ applyFontTheme: (theme, mode, fontTheme) => {
461
+ set((state) => ({
462
+ customFontThemes: {
463
+ ...state.customFontThemes,
464
+ [theme]: {
465
+ ...state.customFontThemes[theme],
466
+ [mode]: fontTheme
467
+ }
468
+ }
469
+ }));
470
+ },
471
+ resetCustomFonts: (theme, mode) => {
472
+ if (mode) {
473
+ set((state) => ({
474
+ customFontThemes: {
475
+ ...state.customFontThemes,
476
+ [theme]: {
477
+ ...state.customFontThemes[theme],
478
+ [mode]: void 0
479
+ }
480
+ }
481
+ }));
482
+ } else {
483
+ set((state) => {
484
+ const { [theme]: _, ...rest } = state.customFontThemes;
485
+ return { customFontThemes: rest };
486
+ });
487
+ }
488
+ },
489
+ getActiveFontTheme: (theme, mode) => {
490
+ return get().customFontThemes[theme]?.[mode] || null;
491
+ },
492
+ // Saved font theme management
493
+ saveFontTheme: (fontThemeData) => {
494
+ const id = `font-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
495
+ const newFontTheme = {
496
+ ...fontThemeData,
497
+ id,
498
+ category: "custom",
499
+ createdAt: Date.now(),
500
+ isCustom: true
501
+ };
502
+ set((state) => ({
503
+ savedFontThemes: [...state.savedFontThemes, newFontTheme]
504
+ }));
505
+ },
506
+ updateFontTheme: (id, updates) => {
507
+ set((state) => ({
508
+ savedFontThemes: state.savedFontThemes.map(
509
+ (ft) => ft.id === id ? { ...ft, ...updates } : ft
510
+ )
511
+ }));
512
+ },
513
+ renameFontTheme: (id, newName) => {
514
+ set((state) => ({
515
+ savedFontThemes: state.savedFontThemes.map(
516
+ (ft) => ft.id === id ? { ...ft, name: newName } : ft
517
+ )
518
+ }));
519
+ },
520
+ deleteFontTheme: (id) => {
521
+ set((state) => ({
522
+ savedFontThemes: state.savedFontThemes.filter((ft) => ft.id !== id)
523
+ }));
524
+ },
525
+ reorderFontThemes: (fontThemes) => {
526
+ set({ savedFontThemes: fontThemes });
527
+ },
528
+ getSavedFontThemes: () => {
529
+ return get().savedFontThemes;
530
+ }
531
+ }),
532
+ {
533
+ name: "ecosystem-customizer",
534
+ version: 4,
535
+ partialize: (state) => ({
536
+ motion: state.motion,
537
+ prefersReducedMotion: state.prefersReducedMotion,
538
+ customizationMode: state.customizationMode,
539
+ customColors: state.customColors,
540
+ savedPalettes: state.savedPalettes,
541
+ customFontThemes: state.customFontThemes,
542
+ savedFontThemes: state.savedFontThemes
543
+ })
544
+ }
545
+ )
546
+ );
547
+
548
+ // src/providers/ThemeProvider.tsx
549
+ var import_tokens2 = require("@sage/tokens");
550
+ var import_jsx_runtime = require("react/jsx-runtime");
551
+ var themeTokens = {
552
+ studio: import_tokens2.studioTokens,
553
+ sage: import_tokens2.sageTokens,
554
+ volt: import_tokens2.voltTokens
555
+ };
556
+ var fontFamilies = {
557
+ studio: {
558
+ heading: "var(--font-studio-heading)",
559
+ body: "var(--font-studio-body)",
560
+ mono: "var(--font-mono)"
561
+ },
562
+ sage: {
563
+ sans: "var(--font-sage-body)",
564
+ serif: "var(--font-sage-heading)",
565
+ mono: "var(--font-mono)"
566
+ },
567
+ volt: {
568
+ sans: "var(--font-volt-heading)",
569
+ mono: "var(--font-mono)"
570
+ }
571
+ };
572
+ function getThemeVars(theme, mode) {
573
+ const tokens = themeTokens[theme];
574
+ const colors = tokens[mode]?.colors;
575
+ const effects = tokens[mode]?.effects;
576
+ const fonts = fontFamilies[theme];
577
+ return {
578
+ // Colors - Base
579
+ "--color-background": colors?.background || "#ffffff",
580
+ "--color-background-secondary": colors?.backgroundSecondary || colors?.background || "#fafafa",
581
+ "--color-background-tertiary": colors?.backgroundTertiary || colors?.backgroundSecondary || colors?.background || "#f5f5f5",
582
+ "--color-foreground": colors?.foreground || "#0a0a0a",
583
+ "--color-primary": colors?.primary || "#0a0a0a",
584
+ "--color-primary-foreground": colors?.primaryForeground || "#ffffff",
585
+ "--color-secondary": colors?.secondary || "#f5f5f5",
586
+ "--color-secondary-foreground": colors?.secondaryForeground || "#0a0a0a",
587
+ "--color-accent": colors?.accent || colors?.primary || "#0070f3",
588
+ "--color-accent-foreground": colors?.accentForeground || "#ffffff",
589
+ "--color-success": colors?.success || "#00a86b",
590
+ "--color-success-foreground": colors?.successForeground || "#ffffff",
591
+ "--color-warning": colors?.warning || "#f59e0b",
592
+ "--color-warning-foreground": colors?.warningForeground || "#ffffff",
593
+ "--color-error": colors?.error || "#ef4444",
594
+ "--color-error-foreground": colors?.errorForeground || "#ffffff",
595
+ "--color-info": colors?.info || colors?.accent || "#0070f3",
596
+ "--color-info-foreground": colors?.infoForeground || "#ffffff",
597
+ "--color-glass": colors?.glass || "rgba(255, 255, 255, 0.7)",
598
+ "--color-glass-border": colors?.glassBorder || "rgba(0, 0, 0, 0.1)",
599
+ // Semantic color aliases (matching README examples)
600
+ "--color-text-primary": colors?.foreground || "#0a0a0a",
601
+ "--color-text-secondary": colors?.foregroundSecondary || "#525252",
602
+ "--color-text-muted": colors?.foregroundTertiary || "#a3a3a3",
603
+ "--color-surface": colors?.backgroundSecondary || colors?.background || "#fafafa",
604
+ "--color-border": colors?.border || colors?.glassBorder || "rgba(0, 0, 0, 0.1)",
605
+ "--color-focus": colors?.accent || colors?.primary || "#0070f3",
606
+ // Links and focus rings (can be overridden by derived tokens)
607
+ "--color-link": colors?.link || colors?.primary || "#0a0a0a",
608
+ "--color-ring": colors?.ring || colors?.primary || "#0a0a0a",
609
+ // Interactive states
610
+ "--color-hover": colors?.hover || colors?.backgroundSecondary || "#fafafa",
611
+ "--color-active": colors?.active || colors?.backgroundTertiary || "#f0f0f0",
612
+ "--color-link-hover": colors?.linkHover || colors?.primary || "#0a0a0a",
613
+ "--color-link-hover-foreground": colors?.linkHoverForeground || colors?.background || "#ffffff",
614
+ // Effects - Blur
615
+ "--effect-blur-sm": effects?.blur?.sm || "blur(4px)",
616
+ "--effect-blur-md": effects?.blur?.md || "blur(8px)",
617
+ "--effect-blur-lg": effects?.blur?.lg || "blur(16px)",
618
+ "--effect-blur-xl": effects?.blur?.xl || effects?.blur?.lg || "blur(24px)",
619
+ // Effects - Shadow
620
+ "--effect-shadow-sm": effects?.shadow?.sm || "0 1px 2px 0 rgba(0, 0, 0, 0.05)",
621
+ "--effect-shadow-md": effects?.shadow?.md || effects?.shadow?.sm || "0 4px 6px -1px rgba(0, 0, 0, 0.1)",
622
+ "--effect-shadow-lg": effects?.shadow?.lg || effects?.shadow?.md || effects?.shadow?.sm || "0 10px 15px -3px rgba(0, 0, 0, 0.1)",
623
+ // Typography - Font Families
624
+ "--font-heading": fonts?.heading || (theme === "sage" && fonts?.serif ? fonts.serif : fonts?.sans) || "var(--font-studio-heading)",
625
+ "--font-body": fonts?.body || fonts?.sans || "var(--font-studio-body)",
626
+ "--font-mono": fonts?.mono || "var(--font-studio-mono)",
627
+ // Motion - These are accessed programmatically via tokens
628
+ // but we can set defaults for CSS animations
629
+ "--ease-default": tokens?.motion?.ease?.default || "cubic-bezier(0.4, 0, 0.2, 1)",
630
+ "--ease-spring": tokens?.motion?.ease?.spring || tokens?.motion?.ease?.default || "cubic-bezier(0.16, 1, 0.3, 1)",
631
+ // Syntax Highlighting - Based on VS Code Dark+ theme
632
+ "--syntax-comment": mode === "light" ? import_tokens2.syntaxColors.light.comment : import_tokens2.syntaxColors.dark.comment,
633
+ "--syntax-keyword": mode === "light" ? import_tokens2.syntaxColors.light.keyword : import_tokens2.syntaxColors.dark.keyword,
634
+ "--syntax-function": mode === "light" ? import_tokens2.syntaxColors.light.function : import_tokens2.syntaxColors.dark.function,
635
+ "--syntax-string": mode === "light" ? import_tokens2.syntaxColors.light.string : import_tokens2.syntaxColors.dark.string,
636
+ "--syntax-number": mode === "light" ? import_tokens2.syntaxColors.light.number : import_tokens2.syntaxColors.dark.number,
637
+ "--syntax-boolean": mode === "light" ? import_tokens2.syntaxColors.light.boolean : import_tokens2.syntaxColors.dark.boolean,
638
+ "--syntax-operator": mode === "light" ? import_tokens2.syntaxColors.light.operator : import_tokens2.syntaxColors.dark.operator,
639
+ "--syntax-property": mode === "light" ? import_tokens2.syntaxColors.light.property : import_tokens2.syntaxColors.dark.property,
640
+ "--syntax-className": mode === "light" ? import_tokens2.syntaxColors.light.className : import_tokens2.syntaxColors.dark.className,
641
+ "--syntax-tag": mode === "light" ? import_tokens2.syntaxColors.light.tag : import_tokens2.syntaxColors.dark.tag,
642
+ "--syntax-attribute": mode === "light" ? import_tokens2.syntaxColors.light.attribute : import_tokens2.syntaxColors.dark.attribute,
643
+ "--syntax-variable": mode === "light" ? import_tokens2.syntaxColors.light.variable : import_tokens2.syntaxColors.dark.variable,
644
+ "--syntax-punctuation": mode === "light" ? import_tokens2.syntaxColors.light.punctuation : import_tokens2.syntaxColors.dark.punctuation,
645
+ "--syntax-plain": mode === "light" ? import_tokens2.syntaxColors.light.plain : import_tokens2.syntaxColors.dark.plain,
646
+ // Code Block Backgrounds and Borders - Accessible contrast (WCAG AA 4.5:1)
647
+ "--code-block-bg": mode === "light" ? import_tokens2.codeColors.light.blockBackground : import_tokens2.codeColors.dark.blockBackground,
648
+ "--code-inline-bg": mode === "light" ? import_tokens2.codeColors.light.inlineBackground : import_tokens2.codeColors.dark.inlineBackground,
649
+ "--code-border": mode === "light" ? import_tokens2.codeColors.light.border : import_tokens2.codeColors.dark.border
650
+ };
651
+ }
652
+ function mergeCustomColorTokens(baseTokens, customPalette) {
653
+ return {
654
+ ...baseTokens,
655
+ // Override primary color
656
+ "--color-primary": customPalette.primary,
657
+ "--color-primary-foreground": customPalette.primaryForeground,
658
+ // Apply color scale (for utilities like bg-primary/50)
659
+ "--color-primary-50": customPalette.scale[50],
660
+ "--color-primary-100": customPalette.scale[100],
661
+ "--color-primary-200": customPalette.scale[200],
662
+ "--color-primary-300": customPalette.scale[300],
663
+ "--color-primary-400": customPalette.scale[400],
664
+ "--color-primary-500": customPalette.scale[500],
665
+ "--color-primary-600": customPalette.scale[600],
666
+ "--color-primary-700": customPalette.scale[700],
667
+ "--color-primary-800": customPalette.scale[800],
668
+ "--color-primary-900": customPalette.scale[900],
669
+ // Override secondary color if provided (advanced mode)
670
+ ...customPalette.secondary && {
671
+ "--color-secondary": customPalette.secondary,
672
+ "--color-secondary-foreground": customPalette.secondaryForeground || baseTokens["--color-secondary-foreground"]
673
+ },
674
+ // Override accent color if provided (advanced mode)
675
+ ...customPalette.accent && {
676
+ "--color-accent": customPalette.accent,
677
+ "--color-accent-foreground": customPalette.accentForeground || baseTokens["--color-accent-foreground"]
678
+ },
679
+ // Apply ALL derived tokens from dependency graph
680
+ // This automatically updates:
681
+ // - Links (--color-link, --color-link-hover)
682
+ // - Focus rings (--color-ring)
683
+ // - Charts (--chart-1, --chart-2, --chart-3, --chart-4, --chart-5)
684
+ // - Buttons, badges, and any other dependent tokens
685
+ ...customPalette.derivedTokens
686
+ };
687
+ }
688
+ function ThemeProvider({ children }) {
689
+ const { theme, mode } = useThemeStore();
690
+ const customPalette = useCustomizer((state) => state.customColors?.[theme]?.[mode]);
691
+ const [isTransitioning, setIsTransitioning] = (0, import_react.useState)(false);
692
+ const [mounted, setMounted] = (0, import_react.useState)(false);
693
+ (0, import_react.useEffect)(() => {
694
+ setMounted(true);
695
+ }, []);
696
+ (0, import_react.useEffect)(() => {
697
+ if (!mounted) return;
698
+ setIsTransitioning(true);
699
+ const root = document.documentElement;
700
+ const baseTokens = getThemeVars(theme, mode);
701
+ console.log("[ThemeProvider] Update:", {
702
+ theme,
703
+ mode,
704
+ hasCustomPalette: !!customPalette,
705
+ customPrimary: customPalette?.primary,
706
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
707
+ });
708
+ const finalTokens = customPalette ? mergeCustomColorTokens(baseTokens, customPalette) : baseTokens;
709
+ root.classList.add("theme-transitioning");
710
+ Object.entries(finalTokens).forEach(([key, value]) => {
711
+ root.style.setProperty(key, value);
712
+ });
713
+ root.setAttribute("data-theme", theme);
714
+ root.setAttribute("data-mode", mode);
715
+ root.setAttribute("data-custom-colors", customPalette ? "active" : "default");
716
+ if (mode === "dark") {
717
+ root.classList.add("dark");
718
+ } else {
719
+ root.classList.remove("dark");
720
+ }
721
+ const timeout = setTimeout(() => {
722
+ root.classList.remove("theme-transitioning");
723
+ setIsTransitioning(false);
724
+ }, 400);
725
+ return () => clearTimeout(timeout);
726
+ }, [theme, mode, mounted, customPalette]);
727
+ if (!mounted) {
728
+ return null;
729
+ }
730
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children });
731
+ }
732
+ // Annotate the CommonJS export names for ESM import in node:
733
+ 0 && (module.exports = {
734
+ ThemeProvider
735
+ });
736
+ //# sourceMappingURL=providers.js.map