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