@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/hooks/index.js
CHANGED
|
@@ -1014,30 +1014,76 @@ function useEmitEvent() {
|
|
|
1014
1014
|
[eventBus]
|
|
1015
1015
|
);
|
|
1016
1016
|
}
|
|
1017
|
-
var
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
"
|
|
1026
|
-
"
|
|
1027
|
-
"hud-
|
|
1028
|
-
"hud-
|
|
1029
|
-
|
|
1030
|
-
|
|
1017
|
+
var DEFAULT_SOURCE_KEY = "__default__";
|
|
1018
|
+
var MULTI_SOURCE_STACK_TRAIT = "__multi_source_stack__";
|
|
1019
|
+
var ALL_SLOTS = [
|
|
1020
|
+
"main",
|
|
1021
|
+
"sidebar",
|
|
1022
|
+
"modal",
|
|
1023
|
+
"drawer",
|
|
1024
|
+
"overlay",
|
|
1025
|
+
"center",
|
|
1026
|
+
"toast",
|
|
1027
|
+
"hud-top",
|
|
1028
|
+
"hud-bottom",
|
|
1029
|
+
"hud-left",
|
|
1030
|
+
"hud-right",
|
|
1031
|
+
"floating"
|
|
1032
|
+
];
|
|
1033
|
+
var DEFAULT_SLOTS = ALL_SLOTS.reduce(
|
|
1034
|
+
(acc, slot) => {
|
|
1035
|
+
acc[slot] = null;
|
|
1036
|
+
return acc;
|
|
1037
|
+
},
|
|
1038
|
+
{}
|
|
1039
|
+
);
|
|
1040
|
+
var DEFAULT_SOURCES = ALL_SLOTS.reduce(
|
|
1041
|
+
(acc, slot) => {
|
|
1042
|
+
acc[slot] = {};
|
|
1043
|
+
return acc;
|
|
1044
|
+
},
|
|
1045
|
+
{}
|
|
1046
|
+
);
|
|
1031
1047
|
var idCounter = 0;
|
|
1032
1048
|
function generateId() {
|
|
1033
1049
|
return `slot-content-${++idCounter}-${Date.now()}`;
|
|
1034
1050
|
}
|
|
1051
|
+
function aggregateSlot(sources) {
|
|
1052
|
+
if (!sources) return null;
|
|
1053
|
+
const entries = Object.entries(sources);
|
|
1054
|
+
if (entries.length === 0) return null;
|
|
1055
|
+
if (entries.length === 1) return entries[0][1];
|
|
1056
|
+
const children = entries.map(([, entry]) => ({
|
|
1057
|
+
type: entry.pattern,
|
|
1058
|
+
...entry.props
|
|
1059
|
+
}));
|
|
1060
|
+
const stackId = `slot-content-stack-${entries.map(([k]) => k).join("-")}`;
|
|
1061
|
+
return {
|
|
1062
|
+
id: stackId,
|
|
1063
|
+
pattern: "stack",
|
|
1064
|
+
props: {
|
|
1065
|
+
direction: "vertical",
|
|
1066
|
+
gap: "lg",
|
|
1067
|
+
children
|
|
1068
|
+
},
|
|
1069
|
+
priority: 0,
|
|
1070
|
+
animation: "fade",
|
|
1071
|
+
sourceTrait: MULTI_SOURCE_STACK_TRAIT
|
|
1072
|
+
};
|
|
1073
|
+
}
|
|
1035
1074
|
function useUISlotManager() {
|
|
1036
|
-
const [
|
|
1075
|
+
const [sources, setSources] = useState(DEFAULT_SOURCES);
|
|
1037
1076
|
const subscribersRef = useRef(/* @__PURE__ */ new Set());
|
|
1038
1077
|
const timersRef = useRef(/* @__PURE__ */ new Map());
|
|
1039
1078
|
const traitIndexRef = useRef(/* @__PURE__ */ new Map());
|
|
1040
1079
|
const traitSubscribersRef = useRef(/* @__PURE__ */ new Map());
|
|
1080
|
+
const slots = useMemo(() => {
|
|
1081
|
+
const out = { ...DEFAULT_SLOTS };
|
|
1082
|
+
for (const slot of ALL_SLOTS) {
|
|
1083
|
+
out[slot] = aggregateSlot(sources[slot]);
|
|
1084
|
+
}
|
|
1085
|
+
return out;
|
|
1086
|
+
}, [sources]);
|
|
1041
1087
|
useEffect(() => {
|
|
1042
1088
|
return () => {
|
|
1043
1089
|
timersRef.current.forEach((timer) => clearTimeout(timer));
|
|
@@ -1076,103 +1122,160 @@ function useUISlotManager() {
|
|
|
1076
1122
|
const unindexTrait = useCallback((traitName) => {
|
|
1077
1123
|
traitIndexRef.current.delete(traitName);
|
|
1078
1124
|
}, []);
|
|
1079
|
-
const render = useCallback(
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
);
|
|
1111
|
-
return prev;
|
|
1112
|
-
}
|
|
1113
|
-
if (content.sourceTrait) {
|
|
1114
|
-
indexTraitRender(content.sourceTrait, content);
|
|
1115
|
-
notifyTraitSubscribers(content.sourceTrait, content);
|
|
1125
|
+
const render = useCallback(
|
|
1126
|
+
(config) => {
|
|
1127
|
+
const id = generateId();
|
|
1128
|
+
const sourceKey = config.sourceTrait ?? DEFAULT_SOURCE_KEY;
|
|
1129
|
+
const content = {
|
|
1130
|
+
id,
|
|
1131
|
+
pattern: config.pattern,
|
|
1132
|
+
props: config.props ?? {},
|
|
1133
|
+
priority: config.priority ?? 0,
|
|
1134
|
+
animation: config.animation ?? "fade",
|
|
1135
|
+
onDismiss: config.onDismiss,
|
|
1136
|
+
sourceTrait: config.sourceTrait
|
|
1137
|
+
};
|
|
1138
|
+
if (config.autoDismissMs && config.autoDismissMs > 0) {
|
|
1139
|
+
content.autoDismissAt = Date.now() + config.autoDismissMs;
|
|
1140
|
+
const timer = setTimeout(() => {
|
|
1141
|
+
setSources((prev) => {
|
|
1142
|
+
const slotSources = prev[config.target];
|
|
1143
|
+
if (slotSources && slotSources[sourceKey]?.id === id) {
|
|
1144
|
+
content.onDismiss?.();
|
|
1145
|
+
const next = { ...slotSources };
|
|
1146
|
+
delete next[sourceKey];
|
|
1147
|
+
const updated = { ...prev, [config.target]: next };
|
|
1148
|
+
notifySubscribers(config.target, aggregateSlot(next));
|
|
1149
|
+
return updated;
|
|
1150
|
+
}
|
|
1151
|
+
return prev;
|
|
1152
|
+
});
|
|
1153
|
+
timersRef.current.delete(id);
|
|
1154
|
+
}, config.autoDismissMs);
|
|
1155
|
+
timersRef.current.set(id, timer);
|
|
1116
1156
|
}
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
if (content) {
|
|
1126
|
-
const timer = timersRef.current.get(content.id);
|
|
1127
|
-
if (timer) {
|
|
1128
|
-
clearTimeout(timer);
|
|
1129
|
-
timersRef.current.delete(content.id);
|
|
1157
|
+
setSources((prev) => {
|
|
1158
|
+
const slotSources = prev[config.target] ?? {};
|
|
1159
|
+
const existing = slotSources[sourceKey];
|
|
1160
|
+
if (existing && existing.priority > content.priority) {
|
|
1161
|
+
console.warn(
|
|
1162
|
+
`[UISlots] Slot "${config.target}" source "${sourceKey}" already has higher priority content (${existing.priority} > ${content.priority})`
|
|
1163
|
+
);
|
|
1164
|
+
return prev;
|
|
1130
1165
|
}
|
|
1131
|
-
|
|
1166
|
+
const nextSources = {
|
|
1167
|
+
...slotSources,
|
|
1168
|
+
[sourceKey]: content
|
|
1169
|
+
};
|
|
1170
|
+
const nextAll = { ...prev, [config.target]: nextSources };
|
|
1132
1171
|
if (content.sourceTrait) {
|
|
1133
|
-
|
|
1134
|
-
notifyTraitSubscribers(content.sourceTrait,
|
|
1172
|
+
indexTraitRender(content.sourceTrait, content);
|
|
1173
|
+
notifyTraitSubscribers(content.sourceTrait, content);
|
|
1174
|
+
}
|
|
1175
|
+
notifySubscribers(config.target, aggregateSlot(nextSources));
|
|
1176
|
+
return nextAll;
|
|
1177
|
+
});
|
|
1178
|
+
return id;
|
|
1179
|
+
},
|
|
1180
|
+
[notifySubscribers, notifyTraitSubscribers, indexTraitRender]
|
|
1181
|
+
);
|
|
1182
|
+
const clear = useCallback(
|
|
1183
|
+
(slot) => {
|
|
1184
|
+
setSources((prev) => {
|
|
1185
|
+
const slotSources = prev[slot];
|
|
1186
|
+
if (!slotSources || Object.keys(slotSources).length === 0) {
|
|
1187
|
+
return prev;
|
|
1188
|
+
}
|
|
1189
|
+
for (const content of Object.values(slotSources)) {
|
|
1190
|
+
const timer = timersRef.current.get(content.id);
|
|
1191
|
+
if (timer) {
|
|
1192
|
+
clearTimeout(timer);
|
|
1193
|
+
timersRef.current.delete(content.id);
|
|
1194
|
+
}
|
|
1195
|
+
content.onDismiss?.();
|
|
1196
|
+
if (content.sourceTrait) {
|
|
1197
|
+
unindexTrait(content.sourceTrait);
|
|
1198
|
+
notifyTraitSubscribers(content.sourceTrait, null);
|
|
1199
|
+
}
|
|
1135
1200
|
}
|
|
1136
1201
|
notifySubscribers(slot, null);
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
}
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
const
|
|
1202
|
+
return { ...prev, [slot]: {} };
|
|
1203
|
+
});
|
|
1204
|
+
},
|
|
1205
|
+
[notifySubscribers, notifyTraitSubscribers, unindexTrait]
|
|
1206
|
+
);
|
|
1207
|
+
const clearBySource = useCallback(
|
|
1208
|
+
(slot, sourceTrait) => {
|
|
1209
|
+
const sourceKey = sourceTrait;
|
|
1210
|
+
setSources((prev) => {
|
|
1211
|
+
const slotSources = prev[slot];
|
|
1212
|
+
if (!slotSources || !(sourceKey in slotSources)) return prev;
|
|
1213
|
+
const content = slotSources[sourceKey];
|
|
1214
|
+
const timer = timersRef.current.get(content.id);
|
|
1147
1215
|
if (timer) {
|
|
1148
1216
|
clearTimeout(timer);
|
|
1149
|
-
timersRef.current.delete(id);
|
|
1217
|
+
timersRef.current.delete(content.id);
|
|
1150
1218
|
}
|
|
1151
1219
|
content.onDismiss?.();
|
|
1152
1220
|
if (content.sourceTrait) {
|
|
1153
1221
|
unindexTrait(content.sourceTrait);
|
|
1154
1222
|
notifyTraitSubscribers(content.sourceTrait, null);
|
|
1155
1223
|
}
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1224
|
+
const nextSources = { ...slotSources };
|
|
1225
|
+
delete nextSources[sourceKey];
|
|
1226
|
+
notifySubscribers(slot, aggregateSlot(nextSources));
|
|
1227
|
+
return { ...prev, [slot]: nextSources };
|
|
1228
|
+
});
|
|
1229
|
+
},
|
|
1230
|
+
[notifySubscribers, notifyTraitSubscribers, unindexTrait]
|
|
1231
|
+
);
|
|
1232
|
+
const clearById = useCallback(
|
|
1233
|
+
(id) => {
|
|
1234
|
+
setSources((prev) => {
|
|
1235
|
+
for (const slot of ALL_SLOTS) {
|
|
1236
|
+
const slotSources = prev[slot];
|
|
1237
|
+
if (!slotSources) continue;
|
|
1238
|
+
const matchKey = Object.keys(slotSources).find(
|
|
1239
|
+
(k) => slotSources[k].id === id
|
|
1240
|
+
);
|
|
1241
|
+
if (!matchKey) continue;
|
|
1242
|
+
const content = slotSources[matchKey];
|
|
1243
|
+
const timer = timersRef.current.get(id);
|
|
1244
|
+
if (timer) {
|
|
1245
|
+
clearTimeout(timer);
|
|
1246
|
+
timersRef.current.delete(id);
|
|
1247
|
+
}
|
|
1248
|
+
content.onDismiss?.();
|
|
1249
|
+
if (content.sourceTrait) {
|
|
1250
|
+
unindexTrait(content.sourceTrait);
|
|
1251
|
+
notifyTraitSubscribers(content.sourceTrait, null);
|
|
1252
|
+
}
|
|
1253
|
+
const nextSources = { ...slotSources };
|
|
1254
|
+
delete nextSources[matchKey];
|
|
1255
|
+
notifySubscribers(slot, aggregateSlot(nextSources));
|
|
1256
|
+
return { ...prev, [slot]: nextSources };
|
|
1257
|
+
}
|
|
1258
|
+
return prev;
|
|
1259
|
+
});
|
|
1260
|
+
},
|
|
1261
|
+
[notifySubscribers, notifyTraitSubscribers, unindexTrait]
|
|
1262
|
+
);
|
|
1162
1263
|
const clearAll = useCallback(() => {
|
|
1163
1264
|
timersRef.current.forEach((timer) => clearTimeout(timer));
|
|
1164
1265
|
timersRef.current.clear();
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1266
|
+
setSources((prev) => {
|
|
1267
|
+
for (const slot of ALL_SLOTS) {
|
|
1268
|
+
const slotSources = prev[slot];
|
|
1269
|
+
if (!slotSources) continue;
|
|
1270
|
+
for (const content of Object.values(slotSources)) {
|
|
1168
1271
|
content.onDismiss?.();
|
|
1169
1272
|
if (content.sourceTrait) {
|
|
1170
1273
|
notifyTraitSubscribers(content.sourceTrait, null);
|
|
1171
1274
|
}
|
|
1172
|
-
notifySubscribers(slot, null);
|
|
1173
1275
|
}
|
|
1174
|
-
|
|
1175
|
-
|
|
1276
|
+
notifySubscribers(slot, null);
|
|
1277
|
+
}
|
|
1278
|
+
return DEFAULT_SOURCES;
|
|
1176
1279
|
});
|
|
1177
1280
|
traitIndexRef.current.clear();
|
|
1178
1281
|
}, [notifySubscribers, notifyTraitSubscribers]);
|
|
@@ -1182,16 +1285,16 @@ function useUISlotManager() {
|
|
|
1182
1285
|
subscribersRef.current.delete(callback);
|
|
1183
1286
|
};
|
|
1184
1287
|
}, []);
|
|
1185
|
-
const hasContent = useCallback(
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1288
|
+
const hasContent = useCallback(
|
|
1289
|
+
(slot) => slots[slot] !== null,
|
|
1290
|
+
[slots]
|
|
1291
|
+
);
|
|
1292
|
+
const getContent = useCallback(
|
|
1293
|
+
(slot) => slots[slot],
|
|
1294
|
+
[slots]
|
|
1295
|
+
);
|
|
1191
1296
|
const getTraitContent = useCallback(
|
|
1192
|
-
(traitName) =>
|
|
1193
|
-
return traitIndexRef.current.get(traitName) ?? null;
|
|
1194
|
-
},
|
|
1297
|
+
(traitName) => traitIndexRef.current.get(traitName) ?? null,
|
|
1195
1298
|
[]
|
|
1196
1299
|
);
|
|
1197
1300
|
const subscribeTrait = useCallback(
|
|
@@ -1217,6 +1320,7 @@ function useUISlotManager() {
|
|
|
1217
1320
|
slots,
|
|
1218
1321
|
render,
|
|
1219
1322
|
clear,
|
|
1323
|
+
clearBySource,
|
|
1220
1324
|
clearById,
|
|
1221
1325
|
clearAll,
|
|
1222
1326
|
subscribe: subscribe2,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { EventPayload } from '@almadar/core';
|
|
1
2
|
/**
|
|
2
3
|
* Valid UI slot names
|
|
3
4
|
*/
|
|
@@ -6,6 +7,14 @@ export type UISlot = 'main' | 'sidebar' | 'modal' | 'drawer' | 'overlay' | 'cent
|
|
|
6
7
|
* Animation types for slot transitions
|
|
7
8
|
*/
|
|
8
9
|
export type SlotAnimation = 'fade' | 'slide' | 'scale' | 'none';
|
|
10
|
+
/**
|
|
11
|
+
* Pattern-specific props carried by a rendered slot. Pattern authors decide
|
|
12
|
+
* the concrete shape; the slot manager treats this as an opaque record of
|
|
13
|
+
* field-like values sourced from the event-bus payload vocabulary so the
|
|
14
|
+
* same types round-trip through render-ui → useUISlots → UISlotRenderer
|
|
15
|
+
* without a private re-coercion boundary.
|
|
16
|
+
*/
|
|
17
|
+
export type SlotProps = Record<string, EventPayload[string] | unknown>;
|
|
9
18
|
/**
|
|
10
19
|
* Content rendered in a slot
|
|
11
20
|
*/
|
|
@@ -15,7 +24,7 @@ export interface SlotContent {
|
|
|
15
24
|
/** Pattern/component type to render */
|
|
16
25
|
pattern: string;
|
|
17
26
|
/** Props to pass to the pattern component */
|
|
18
|
-
props:
|
|
27
|
+
props: SlotProps;
|
|
19
28
|
/** Priority for conflict resolution (higher wins) */
|
|
20
29
|
priority: number;
|
|
21
30
|
/** Animation for showing/hiding */
|
|
@@ -38,7 +47,7 @@ export interface RenderUIConfig {
|
|
|
38
47
|
/** Pattern/component to render */
|
|
39
48
|
pattern: string;
|
|
40
49
|
/** Props for the pattern */
|
|
41
|
-
props?:
|
|
50
|
+
props?: SlotProps;
|
|
42
51
|
/** Priority (default: 0) */
|
|
43
52
|
priority?: number;
|
|
44
53
|
/** Animation type */
|
|
@@ -68,12 +77,20 @@ export type TraitChangeCallback = (content: SlotContent | null) => void;
|
|
|
68
77
|
* UI Slot Manager interface
|
|
69
78
|
*/
|
|
70
79
|
export interface UISlotManager {
|
|
71
|
-
/**
|
|
80
|
+
/**
|
|
81
|
+
* Current aggregate content for each slot. Single-source slots hold
|
|
82
|
+
* that source's SlotContent; multi-source slots hold a synthetic
|
|
83
|
+
* `stack` wrapper whose `children` prop is the list of per-source
|
|
84
|
+
* pattern configs in insertion order. Single consumers can continue
|
|
85
|
+
* to read `slots[slot]` without knowing the slot is multi-source.
|
|
86
|
+
*/
|
|
72
87
|
slots: Record<UISlot, SlotContent | null>;
|
|
73
88
|
/** Render content to a slot */
|
|
74
89
|
render: (config: RenderUIConfig) => string;
|
|
75
|
-
/** Clear a
|
|
90
|
+
/** Clear all source entries from a slot */
|
|
76
91
|
clear: (slot: UISlot) => void;
|
|
92
|
+
/** Clear a single source's contribution from a slot, keeping others */
|
|
93
|
+
clearBySource: (slot: UISlot, sourceTrait: string) => void;
|
|
77
94
|
/** Clear content by ID */
|
|
78
95
|
clearById: (id: string) => void;
|
|
79
96
|
/** Clear all slots */
|
|
@@ -82,7 +99,7 @@ export interface UISlotManager {
|
|
|
82
99
|
subscribe: (callback: SlotChangeCallback) => () => void;
|
|
83
100
|
/** Check if a slot has content */
|
|
84
101
|
hasContent: (slot: UISlot) => boolean;
|
|
85
|
-
/** Get content for a slot */
|
|
102
|
+
/** Get aggregated content for a slot (single or synthetic stack) */
|
|
86
103
|
getContent: (slot: UISlot) => SlotContent | null;
|
|
87
104
|
/**
|
|
88
105
|
* Look up the most recent `render-ui` output a given trait produced,
|
package/dist/runtime/index.cjs
CHANGED
|
@@ -37828,6 +37828,34 @@ var init_UISlotRenderer = __esm({
|
|
|
37828
37828
|
|
|
37829
37829
|
// hooks/index.ts
|
|
37830
37830
|
init_useEventBus();
|
|
37831
|
+
var ALL_SLOTS = [
|
|
37832
|
+
"main",
|
|
37833
|
+
"sidebar",
|
|
37834
|
+
"modal",
|
|
37835
|
+
"drawer",
|
|
37836
|
+
"overlay",
|
|
37837
|
+
"center",
|
|
37838
|
+
"toast",
|
|
37839
|
+
"hud-top",
|
|
37840
|
+
"hud-bottom",
|
|
37841
|
+
"hud-left",
|
|
37842
|
+
"hud-right",
|
|
37843
|
+
"floating"
|
|
37844
|
+
];
|
|
37845
|
+
ALL_SLOTS.reduce(
|
|
37846
|
+
(acc, slot) => {
|
|
37847
|
+
acc[slot] = null;
|
|
37848
|
+
return acc;
|
|
37849
|
+
},
|
|
37850
|
+
{}
|
|
37851
|
+
);
|
|
37852
|
+
ALL_SLOTS.reduce(
|
|
37853
|
+
(acc, slot) => {
|
|
37854
|
+
acc[slot] = {};
|
|
37855
|
+
return acc;
|
|
37856
|
+
},
|
|
37857
|
+
{}
|
|
37858
|
+
);
|
|
37831
37859
|
|
|
37832
37860
|
// hooks/useUIEvents.ts
|
|
37833
37861
|
init_useEventBus();
|
|
@@ -38870,13 +38898,11 @@ function SlotBridge() {
|
|
|
38870
38898
|
return null;
|
|
38871
38899
|
}
|
|
38872
38900
|
function applyServerEffects(effects, uiSlots, onNavigate) {
|
|
38873
|
-
const perSlotRenders = /* @__PURE__ */ new Map();
|
|
38874
38901
|
for (const eff of effects) {
|
|
38875
38902
|
if (eff.type === "render-ui" && eff.slot && eff.pattern) {
|
|
38876
38903
|
const patternRecord = eff.pattern;
|
|
38877
38904
|
const { type: patternType, children, ...inlineProps } = patternRecord;
|
|
38878
38905
|
const normalizedChildren = Array.isArray(children) ? children.map((c) => normalizeChild(c)) : children;
|
|
38879
|
-
const sourceTrait = eff.traitName ?? "server";
|
|
38880
38906
|
uiSlots.render({
|
|
38881
38907
|
target: eff.slot,
|
|
38882
38908
|
pattern: patternType,
|
|
@@ -38884,38 +38910,12 @@ function applyServerEffects(effects, uiSlots, onNavigate) {
|
|
|
38884
38910
|
...inlineProps,
|
|
38885
38911
|
...normalizedChildren !== void 0 ? { children: normalizedChildren } : {}
|
|
38886
38912
|
},
|
|
38887
|
-
sourceTrait
|
|
38913
|
+
sourceTrait: eff.traitName ?? "server"
|
|
38888
38914
|
});
|
|
38889
|
-
const bucket = perSlotRenders.get(eff.slot) ?? [];
|
|
38890
|
-
bucket.push({
|
|
38891
|
-
sourceTrait,
|
|
38892
|
-
pattern: {
|
|
38893
|
-
type: patternType,
|
|
38894
|
-
...inlineProps,
|
|
38895
|
-
...normalizedChildren !== void 0 ? { children: normalizedChildren } : {}
|
|
38896
|
-
}
|
|
38897
|
-
});
|
|
38898
|
-
perSlotRenders.set(eff.slot, bucket);
|
|
38899
38915
|
} else if (eff.type === "navigate" && eff.route && onNavigate) {
|
|
38900
38916
|
onNavigate(eff.route, eff.params);
|
|
38901
38917
|
}
|
|
38902
38918
|
}
|
|
38903
|
-
for (const [slot, bucket] of perSlotRenders) {
|
|
38904
|
-
const distinctSources = new Set(bucket.map((b) => b.sourceTrait));
|
|
38905
|
-
if (distinctSources.size <= 1) continue;
|
|
38906
|
-
uiSlots.render({
|
|
38907
|
-
target: slot,
|
|
38908
|
-
pattern: "stack",
|
|
38909
|
-
props: {
|
|
38910
|
-
direction: "vertical",
|
|
38911
|
-
gap: "lg",
|
|
38912
|
-
children: bucket.map((b) => b.pattern)
|
|
38913
|
-
},
|
|
38914
|
-
// Use a synthetic wrapper source trait; individual traits' frames
|
|
38915
|
-
// already live in the per-trait index from the per-effect loop.
|
|
38916
|
-
sourceTrait: "__multi_source_stack__"
|
|
38917
|
-
});
|
|
38918
|
-
}
|
|
38919
38919
|
}
|
|
38920
38920
|
function TraitInitializer({ traits: traits2, orbitalNames, onNavigate, onLocalFallback, persistence }) {
|
|
38921
38921
|
const slotsActions = useSlotsActions();
|
package/dist/runtime/index.js
CHANGED
|
@@ -37783,6 +37783,34 @@ var init_UISlotRenderer = __esm({
|
|
|
37783
37783
|
|
|
37784
37784
|
// hooks/index.ts
|
|
37785
37785
|
init_useEventBus();
|
|
37786
|
+
var ALL_SLOTS = [
|
|
37787
|
+
"main",
|
|
37788
|
+
"sidebar",
|
|
37789
|
+
"modal",
|
|
37790
|
+
"drawer",
|
|
37791
|
+
"overlay",
|
|
37792
|
+
"center",
|
|
37793
|
+
"toast",
|
|
37794
|
+
"hud-top",
|
|
37795
|
+
"hud-bottom",
|
|
37796
|
+
"hud-left",
|
|
37797
|
+
"hud-right",
|
|
37798
|
+
"floating"
|
|
37799
|
+
];
|
|
37800
|
+
ALL_SLOTS.reduce(
|
|
37801
|
+
(acc, slot) => {
|
|
37802
|
+
acc[slot] = null;
|
|
37803
|
+
return acc;
|
|
37804
|
+
},
|
|
37805
|
+
{}
|
|
37806
|
+
);
|
|
37807
|
+
ALL_SLOTS.reduce(
|
|
37808
|
+
(acc, slot) => {
|
|
37809
|
+
acc[slot] = {};
|
|
37810
|
+
return acc;
|
|
37811
|
+
},
|
|
37812
|
+
{}
|
|
37813
|
+
);
|
|
37786
37814
|
|
|
37787
37815
|
// hooks/useUIEvents.ts
|
|
37788
37816
|
init_useEventBus();
|
|
@@ -38825,13 +38853,11 @@ function SlotBridge() {
|
|
|
38825
38853
|
return null;
|
|
38826
38854
|
}
|
|
38827
38855
|
function applyServerEffects(effects, uiSlots, onNavigate) {
|
|
38828
|
-
const perSlotRenders = /* @__PURE__ */ new Map();
|
|
38829
38856
|
for (const eff of effects) {
|
|
38830
38857
|
if (eff.type === "render-ui" && eff.slot && eff.pattern) {
|
|
38831
38858
|
const patternRecord = eff.pattern;
|
|
38832
38859
|
const { type: patternType, children, ...inlineProps } = patternRecord;
|
|
38833
38860
|
const normalizedChildren = Array.isArray(children) ? children.map((c) => normalizeChild(c)) : children;
|
|
38834
|
-
const sourceTrait = eff.traitName ?? "server";
|
|
38835
38861
|
uiSlots.render({
|
|
38836
38862
|
target: eff.slot,
|
|
38837
38863
|
pattern: patternType,
|
|
@@ -38839,38 +38865,12 @@ function applyServerEffects(effects, uiSlots, onNavigate) {
|
|
|
38839
38865
|
...inlineProps,
|
|
38840
38866
|
...normalizedChildren !== void 0 ? { children: normalizedChildren } : {}
|
|
38841
38867
|
},
|
|
38842
|
-
sourceTrait
|
|
38868
|
+
sourceTrait: eff.traitName ?? "server"
|
|
38843
38869
|
});
|
|
38844
|
-
const bucket = perSlotRenders.get(eff.slot) ?? [];
|
|
38845
|
-
bucket.push({
|
|
38846
|
-
sourceTrait,
|
|
38847
|
-
pattern: {
|
|
38848
|
-
type: patternType,
|
|
38849
|
-
...inlineProps,
|
|
38850
|
-
...normalizedChildren !== void 0 ? { children: normalizedChildren } : {}
|
|
38851
|
-
}
|
|
38852
|
-
});
|
|
38853
|
-
perSlotRenders.set(eff.slot, bucket);
|
|
38854
38870
|
} else if (eff.type === "navigate" && eff.route && onNavigate) {
|
|
38855
38871
|
onNavigate(eff.route, eff.params);
|
|
38856
38872
|
}
|
|
38857
38873
|
}
|
|
38858
|
-
for (const [slot, bucket] of perSlotRenders) {
|
|
38859
|
-
const distinctSources = new Set(bucket.map((b) => b.sourceTrait));
|
|
38860
|
-
if (distinctSources.size <= 1) continue;
|
|
38861
|
-
uiSlots.render({
|
|
38862
|
-
target: slot,
|
|
38863
|
-
pattern: "stack",
|
|
38864
|
-
props: {
|
|
38865
|
-
direction: "vertical",
|
|
38866
|
-
gap: "lg",
|
|
38867
|
-
children: bucket.map((b) => b.pattern)
|
|
38868
|
-
},
|
|
38869
|
-
// Use a synthetic wrapper source trait; individual traits' frames
|
|
38870
|
-
// already live in the per-trait index from the per-effect loop.
|
|
38871
|
-
sourceTrait: "__multi_source_stack__"
|
|
38872
|
-
});
|
|
38873
|
-
}
|
|
38874
38874
|
}
|
|
38875
38875
|
function TraitInitializer({ traits: traits2, orbitalNames, onNavigate, onLocalFallback, persistence }) {
|
|
38876
38876
|
const slotsActions = useSlotsActions();
|