@almadar/ui 5.158.0 → 5.159.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{EntityBindingContext-Bn3ePJQC.d.cts → EntityBindingContext-0Evn_LcT.d.cts} +1 -1
- package/dist/{EntityBindingContext-Bn3ePJQC.d.ts → EntityBindingContext-0Evn_LcT.d.ts} +1 -1
- package/dist/avl/index.cjs +144 -34
- package/dist/avl/index.js +145 -35
- package/dist/components/index.cjs +192 -7
- package/dist/components/index.d.cts +8 -0
- package/dist/components/index.d.ts +8 -0
- package/dist/components/index.js +193 -8
- package/dist/context/index.cjs +134 -39
- package/dist/context/index.js +92 -1
- package/dist/hooks/index.cjs +328 -233
- package/dist/hooks/index.js +93 -2
- package/dist/lib/index.cjs +92 -0
- package/dist/lib/index.d.cts +58 -1
- package/dist/lib/index.d.ts +58 -1
- package/dist/lib/index.js +62 -1
- package/dist/locales/index.cjs +3 -0
- package/dist/locales/index.js +3 -0
- package/dist/perf-DaVdsbU0.d.cts +21 -0
- package/dist/perf-DaVdsbU0.d.ts +21 -0
- package/dist/providers/index.cjs +256 -96
- package/dist/providers/index.d.cts +1 -1
- package/dist/providers/index.d.ts +1 -1
- package/dist/providers/index.js +257 -97
- package/dist/runtime/index.cjs +152 -39
- package/dist/runtime/index.d.cts +5 -22
- package/dist/runtime/index.d.ts +5 -22
- package/dist/runtime/index.js +154 -40
- package/locales/ar.json +1 -0
- package/locales/en.json +1 -0
- package/locales/sl.json +1 -0
- package/package.json +5 -5
package/dist/context/index.cjs
CHANGED
|
@@ -1,11 +1,98 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var React = require('react');
|
|
4
4
|
var logger = require('@almadar/logger');
|
|
5
|
+
var core = require('@almadar/core');
|
|
5
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
7
|
var providers = require('@almadar/ui/providers');
|
|
7
8
|
var context = require('@almadar/ui/context');
|
|
8
9
|
|
|
10
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
|
+
|
|
12
|
+
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
13
|
+
|
|
14
|
+
function expressionEqual(a, b) {
|
|
15
|
+
if (Object.is(a, b)) return true;
|
|
16
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
17
|
+
if (a.length !== b.length) return false;
|
|
18
|
+
for (let i = 0; i < a.length; i++) {
|
|
19
|
+
if (!expressionEqual(a[i], b[i])) return false;
|
|
20
|
+
}
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
if (a !== null && b !== null && typeof a === "object" && typeof b === "object" && !Array.isArray(a) && !Array.isArray(b) && !(a instanceof Date) && !(b instanceof Date)) {
|
|
24
|
+
const aKeys = Object.keys(a);
|
|
25
|
+
const bKeys = Object.keys(b);
|
|
26
|
+
if (aKeys.length !== bKeys.length) return false;
|
|
27
|
+
for (const key of aKeys) {
|
|
28
|
+
if (!Object.prototype.hasOwnProperty.call(b, key)) return false;
|
|
29
|
+
if (!expressionEqual(
|
|
30
|
+
a[key],
|
|
31
|
+
b[key]
|
|
32
|
+
)) return false;
|
|
33
|
+
}
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
function isPlainSlotObject(value) {
|
|
39
|
+
if (value === null || value === void 0 || typeof value !== "object") return false;
|
|
40
|
+
if (Array.isArray(value)) return false;
|
|
41
|
+
if (React__default.default.isValidElement(value)) return false;
|
|
42
|
+
if (value instanceof Date) return false;
|
|
43
|
+
if (core.isRenderBindingMarker(value)) return false;
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
function shareValue(prev, next) {
|
|
47
|
+
if (Object.is(prev, next)) return { value: prev, equal: true };
|
|
48
|
+
const prevMarker = core.isRenderBindingMarker(prev) ? prev : void 0;
|
|
49
|
+
const nextMarker = core.isRenderBindingMarker(next) ? next : void 0;
|
|
50
|
+
if (prevMarker !== void 0 || nextMarker !== void 0) {
|
|
51
|
+
if (prevMarker !== void 0 && nextMarker !== void 0 && expressionEqual(prevMarker.expression, nextMarker.expression)) {
|
|
52
|
+
return { value: prev, equal: true };
|
|
53
|
+
}
|
|
54
|
+
return { value: next, equal: false };
|
|
55
|
+
}
|
|
56
|
+
if (prev instanceof Date || next instanceof Date) {
|
|
57
|
+
return prev instanceof Date && next instanceof Date && prev.getTime() === next.getTime() ? { value: prev, equal: true } : { value: next, equal: false };
|
|
58
|
+
}
|
|
59
|
+
if (typeof prev === "function" || typeof next === "function") return { value: next, equal: false };
|
|
60
|
+
if (React__default.default.isValidElement(prev) || React__default.default.isValidElement(next)) return { value: next, equal: false };
|
|
61
|
+
if (Array.isArray(prev) && Array.isArray(next)) {
|
|
62
|
+
let equal = prev.length === next.length;
|
|
63
|
+
const out = new Array(next.length);
|
|
64
|
+
for (let i = 0; i < next.length; i++) {
|
|
65
|
+
const child = shareValue(prev[i], next[i]);
|
|
66
|
+
out[i] = child.value;
|
|
67
|
+
if (!child.equal) equal = false;
|
|
68
|
+
}
|
|
69
|
+
return equal ? { value: prev, equal: true } : { value: out, equal: false };
|
|
70
|
+
}
|
|
71
|
+
if (isPlainSlotObject(prev) && isPlainSlotObject(next)) {
|
|
72
|
+
const prevKeys = Object.keys(prev);
|
|
73
|
+
const nextKeys = Object.keys(next);
|
|
74
|
+
let equal = prevKeys.length === nextKeys.length;
|
|
75
|
+
const out = {};
|
|
76
|
+
for (const key of nextKeys) {
|
|
77
|
+
if (!Object.prototype.hasOwnProperty.call(prev, key)) {
|
|
78
|
+
equal = false;
|
|
79
|
+
out[key] = next[key];
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const child = shareValue(prev[key], next[key]);
|
|
83
|
+
out[key] = child.value;
|
|
84
|
+
if (!child.equal) equal = false;
|
|
85
|
+
}
|
|
86
|
+
return equal ? { value: prev, equal: true } : { value: out, equal: false };
|
|
87
|
+
}
|
|
88
|
+
return { value: next, equal: false };
|
|
89
|
+
}
|
|
90
|
+
function reconcileSlotProps(prev, next) {
|
|
91
|
+
const result = shareValue(prev, next);
|
|
92
|
+
return { value: result.value, equal: result.equal };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// hooks/useUISlots.ts
|
|
9
96
|
var log = logger.createLogger("almadar:ui:ui-slots");
|
|
10
97
|
var DEFAULT_SOURCE_KEY = "__default__";
|
|
11
98
|
var MULTI_SOURCE_STACK_TRAIT = "__multi_source_stack__";
|
|
@@ -60,25 +147,25 @@ function aggregateSlot(sources) {
|
|
|
60
147
|
};
|
|
61
148
|
}
|
|
62
149
|
function useUISlotManager() {
|
|
63
|
-
const [sources, setSources] =
|
|
64
|
-
const subscribersRef =
|
|
65
|
-
const timersRef =
|
|
66
|
-
const traitIndexRef =
|
|
67
|
-
const traitSubscribersRef =
|
|
68
|
-
const slots =
|
|
150
|
+
const [sources, setSources] = React.useState(DEFAULT_SOURCES);
|
|
151
|
+
const subscribersRef = React.useRef(/* @__PURE__ */ new Set());
|
|
152
|
+
const timersRef = React.useRef(/* @__PURE__ */ new Map());
|
|
153
|
+
const traitIndexRef = React.useRef(/* @__PURE__ */ new Map());
|
|
154
|
+
const traitSubscribersRef = React.useRef(/* @__PURE__ */ new Map());
|
|
155
|
+
const slots = React.useMemo(() => {
|
|
69
156
|
const out = { ...DEFAULT_SLOTS };
|
|
70
157
|
for (const slot of ALL_SLOTS) {
|
|
71
158
|
out[slot] = aggregateSlot(sources[slot]);
|
|
72
159
|
}
|
|
73
160
|
return out;
|
|
74
161
|
}, [sources]);
|
|
75
|
-
|
|
162
|
+
React.useEffect(() => {
|
|
76
163
|
return () => {
|
|
77
164
|
timersRef.current.forEach((timer) => clearTimeout(timer));
|
|
78
165
|
timersRef.current.clear();
|
|
79
166
|
};
|
|
80
167
|
}, []);
|
|
81
|
-
const notifySubscribers =
|
|
168
|
+
const notifySubscribers = React.useCallback((slot, content) => {
|
|
82
169
|
subscribersRef.current.forEach((callback) => {
|
|
83
170
|
try {
|
|
84
171
|
callback(slot, content);
|
|
@@ -87,7 +174,7 @@ function useUISlotManager() {
|
|
|
87
174
|
}
|
|
88
175
|
});
|
|
89
176
|
}, []);
|
|
90
|
-
const notifyTraitSubscribers =
|
|
177
|
+
const notifyTraitSubscribers = React.useCallback(
|
|
91
178
|
(traitName, content) => {
|
|
92
179
|
const subs = traitSubscribersRef.current.get(traitName);
|
|
93
180
|
if (!subs) return;
|
|
@@ -101,16 +188,16 @@ function useUISlotManager() {
|
|
|
101
188
|
},
|
|
102
189
|
[]
|
|
103
190
|
);
|
|
104
|
-
const indexTraitRender =
|
|
191
|
+
const indexTraitRender = React.useCallback(
|
|
105
192
|
(traitName, content) => {
|
|
106
193
|
traitIndexRef.current.set(traitName, content);
|
|
107
194
|
},
|
|
108
195
|
[]
|
|
109
196
|
);
|
|
110
|
-
const unindexTrait =
|
|
197
|
+
const unindexTrait = React.useCallback((traitName) => {
|
|
111
198
|
traitIndexRef.current.delete(traitName);
|
|
112
199
|
}, []);
|
|
113
|
-
const render =
|
|
200
|
+
const render = React.useCallback(
|
|
114
201
|
(config) => {
|
|
115
202
|
const sourceKey = config.sourceTrait ?? DEFAULT_SOURCE_KEY;
|
|
116
203
|
const id = `slot-content-${config.target}-${sourceKey}`;
|
|
@@ -160,6 +247,14 @@ function useUISlotManager() {
|
|
|
160
247
|
});
|
|
161
248
|
return prev;
|
|
162
249
|
}
|
|
250
|
+
if (existing && existing.priority === content.priority && existing.pattern === content.pattern && existing.animation === content.animation && existing.transitionEvent === content.transitionEvent && existing.fromState === content.fromState && existing.entity === content.entity && existing.nodeId === content.nodeId && existing.autoDismissAt === void 0 && content.autoDismissAt === void 0 && existing.onDismiss === void 0 === (content.onDismiss === void 0)) {
|
|
251
|
+
const reconciled = reconcileSlotProps(existing.props, content.props);
|
|
252
|
+
if (reconciled.equal) {
|
|
253
|
+
log.debug("slot:flush-bail", { slot: config.target, sourceKey, pattern: content.pattern });
|
|
254
|
+
return prev;
|
|
255
|
+
}
|
|
256
|
+
content.props = reconciled.value;
|
|
257
|
+
}
|
|
163
258
|
const nextSources = {
|
|
164
259
|
...slotSources,
|
|
165
260
|
[sourceKey]: content
|
|
@@ -191,7 +286,7 @@ function useUISlotManager() {
|
|
|
191
286
|
},
|
|
192
287
|
[notifySubscribers, notifyTraitSubscribers, indexTraitRender]
|
|
193
288
|
);
|
|
194
|
-
const clear =
|
|
289
|
+
const clear = React.useCallback(
|
|
195
290
|
(slot) => {
|
|
196
291
|
setSources((prev) => {
|
|
197
292
|
const slotSources = prev[slot];
|
|
@@ -216,7 +311,7 @@ function useUISlotManager() {
|
|
|
216
311
|
},
|
|
217
312
|
[notifySubscribers, notifyTraitSubscribers, unindexTrait]
|
|
218
313
|
);
|
|
219
|
-
const clearBySource =
|
|
314
|
+
const clearBySource = React.useCallback(
|
|
220
315
|
(slot, sourceTrait) => {
|
|
221
316
|
const sourceKey = sourceTrait;
|
|
222
317
|
setSources((prev) => {
|
|
@@ -245,7 +340,7 @@ function useUISlotManager() {
|
|
|
245
340
|
},
|
|
246
341
|
[notifySubscribers, notifyTraitSubscribers, unindexTrait]
|
|
247
342
|
);
|
|
248
|
-
const clearById =
|
|
343
|
+
const clearById = React.useCallback(
|
|
249
344
|
(id) => {
|
|
250
345
|
setSources((prev) => {
|
|
251
346
|
for (const slot of ALL_SLOTS) {
|
|
@@ -276,7 +371,7 @@ function useUISlotManager() {
|
|
|
276
371
|
},
|
|
277
372
|
[notifySubscribers, notifyTraitSubscribers, unindexTrait]
|
|
278
373
|
);
|
|
279
|
-
const clearAll =
|
|
374
|
+
const clearAll = React.useCallback(() => {
|
|
280
375
|
timersRef.current.forEach((timer) => clearTimeout(timer));
|
|
281
376
|
timersRef.current.clear();
|
|
282
377
|
setSources((prev) => {
|
|
@@ -295,25 +390,25 @@ function useUISlotManager() {
|
|
|
295
390
|
});
|
|
296
391
|
traitIndexRef.current.clear();
|
|
297
392
|
}, [notifySubscribers, notifyTraitSubscribers]);
|
|
298
|
-
const subscribe =
|
|
393
|
+
const subscribe = React.useCallback((callback) => {
|
|
299
394
|
subscribersRef.current.add(callback);
|
|
300
395
|
return () => {
|
|
301
396
|
subscribersRef.current.delete(callback);
|
|
302
397
|
};
|
|
303
398
|
}, []);
|
|
304
|
-
const hasContent =
|
|
399
|
+
const hasContent = React.useCallback(
|
|
305
400
|
(slot) => slots[slot] !== null,
|
|
306
401
|
[slots]
|
|
307
402
|
);
|
|
308
|
-
const getContent =
|
|
403
|
+
const getContent = React.useCallback(
|
|
309
404
|
(slot) => slots[slot] ?? null,
|
|
310
405
|
[slots]
|
|
311
406
|
);
|
|
312
|
-
const getTraitContent =
|
|
407
|
+
const getTraitContent = React.useCallback(
|
|
313
408
|
(traitName) => traitIndexRef.current.get(traitName) ?? null,
|
|
314
409
|
[]
|
|
315
410
|
);
|
|
316
|
-
const subscribeTrait =
|
|
411
|
+
const subscribeTrait = React.useCallback(
|
|
317
412
|
(traitName, callback) => {
|
|
318
413
|
let set = traitSubscribersRef.current.get(traitName);
|
|
319
414
|
if (!set) {
|
|
@@ -332,7 +427,7 @@ function useUISlotManager() {
|
|
|
332
427
|
},
|
|
333
428
|
[]
|
|
334
429
|
);
|
|
335
|
-
const updateTraitContent =
|
|
430
|
+
const updateTraitContent = React.useCallback(
|
|
336
431
|
(traitName, content) => {
|
|
337
432
|
const id = `slot-content-trait-${traitName}`;
|
|
338
433
|
const fullContent = { ...content, id, sourceTrait: traitName };
|
|
@@ -357,14 +452,14 @@ function useUISlotManager() {
|
|
|
357
452
|
updateTraitContent
|
|
358
453
|
};
|
|
359
454
|
}
|
|
360
|
-
var UISlotContext =
|
|
455
|
+
var UISlotContext = React.createContext(null);
|
|
361
456
|
function UISlotProvider({ children }) {
|
|
362
457
|
const slotManager = useUISlotManager();
|
|
363
|
-
const contextValue =
|
|
458
|
+
const contextValue = React.useMemo(() => slotManager, [slotManager]);
|
|
364
459
|
return /* @__PURE__ */ jsxRuntime.jsx(UISlotContext.Provider, { value: contextValue, children });
|
|
365
460
|
}
|
|
366
461
|
function useUISlots() {
|
|
367
|
-
const context =
|
|
462
|
+
const context = React.useContext(UISlotContext);
|
|
368
463
|
if (!context) {
|
|
369
464
|
throw new Error(
|
|
370
465
|
"useUISlots must be used within a UISlotProvider. Make sure your component tree is wrapped with <UISlotProvider>."
|
|
@@ -512,7 +607,7 @@ var BUILT_IN_THEMES = [
|
|
|
512
607
|
hasDarkMode: true
|
|
513
608
|
}
|
|
514
609
|
];
|
|
515
|
-
var ThemeContext =
|
|
610
|
+
var ThemeContext = React.createContext(void 0);
|
|
516
611
|
var THEME_STORAGE_KEY = "theme";
|
|
517
612
|
var MODE_STORAGE_KEY = "theme-mode";
|
|
518
613
|
function getSystemMode() {
|
|
@@ -532,14 +627,14 @@ var ThemeProvider = ({
|
|
|
532
627
|
defaultMode = "system",
|
|
533
628
|
targetRef
|
|
534
629
|
}) => {
|
|
535
|
-
const availableThemes =
|
|
630
|
+
const availableThemes = React.useMemo(() => {
|
|
536
631
|
const themeMap = /* @__PURE__ */ new Map();
|
|
537
632
|
BUILT_IN_THEMES.forEach((t) => themeMap.set(t.name, t));
|
|
538
633
|
themes.forEach((t) => themeMap.set(t.name, t));
|
|
539
634
|
return Array.from(themeMap.values());
|
|
540
635
|
}, [themes]);
|
|
541
636
|
const isScoped = !!targetRef;
|
|
542
|
-
const [theme, setThemeState] =
|
|
637
|
+
const [theme, setThemeState] = React.useState(() => {
|
|
543
638
|
if (isScoped || typeof window === "undefined") return defaultTheme;
|
|
544
639
|
const stored = localStorage.getItem(THEME_STORAGE_KEY);
|
|
545
640
|
const validThemes = [
|
|
@@ -551,7 +646,7 @@ var ThemeProvider = ({
|
|
|
551
646
|
}
|
|
552
647
|
return defaultTheme;
|
|
553
648
|
});
|
|
554
|
-
const [mode, setModeState] =
|
|
649
|
+
const [mode, setModeState] = React.useState(() => {
|
|
555
650
|
if (isScoped || typeof window === "undefined") return defaultMode;
|
|
556
651
|
const stored = localStorage.getItem(MODE_STORAGE_KEY);
|
|
557
652
|
if (stored === "light" || stored === "dark" || stored === "system") {
|
|
@@ -559,14 +654,14 @@ var ThemeProvider = ({
|
|
|
559
654
|
}
|
|
560
655
|
return defaultMode;
|
|
561
656
|
});
|
|
562
|
-
const [resolvedMode, setResolvedMode] =
|
|
657
|
+
const [resolvedMode, setResolvedMode] = React.useState(
|
|
563
658
|
() => resolveMode(mode)
|
|
564
659
|
);
|
|
565
|
-
const appliedTheme =
|
|
660
|
+
const appliedTheme = React.useMemo(
|
|
566
661
|
() => `${theme}-${resolvedMode}`,
|
|
567
662
|
[theme, resolvedMode]
|
|
568
663
|
);
|
|
569
|
-
|
|
664
|
+
React.useEffect(() => {
|
|
570
665
|
const updateResolved = () => {
|
|
571
666
|
setResolvedMode(resolveMode(mode));
|
|
572
667
|
};
|
|
@@ -579,7 +674,7 @@ var ThemeProvider = ({
|
|
|
579
674
|
}
|
|
580
675
|
return void 0;
|
|
581
676
|
}, [mode]);
|
|
582
|
-
|
|
677
|
+
React.useEffect(() => {
|
|
583
678
|
if (isScoped) {
|
|
584
679
|
if (targetRef?.current) {
|
|
585
680
|
targetRef.current.setAttribute("data-theme", appliedTheme);
|
|
@@ -594,7 +689,7 @@ var ThemeProvider = ({
|
|
|
594
689
|
root.classList.remove("light", "dark");
|
|
595
690
|
root.classList.add(resolvedMode);
|
|
596
691
|
}, [appliedTheme, resolvedMode, targetRef, isScoped]);
|
|
597
|
-
const setTheme =
|
|
692
|
+
const setTheme = React.useCallback(
|
|
598
693
|
(newTheme) => {
|
|
599
694
|
const validTheme = availableThemes.find((t) => t.name === newTheme);
|
|
600
695
|
if (validTheme) {
|
|
@@ -611,17 +706,17 @@ var ThemeProvider = ({
|
|
|
611
706
|
},
|
|
612
707
|
[availableThemes]
|
|
613
708
|
);
|
|
614
|
-
const setMode =
|
|
709
|
+
const setMode = React.useCallback((newMode) => {
|
|
615
710
|
setModeState(newMode);
|
|
616
711
|
if (!isScoped && typeof window !== "undefined") {
|
|
617
712
|
localStorage.setItem(MODE_STORAGE_KEY, newMode);
|
|
618
713
|
}
|
|
619
714
|
}, []);
|
|
620
|
-
const toggleMode =
|
|
715
|
+
const toggleMode = React.useCallback(() => {
|
|
621
716
|
const newMode = resolvedMode === "dark" ? "light" : "dark";
|
|
622
717
|
setMode(newMode);
|
|
623
718
|
}, [resolvedMode, setMode]);
|
|
624
|
-
const contextValue =
|
|
719
|
+
const contextValue = React.useMemo(
|
|
625
720
|
() => ({
|
|
626
721
|
theme,
|
|
627
722
|
mode,
|
|
@@ -646,7 +741,7 @@ var ThemeProvider = ({
|
|
|
646
741
|
return /* @__PURE__ */ jsxRuntime.jsx(ThemeContext.Provider, { value: contextValue, children });
|
|
647
742
|
};
|
|
648
743
|
function useTheme() {
|
|
649
|
-
const context =
|
|
744
|
+
const context = React.useContext(ThemeContext);
|
|
650
745
|
if (context === void 0) {
|
|
651
746
|
return {
|
|
652
747
|
theme: "wireframe",
|
package/dist/context/index.js
CHANGED
|
@@ -1,9 +1,92 @@
|
|
|
1
|
-
import { createContext, useMemo, useContext, useState, useEffect, useCallback, useRef } from 'react';
|
|
1
|
+
import React, { createContext, useMemo, useContext, useState, useEffect, useCallback, useRef } from 'react';
|
|
2
2
|
import { createLogger } from '@almadar/logger';
|
|
3
|
+
import { isRenderBindingMarker } from '@almadar/core';
|
|
3
4
|
import { jsx } from 'react/jsx-runtime';
|
|
4
5
|
export { ANONYMOUS_USER, CurrentPagePathContext, CurrentPagePathProvider, OrbitalThemeProvider, UserContext, UserProvider, useCurrentPagePath, useHasPermission, useHasRole, useUser, useUserForEvaluation } from '@almadar/ui/providers';
|
|
5
6
|
import { ThemeProvider as ThemeProvider$1, useTheme as useTheme$1 } from '@almadar/ui/context';
|
|
6
7
|
|
|
8
|
+
function expressionEqual(a, b) {
|
|
9
|
+
if (Object.is(a, b)) return true;
|
|
10
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
11
|
+
if (a.length !== b.length) return false;
|
|
12
|
+
for (let i = 0; i < a.length; i++) {
|
|
13
|
+
if (!expressionEqual(a[i], b[i])) return false;
|
|
14
|
+
}
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
if (a !== null && b !== null && typeof a === "object" && typeof b === "object" && !Array.isArray(a) && !Array.isArray(b) && !(a instanceof Date) && !(b instanceof Date)) {
|
|
18
|
+
const aKeys = Object.keys(a);
|
|
19
|
+
const bKeys = Object.keys(b);
|
|
20
|
+
if (aKeys.length !== bKeys.length) return false;
|
|
21
|
+
for (const key of aKeys) {
|
|
22
|
+
if (!Object.prototype.hasOwnProperty.call(b, key)) return false;
|
|
23
|
+
if (!expressionEqual(
|
|
24
|
+
a[key],
|
|
25
|
+
b[key]
|
|
26
|
+
)) return false;
|
|
27
|
+
}
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
function isPlainSlotObject(value) {
|
|
33
|
+
if (value === null || value === void 0 || typeof value !== "object") return false;
|
|
34
|
+
if (Array.isArray(value)) return false;
|
|
35
|
+
if (React.isValidElement(value)) return false;
|
|
36
|
+
if (value instanceof Date) return false;
|
|
37
|
+
if (isRenderBindingMarker(value)) return false;
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
function shareValue(prev, next) {
|
|
41
|
+
if (Object.is(prev, next)) return { value: prev, equal: true };
|
|
42
|
+
const prevMarker = isRenderBindingMarker(prev) ? prev : void 0;
|
|
43
|
+
const nextMarker = isRenderBindingMarker(next) ? next : void 0;
|
|
44
|
+
if (prevMarker !== void 0 || nextMarker !== void 0) {
|
|
45
|
+
if (prevMarker !== void 0 && nextMarker !== void 0 && expressionEqual(prevMarker.expression, nextMarker.expression)) {
|
|
46
|
+
return { value: prev, equal: true };
|
|
47
|
+
}
|
|
48
|
+
return { value: next, equal: false };
|
|
49
|
+
}
|
|
50
|
+
if (prev instanceof Date || next instanceof Date) {
|
|
51
|
+
return prev instanceof Date && next instanceof Date && prev.getTime() === next.getTime() ? { value: prev, equal: true } : { value: next, equal: false };
|
|
52
|
+
}
|
|
53
|
+
if (typeof prev === "function" || typeof next === "function") return { value: next, equal: false };
|
|
54
|
+
if (React.isValidElement(prev) || React.isValidElement(next)) return { value: next, equal: false };
|
|
55
|
+
if (Array.isArray(prev) && Array.isArray(next)) {
|
|
56
|
+
let equal = prev.length === next.length;
|
|
57
|
+
const out = new Array(next.length);
|
|
58
|
+
for (let i = 0; i < next.length; i++) {
|
|
59
|
+
const child = shareValue(prev[i], next[i]);
|
|
60
|
+
out[i] = child.value;
|
|
61
|
+
if (!child.equal) equal = false;
|
|
62
|
+
}
|
|
63
|
+
return equal ? { value: prev, equal: true } : { value: out, equal: false };
|
|
64
|
+
}
|
|
65
|
+
if (isPlainSlotObject(prev) && isPlainSlotObject(next)) {
|
|
66
|
+
const prevKeys = Object.keys(prev);
|
|
67
|
+
const nextKeys = Object.keys(next);
|
|
68
|
+
let equal = prevKeys.length === nextKeys.length;
|
|
69
|
+
const out = {};
|
|
70
|
+
for (const key of nextKeys) {
|
|
71
|
+
if (!Object.prototype.hasOwnProperty.call(prev, key)) {
|
|
72
|
+
equal = false;
|
|
73
|
+
out[key] = next[key];
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const child = shareValue(prev[key], next[key]);
|
|
77
|
+
out[key] = child.value;
|
|
78
|
+
if (!child.equal) equal = false;
|
|
79
|
+
}
|
|
80
|
+
return equal ? { value: prev, equal: true } : { value: out, equal: false };
|
|
81
|
+
}
|
|
82
|
+
return { value: next, equal: false };
|
|
83
|
+
}
|
|
84
|
+
function reconcileSlotProps(prev, next) {
|
|
85
|
+
const result = shareValue(prev, next);
|
|
86
|
+
return { value: result.value, equal: result.equal };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// hooks/useUISlots.ts
|
|
7
90
|
var log = createLogger("almadar:ui:ui-slots");
|
|
8
91
|
var DEFAULT_SOURCE_KEY = "__default__";
|
|
9
92
|
var MULTI_SOURCE_STACK_TRAIT = "__multi_source_stack__";
|
|
@@ -158,6 +241,14 @@ function useUISlotManager() {
|
|
|
158
241
|
});
|
|
159
242
|
return prev;
|
|
160
243
|
}
|
|
244
|
+
if (existing && existing.priority === content.priority && existing.pattern === content.pattern && existing.animation === content.animation && existing.transitionEvent === content.transitionEvent && existing.fromState === content.fromState && existing.entity === content.entity && existing.nodeId === content.nodeId && existing.autoDismissAt === void 0 && content.autoDismissAt === void 0 && existing.onDismiss === void 0 === (content.onDismiss === void 0)) {
|
|
245
|
+
const reconciled = reconcileSlotProps(existing.props, content.props);
|
|
246
|
+
if (reconciled.equal) {
|
|
247
|
+
log.debug("slot:flush-bail", { slot: config.target, sourceKey, pattern: content.pattern });
|
|
248
|
+
return prev;
|
|
249
|
+
}
|
|
250
|
+
content.props = reconciled.value;
|
|
251
|
+
}
|
|
161
252
|
const nextSources = {
|
|
162
253
|
...slotSources,
|
|
163
254
|
[sourceKey]: content
|