@almadar/ui 4.0.1 → 4.1.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/avl/index.cjs +208 -132
- package/dist/avl/index.js +208 -132
- package/dist/components/index.cjs +204 -100
- package/dist/components/index.js +204 -100
- package/dist/context/index.cjs +204 -100
- package/dist/context/index.js +204 -100
- package/dist/hooks/index.cjs +204 -100
- package/dist/hooks/index.js +204 -100
- package/dist/hooks/useUISlots.d.ts +22 -5
- package/dist/runtime/index.cjs +29 -29
- package/dist/runtime/index.js +29 -29
- package/package.json +1 -1
package/dist/context/index.js
CHANGED
|
@@ -1,30 +1,76 @@
|
|
|
1
1
|
import { createContext, useMemo, useContext, useState, useEffect, useCallback, useRef } from 'react';
|
|
2
2
|
import { jsx } from 'react/jsx-runtime';
|
|
3
3
|
|
|
4
|
-
var
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"hud-
|
|
15
|
-
"hud-
|
|
16
|
-
|
|
17
|
-
|
|
4
|
+
var DEFAULT_SOURCE_KEY = "__default__";
|
|
5
|
+
var MULTI_SOURCE_STACK_TRAIT = "__multi_source_stack__";
|
|
6
|
+
var ALL_SLOTS = [
|
|
7
|
+
"main",
|
|
8
|
+
"sidebar",
|
|
9
|
+
"modal",
|
|
10
|
+
"drawer",
|
|
11
|
+
"overlay",
|
|
12
|
+
"center",
|
|
13
|
+
"toast",
|
|
14
|
+
"hud-top",
|
|
15
|
+
"hud-bottom",
|
|
16
|
+
"hud-left",
|
|
17
|
+
"hud-right",
|
|
18
|
+
"floating"
|
|
19
|
+
];
|
|
20
|
+
var DEFAULT_SLOTS = ALL_SLOTS.reduce(
|
|
21
|
+
(acc, slot) => {
|
|
22
|
+
acc[slot] = null;
|
|
23
|
+
return acc;
|
|
24
|
+
},
|
|
25
|
+
{}
|
|
26
|
+
);
|
|
27
|
+
var DEFAULT_SOURCES = ALL_SLOTS.reduce(
|
|
28
|
+
(acc, slot) => {
|
|
29
|
+
acc[slot] = {};
|
|
30
|
+
return acc;
|
|
31
|
+
},
|
|
32
|
+
{}
|
|
33
|
+
);
|
|
18
34
|
var idCounter = 0;
|
|
19
35
|
function generateId() {
|
|
20
36
|
return `slot-content-${++idCounter}-${Date.now()}`;
|
|
21
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
|
+
}
|
|
22
61
|
function useUISlotManager() {
|
|
23
|
-
const [
|
|
62
|
+
const [sources, setSources] = useState(DEFAULT_SOURCES);
|
|
24
63
|
const subscribersRef = useRef(/* @__PURE__ */ new Set());
|
|
25
64
|
const timersRef = useRef(/* @__PURE__ */ new Map());
|
|
26
65
|
const traitIndexRef = useRef(/* @__PURE__ */ new Map());
|
|
27
66
|
const traitSubscribersRef = useRef(/* @__PURE__ */ new Map());
|
|
67
|
+
const slots = 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]);
|
|
28
74
|
useEffect(() => {
|
|
29
75
|
return () => {
|
|
30
76
|
timersRef.current.forEach((timer) => clearTimeout(timer));
|
|
@@ -63,103 +109,160 @@ function useUISlotManager() {
|
|
|
63
109
|
const unindexTrait = useCallback((traitName) => {
|
|
64
110
|
traitIndexRef.current.delete(traitName);
|
|
65
111
|
}, []);
|
|
66
|
-
const render = useCallback(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
);
|
|
98
|
-
return prev;
|
|
99
|
-
}
|
|
100
|
-
if (content.sourceTrait) {
|
|
101
|
-
indexTraitRender(content.sourceTrait, content);
|
|
102
|
-
notifyTraitSubscribers(content.sourceTrait, content);
|
|
112
|
+
const render = useCallback(
|
|
113
|
+
(config) => {
|
|
114
|
+
const id = generateId();
|
|
115
|
+
const sourceKey = config.sourceTrait ?? DEFAULT_SOURCE_KEY;
|
|
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
|
+
};
|
|
125
|
+
if (config.autoDismissMs && config.autoDismissMs > 0) {
|
|
126
|
+
content.autoDismissAt = Date.now() + config.autoDismissMs;
|
|
127
|
+
const timer = setTimeout(() => {
|
|
128
|
+
setSources((prev) => {
|
|
129
|
+
const slotSources = prev[config.target];
|
|
130
|
+
if (slotSources && slotSources[sourceKey]?.id === id) {
|
|
131
|
+
content.onDismiss?.();
|
|
132
|
+
const next = { ...slotSources };
|
|
133
|
+
delete next[sourceKey];
|
|
134
|
+
const updated = { ...prev, [config.target]: next };
|
|
135
|
+
notifySubscribers(config.target, aggregateSlot(next));
|
|
136
|
+
return updated;
|
|
137
|
+
}
|
|
138
|
+
return prev;
|
|
139
|
+
});
|
|
140
|
+
timersRef.current.delete(id);
|
|
141
|
+
}, config.autoDismissMs);
|
|
142
|
+
timersRef.current.set(id, timer);
|
|
103
143
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
if (content) {
|
|
113
|
-
const timer = timersRef.current.get(content.id);
|
|
114
|
-
if (timer) {
|
|
115
|
-
clearTimeout(timer);
|
|
116
|
-
timersRef.current.delete(content.id);
|
|
144
|
+
setSources((prev) => {
|
|
145
|
+
const slotSources = prev[config.target] ?? {};
|
|
146
|
+
const existing = slotSources[sourceKey];
|
|
147
|
+
if (existing && existing.priority > content.priority) {
|
|
148
|
+
console.warn(
|
|
149
|
+
`[UISlots] Slot "${config.target}" source "${sourceKey}" already has higher priority content (${existing.priority} > ${content.priority})`
|
|
150
|
+
);
|
|
151
|
+
return prev;
|
|
117
152
|
}
|
|
118
|
-
|
|
153
|
+
const nextSources = {
|
|
154
|
+
...slotSources,
|
|
155
|
+
[sourceKey]: content
|
|
156
|
+
};
|
|
157
|
+
const nextAll = { ...prev, [config.target]: nextSources };
|
|
119
158
|
if (content.sourceTrait) {
|
|
120
|
-
|
|
121
|
-
notifyTraitSubscribers(content.sourceTrait,
|
|
159
|
+
indexTraitRender(content.sourceTrait, content);
|
|
160
|
+
notifyTraitSubscribers(content.sourceTrait, content);
|
|
161
|
+
}
|
|
162
|
+
notifySubscribers(config.target, aggregateSlot(nextSources));
|
|
163
|
+
return nextAll;
|
|
164
|
+
});
|
|
165
|
+
return id;
|
|
166
|
+
},
|
|
167
|
+
[notifySubscribers, notifyTraitSubscribers, indexTraitRender]
|
|
168
|
+
);
|
|
169
|
+
const clear = useCallback(
|
|
170
|
+
(slot) => {
|
|
171
|
+
setSources((prev) => {
|
|
172
|
+
const slotSources = prev[slot];
|
|
173
|
+
if (!slotSources || Object.keys(slotSources).length === 0) {
|
|
174
|
+
return prev;
|
|
175
|
+
}
|
|
176
|
+
for (const content of Object.values(slotSources)) {
|
|
177
|
+
const timer = timersRef.current.get(content.id);
|
|
178
|
+
if (timer) {
|
|
179
|
+
clearTimeout(timer);
|
|
180
|
+
timersRef.current.delete(content.id);
|
|
181
|
+
}
|
|
182
|
+
content.onDismiss?.();
|
|
183
|
+
if (content.sourceTrait) {
|
|
184
|
+
unindexTrait(content.sourceTrait);
|
|
185
|
+
notifyTraitSubscribers(content.sourceTrait, null);
|
|
186
|
+
}
|
|
122
187
|
}
|
|
123
188
|
notifySubscribers(slot, null);
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const
|
|
189
|
+
return { ...prev, [slot]: {} };
|
|
190
|
+
});
|
|
191
|
+
},
|
|
192
|
+
[notifySubscribers, notifyTraitSubscribers, unindexTrait]
|
|
193
|
+
);
|
|
194
|
+
const clearBySource = useCallback(
|
|
195
|
+
(slot, sourceTrait) => {
|
|
196
|
+
const sourceKey = sourceTrait;
|
|
197
|
+
setSources((prev) => {
|
|
198
|
+
const slotSources = prev[slot];
|
|
199
|
+
if (!slotSources || !(sourceKey in slotSources)) return prev;
|
|
200
|
+
const content = slotSources[sourceKey];
|
|
201
|
+
const timer = timersRef.current.get(content.id);
|
|
134
202
|
if (timer) {
|
|
135
203
|
clearTimeout(timer);
|
|
136
|
-
timersRef.current.delete(id);
|
|
204
|
+
timersRef.current.delete(content.id);
|
|
137
205
|
}
|
|
138
206
|
content.onDismiss?.();
|
|
139
207
|
if (content.sourceTrait) {
|
|
140
208
|
unindexTrait(content.sourceTrait);
|
|
141
209
|
notifyTraitSubscribers(content.sourceTrait, null);
|
|
142
210
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
211
|
+
const nextSources = { ...slotSources };
|
|
212
|
+
delete nextSources[sourceKey];
|
|
213
|
+
notifySubscribers(slot, aggregateSlot(nextSources));
|
|
214
|
+
return { ...prev, [slot]: nextSources };
|
|
215
|
+
});
|
|
216
|
+
},
|
|
217
|
+
[notifySubscribers, notifyTraitSubscribers, unindexTrait]
|
|
218
|
+
);
|
|
219
|
+
const clearById = useCallback(
|
|
220
|
+
(id) => {
|
|
221
|
+
setSources((prev) => {
|
|
222
|
+
for (const slot of ALL_SLOTS) {
|
|
223
|
+
const slotSources = prev[slot];
|
|
224
|
+
if (!slotSources) continue;
|
|
225
|
+
const matchKey = Object.keys(slotSources).find(
|
|
226
|
+
(k) => slotSources[k].id === id
|
|
227
|
+
);
|
|
228
|
+
if (!matchKey) continue;
|
|
229
|
+
const content = slotSources[matchKey];
|
|
230
|
+
const timer = timersRef.current.get(id);
|
|
231
|
+
if (timer) {
|
|
232
|
+
clearTimeout(timer);
|
|
233
|
+
timersRef.current.delete(id);
|
|
234
|
+
}
|
|
235
|
+
content.onDismiss?.();
|
|
236
|
+
if (content.sourceTrait) {
|
|
237
|
+
unindexTrait(content.sourceTrait);
|
|
238
|
+
notifyTraitSubscribers(content.sourceTrait, null);
|
|
239
|
+
}
|
|
240
|
+
const nextSources = { ...slotSources };
|
|
241
|
+
delete nextSources[matchKey];
|
|
242
|
+
notifySubscribers(slot, aggregateSlot(nextSources));
|
|
243
|
+
return { ...prev, [slot]: nextSources };
|
|
244
|
+
}
|
|
245
|
+
return prev;
|
|
246
|
+
});
|
|
247
|
+
},
|
|
248
|
+
[notifySubscribers, notifyTraitSubscribers, unindexTrait]
|
|
249
|
+
);
|
|
149
250
|
const clearAll = useCallback(() => {
|
|
150
251
|
timersRef.current.forEach((timer) => clearTimeout(timer));
|
|
151
252
|
timersRef.current.clear();
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
253
|
+
setSources((prev) => {
|
|
254
|
+
for (const slot of ALL_SLOTS) {
|
|
255
|
+
const slotSources = prev[slot];
|
|
256
|
+
if (!slotSources) continue;
|
|
257
|
+
for (const content of Object.values(slotSources)) {
|
|
155
258
|
content.onDismiss?.();
|
|
156
259
|
if (content.sourceTrait) {
|
|
157
260
|
notifyTraitSubscribers(content.sourceTrait, null);
|
|
158
261
|
}
|
|
159
|
-
notifySubscribers(slot, null);
|
|
160
262
|
}
|
|
161
|
-
|
|
162
|
-
|
|
263
|
+
notifySubscribers(slot, null);
|
|
264
|
+
}
|
|
265
|
+
return DEFAULT_SOURCES;
|
|
163
266
|
});
|
|
164
267
|
traitIndexRef.current.clear();
|
|
165
268
|
}, [notifySubscribers, notifyTraitSubscribers]);
|
|
@@ -169,16 +272,16 @@ function useUISlotManager() {
|
|
|
169
272
|
subscribersRef.current.delete(callback);
|
|
170
273
|
};
|
|
171
274
|
}, []);
|
|
172
|
-
const hasContent = useCallback(
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
275
|
+
const hasContent = useCallback(
|
|
276
|
+
(slot) => slots[slot] !== null,
|
|
277
|
+
[slots]
|
|
278
|
+
);
|
|
279
|
+
const getContent = useCallback(
|
|
280
|
+
(slot) => slots[slot],
|
|
281
|
+
[slots]
|
|
282
|
+
);
|
|
178
283
|
const getTraitContent = useCallback(
|
|
179
|
-
(traitName) =>
|
|
180
|
-
return traitIndexRef.current.get(traitName) ?? null;
|
|
181
|
-
},
|
|
284
|
+
(traitName) => traitIndexRef.current.get(traitName) ?? null,
|
|
182
285
|
[]
|
|
183
286
|
);
|
|
184
287
|
const subscribeTrait = useCallback(
|
|
@@ -204,6 +307,7 @@ function useUISlotManager() {
|
|
|
204
307
|
slots,
|
|
205
308
|
render,
|
|
206
309
|
clear,
|
|
310
|
+
clearBySource,
|
|
207
311
|
clearById,
|
|
208
312
|
clearAll,
|
|
209
313
|
subscribe,
|