@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.cjs
CHANGED
|
@@ -1016,30 +1016,76 @@ function useEmitEvent() {
|
|
|
1016
1016
|
[eventBus]
|
|
1017
1017
|
);
|
|
1018
1018
|
}
|
|
1019
|
-
var
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
"
|
|
1028
|
-
"
|
|
1029
|
-
"hud-
|
|
1030
|
-
"hud-
|
|
1031
|
-
|
|
1032
|
-
|
|
1019
|
+
var DEFAULT_SOURCE_KEY = "__default__";
|
|
1020
|
+
var MULTI_SOURCE_STACK_TRAIT = "__multi_source_stack__";
|
|
1021
|
+
var ALL_SLOTS = [
|
|
1022
|
+
"main",
|
|
1023
|
+
"sidebar",
|
|
1024
|
+
"modal",
|
|
1025
|
+
"drawer",
|
|
1026
|
+
"overlay",
|
|
1027
|
+
"center",
|
|
1028
|
+
"toast",
|
|
1029
|
+
"hud-top",
|
|
1030
|
+
"hud-bottom",
|
|
1031
|
+
"hud-left",
|
|
1032
|
+
"hud-right",
|
|
1033
|
+
"floating"
|
|
1034
|
+
];
|
|
1035
|
+
var DEFAULT_SLOTS = ALL_SLOTS.reduce(
|
|
1036
|
+
(acc, slot) => {
|
|
1037
|
+
acc[slot] = null;
|
|
1038
|
+
return acc;
|
|
1039
|
+
},
|
|
1040
|
+
{}
|
|
1041
|
+
);
|
|
1042
|
+
var DEFAULT_SOURCES = ALL_SLOTS.reduce(
|
|
1043
|
+
(acc, slot) => {
|
|
1044
|
+
acc[slot] = {};
|
|
1045
|
+
return acc;
|
|
1046
|
+
},
|
|
1047
|
+
{}
|
|
1048
|
+
);
|
|
1033
1049
|
var idCounter = 0;
|
|
1034
1050
|
function generateId() {
|
|
1035
1051
|
return `slot-content-${++idCounter}-${Date.now()}`;
|
|
1036
1052
|
}
|
|
1053
|
+
function aggregateSlot(sources) {
|
|
1054
|
+
if (!sources) return null;
|
|
1055
|
+
const entries = Object.entries(sources);
|
|
1056
|
+
if (entries.length === 0) return null;
|
|
1057
|
+
if (entries.length === 1) return entries[0][1];
|
|
1058
|
+
const children = entries.map(([, entry]) => ({
|
|
1059
|
+
type: entry.pattern,
|
|
1060
|
+
...entry.props
|
|
1061
|
+
}));
|
|
1062
|
+
const stackId = `slot-content-stack-${entries.map(([k]) => k).join("-")}`;
|
|
1063
|
+
return {
|
|
1064
|
+
id: stackId,
|
|
1065
|
+
pattern: "stack",
|
|
1066
|
+
props: {
|
|
1067
|
+
direction: "vertical",
|
|
1068
|
+
gap: "lg",
|
|
1069
|
+
children
|
|
1070
|
+
},
|
|
1071
|
+
priority: 0,
|
|
1072
|
+
animation: "fade",
|
|
1073
|
+
sourceTrait: MULTI_SOURCE_STACK_TRAIT
|
|
1074
|
+
};
|
|
1075
|
+
}
|
|
1037
1076
|
function useUISlotManager() {
|
|
1038
|
-
const [
|
|
1077
|
+
const [sources, setSources] = react.useState(DEFAULT_SOURCES);
|
|
1039
1078
|
const subscribersRef = react.useRef(/* @__PURE__ */ new Set());
|
|
1040
1079
|
const timersRef = react.useRef(/* @__PURE__ */ new Map());
|
|
1041
1080
|
const traitIndexRef = react.useRef(/* @__PURE__ */ new Map());
|
|
1042
1081
|
const traitSubscribersRef = react.useRef(/* @__PURE__ */ new Map());
|
|
1082
|
+
const slots = react.useMemo(() => {
|
|
1083
|
+
const out = { ...DEFAULT_SLOTS };
|
|
1084
|
+
for (const slot of ALL_SLOTS) {
|
|
1085
|
+
out[slot] = aggregateSlot(sources[slot]);
|
|
1086
|
+
}
|
|
1087
|
+
return out;
|
|
1088
|
+
}, [sources]);
|
|
1043
1089
|
react.useEffect(() => {
|
|
1044
1090
|
return () => {
|
|
1045
1091
|
timersRef.current.forEach((timer) => clearTimeout(timer));
|
|
@@ -1078,103 +1124,160 @@ function useUISlotManager() {
|
|
|
1078
1124
|
const unindexTrait = react.useCallback((traitName) => {
|
|
1079
1125
|
traitIndexRef.current.delete(traitName);
|
|
1080
1126
|
}, []);
|
|
1081
|
-
const render = react.useCallback(
|
|
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
|
-
|
|
1112
|
-
);
|
|
1113
|
-
return prev;
|
|
1114
|
-
}
|
|
1115
|
-
if (content.sourceTrait) {
|
|
1116
|
-
indexTraitRender(content.sourceTrait, content);
|
|
1117
|
-
notifyTraitSubscribers(content.sourceTrait, content);
|
|
1127
|
+
const render = react.useCallback(
|
|
1128
|
+
(config) => {
|
|
1129
|
+
const id = generateId();
|
|
1130
|
+
const sourceKey = config.sourceTrait ?? DEFAULT_SOURCE_KEY;
|
|
1131
|
+
const content = {
|
|
1132
|
+
id,
|
|
1133
|
+
pattern: config.pattern,
|
|
1134
|
+
props: config.props ?? {},
|
|
1135
|
+
priority: config.priority ?? 0,
|
|
1136
|
+
animation: config.animation ?? "fade",
|
|
1137
|
+
onDismiss: config.onDismiss,
|
|
1138
|
+
sourceTrait: config.sourceTrait
|
|
1139
|
+
};
|
|
1140
|
+
if (config.autoDismissMs && config.autoDismissMs > 0) {
|
|
1141
|
+
content.autoDismissAt = Date.now() + config.autoDismissMs;
|
|
1142
|
+
const timer = setTimeout(() => {
|
|
1143
|
+
setSources((prev) => {
|
|
1144
|
+
const slotSources = prev[config.target];
|
|
1145
|
+
if (slotSources && slotSources[sourceKey]?.id === id) {
|
|
1146
|
+
content.onDismiss?.();
|
|
1147
|
+
const next = { ...slotSources };
|
|
1148
|
+
delete next[sourceKey];
|
|
1149
|
+
const updated = { ...prev, [config.target]: next };
|
|
1150
|
+
notifySubscribers(config.target, aggregateSlot(next));
|
|
1151
|
+
return updated;
|
|
1152
|
+
}
|
|
1153
|
+
return prev;
|
|
1154
|
+
});
|
|
1155
|
+
timersRef.current.delete(id);
|
|
1156
|
+
}, config.autoDismissMs);
|
|
1157
|
+
timersRef.current.set(id, timer);
|
|
1118
1158
|
}
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
if (content) {
|
|
1128
|
-
const timer = timersRef.current.get(content.id);
|
|
1129
|
-
if (timer) {
|
|
1130
|
-
clearTimeout(timer);
|
|
1131
|
-
timersRef.current.delete(content.id);
|
|
1159
|
+
setSources((prev) => {
|
|
1160
|
+
const slotSources = prev[config.target] ?? {};
|
|
1161
|
+
const existing = slotSources[sourceKey];
|
|
1162
|
+
if (existing && existing.priority > content.priority) {
|
|
1163
|
+
console.warn(
|
|
1164
|
+
`[UISlots] Slot "${config.target}" source "${sourceKey}" already has higher priority content (${existing.priority} > ${content.priority})`
|
|
1165
|
+
);
|
|
1166
|
+
return prev;
|
|
1132
1167
|
}
|
|
1133
|
-
|
|
1168
|
+
const nextSources = {
|
|
1169
|
+
...slotSources,
|
|
1170
|
+
[sourceKey]: content
|
|
1171
|
+
};
|
|
1172
|
+
const nextAll = { ...prev, [config.target]: nextSources };
|
|
1134
1173
|
if (content.sourceTrait) {
|
|
1135
|
-
|
|
1136
|
-
notifyTraitSubscribers(content.sourceTrait,
|
|
1174
|
+
indexTraitRender(content.sourceTrait, content);
|
|
1175
|
+
notifyTraitSubscribers(content.sourceTrait, content);
|
|
1176
|
+
}
|
|
1177
|
+
notifySubscribers(config.target, aggregateSlot(nextSources));
|
|
1178
|
+
return nextAll;
|
|
1179
|
+
});
|
|
1180
|
+
return id;
|
|
1181
|
+
},
|
|
1182
|
+
[notifySubscribers, notifyTraitSubscribers, indexTraitRender]
|
|
1183
|
+
);
|
|
1184
|
+
const clear = react.useCallback(
|
|
1185
|
+
(slot) => {
|
|
1186
|
+
setSources((prev) => {
|
|
1187
|
+
const slotSources = prev[slot];
|
|
1188
|
+
if (!slotSources || Object.keys(slotSources).length === 0) {
|
|
1189
|
+
return prev;
|
|
1190
|
+
}
|
|
1191
|
+
for (const content of Object.values(slotSources)) {
|
|
1192
|
+
const timer = timersRef.current.get(content.id);
|
|
1193
|
+
if (timer) {
|
|
1194
|
+
clearTimeout(timer);
|
|
1195
|
+
timersRef.current.delete(content.id);
|
|
1196
|
+
}
|
|
1197
|
+
content.onDismiss?.();
|
|
1198
|
+
if (content.sourceTrait) {
|
|
1199
|
+
unindexTrait(content.sourceTrait);
|
|
1200
|
+
notifyTraitSubscribers(content.sourceTrait, null);
|
|
1201
|
+
}
|
|
1137
1202
|
}
|
|
1138
1203
|
notifySubscribers(slot, null);
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
}
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
const
|
|
1204
|
+
return { ...prev, [slot]: {} };
|
|
1205
|
+
});
|
|
1206
|
+
},
|
|
1207
|
+
[notifySubscribers, notifyTraitSubscribers, unindexTrait]
|
|
1208
|
+
);
|
|
1209
|
+
const clearBySource = react.useCallback(
|
|
1210
|
+
(slot, sourceTrait) => {
|
|
1211
|
+
const sourceKey = sourceTrait;
|
|
1212
|
+
setSources((prev) => {
|
|
1213
|
+
const slotSources = prev[slot];
|
|
1214
|
+
if (!slotSources || !(sourceKey in slotSources)) return prev;
|
|
1215
|
+
const content = slotSources[sourceKey];
|
|
1216
|
+
const timer = timersRef.current.get(content.id);
|
|
1149
1217
|
if (timer) {
|
|
1150
1218
|
clearTimeout(timer);
|
|
1151
|
-
timersRef.current.delete(id);
|
|
1219
|
+
timersRef.current.delete(content.id);
|
|
1152
1220
|
}
|
|
1153
1221
|
content.onDismiss?.();
|
|
1154
1222
|
if (content.sourceTrait) {
|
|
1155
1223
|
unindexTrait(content.sourceTrait);
|
|
1156
1224
|
notifyTraitSubscribers(content.sourceTrait, null);
|
|
1157
1225
|
}
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1226
|
+
const nextSources = { ...slotSources };
|
|
1227
|
+
delete nextSources[sourceKey];
|
|
1228
|
+
notifySubscribers(slot, aggregateSlot(nextSources));
|
|
1229
|
+
return { ...prev, [slot]: nextSources };
|
|
1230
|
+
});
|
|
1231
|
+
},
|
|
1232
|
+
[notifySubscribers, notifyTraitSubscribers, unindexTrait]
|
|
1233
|
+
);
|
|
1234
|
+
const clearById = react.useCallback(
|
|
1235
|
+
(id) => {
|
|
1236
|
+
setSources((prev) => {
|
|
1237
|
+
for (const slot of ALL_SLOTS) {
|
|
1238
|
+
const slotSources = prev[slot];
|
|
1239
|
+
if (!slotSources) continue;
|
|
1240
|
+
const matchKey = Object.keys(slotSources).find(
|
|
1241
|
+
(k) => slotSources[k].id === id
|
|
1242
|
+
);
|
|
1243
|
+
if (!matchKey) continue;
|
|
1244
|
+
const content = slotSources[matchKey];
|
|
1245
|
+
const timer = timersRef.current.get(id);
|
|
1246
|
+
if (timer) {
|
|
1247
|
+
clearTimeout(timer);
|
|
1248
|
+
timersRef.current.delete(id);
|
|
1249
|
+
}
|
|
1250
|
+
content.onDismiss?.();
|
|
1251
|
+
if (content.sourceTrait) {
|
|
1252
|
+
unindexTrait(content.sourceTrait);
|
|
1253
|
+
notifyTraitSubscribers(content.sourceTrait, null);
|
|
1254
|
+
}
|
|
1255
|
+
const nextSources = { ...slotSources };
|
|
1256
|
+
delete nextSources[matchKey];
|
|
1257
|
+
notifySubscribers(slot, aggregateSlot(nextSources));
|
|
1258
|
+
return { ...prev, [slot]: nextSources };
|
|
1259
|
+
}
|
|
1260
|
+
return prev;
|
|
1261
|
+
});
|
|
1262
|
+
},
|
|
1263
|
+
[notifySubscribers, notifyTraitSubscribers, unindexTrait]
|
|
1264
|
+
);
|
|
1164
1265
|
const clearAll = react.useCallback(() => {
|
|
1165
1266
|
timersRef.current.forEach((timer) => clearTimeout(timer));
|
|
1166
1267
|
timersRef.current.clear();
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1268
|
+
setSources((prev) => {
|
|
1269
|
+
for (const slot of ALL_SLOTS) {
|
|
1270
|
+
const slotSources = prev[slot];
|
|
1271
|
+
if (!slotSources) continue;
|
|
1272
|
+
for (const content of Object.values(slotSources)) {
|
|
1170
1273
|
content.onDismiss?.();
|
|
1171
1274
|
if (content.sourceTrait) {
|
|
1172
1275
|
notifyTraitSubscribers(content.sourceTrait, null);
|
|
1173
1276
|
}
|
|
1174
|
-
notifySubscribers(slot, null);
|
|
1175
1277
|
}
|
|
1176
|
-
|
|
1177
|
-
|
|
1278
|
+
notifySubscribers(slot, null);
|
|
1279
|
+
}
|
|
1280
|
+
return DEFAULT_SOURCES;
|
|
1178
1281
|
});
|
|
1179
1282
|
traitIndexRef.current.clear();
|
|
1180
1283
|
}, [notifySubscribers, notifyTraitSubscribers]);
|
|
@@ -1184,16 +1287,16 @@ function useUISlotManager() {
|
|
|
1184
1287
|
subscribersRef.current.delete(callback);
|
|
1185
1288
|
};
|
|
1186
1289
|
}, []);
|
|
1187
|
-
const hasContent = react.useCallback(
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1290
|
+
const hasContent = react.useCallback(
|
|
1291
|
+
(slot) => slots[slot] !== null,
|
|
1292
|
+
[slots]
|
|
1293
|
+
);
|
|
1294
|
+
const getContent = react.useCallback(
|
|
1295
|
+
(slot) => slots[slot],
|
|
1296
|
+
[slots]
|
|
1297
|
+
);
|
|
1193
1298
|
const getTraitContent = react.useCallback(
|
|
1194
|
-
(traitName) =>
|
|
1195
|
-
return traitIndexRef.current.get(traitName) ?? null;
|
|
1196
|
-
},
|
|
1299
|
+
(traitName) => traitIndexRef.current.get(traitName) ?? null,
|
|
1197
1300
|
[]
|
|
1198
1301
|
);
|
|
1199
1302
|
const subscribeTrait = react.useCallback(
|
|
@@ -1219,6 +1322,7 @@ function useUISlotManager() {
|
|
|
1219
1322
|
slots,
|
|
1220
1323
|
render,
|
|
1221
1324
|
clear,
|
|
1325
|
+
clearBySource,
|
|
1222
1326
|
clearById,
|
|
1223
1327
|
clearAll,
|
|
1224
1328
|
subscribe: subscribe2,
|