@almadar/ui 5.76.1 → 5.76.2

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.
@@ -1,4 +1,675 @@
1
- export { ANONYMOUS_USER, BUILT_IN_THEMES, CurrentPagePathContext, CurrentPagePathProvider, DesignThemeProvider, OrbitalThemeProvider, default as ThemeContext, ThemeProvider, UISlotContext, UISlotProvider, UserContext, UserProvider, useCurrentPagePath, useDesignTheme, useHasPermission, useHasRole, useSlotContent, useSlotHasContent, useTheme, useUISlots, useUser, useUserForEvaluation } from '@almadar/ui/providers';
1
+ import { createContext, useMemo, useContext, useState, useEffect, useCallback, useRef } from 'react';
2
+ import { createLogger } from '@almadar/logger';
3
+ import { jsx } from 'react/jsx-runtime';
4
+ export { ANONYMOUS_USER, CurrentPagePathContext, CurrentPagePathProvider, OrbitalThemeProvider, UserContext, UserProvider, useCurrentPagePath, useHasPermission, useHasRole, useUser, useUserForEvaluation } from '@almadar/ui/providers';
5
+ import { ThemeProvider as ThemeProvider$1, useTheme as useTheme$1 } from '@almadar/ui/context';
6
+
7
+ var log = createLogger("almadar:ui:ui-slots");
8
+ var DEFAULT_SOURCE_KEY = "__default__";
9
+ var MULTI_SOURCE_STACK_TRAIT = "__multi_source_stack__";
10
+ var ALL_SLOTS = [
11
+ "main",
12
+ "sidebar",
13
+ "modal",
14
+ "drawer",
15
+ "overlay",
16
+ "center",
17
+ "toast",
18
+ "hud-top",
19
+ "hud-bottom",
20
+ "floating"
21
+ ];
22
+ var DEFAULT_SLOTS = ALL_SLOTS.reduce(
23
+ (acc, slot) => {
24
+ acc[slot] = null;
25
+ return acc;
26
+ },
27
+ {}
28
+ );
29
+ var DEFAULT_SOURCES = ALL_SLOTS.reduce(
30
+ (acc, slot) => {
31
+ acc[slot] = {};
32
+ return acc;
33
+ },
34
+ {}
35
+ );
36
+ function aggregateSlot(sources) {
37
+ if (!sources) return null;
38
+ const entries = Object.entries(sources);
39
+ if (entries.length === 0) return null;
40
+ if (entries.length === 1) return entries[0][1];
41
+ const children = entries.map(([, entry]) => ({
42
+ type: entry.pattern,
43
+ ...entry.props
44
+ }));
45
+ const stackId = `slot-content-stack-${entries.map(([k]) => k).join("-")}`;
46
+ return {
47
+ id: stackId,
48
+ pattern: "stack",
49
+ props: {
50
+ direction: "vertical",
51
+ gap: "lg",
52
+ children
53
+ },
54
+ priority: 0,
55
+ animation: "fade",
56
+ sourceTrait: MULTI_SOURCE_STACK_TRAIT
57
+ };
58
+ }
59
+ function useUISlotManager() {
60
+ const [sources, setSources] = useState(DEFAULT_SOURCES);
61
+ const subscribersRef = useRef(/* @__PURE__ */ new Set());
62
+ const timersRef = useRef(/* @__PURE__ */ new Map());
63
+ const traitIndexRef = useRef(/* @__PURE__ */ new Map());
64
+ const traitSubscribersRef = useRef(/* @__PURE__ */ new Map());
65
+ const slots = useMemo(() => {
66
+ const out = { ...DEFAULT_SLOTS };
67
+ for (const slot of ALL_SLOTS) {
68
+ out[slot] = aggregateSlot(sources[slot]);
69
+ }
70
+ return out;
71
+ }, [sources]);
72
+ useEffect(() => {
73
+ return () => {
74
+ timersRef.current.forEach((timer) => clearTimeout(timer));
75
+ timersRef.current.clear();
76
+ };
77
+ }, []);
78
+ const notifySubscribers = useCallback((slot, content) => {
79
+ subscribersRef.current.forEach((callback) => {
80
+ try {
81
+ callback(slot, content);
82
+ } catch (error) {
83
+ log.error("Subscriber error", { error: error instanceof Error ? error : String(error) });
84
+ }
85
+ });
86
+ }, []);
87
+ const notifyTraitSubscribers = useCallback(
88
+ (traitName, content) => {
89
+ const subs = traitSubscribersRef.current.get(traitName);
90
+ if (!subs) return;
91
+ subs.forEach((callback) => {
92
+ try {
93
+ callback(content);
94
+ } catch (error) {
95
+ log.error("Trait subscriber error", { traitName, error: error instanceof Error ? error : String(error) });
96
+ }
97
+ });
98
+ },
99
+ []
100
+ );
101
+ const indexTraitRender = useCallback(
102
+ (traitName, content) => {
103
+ traitIndexRef.current.set(traitName, content);
104
+ },
105
+ []
106
+ );
107
+ const unindexTrait = useCallback((traitName) => {
108
+ traitIndexRef.current.delete(traitName);
109
+ }, []);
110
+ const render = useCallback(
111
+ (config) => {
112
+ const sourceKey = config.sourceTrait ?? DEFAULT_SOURCE_KEY;
113
+ const id = `slot-content-${config.target}-${sourceKey}`;
114
+ const content = {
115
+ id,
116
+ pattern: config.pattern,
117
+ props: config.props ?? {},
118
+ priority: config.priority ?? 0,
119
+ animation: config.animation ?? "fade",
120
+ onDismiss: config.onDismiss,
121
+ sourceTrait: config.sourceTrait,
122
+ slot: config.target,
123
+ transitionEvent: config.transitionEvent,
124
+ fromState: config.fromState,
125
+ entity: config.entity
126
+ };
127
+ if (config.autoDismissMs && config.autoDismissMs > 0) {
128
+ content.autoDismissAt = Date.now() + config.autoDismissMs;
129
+ const prevTimer = timersRef.current.get(id);
130
+ if (prevTimer) clearTimeout(prevTimer);
131
+ const timer = setTimeout(() => {
132
+ setSources((prev) => {
133
+ const slotSources = prev[config.target];
134
+ if (slotSources && slotSources[sourceKey] === content) {
135
+ content.onDismiss?.();
136
+ const next = { ...slotSources };
137
+ delete next[sourceKey];
138
+ const updated = { ...prev, [config.target]: next };
139
+ notifySubscribers(config.target, aggregateSlot(next));
140
+ return updated;
141
+ }
142
+ return prev;
143
+ });
144
+ timersRef.current.delete(id);
145
+ }, config.autoDismissMs);
146
+ timersRef.current.set(id, timer);
147
+ }
148
+ setSources((prev) => {
149
+ const slotSources = prev[config.target] ?? {};
150
+ const existing = slotSources[sourceKey];
151
+ if (existing && existing.priority > content.priority) {
152
+ log.warn("Slot already has higher priority content", {
153
+ slot: config.target,
154
+ sourceKey,
155
+ existingPriority: existing.priority,
156
+ newPriority: content.priority
157
+ });
158
+ return prev;
159
+ }
160
+ const nextSources = {
161
+ ...slotSources,
162
+ [sourceKey]: content
163
+ };
164
+ const nextAll = { ...prev, [config.target]: nextSources };
165
+ if (content.sourceTrait) {
166
+ indexTraitRender(content.sourceTrait, content);
167
+ notifyTraitSubscribers(content.sourceTrait, content);
168
+ }
169
+ log.info("slot:written", {
170
+ slot: config.target,
171
+ sourceKey,
172
+ sourceTrait: content.sourceTrait,
173
+ patternType: content.pattern,
174
+ priority: content.priority
175
+ });
176
+ notifySubscribers(config.target, aggregateSlot(nextSources));
177
+ return nextAll;
178
+ });
179
+ return id;
180
+ },
181
+ [notifySubscribers, notifyTraitSubscribers, indexTraitRender]
182
+ );
183
+ const clear = useCallback(
184
+ (slot) => {
185
+ setSources((prev) => {
186
+ const slotSources = prev[slot];
187
+ if (!slotSources || Object.keys(slotSources).length === 0) {
188
+ return prev;
189
+ }
190
+ for (const content of Object.values(slotSources)) {
191
+ const timer = timersRef.current.get(content.id);
192
+ if (timer) {
193
+ clearTimeout(timer);
194
+ timersRef.current.delete(content.id);
195
+ }
196
+ content.onDismiss?.();
197
+ if (content.sourceTrait) {
198
+ unindexTrait(content.sourceTrait);
199
+ notifyTraitSubscribers(content.sourceTrait, null);
200
+ }
201
+ }
202
+ notifySubscribers(slot, null);
203
+ return { ...prev, [slot]: {} };
204
+ });
205
+ },
206
+ [notifySubscribers, notifyTraitSubscribers, unindexTrait]
207
+ );
208
+ const clearBySource = useCallback(
209
+ (slot, sourceTrait) => {
210
+ const sourceKey = sourceTrait;
211
+ setSources((prev) => {
212
+ const slotSources = prev[slot];
213
+ if (!slotSources || !(sourceKey in slotSources)) {
214
+ log.debug("slot:clear-noop", { slot, sourceTrait, reason: !slotSources ? "no-slot" : "no-source" });
215
+ return prev;
216
+ }
217
+ const content = slotSources[sourceKey];
218
+ const timer = timersRef.current.get(content.id);
219
+ if (timer) {
220
+ clearTimeout(timer);
221
+ timersRef.current.delete(content.id);
222
+ }
223
+ content.onDismiss?.();
224
+ if (content.sourceTrait) {
225
+ unindexTrait(content.sourceTrait);
226
+ notifyTraitSubscribers(content.sourceTrait, null);
227
+ }
228
+ const nextSources = { ...slotSources };
229
+ delete nextSources[sourceKey];
230
+ log.info("slot:cleared", { slot, sourceTrait, lastPatternType: content.pattern });
231
+ notifySubscribers(slot, aggregateSlot(nextSources));
232
+ return { ...prev, [slot]: nextSources };
233
+ });
234
+ },
235
+ [notifySubscribers, notifyTraitSubscribers, unindexTrait]
236
+ );
237
+ const clearById = useCallback(
238
+ (id) => {
239
+ setSources((prev) => {
240
+ for (const slot of ALL_SLOTS) {
241
+ const slotSources = prev[slot];
242
+ if (!slotSources) continue;
243
+ const matchKey = Object.keys(slotSources).find(
244
+ (k) => slotSources[k].id === id
245
+ );
246
+ if (!matchKey) continue;
247
+ const content = slotSources[matchKey];
248
+ const timer = timersRef.current.get(id);
249
+ if (timer) {
250
+ clearTimeout(timer);
251
+ timersRef.current.delete(id);
252
+ }
253
+ content.onDismiss?.();
254
+ if (content.sourceTrait) {
255
+ unindexTrait(content.sourceTrait);
256
+ notifyTraitSubscribers(content.sourceTrait, null);
257
+ }
258
+ const nextSources = { ...slotSources };
259
+ delete nextSources[matchKey];
260
+ notifySubscribers(slot, aggregateSlot(nextSources));
261
+ return { ...prev, [slot]: nextSources };
262
+ }
263
+ return prev;
264
+ });
265
+ },
266
+ [notifySubscribers, notifyTraitSubscribers, unindexTrait]
267
+ );
268
+ const clearAll = useCallback(() => {
269
+ timersRef.current.forEach((timer) => clearTimeout(timer));
270
+ timersRef.current.clear();
271
+ setSources((prev) => {
272
+ for (const slot of ALL_SLOTS) {
273
+ const slotSources = prev[slot];
274
+ if (!slotSources) continue;
275
+ for (const content of Object.values(slotSources)) {
276
+ content.onDismiss?.();
277
+ if (content.sourceTrait) {
278
+ notifyTraitSubscribers(content.sourceTrait, null);
279
+ }
280
+ }
281
+ notifySubscribers(slot, null);
282
+ }
283
+ return DEFAULT_SOURCES;
284
+ });
285
+ traitIndexRef.current.clear();
286
+ }, [notifySubscribers, notifyTraitSubscribers]);
287
+ const subscribe = useCallback((callback) => {
288
+ subscribersRef.current.add(callback);
289
+ return () => {
290
+ subscribersRef.current.delete(callback);
291
+ };
292
+ }, []);
293
+ const hasContent = useCallback(
294
+ (slot) => slots[slot] !== null,
295
+ [slots]
296
+ );
297
+ const getContent = useCallback(
298
+ (slot) => slots[slot] ?? null,
299
+ [slots]
300
+ );
301
+ const getTraitContent = useCallback(
302
+ (traitName) => traitIndexRef.current.get(traitName) ?? null,
303
+ []
304
+ );
305
+ const subscribeTrait = useCallback(
306
+ (traitName, callback) => {
307
+ let set = traitSubscribersRef.current.get(traitName);
308
+ if (!set) {
309
+ set = /* @__PURE__ */ new Set();
310
+ traitSubscribersRef.current.set(traitName, set);
311
+ }
312
+ set.add(callback);
313
+ return () => {
314
+ const s = traitSubscribersRef.current.get(traitName);
315
+ if (!s) return;
316
+ s.delete(callback);
317
+ if (s.size === 0) {
318
+ traitSubscribersRef.current.delete(traitName);
319
+ }
320
+ };
321
+ },
322
+ []
323
+ );
324
+ const updateTraitContent = useCallback(
325
+ (traitName, content) => {
326
+ const id = `slot-content-trait-${traitName}`;
327
+ const fullContent = { ...content, id, sourceTrait: traitName };
328
+ indexTraitRender(traitName, fullContent);
329
+ notifyTraitSubscribers(traitName, fullContent);
330
+ return id;
331
+ },
332
+ [indexTraitRender, notifyTraitSubscribers]
333
+ );
334
+ return {
335
+ slots,
336
+ render,
337
+ clear,
338
+ clearBySource,
339
+ clearById,
340
+ clearAll,
341
+ subscribe,
342
+ hasContent,
343
+ getContent,
344
+ getTraitContent,
345
+ subscribeTrait,
346
+ updateTraitContent
347
+ };
348
+ }
349
+ var UISlotContext = createContext(null);
350
+ function UISlotProvider({ children }) {
351
+ const slotManager = useUISlotManager();
352
+ const contextValue = useMemo(() => slotManager, [slotManager]);
353
+ return /* @__PURE__ */ jsx(UISlotContext.Provider, { value: contextValue, children });
354
+ }
355
+ function useUISlots() {
356
+ const context = useContext(UISlotContext);
357
+ if (!context) {
358
+ throw new Error(
359
+ "useUISlots must be used within a UISlotProvider. Make sure your component tree is wrapped with <UISlotProvider>."
360
+ );
361
+ }
362
+ return context;
363
+ }
364
+ function useSlotContent(slot) {
365
+ const { getContent } = useUISlots();
366
+ return getContent(slot);
367
+ }
368
+ function useSlotHasContent(slot) {
369
+ const { hasContent } = useUISlots();
370
+ return hasContent(slot);
371
+ }
372
+ var log2 = createLogger("almadar:ui:theme");
373
+ var BUILT_IN_THEMES = [
374
+ {
375
+ name: "wireframe",
376
+ displayName: "Wireframe",
377
+ hasLightMode: true,
378
+ hasDarkMode: true
379
+ },
380
+ {
381
+ name: "minimalist",
382
+ displayName: "Minimalist",
383
+ hasLightMode: true,
384
+ hasDarkMode: true
385
+ },
386
+ {
387
+ name: "almadar",
388
+ displayName: "Almadar",
389
+ hasLightMode: true,
390
+ hasDarkMode: true
391
+ },
392
+ {
393
+ name: "trait-wars",
394
+ displayName: "Trait Wars",
395
+ hasLightMode: false,
396
+ hasDarkMode: true
397
+ },
398
+ // Extended themes
399
+ {
400
+ name: "ocean",
401
+ displayName: "Ocean",
402
+ hasLightMode: true,
403
+ hasDarkMode: true
404
+ },
405
+ {
406
+ name: "forest",
407
+ displayName: "Forest",
408
+ hasLightMode: true,
409
+ hasDarkMode: true
410
+ },
411
+ {
412
+ name: "sunset",
413
+ displayName: "Sunset",
414
+ hasLightMode: true,
415
+ hasDarkMode: true
416
+ },
417
+ {
418
+ name: "lavender",
419
+ displayName: "Lavender",
420
+ hasLightMode: true,
421
+ hasDarkMode: true
422
+ },
423
+ {
424
+ name: "rose",
425
+ displayName: "Rose",
426
+ hasLightMode: true,
427
+ hasDarkMode: true
428
+ },
429
+ {
430
+ name: "slate",
431
+ displayName: "Slate",
432
+ hasLightMode: true,
433
+ hasDarkMode: true
434
+ },
435
+ {
436
+ name: "ember",
437
+ displayName: "Ember",
438
+ hasLightMode: true,
439
+ hasDarkMode: true
440
+ },
441
+ {
442
+ name: "midnight",
443
+ displayName: "Midnight",
444
+ hasLightMode: true,
445
+ hasDarkMode: true
446
+ },
447
+ {
448
+ name: "sand",
449
+ displayName: "Sand",
450
+ hasLightMode: true,
451
+ hasDarkMode: true
452
+ },
453
+ {
454
+ name: "neon",
455
+ displayName: "Neon",
456
+ hasLightMode: true,
457
+ hasDarkMode: true
458
+ },
459
+ {
460
+ name: "arctic",
461
+ displayName: "Arctic",
462
+ hasLightMode: true,
463
+ hasDarkMode: true
464
+ },
465
+ {
466
+ name: "copper",
467
+ displayName: "Copper",
468
+ hasLightMode: true,
469
+ hasDarkMode: true
470
+ },
471
+ // Layer 1 skin axes — truly-unique themes (compact tech / editorial / brutalist dense / display-heavy / touch-first)
472
+ {
473
+ name: "prism",
474
+ displayName: "Prism",
475
+ hasLightMode: true,
476
+ hasDarkMode: true
477
+ },
478
+ {
479
+ name: "gazette",
480
+ displayName: "Gazette",
481
+ hasLightMode: true,
482
+ hasDarkMode: true
483
+ },
484
+ {
485
+ name: "terminal",
486
+ displayName: "Terminal",
487
+ hasLightMode: true,
488
+ hasDarkMode: true
489
+ },
490
+ {
491
+ name: "atelier",
492
+ displayName: "Atelier",
493
+ hasLightMode: true,
494
+ hasDarkMode: true
495
+ },
496
+ {
497
+ name: "kiosk",
498
+ displayName: "Kiosk",
499
+ hasLightMode: true,
500
+ hasDarkMode: true
501
+ },
502
+ {
503
+ name: "linear-clean",
504
+ displayName: "Linear Clean",
505
+ hasLightMode: true,
506
+ hasDarkMode: true
507
+ },
508
+ {
509
+ name: "notion-editorial",
510
+ displayName: "Notion Editorial",
511
+ hasLightMode: true,
512
+ hasDarkMode: true
513
+ },
514
+ {
515
+ name: "bloomberg-dense",
516
+ displayName: "Bloomberg Dense",
517
+ hasLightMode: true,
518
+ hasDarkMode: true
519
+ }
520
+ ];
521
+ var ThemeContext = createContext(void 0);
522
+ var THEME_STORAGE_KEY = "theme";
523
+ var MODE_STORAGE_KEY = "theme-mode";
524
+ function getSystemMode() {
525
+ if (typeof window === "undefined") return "light";
526
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
527
+ }
528
+ function resolveMode(mode) {
529
+ if (mode === "system") {
530
+ return getSystemMode();
531
+ }
532
+ return mode;
533
+ }
534
+ var ThemeProvider = ({
535
+ children,
536
+ themes = [],
537
+ defaultTheme = "wireframe",
538
+ defaultMode = "system",
539
+ targetRef
540
+ }) => {
541
+ const availableThemes = useMemo(() => {
542
+ const themeMap = /* @__PURE__ */ new Map();
543
+ BUILT_IN_THEMES.forEach((t) => themeMap.set(t.name, t));
544
+ themes.forEach((t) => themeMap.set(t.name, t));
545
+ return Array.from(themeMap.values());
546
+ }, [themes]);
547
+ const isScoped = !!targetRef;
548
+ const [theme, setThemeState] = useState(() => {
549
+ if (isScoped || typeof window === "undefined") return defaultTheme;
550
+ const stored = localStorage.getItem(THEME_STORAGE_KEY);
551
+ const validThemes = [
552
+ ...BUILT_IN_THEMES.map((t) => t.name),
553
+ ...themes.map((t) => t.name)
554
+ ];
555
+ if (stored && validThemes.includes(stored)) {
556
+ return stored;
557
+ }
558
+ return defaultTheme;
559
+ });
560
+ const [mode, setModeState] = useState(() => {
561
+ if (isScoped || typeof window === "undefined") return defaultMode;
562
+ const stored = localStorage.getItem(MODE_STORAGE_KEY);
563
+ if (stored === "light" || stored === "dark" || stored === "system") {
564
+ return stored;
565
+ }
566
+ return defaultMode;
567
+ });
568
+ const [resolvedMode, setResolvedMode] = useState(
569
+ () => resolveMode(mode)
570
+ );
571
+ const appliedTheme = useMemo(
572
+ () => `${theme}-${resolvedMode}`,
573
+ [theme, resolvedMode]
574
+ );
575
+ useEffect(() => {
576
+ const updateResolved = () => {
577
+ setResolvedMode(resolveMode(mode));
578
+ };
579
+ updateResolved();
580
+ if (mode === "system") {
581
+ const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
582
+ const handleChange = () => updateResolved();
583
+ mediaQuery.addEventListener("change", handleChange);
584
+ return () => mediaQuery.removeEventListener("change", handleChange);
585
+ }
586
+ return void 0;
587
+ }, [mode]);
588
+ useEffect(() => {
589
+ if (isScoped) {
590
+ if (targetRef?.current) {
591
+ targetRef.current.setAttribute("data-theme", appliedTheme);
592
+ targetRef.current.classList.remove("light", "dark");
593
+ targetRef.current.classList.add(resolvedMode);
594
+ }
595
+ return;
596
+ }
597
+ const root = document.documentElement;
598
+ root.setAttribute("data-theme", appliedTheme);
599
+ root.classList.remove("light", "dark");
600
+ root.classList.add(resolvedMode);
601
+ }, [appliedTheme, resolvedMode, targetRef, isScoped]);
602
+ const setTheme = useCallback(
603
+ (newTheme) => {
604
+ const validTheme = availableThemes.find((t) => t.name === newTheme);
605
+ if (validTheme) {
606
+ setThemeState(newTheme);
607
+ if (!isScoped && typeof window !== "undefined") {
608
+ localStorage.setItem(THEME_STORAGE_KEY, newTheme);
609
+ }
610
+ } else {
611
+ log2.warn("Theme not found", {
612
+ theme: newTheme,
613
+ available: availableThemes.map((t) => t.name)
614
+ });
615
+ }
616
+ },
617
+ [availableThemes]
618
+ );
619
+ const setMode = useCallback((newMode) => {
620
+ setModeState(newMode);
621
+ if (!isScoped && typeof window !== "undefined") {
622
+ localStorage.setItem(MODE_STORAGE_KEY, newMode);
623
+ }
624
+ }, []);
625
+ const toggleMode = useCallback(() => {
626
+ const newMode = resolvedMode === "dark" ? "light" : "dark";
627
+ setMode(newMode);
628
+ }, [resolvedMode, setMode]);
629
+ const contextValue = useMemo(
630
+ () => ({
631
+ theme,
632
+ mode,
633
+ resolvedMode,
634
+ setTheme,
635
+ setMode,
636
+ toggleMode,
637
+ availableThemes,
638
+ appliedTheme
639
+ }),
640
+ [
641
+ theme,
642
+ mode,
643
+ resolvedMode,
644
+ setTheme,
645
+ setMode,
646
+ toggleMode,
647
+ availableThemes,
648
+ appliedTheme
649
+ ]
650
+ );
651
+ return /* @__PURE__ */ jsx(ThemeContext.Provider, { value: contextValue, children });
652
+ };
653
+ function useTheme() {
654
+ const context = useContext(ThemeContext);
655
+ if (context === void 0) {
656
+ return {
657
+ theme: "wireframe",
658
+ mode: "light",
659
+ resolvedMode: "light",
660
+ setTheme: () => {
661
+ },
662
+ setMode: () => {
663
+ },
664
+ toggleMode: () => {
665
+ },
666
+ availableThemes: BUILT_IN_THEMES,
667
+ appliedTheme: "wireframe-light"
668
+ };
669
+ }
670
+ return context;
671
+ }
672
+ var ThemeContext_default = ThemeContext;
2
673
 
3
674
  // lib/themeTokens.ts
4
675
  function themeTokensToCssVars(tokens, mode = "light", darkVariant) {
@@ -215,5 +886,14 @@ function resolveThemeForRuntime(theme) {
215
886
  if (typeof theme === "string") return void 0;
216
887
  return theme;
217
888
  }
889
+ var DesignThemeProvider = ThemeProvider$1;
890
+ function useDesignTheme() {
891
+ const { theme, setTheme, availableThemes } = useTheme$1();
892
+ return {
893
+ designTheme: theme,
894
+ setDesignTheme: setTheme,
895
+ availableThemes: availableThemes.map((t) => t.name)
896
+ };
897
+ }
218
898
 
219
- export { resolveThemeForRuntime, themeTokensToCssVars };
899
+ export { BUILT_IN_THEMES, DesignThemeProvider, ThemeContext_default as ThemeContext, ThemeProvider, UISlotContext, UISlotProvider, resolveThemeForRuntime, themeTokensToCssVars, useDesignTheme, useSlotContent, useSlotHasContent, useTheme, useUISlots };