@almadar/ui 5.157.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-BfZGeDfX.d.cts → EntityBindingContext-0Evn_LcT.d.cts} +7 -3
- package/dist/{EntityBindingContext-BfZGeDfX.d.ts → EntityBindingContext-0Evn_LcT.d.ts} +7 -3
- package/dist/avl/index.cjs +379 -50
- package/dist/avl/index.js +380 -51
- package/dist/components/index.cjs +394 -17
- package/dist/components/index.d.cts +48 -6
- package/dist/components/index.d.ts +48 -6
- package/dist/components/index.js +395 -18
- 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 +461 -106
- package/dist/providers/index.d.cts +1 -1
- package/dist/providers/index.d.ts +1 -1
- package/dist/providers/index.js +462 -107
- package/dist/runtime/index.cjs +387 -55
- package/dist/runtime/index.d.cts +15 -23
- package/dist/runtime/index.d.ts +15 -23
- package/dist/runtime/index.js +389 -56
- 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/runtime/index.cjs
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var React85 = require('react');
|
|
4
4
|
var providers = require('@almadar/ui/providers');
|
|
5
5
|
var logger = require('@almadar/logger');
|
|
6
|
+
var ui = require('@almadar/runtime/ui');
|
|
6
7
|
var runtime = require('@almadar/runtime');
|
|
7
8
|
var core = require('@almadar/core');
|
|
8
9
|
var clsx = require('clsx');
|
|
@@ -13,7 +14,6 @@ var reactDom = require('react-dom');
|
|
|
13
14
|
var hooks = require('@almadar/ui/hooks');
|
|
14
15
|
var context = require('@almadar/ui/context');
|
|
15
16
|
var evaluator = require('@almadar/evaluator');
|
|
16
|
-
var ui = require('@almadar/runtime/ui');
|
|
17
17
|
var reactRouterDom = require('react-router-dom');
|
|
18
18
|
var ELK = require('elkjs/lib/elk.bundled.js');
|
|
19
19
|
var SyntaxHighlighter = require('react-syntax-highlighter/dist/esm/prism-light.js');
|
|
@@ -867,6 +867,22 @@ var init_useTapReveal = __esm({
|
|
|
867
867
|
"hooks/useTapReveal.ts"() {
|
|
868
868
|
}
|
|
869
869
|
});
|
|
870
|
+
function usePerfBuffer() {
|
|
871
|
+
return React85.useSyncExternalStore(ui.perfStore.subscribe, ui.perfStore.getSnapshot, ui.perfStore.getSnapshot);
|
|
872
|
+
}
|
|
873
|
+
exports.profilerOnRender = void 0;
|
|
874
|
+
var init_perf = __esm({
|
|
875
|
+
"lib/perf.ts"() {
|
|
876
|
+
exports.profilerOnRender = (id, phase, actualDuration, baseDuration, _startTime, commitTime) => {
|
|
877
|
+
ui.pushPerfEntry({
|
|
878
|
+
name: `profiler:${id}:${phase}`,
|
|
879
|
+
durationMs: actualDuration,
|
|
880
|
+
ts: commitTime,
|
|
881
|
+
detail: { baseDuration }
|
|
882
|
+
});
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
});
|
|
870
886
|
function resolveMarkerExpression(expression, entity, config, state) {
|
|
871
887
|
const ctx = runtime.createContextFromBindings({
|
|
872
888
|
entity,
|
|
@@ -884,11 +900,54 @@ function isPlainObject(value) {
|
|
|
884
900
|
if (typeof value === "function") return false;
|
|
885
901
|
return true;
|
|
886
902
|
}
|
|
903
|
+
function isEvaluatorResolvedData(value) {
|
|
904
|
+
return evaluatorResolvedData.has(value);
|
|
905
|
+
}
|
|
906
|
+
function brandResolved(value) {
|
|
907
|
+
if (value !== null && typeof value === "object" && !React85__namespace.default.isValidElement(value) && !(value instanceof Date)) {
|
|
908
|
+
resolvedMarkerFree.add(value);
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
function subtreeHasMarker(value) {
|
|
912
|
+
if (resolvedMarkerFree.has(value)) return false;
|
|
913
|
+
const cached = markerPresenceCache.get(value);
|
|
914
|
+
if (cached !== void 0) return cached;
|
|
915
|
+
let found = false;
|
|
916
|
+
const children = Array.isArray(value) ? value : Object.values(value);
|
|
917
|
+
for (const child of children) {
|
|
918
|
+
if (core.isRenderBindingMarker(child)) {
|
|
919
|
+
found = true;
|
|
920
|
+
break;
|
|
921
|
+
}
|
|
922
|
+
if (Array.isArray(child) || isPlainObject(child)) {
|
|
923
|
+
if (subtreeHasMarker(child)) {
|
|
924
|
+
found = true;
|
|
925
|
+
break;
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
markerPresenceCache.set(value, found);
|
|
930
|
+
return found;
|
|
931
|
+
}
|
|
887
932
|
function walkValue(value, scopeTrait, entity, config, state) {
|
|
888
933
|
if (core.isRenderBindingMarker(value)) {
|
|
889
|
-
|
|
934
|
+
const cached = markerResolutionCache.get(value);
|
|
935
|
+
if (cached !== void 0 && cached.entity === entity && cached.config === config && cached.state === state) {
|
|
936
|
+
return { resolved: cached.resolved, changed: false };
|
|
937
|
+
}
|
|
938
|
+
const resolved = resolveMarkerExpression(value.expression, entity, config, state);
|
|
939
|
+
markerResolutionCache.set(value, { entity, config, state, resolved });
|
|
940
|
+
if (resolved !== null && typeof resolved === "object" && !React85__namespace.default.isValidElement(resolved) && !(resolved instanceof Date)) {
|
|
941
|
+
resolvedMarkerFree.add(resolved);
|
|
942
|
+
evaluatorResolvedData.add(resolved);
|
|
943
|
+
}
|
|
944
|
+
return { resolved, changed: true };
|
|
890
945
|
}
|
|
891
946
|
if (Array.isArray(value)) {
|
|
947
|
+
if (!subtreeHasMarker(value)) {
|
|
948
|
+
brandResolved(value);
|
|
949
|
+
return { resolved: value, changed: false };
|
|
950
|
+
}
|
|
892
951
|
const out = [];
|
|
893
952
|
let changed = false;
|
|
894
953
|
for (const item of value) {
|
|
@@ -903,9 +962,14 @@ function walkValue(value, scopeTrait, entity, config, state) {
|
|
|
903
962
|
out.push(resolved);
|
|
904
963
|
if (itemChanged) changed = true;
|
|
905
964
|
}
|
|
965
|
+
brandResolved(out);
|
|
906
966
|
return changed ? { resolved: out, changed: true } : { resolved: value, changed: false };
|
|
907
967
|
}
|
|
908
968
|
if (isPlainObject(value)) {
|
|
969
|
+
if (!subtreeHasMarker(value)) {
|
|
970
|
+
brandResolved(value);
|
|
971
|
+
return { resolved: value, changed: false };
|
|
972
|
+
}
|
|
909
973
|
const sourceTrait = value._sourceTrait;
|
|
910
974
|
if (typeof sourceTrait === "string" && sourceTrait !== scopeTrait) {
|
|
911
975
|
return { resolved: value, changed: false };
|
|
@@ -917,11 +981,13 @@ function walkValue(value, scopeTrait, entity, config, state) {
|
|
|
917
981
|
out[key] = resolved;
|
|
918
982
|
if (itemChanged) changed = true;
|
|
919
983
|
}
|
|
984
|
+
brandResolved(out);
|
|
920
985
|
return changed ? { resolved: out, changed: true } : { resolved: value, changed: false };
|
|
921
986
|
}
|
|
922
987
|
return { resolved: value, changed: false };
|
|
923
988
|
}
|
|
924
989
|
function resolveRenderBindingMarkers(props, scopeTrait, entity, config, state) {
|
|
990
|
+
if (resolvedMarkerFree.has(props)) return props;
|
|
925
991
|
const out = {};
|
|
926
992
|
let changed = false;
|
|
927
993
|
for (const [key, value] of Object.entries(props)) {
|
|
@@ -929,11 +995,17 @@ function resolveRenderBindingMarkers(props, scopeTrait, entity, config, state) {
|
|
|
929
995
|
out[key] = resolved;
|
|
930
996
|
if (propChanged) changed = true;
|
|
931
997
|
}
|
|
998
|
+
brandResolved(out);
|
|
932
999
|
return changed ? out : props;
|
|
933
1000
|
}
|
|
1001
|
+
var markerPresenceCache, markerResolutionCache, resolvedMarkerFree, evaluatorResolvedData;
|
|
934
1002
|
var init_resolve_render_bindings = __esm({
|
|
935
1003
|
"lib/resolve-render-bindings.ts"() {
|
|
936
1004
|
"use client";
|
|
1005
|
+
markerPresenceCache = /* @__PURE__ */ new WeakMap();
|
|
1006
|
+
markerResolutionCache = /* @__PURE__ */ new WeakMap();
|
|
1007
|
+
resolvedMarkerFree = /* @__PURE__ */ new WeakSet();
|
|
1008
|
+
evaluatorResolvedData = /* @__PURE__ */ new WeakSet();
|
|
937
1009
|
}
|
|
938
1010
|
});
|
|
939
1011
|
function cn(...inputs) {
|
|
@@ -12258,6 +12330,7 @@ var init_LearningCanvas = __esm({
|
|
|
12258
12330
|
"components/learning/atoms/LearningCanvas.tsx"() {
|
|
12259
12331
|
"use client";
|
|
12260
12332
|
init_cn();
|
|
12333
|
+
init_perf();
|
|
12261
12334
|
init_useEventBus();
|
|
12262
12335
|
DASH_PATTERNS = { dashed: [6, 4], dotted: [2, 3] };
|
|
12263
12336
|
TRACE_SERIES_COLORS = ["#2563eb", "#dc2626", "#16a34a", "#f59e0b"];
|
|
@@ -12301,6 +12374,7 @@ var init_LearningCanvas = __esm({
|
|
|
12301
12374
|
return [...shapes, ...traceOut, ...readoutOut];
|
|
12302
12375
|
}, [shapes, traces, readouts, width, height]);
|
|
12303
12376
|
const draw = React85.useCallback(() => {
|
|
12377
|
+
const _perfT = ui.perfStart("learningcanvas:paint");
|
|
12304
12378
|
const canvas = canvasRef.current;
|
|
12305
12379
|
if (!canvas) return;
|
|
12306
12380
|
const ctx = canvas.getContext("2d");
|
|
@@ -12322,6 +12396,7 @@ var init_LearningCanvas = __esm({
|
|
|
12322
12396
|
for (const shape of derivedShapes) {
|
|
12323
12397
|
if (shape.type === "text") drawShape(ctx, shape, width, height, derivedShapes);
|
|
12324
12398
|
}
|
|
12399
|
+
ui.perfEnd("learningcanvas:paint", _perfT);
|
|
12325
12400
|
}, [width, height, backgroundColor, derivedShapes]);
|
|
12326
12401
|
React85.useEffect(() => {
|
|
12327
12402
|
draw();
|
|
@@ -26995,7 +27070,7 @@ function fileIcon(name) {
|
|
|
26995
27070
|
return "file";
|
|
26996
27071
|
}
|
|
26997
27072
|
}
|
|
26998
|
-
var TreeNodeItem, FileTree;
|
|
27073
|
+
var TreeNodeItem, FlatTreeNodeItem, FileTree;
|
|
26999
27074
|
var init_FileTree = __esm({
|
|
27000
27075
|
"components/core/molecules/FileTree.tsx"() {
|
|
27001
27076
|
"use client";
|
|
@@ -27080,14 +27155,101 @@ var init_FileTree = __esm({
|
|
|
27080
27155
|
)) })
|
|
27081
27156
|
] });
|
|
27082
27157
|
};
|
|
27158
|
+
FlatTreeNodeItem = ({
|
|
27159
|
+
item,
|
|
27160
|
+
depth,
|
|
27161
|
+
indent,
|
|
27162
|
+
childrenByParent,
|
|
27163
|
+
onNodeSelect,
|
|
27164
|
+
defaultExpanded = false
|
|
27165
|
+
}) => {
|
|
27166
|
+
const [expanded, setExpanded] = React85.useState(defaultExpanded || depth < 1);
|
|
27167
|
+
const children = childrenByParent.get(item.id);
|
|
27168
|
+
const hasChildren = !!children && children.length > 0;
|
|
27169
|
+
const handleClick = React85.useCallback(() => {
|
|
27170
|
+
if (hasChildren) setExpanded((prev) => !prev);
|
|
27171
|
+
onNodeSelect?.(item.id);
|
|
27172
|
+
}, [hasChildren, item.id, onNodeSelect]);
|
|
27173
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
27174
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
27175
|
+
Box,
|
|
27176
|
+
{
|
|
27177
|
+
className: "flex items-center gap-1.5 py-0.5 px-2 cursor-pointer rounded-sm transition-colors hover:bg-muted",
|
|
27178
|
+
style: { paddingLeft: depth * indent + 8 },
|
|
27179
|
+
onClick: handleClick,
|
|
27180
|
+
role: "treeitem",
|
|
27181
|
+
"aria-expanded": hasChildren ? expanded : void 0,
|
|
27182
|
+
children: [
|
|
27183
|
+
hasChildren ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
27184
|
+
Icon,
|
|
27185
|
+
{
|
|
27186
|
+
name: expanded ? "chevron-down" : "chevron-right",
|
|
27187
|
+
size: "xs",
|
|
27188
|
+
className: "text-[var(--color-muted-foreground)] flex-shrink-0"
|
|
27189
|
+
}
|
|
27190
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(Box, { style: { width: 12, flexShrink: 0 } }),
|
|
27191
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
27192
|
+
Icon,
|
|
27193
|
+
{
|
|
27194
|
+
name: item.icon ?? (hasChildren ? expanded ? "folder-open" : "folder" : "file"),
|
|
27195
|
+
size: "xs",
|
|
27196
|
+
className: hasChildren ? "text-[var(--color-warning)]" : "text-[var(--color-muted-foreground)]"
|
|
27197
|
+
}
|
|
27198
|
+
),
|
|
27199
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "truncate font-mono text-xs", children: item.label })
|
|
27200
|
+
]
|
|
27201
|
+
}
|
|
27202
|
+
),
|
|
27203
|
+
hasChildren && expanded && /* @__PURE__ */ jsxRuntime.jsx(Box, { role: "group", children: children.map((child) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
27204
|
+
FlatTreeNodeItem,
|
|
27205
|
+
{
|
|
27206
|
+
item: child,
|
|
27207
|
+
depth: depth + 1,
|
|
27208
|
+
indent,
|
|
27209
|
+
childrenByParent,
|
|
27210
|
+
onNodeSelect
|
|
27211
|
+
},
|
|
27212
|
+
child.id
|
|
27213
|
+
)) })
|
|
27214
|
+
] });
|
|
27215
|
+
};
|
|
27083
27216
|
FileTree = ({
|
|
27084
27217
|
tree,
|
|
27218
|
+
items,
|
|
27085
27219
|
selectedPath,
|
|
27086
27220
|
onFileSelect,
|
|
27221
|
+
onNodeSelect,
|
|
27087
27222
|
className,
|
|
27088
27223
|
indent = 16
|
|
27089
27224
|
}) => {
|
|
27090
|
-
if (
|
|
27225
|
+
if (items) {
|
|
27226
|
+
if (items.length === 0) return null;
|
|
27227
|
+
const ids = new Set(items.map((node) => node.id));
|
|
27228
|
+
const childrenByParent = /* @__PURE__ */ new Map();
|
|
27229
|
+
const roots = [];
|
|
27230
|
+
for (const item of items) {
|
|
27231
|
+
if (item.parentId && ids.has(item.parentId)) {
|
|
27232
|
+
const siblings = childrenByParent.get(item.parentId);
|
|
27233
|
+
if (siblings) siblings.push(item);
|
|
27234
|
+
else childrenByParent.set(item.parentId, [item]);
|
|
27235
|
+
} else {
|
|
27236
|
+
roots.push(item);
|
|
27237
|
+
}
|
|
27238
|
+
}
|
|
27239
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Box, { className: `py-1 overflow-y-auto ${className ?? ""}`, role: "tree", children: roots.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
27240
|
+
FlatTreeNodeItem,
|
|
27241
|
+
{
|
|
27242
|
+
item,
|
|
27243
|
+
depth: 0,
|
|
27244
|
+
indent,
|
|
27245
|
+
childrenByParent,
|
|
27246
|
+
onNodeSelect,
|
|
27247
|
+
defaultExpanded: true
|
|
27248
|
+
},
|
|
27249
|
+
item.id
|
|
27250
|
+
)) });
|
|
27251
|
+
}
|
|
27252
|
+
if (!tree || tree.length === 0) return null;
|
|
27091
27253
|
return /* @__PURE__ */ jsxRuntime.jsx(Box, { className: `py-1 overflow-y-auto ${className ?? ""}`, role: "tree", children: tree.map((node) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
27092
27254
|
TreeNodeItem,
|
|
27093
27255
|
{
|
|
@@ -28418,7 +28580,7 @@ var init_debug = __esm({
|
|
|
28418
28580
|
logger.createLogger("almadar:ui:debug:game-state");
|
|
28419
28581
|
}
|
|
28420
28582
|
});
|
|
28421
|
-
var isRelationsDebugEnabled, RelationSelect;
|
|
28583
|
+
var isRelationsDebugEnabled, MANY_CARDINALITIES, RelationSelect;
|
|
28422
28584
|
var init_RelationSelect = __esm({
|
|
28423
28585
|
"components/core/molecules/RelationSelect.tsx"() {
|
|
28424
28586
|
"use client";
|
|
@@ -28432,6 +28594,11 @@ var init_RelationSelect = __esm({
|
|
|
28432
28594
|
init_Typography();
|
|
28433
28595
|
init_debug();
|
|
28434
28596
|
isRelationsDebugEnabled = () => isDebugEnabled();
|
|
28597
|
+
MANY_CARDINALITIES = [
|
|
28598
|
+
"many",
|
|
28599
|
+
"one-to-many",
|
|
28600
|
+
"many-to-many"
|
|
28601
|
+
];
|
|
28435
28602
|
RelationSelect = ({
|
|
28436
28603
|
value,
|
|
28437
28604
|
onChange,
|
|
@@ -30056,6 +30223,7 @@ var init_MathCanvas = __esm({
|
|
|
30056
30223
|
"components/learning/molecules/MathCanvas.tsx"() {
|
|
30057
30224
|
"use client";
|
|
30058
30225
|
init_useEventBus();
|
|
30226
|
+
init_perf();
|
|
30059
30227
|
init_atoms();
|
|
30060
30228
|
init_Stack();
|
|
30061
30229
|
init_LearningCanvas();
|
|
@@ -30096,17 +30264,21 @@ var init_MathCanvas = __esm({
|
|
|
30096
30264
|
error
|
|
30097
30265
|
}) => {
|
|
30098
30266
|
const eventBus = useEventBus();
|
|
30267
|
+
const keyMapKey = keyMap ? JSON.stringify(keyMap) : null;
|
|
30268
|
+
const keyUpMapKey = keyUpMap ? JSON.stringify(keyUpMap) : null;
|
|
30269
|
+
const stableKeyMap = React85.useMemo(() => keyMap, [keyMapKey]);
|
|
30270
|
+
const stableKeyUpMap = React85.useMemo(() => keyUpMap, [keyUpMapKey]);
|
|
30099
30271
|
React85.useEffect(() => {
|
|
30100
|
-
if (!
|
|
30272
|
+
if (!stableKeyMap && !stableKeyUpMap) return;
|
|
30101
30273
|
const onDown = (e) => {
|
|
30102
|
-
const ev =
|
|
30274
|
+
const ev = stableKeyMap?.[e.code];
|
|
30103
30275
|
if (ev) {
|
|
30104
30276
|
eventBus.emit(`UI:${ev}`, {});
|
|
30105
30277
|
e.preventDefault();
|
|
30106
30278
|
}
|
|
30107
30279
|
};
|
|
30108
30280
|
const onUp = (e) => {
|
|
30109
|
-
const ev =
|
|
30281
|
+
const ev = stableKeyUpMap?.[e.code];
|
|
30110
30282
|
if (ev) eventBus.emit(`UI:${ev}`, {});
|
|
30111
30283
|
};
|
|
30112
30284
|
window.addEventListener("keydown", onDown);
|
|
@@ -30115,8 +30287,9 @@ var init_MathCanvas = __esm({
|
|
|
30115
30287
|
window.removeEventListener("keydown", onDown);
|
|
30116
30288
|
window.removeEventListener("keyup", onUp);
|
|
30117
30289
|
};
|
|
30118
|
-
}, [
|
|
30290
|
+
}, [stableKeyMap, stableKeyUpMap, eventBus]);
|
|
30119
30291
|
const derivedShapes = React85.useMemo(() => {
|
|
30292
|
+
const _perfT = ui.perfStart("mathcanvas:derive");
|
|
30120
30293
|
const out = [];
|
|
30121
30294
|
const margin = 24;
|
|
30122
30295
|
const plotW = width - margin * 2;
|
|
@@ -30360,6 +30533,7 @@ var init_MathCanvas = __esm({
|
|
|
30360
30533
|
}
|
|
30361
30534
|
}
|
|
30362
30535
|
out.push(...shapes);
|
|
30536
|
+
ui.perfEnd("mathcanvas:derive", _perfT);
|
|
30363
30537
|
return out;
|
|
30364
30538
|
}, [
|
|
30365
30539
|
width,
|
|
@@ -36575,7 +36749,7 @@ var init_RichBlockEditor = __esm({
|
|
|
36575
36749
|
{
|
|
36576
36750
|
variant: "bordered",
|
|
36577
36751
|
padding: "none",
|
|
36578
|
-
className: cn("flex flex-col", className),
|
|
36752
|
+
className: cn("flex flex-col text-card-foreground", className),
|
|
36579
36753
|
children: [
|
|
36580
36754
|
enableBlocks && showToolbar && !readOnly && /* @__PURE__ */ jsxRuntime.jsx(
|
|
36581
36755
|
Box,
|
|
@@ -41803,6 +41977,7 @@ var init_DetailPanel = __esm({
|
|
|
41803
41977
|
"use client";
|
|
41804
41978
|
init_atoms();
|
|
41805
41979
|
init_Box();
|
|
41980
|
+
init_Input();
|
|
41806
41981
|
init_Stack();
|
|
41807
41982
|
init_SimpleGrid();
|
|
41808
41983
|
init_Menu();
|
|
@@ -41818,6 +41993,7 @@ var init_DetailPanel = __esm({
|
|
|
41818
41993
|
ReactMarkdown2 = React85.lazy(() => import('react-markdown'));
|
|
41819
41994
|
DetailPanel = ({
|
|
41820
41995
|
title: propTitle,
|
|
41996
|
+
onTitleCommit,
|
|
41821
41997
|
subtitle,
|
|
41822
41998
|
status,
|
|
41823
41999
|
avatar,
|
|
@@ -41839,6 +42015,7 @@ var init_DetailPanel = __esm({
|
|
|
41839
42015
|
}) => {
|
|
41840
42016
|
const eventBus = useEventBus();
|
|
41841
42017
|
const { t } = hooks.useTranslate();
|
|
42018
|
+
const [titleDraft, setTitleDraft] = React85__namespace.default.useState(null);
|
|
41842
42019
|
const isFieldDefArray = (arr) => {
|
|
41843
42020
|
if (!arr || arr.length === 0) return false;
|
|
41844
42021
|
const first = arr[0];
|
|
@@ -42059,6 +42236,50 @@ var init_DetailPanel = __esm({
|
|
|
42059
42236
|
}),
|
|
42060
42237
|
status && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: status.variant ?? "default", children: status.label })
|
|
42061
42238
|
] });
|
|
42239
|
+
const commitTitle = () => {
|
|
42240
|
+
if (!onTitleCommit) return;
|
|
42241
|
+
const next = (titleDraft ?? "").trim();
|
|
42242
|
+
setTitleDraft(null);
|
|
42243
|
+
if (!next || next === title) return;
|
|
42244
|
+
onTitleCommit(next, normalizedData?.id !== void 0 ? String(normalizedData.id) : "");
|
|
42245
|
+
};
|
|
42246
|
+
const titleNode = onTitleCommit && titleDraft !== null ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
42247
|
+
Input,
|
|
42248
|
+
{
|
|
42249
|
+
value: titleDraft,
|
|
42250
|
+
autoFocus: true,
|
|
42251
|
+
"aria-label": t("common.title"),
|
|
42252
|
+
className: "h-auto py-1 text-3xl font-bold tracking-tight",
|
|
42253
|
+
onChange: (e) => setTitleDraft(e.target.value),
|
|
42254
|
+
onBlur: commitTitle,
|
|
42255
|
+
onKeyDown: (e) => {
|
|
42256
|
+
if (e.key === "Enter") {
|
|
42257
|
+
e.preventDefault();
|
|
42258
|
+
commitTitle();
|
|
42259
|
+
} else if (e.key === "Escape") {
|
|
42260
|
+
e.preventDefault();
|
|
42261
|
+
setTitleDraft(null);
|
|
42262
|
+
}
|
|
42263
|
+
},
|
|
42264
|
+
"data-testid": "detail-title-input"
|
|
42265
|
+
}
|
|
42266
|
+
) : onTitleCommit ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
42267
|
+
Box,
|
|
42268
|
+
{
|
|
42269
|
+
role: "button",
|
|
42270
|
+
tabIndex: 0,
|
|
42271
|
+
className: "cursor-text rounded px-1 -mx-1 transition-colors hover:bg-muted/40",
|
|
42272
|
+
onClick: () => setTitleDraft(title ?? ""),
|
|
42273
|
+
onKeyDown: (e) => {
|
|
42274
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
42275
|
+
e.preventDefault();
|
|
42276
|
+
setTitleDraft(title ?? "");
|
|
42277
|
+
}
|
|
42278
|
+
},
|
|
42279
|
+
"data-testid": "detail-title-editable",
|
|
42280
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h2", weight: "bold", children: title || "Details" })
|
|
42281
|
+
}
|
|
42282
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h2", weight: "bold", children: title || "Details" });
|
|
42062
42283
|
const content = /* @__PURE__ */ jsxRuntime.jsx(Card, { variant: "elevated", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "md", className: "p-6", children: [
|
|
42063
42284
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { justify: "between", align: "start", gap: "md", children: [
|
|
42064
42285
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { align: "start", gap: "sm", className: "min-w-0", children: [
|
|
@@ -42078,7 +42299,7 @@ var init_DetailPanel = __esm({
|
|
|
42078
42299
|
avatar,
|
|
42079
42300
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", className: "min-w-0", children: [
|
|
42080
42301
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { align: "center", gap: "sm", wrap: true, children: [
|
|
42081
|
-
|
|
42302
|
+
titleNode,
|
|
42082
42303
|
statusBadges
|
|
42083
42304
|
] }),
|
|
42084
42305
|
subtitle && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", color: "secondary", children: subtitle })
|
|
@@ -42414,6 +42635,9 @@ function determineInputType(field) {
|
|
|
42414
42635
|
if (field.type === "relation" || field.relation) {
|
|
42415
42636
|
return "relation";
|
|
42416
42637
|
}
|
|
42638
|
+
if (field.type === "array") {
|
|
42639
|
+
return "array";
|
|
42640
|
+
}
|
|
42417
42641
|
if (field.type === "enum" || field.values || getEnumOptions(field).length > 0) {
|
|
42418
42642
|
return "select";
|
|
42419
42643
|
}
|
|
@@ -42489,6 +42713,7 @@ var init_Form = __esm({
|
|
|
42489
42713
|
init_Typography();
|
|
42490
42714
|
init_Icon();
|
|
42491
42715
|
init_RelationSelect();
|
|
42716
|
+
init_TagInput();
|
|
42492
42717
|
init_UploadDropZone();
|
|
42493
42718
|
init_Alert();
|
|
42494
42719
|
init_useEventBus();
|
|
@@ -42568,7 +42793,7 @@ var init_Form = __esm({
|
|
|
42568
42793
|
values: "values" in f3 ? f3.values : void 0,
|
|
42569
42794
|
min: f3.min,
|
|
42570
42795
|
max: f3.max,
|
|
42571
|
-
relation: "relation" in f3 ? { entity: f3.relation.entity } : void 0
|
|
42796
|
+
relation: "relation" in f3 ? { entity: f3.relation.entity, cardinality: f3.relation.cardinality } : void 0
|
|
42572
42797
|
})
|
|
42573
42798
|
);
|
|
42574
42799
|
}, [entity, fields]);
|
|
@@ -42635,7 +42860,7 @@ var init_Form = __esm({
|
|
|
42635
42860
|
});
|
|
42636
42861
|
debug(
|
|
42637
42862
|
"forms",
|
|
42638
|
-
`Calculation triggered: ${calc.variableName} = ${value}`
|
|
42863
|
+
`Calculation triggered: ${calc.variableName} = ${String(value)}`
|
|
42639
42864
|
);
|
|
42640
42865
|
}
|
|
42641
42866
|
});
|
|
@@ -42803,7 +43028,7 @@ var init_Form = __esm({
|
|
|
42803
43028
|
values: "values" in entityField ? entityField.values : void 0,
|
|
42804
43029
|
min: entityField.min,
|
|
42805
43030
|
max: entityField.max,
|
|
42806
|
-
relation: "relation" in entityField ? { entity: entityField.relation.entity } : void 0
|
|
43031
|
+
relation: "relation" in entityField ? { entity: entityField.relation.entity, cardinality: entityField.relation.cardinality } : void 0
|
|
42807
43032
|
};
|
|
42808
43033
|
}
|
|
42809
43034
|
return { name: field, type: "string" };
|
|
@@ -42915,6 +43140,22 @@ var init_Form = __esm({
|
|
|
42915
43140
|
case "relation": {
|
|
42916
43141
|
const relationOptions = relationsData[fieldName] || [];
|
|
42917
43142
|
const relationLoading = relationsLoading[fieldName] || false;
|
|
43143
|
+
if (field.relation?.cardinality !== void 0 && MANY_CARDINALITIES.includes(field.relation.cardinality)) {
|
|
43144
|
+
const selectedValues = Array.isArray(currentValue) ? currentValue.map((v) => String(v)) : [];
|
|
43145
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
43146
|
+
Select,
|
|
43147
|
+
{
|
|
43148
|
+
...commonProps,
|
|
43149
|
+
multiple: true,
|
|
43150
|
+
searchable: true,
|
|
43151
|
+
clearable: true,
|
|
43152
|
+
options: [...relationOptions],
|
|
43153
|
+
value: selectedValues,
|
|
43154
|
+
onValueChange: (value) => handleChange(fieldName, Array.isArray(value) ? value : [value]),
|
|
43155
|
+
placeholder: field.placeholder || `Select ${label}...`
|
|
43156
|
+
}
|
|
43157
|
+
);
|
|
43158
|
+
}
|
|
42918
43159
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
42919
43160
|
RelationSelect,
|
|
42920
43161
|
{
|
|
@@ -42929,6 +43170,18 @@ var init_Form = __esm({
|
|
|
42929
43170
|
}
|
|
42930
43171
|
);
|
|
42931
43172
|
}
|
|
43173
|
+
case "array": {
|
|
43174
|
+
const arrayValue = Array.isArray(currentValue) ? currentValue.map((v) => String(v)) : currentValue != null && currentValue !== "" ? [String(currentValue)] : [];
|
|
43175
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
43176
|
+
TagInput,
|
|
43177
|
+
{
|
|
43178
|
+
placeholder: field.placeholder,
|
|
43179
|
+
disabled: isLoading,
|
|
43180
|
+
value: arrayValue,
|
|
43181
|
+
onChange: (next) => handleChange(fieldName, [...next])
|
|
43182
|
+
}
|
|
43183
|
+
);
|
|
43184
|
+
}
|
|
42932
43185
|
case "number":
|
|
42933
43186
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
42934
43187
|
Input,
|
|
@@ -48497,7 +48750,10 @@ function enrichFormFields(fields, entityDef) {
|
|
|
48497
48750
|
enriched.values = entityField.enumValues;
|
|
48498
48751
|
}
|
|
48499
48752
|
if (entityField.relation) {
|
|
48500
|
-
enriched.relation =
|
|
48753
|
+
enriched.relation = {
|
|
48754
|
+
entity: entityField.relation.entity,
|
|
48755
|
+
cardinality: entityField.relation.cardinality
|
|
48756
|
+
};
|
|
48501
48757
|
}
|
|
48502
48758
|
return enriched;
|
|
48503
48759
|
}
|
|
@@ -48525,7 +48781,10 @@ function enrichFormFields(fields, entityDef) {
|
|
|
48525
48781
|
}
|
|
48526
48782
|
}
|
|
48527
48783
|
if (!obj.relation && entityField.relation) {
|
|
48528
|
-
enriched.relation =
|
|
48784
|
+
enriched.relation = {
|
|
48785
|
+
entity: entityField.relation.entity,
|
|
48786
|
+
cardinality: entityField.relation.cardinality
|
|
48787
|
+
};
|
|
48529
48788
|
}
|
|
48530
48789
|
return enriched;
|
|
48531
48790
|
}
|
|
@@ -48540,7 +48799,12 @@ function enrichDetailFields(fields, entityDef) {
|
|
|
48540
48799
|
const meta = { type: entityField.type };
|
|
48541
48800
|
const values = entityField.values ?? entityField.enumValues;
|
|
48542
48801
|
if (values && values.length > 0) meta.values = values;
|
|
48543
|
-
if (entityField.relation)
|
|
48802
|
+
if (entityField.relation) {
|
|
48803
|
+
meta.relation = {
|
|
48804
|
+
entity: entityField.relation.entity,
|
|
48805
|
+
cardinality: entityField.relation.cardinality
|
|
48806
|
+
};
|
|
48807
|
+
}
|
|
48544
48808
|
return meta;
|
|
48545
48809
|
};
|
|
48546
48810
|
return fields.map((field) => {
|
|
@@ -49094,6 +49358,33 @@ function isPlainConfigObject(value) {
|
|
|
49094
49358
|
const proto = Object.getPrototypeOf(value);
|
|
49095
49359
|
return proto === Object.prototype || proto === null;
|
|
49096
49360
|
}
|
|
49361
|
+
function subtreeHasTraitRef(value) {
|
|
49362
|
+
if (isEvaluatorResolvedData(value)) return false;
|
|
49363
|
+
const cached = traitRefPresenceCache.get(value);
|
|
49364
|
+
if (cached !== void 0) return cached;
|
|
49365
|
+
let found = false;
|
|
49366
|
+
const children = Array.isArray(value) ? value : Object.values(value);
|
|
49367
|
+
for (const child of children) {
|
|
49368
|
+
if (typeof child === "string" && TRAIT_BINDING_RE.test(child)) {
|
|
49369
|
+
found = true;
|
|
49370
|
+
break;
|
|
49371
|
+
}
|
|
49372
|
+
if (core.isRenderBindingMarker(child)) continue;
|
|
49373
|
+
if (Array.isArray(child)) {
|
|
49374
|
+
if (subtreeHasTraitRef(child)) {
|
|
49375
|
+
found = true;
|
|
49376
|
+
break;
|
|
49377
|
+
}
|
|
49378
|
+
} else if (child !== null && typeof child === "object" && isPlainConfigObject(child)) {
|
|
49379
|
+
if (subtreeHasTraitRef(child)) {
|
|
49380
|
+
found = true;
|
|
49381
|
+
break;
|
|
49382
|
+
}
|
|
49383
|
+
}
|
|
49384
|
+
}
|
|
49385
|
+
traitRefPresenceCache.set(value, found);
|
|
49386
|
+
return found;
|
|
49387
|
+
}
|
|
49097
49388
|
function substituteTraitRefsDeep(value, pathKey) {
|
|
49098
49389
|
if (core.isRenderBindingMarker(value)) return value;
|
|
49099
49390
|
if (typeof value === "string") {
|
|
@@ -49108,11 +49399,13 @@ function substituteTraitRefsDeep(value, pathKey) {
|
|
|
49108
49399
|
return value;
|
|
49109
49400
|
}
|
|
49110
49401
|
if (Array.isArray(value)) {
|
|
49402
|
+
if (!subtreeHasTraitRef(value)) return value;
|
|
49111
49403
|
return value.map(
|
|
49112
49404
|
(item, i) => substituteTraitRefsDeep(item, `${pathKey}[${i}]`)
|
|
49113
49405
|
);
|
|
49114
49406
|
}
|
|
49115
49407
|
if (typeof value === "object" && isPlainConfigObject(value)) {
|
|
49408
|
+
if (!subtreeHasTraitRef(value)) return value;
|
|
49116
49409
|
const out = {};
|
|
49117
49410
|
for (const [k, v] of Object.entries(value)) {
|
|
49118
49411
|
out[k] = substituteTraitRefsDeep(v, `${pathKey}.${k}`);
|
|
@@ -49139,6 +49432,10 @@ function renderPatternProps(props, onDismiss, propsSchema) {
|
|
|
49139
49432
|
};
|
|
49140
49433
|
rendered[key] = /* @__PURE__ */ jsxRuntime.jsx(SlotContentRenderer, { content: childContent, onDismiss });
|
|
49141
49434
|
} else if (Array.isArray(value)) {
|
|
49435
|
+
if (!isEvaluatorResolvedData(value) && value.some((el) => isPatternConfig(el))) ; else if (!subtreeHasTraitRef(value)) {
|
|
49436
|
+
rendered[key] = value;
|
|
49437
|
+
continue;
|
|
49438
|
+
}
|
|
49142
49439
|
const isDataArray = propsSchema?.[key]?.items?.types?.includes("object") ?? false;
|
|
49143
49440
|
rendered[key] = value.map((item, i) => {
|
|
49144
49441
|
const el = item;
|
|
@@ -49401,7 +49698,7 @@ function UISlotRenderer({
|
|
|
49401
49698
|
}
|
|
49402
49699
|
return wrapped;
|
|
49403
49700
|
}
|
|
49404
|
-
var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SlotContainedContext, SLOT_SKELETON_MAP, SELF_OVERLAY_PATTERNS, CONTENT_NODE_SLOTS, PATTERNS_WITH_CHILDREN;
|
|
49701
|
+
var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SlotContainedContext, SLOT_SKELETON_MAP, SELF_OVERLAY_PATTERNS, CONTENT_NODE_SLOTS, PATTERNS_WITH_CHILDREN, traitRefPresenceCache;
|
|
49405
49702
|
var init_UISlotRenderer = __esm({
|
|
49406
49703
|
"components/core/organisms/UISlotRenderer.tsx"() {
|
|
49407
49704
|
"use client";
|
|
@@ -49475,6 +49772,7 @@ var init_UISlotRenderer = __esm({
|
|
|
49475
49772
|
"alert",
|
|
49476
49773
|
"dialog"
|
|
49477
49774
|
]);
|
|
49775
|
+
traitRefPresenceCache = /* @__PURE__ */ new WeakMap();
|
|
49478
49776
|
UISlotRenderer.displayName = "UISlotRenderer";
|
|
49479
49777
|
}
|
|
49480
49778
|
});
|
|
@@ -49602,6 +49900,23 @@ function createClientEffectHandlers(options) {
|
|
|
49602
49900
|
})
|
|
49603
49901
|
};
|
|
49604
49902
|
}
|
|
49903
|
+
|
|
49904
|
+
// lib/event-queue-coalesce.ts
|
|
49905
|
+
function enqueueEvent(queue, entry) {
|
|
49906
|
+
if (entry.tick !== void 0) {
|
|
49907
|
+
const pending = queue.find(
|
|
49908
|
+
(e) => e.tick !== void 0 && e.eventKey === entry.eventKey && e.targetTrait === entry.targetTrait
|
|
49909
|
+
);
|
|
49910
|
+
if (pending !== void 0) {
|
|
49911
|
+
pending.payload = entry.payload;
|
|
49912
|
+
return;
|
|
49913
|
+
}
|
|
49914
|
+
}
|
|
49915
|
+
queue.push(entry);
|
|
49916
|
+
}
|
|
49917
|
+
|
|
49918
|
+
// hooks/useTraitStateMachine.ts
|
|
49919
|
+
init_perf();
|
|
49605
49920
|
var lambdaLog = logger.createLogger("almadar:ui:fn-form-lambda");
|
|
49606
49921
|
function isOperatorCall(value) {
|
|
49607
49922
|
const first = value[0];
|
|
@@ -50347,12 +50662,13 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
50347
50662
|
entityId
|
|
50348
50663
|
};
|
|
50349
50664
|
const emittedDuringExec = [];
|
|
50665
|
+
const tickName = flushEvent.startsWith("tick:") ? flushEvent.slice(5) : void 0;
|
|
50350
50666
|
const baseEmit = handlers.emit;
|
|
50351
50667
|
const trackingHandlers = {
|
|
50352
50668
|
...handlers,
|
|
50353
50669
|
emit: (event, eventPayload, source) => {
|
|
50354
50670
|
emittedDuringExec.push(event);
|
|
50355
|
-
baseEmit(event, eventPayload, source);
|
|
50671
|
+
baseEmit(event, eventPayload, tickName !== void 0 ? { ...source, tick: tickName } : source);
|
|
50356
50672
|
}
|
|
50357
50673
|
};
|
|
50358
50674
|
if (traitName === "Hero") {
|
|
@@ -50459,6 +50775,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
50459
50775
|
}, [eventBus]);
|
|
50460
50776
|
React85.useEffect(() => {
|
|
50461
50777
|
const scheduler = runtime.createTickScheduler();
|
|
50778
|
+
const timedTick = (key, fn) => () => ui.perfTimeAsync(key, fn);
|
|
50462
50779
|
const pureWriterTickKeys = /* @__PURE__ */ new Set();
|
|
50463
50780
|
for (const group of sharedGroups.values()) {
|
|
50464
50781
|
const ticksByInterval = /* @__PURE__ */ new Map();
|
|
@@ -50475,12 +50792,12 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
50475
50792
|
}
|
|
50476
50793
|
for (const entries of ticksByInterval.values()) {
|
|
50477
50794
|
const interval = entries[0].tick.interval;
|
|
50478
|
-
const onDue = () => {
|
|
50795
|
+
const onDue = timedTick(`tick:shared:${group.storeKey}@${String(interval)}`, () => {
|
|
50479
50796
|
const writers = entries.map(
|
|
50480
50797
|
({ binding, tick }) => createSharedEntityWriter(binding, tick, traitStatesRef, emitFromSharedWriter)
|
|
50481
50798
|
);
|
|
50482
50799
|
runTickFrame(group.storeKey, writers, sharedEntityStore);
|
|
50483
|
-
};
|
|
50800
|
+
});
|
|
50484
50801
|
if (interval === "frame") {
|
|
50485
50802
|
scheduler.add(0, onDue);
|
|
50486
50803
|
} else if (typeof interval === "number") {
|
|
@@ -50498,21 +50815,23 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
50498
50815
|
if (sharedKey !== void 0 && pureWriterTickKeys.has(`${binding.trait.name}::${tick.name}`)) {
|
|
50499
50816
|
continue;
|
|
50500
50817
|
}
|
|
50818
|
+
const tickKey = `tick:${binding.trait.name}::${tick.name}`;
|
|
50501
50819
|
if (tick.interval === "frame") {
|
|
50502
|
-
scheduler.add(0, () => runTickEffects(tick, binding));
|
|
50820
|
+
scheduler.add(0, timedTick(tickKey, () => runTickEffects(tick, binding)));
|
|
50503
50821
|
} else if (typeof tick.interval === "number") {
|
|
50504
|
-
scheduler.add(tick.interval, () => runTickEffects(tick, binding));
|
|
50822
|
+
scheduler.add(tick.interval, timedTick(tickKey, () => runTickEffects(tick, binding)));
|
|
50505
50823
|
} else if (runtime.isValidCronExpression(tick.interval)) {
|
|
50506
|
-
scheduler.addCron(tick.interval, () => runTickEffects(tick, binding));
|
|
50824
|
+
scheduler.addCron(tick.interval, timedTick(tickKey, () => runTickEffects(tick, binding)));
|
|
50507
50825
|
} else {
|
|
50508
|
-
scheduler.add(runtime.parseDurationString(tick.interval), () => runTickEffects(tick, binding));
|
|
50826
|
+
scheduler.add(runtime.parseDurationString(tick.interval), timedTick(tickKey, () => runTickEffects(tick, binding)));
|
|
50509
50827
|
}
|
|
50510
50828
|
}
|
|
50511
50829
|
}
|
|
50512
50830
|
return () => scheduler.stopAll();
|
|
50513
50831
|
}, [traitBindings, runTickEffects, sharedGroups, sharedEntityStore, emitFromSharedWriter]);
|
|
50514
|
-
const processEventQueued = React85.useCallback(async (eventKey, payload, targetTrait) => {
|
|
50832
|
+
const processEventQueued = React85.useCallback(async (eventKey, payload, targetTrait, tick, sourceTrait) => {
|
|
50515
50833
|
const normalizedEvent = normalizeEventKey(eventKey);
|
|
50834
|
+
const _perfT0 = ui.perfStart("processEvent:total");
|
|
50516
50835
|
const bindings = traitBindingsRef.current;
|
|
50517
50836
|
const currentManager = managerRef.current;
|
|
50518
50837
|
crossTraitLog.debug("processEvent:enter", () => ({
|
|
@@ -50536,6 +50855,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
50536
50855
|
entityByTrait[name] = { ...sharedEntityStore.getSnapshot(sharedKey) };
|
|
50537
50856
|
}
|
|
50538
50857
|
}
|
|
50858
|
+
const _perfT1 = ui.perfStart("processEvent:guardMatch");
|
|
50539
50859
|
const results = currentManager.sendEvent(
|
|
50540
50860
|
normalizedEvent,
|
|
50541
50861
|
payload,
|
|
@@ -50544,6 +50864,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
50544
50864
|
void 0,
|
|
50545
50865
|
targetTrait
|
|
50546
50866
|
);
|
|
50867
|
+
ui.perfEnd("processEvent:guardMatch", _perfT1);
|
|
50547
50868
|
crossTraitLog.debug("processEvent:results", {
|
|
50548
50869
|
event: normalizedEvent,
|
|
50549
50870
|
executedCount: results.length,
|
|
@@ -50593,6 +50914,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
50593
50914
|
transition: `${result.previousState} -> ${result.newState}`,
|
|
50594
50915
|
effects: JSON.stringify(result.effects)
|
|
50595
50916
|
}));
|
|
50917
|
+
const _perfT2 = ui.perfStart("processEvent:executeAll");
|
|
50596
50918
|
const emittedDuringExec = await executeTransitionEffects({
|
|
50597
50919
|
binding,
|
|
50598
50920
|
// upstream gap: /runtime TransitionResult.effects is unknown[] — they are SExpr at runtime (see Almadar_UI_Gaps.md)
|
|
@@ -50604,6 +50926,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
50604
50926
|
syncOnly: false,
|
|
50605
50927
|
log: stateLog
|
|
50606
50928
|
});
|
|
50929
|
+
ui.perfEnd("processEvent:executeAll", _perfT2);
|
|
50607
50930
|
emittedByTrait.set(traitName, emittedDuringExec);
|
|
50608
50931
|
for (const emittedKey of emittedDuringExec) {
|
|
50609
50932
|
bridgeEchoPendingRef.current.set(
|
|
@@ -50700,23 +51023,31 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
50700
51023
|
if (orbital) dispatchedOrbitals.add(orbital);
|
|
50701
51024
|
}
|
|
50702
51025
|
const relayPayload = targetTrait !== void 0 ? { ...payload ?? {}, _targetTrait: targetTrait } : payload;
|
|
50703
|
-
|
|
51026
|
+
void onEventProcessed(normalizedEvent, relayPayload, dispatchedOrbitals, tick, sourceTrait);
|
|
50704
51027
|
}
|
|
51028
|
+
ui.perfEnd("processEvent:total", _perfT0);
|
|
51029
|
+
ui.perfEnd(`event:${normalizedEvent}`, _perfT0);
|
|
50705
51030
|
}, [entities, eventBus, sharedEntityStore]);
|
|
50706
51031
|
const drainEventQueue = React85.useCallback(async () => {
|
|
50707
51032
|
if (processingRef.current) return;
|
|
50708
51033
|
processingRef.current = true;
|
|
51034
|
+
const _perfT = ui.perfStart("drain:pass");
|
|
51035
|
+
let _perfN = 0;
|
|
50709
51036
|
try {
|
|
50710
51037
|
while (eventQueueRef.current.length > 0) {
|
|
50711
51038
|
const entry = eventQueueRef.current.shift();
|
|
50712
|
-
|
|
51039
|
+
_perfN++;
|
|
51040
|
+
await processEventQueued(entry.eventKey, entry.payload, entry.targetTrait, entry.tick, entry.sourceTrait);
|
|
50713
51041
|
}
|
|
50714
51042
|
} finally {
|
|
50715
51043
|
processingRef.current = false;
|
|
51044
|
+
ui.perfEnd("drain:pass", _perfT);
|
|
51045
|
+
ui.perfGauge("drain:passEntries", _perfN);
|
|
50716
51046
|
}
|
|
50717
51047
|
}, [processEventQueued]);
|
|
50718
|
-
const enqueueAndDrain = React85.useCallback((eventKey, payload, targetTrait) => {
|
|
50719
|
-
eventQueueRef.current
|
|
51048
|
+
const enqueueAndDrain = React85.useCallback((eventKey, payload, targetTrait, tick, sourceTrait) => {
|
|
51049
|
+
enqueueEvent(eventQueueRef.current, { eventKey, payload, targetTrait, tick, sourceTrait });
|
|
51050
|
+
ui.perfGauge("queue:depthAtEnqueue", eventQueueRef.current.length);
|
|
50720
51051
|
void drainEventQueue();
|
|
50721
51052
|
}, [drainEventQueue]);
|
|
50722
51053
|
React85.useCallback((eventKey, payload) => {
|
|
@@ -50769,7 +51100,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
50769
51100
|
crossTraitLog.debug("self:fire-server-cascade", { traitName, busKey: selfBusKey, eventKey });
|
|
50770
51101
|
}
|
|
50771
51102
|
crossTraitLog.debug("self:fire", { traitName, busKey: selfBusKey, eventKey });
|
|
50772
|
-
enqueueAndDrain(eventKey, event.payload, traitName);
|
|
51103
|
+
enqueueAndDrain(eventKey, event.payload, traitName, event.source?.tick, event.source?.trait);
|
|
50773
51104
|
});
|
|
50774
51105
|
unsubscribes.push(() => {
|
|
50775
51106
|
crossTraitLog.debug("self:unsubscribe", { traitName, busKey: selfBusKey, eventKey });
|
|
@@ -50787,7 +51118,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
50787
51118
|
const bareKey = `UI:${eventKey}`;
|
|
50788
51119
|
const unsub = eventBus.on(bareKey, (event) => {
|
|
50789
51120
|
crossTraitLog.debug("bare-cascade:fire", { bareKey, eventKey });
|
|
50790
|
-
enqueueAndDrain(eventKey, event.payload);
|
|
51121
|
+
enqueueAndDrain(eventKey, event.payload, void 0, event.source?.tick, event.source?.trait);
|
|
50791
51122
|
});
|
|
50792
51123
|
unsubscribes.push(() => {
|
|
50793
51124
|
crossTraitLog.debug("bare-cascade:unsubscribe", { bareKey, eventKey });
|
|
@@ -50821,7 +51152,9 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
50821
51152
|
enqueueAndDrain(
|
|
50822
51153
|
listen.triggers,
|
|
50823
51154
|
core.applyListenPayloadMapping(listen.payloadMapping, event.payload, evaluator.evaluateListenPayloadExpr),
|
|
50824
|
-
binding.trait.name
|
|
51155
|
+
binding.trait.name,
|
|
51156
|
+
event.source?.tick,
|
|
51157
|
+
event.source?.trait
|
|
50825
51158
|
);
|
|
50826
51159
|
});
|
|
50827
51160
|
unsubscribes.push(() => {
|
|
@@ -51116,7 +51449,7 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
|
|
|
51116
51449
|
[serverActiveTraits]
|
|
51117
51450
|
);
|
|
51118
51451
|
const uiSlots = context.useUISlots();
|
|
51119
|
-
const onEventProcessed = React85.useCallback(
|
|
51452
|
+
const onEventProcessed = React85.useCallback((event, payload, dispatchedOrbitals, tick, sourceTrait) => {
|
|
51120
51453
|
if (!bridge.connected || !orbitalNames?.length) return;
|
|
51121
51454
|
const targets = dispatchedOrbitals && dispatchedOrbitals.size > 0 ? orbitalNames.filter((n) => dispatchedOrbitals.has(n)) : orbitalNames;
|
|
51122
51455
|
xOrbitalLog.debug("TraitInitializer:fanout", () => ({
|
|
@@ -51126,9 +51459,14 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
|
|
|
51126
51459
|
dispatchedOrbitalsSize: dispatchedOrbitals?.size ?? 0
|
|
51127
51460
|
}));
|
|
51128
51461
|
for (const name of targets) {
|
|
51129
|
-
|
|
51130
|
-
|
|
51131
|
-
|
|
51462
|
+
if (tick !== void 0) {
|
|
51463
|
+
void bridge.sendEvent(name, event, withActiveTraits(payload), tick, sourceTrait);
|
|
51464
|
+
continue;
|
|
51465
|
+
}
|
|
51466
|
+
void bridge.sendEvent(name, event, withActiveTraits(payload)).then(({ effects, meta }) => {
|
|
51467
|
+
recordServerResponse(name, event, meta);
|
|
51468
|
+
applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits, activeTraitNames, onNavigateBack);
|
|
51469
|
+
});
|
|
51132
51470
|
}
|
|
51133
51471
|
}, [bridge.connected, bridge.sendEvent, orbitalNames, uiSlots, onNavigate, onNavigateBack, embeddedTraits, activeTraitNames, withActiveTraits]);
|
|
51134
51472
|
const opts = orbitalNames ? { onEventProcessed, navigate: onNavigate, navigateBack: onNavigateBack, traitConfigsByName, orbitalsByTrait, embeddedTraits, initPayload: routeParams } : { navigate: onNavigate, navigateBack: onNavigateBack, persistence, traitConfigsByName, orbitalsByTrait, embeddedTraits, initPayload: routeParams };
|
|
@@ -51446,14 +51784,15 @@ function OrbPreview({
|
|
|
51446
51784
|
return pattern.replace(/:([A-Za-z0-9_]+)/g, (whole, key) => routeParams[key] ?? whole);
|
|
51447
51785
|
}, [currentPagePath, routeParams]);
|
|
51448
51786
|
const navStackRef = React85.useRef(null);
|
|
51449
|
-
const handleNavigate = React85.useCallback((path) => {
|
|
51787
|
+
const handleNavigate = React85.useCallback((path, navState) => {
|
|
51450
51788
|
const hit = providers.matchPathAmong(pages, path, (entry) => entry.page.path);
|
|
51451
51789
|
const match = hit?.candidate;
|
|
51452
|
-
const params = hit?.params ?? {};
|
|
51790
|
+
const params = { ...hit?.params ?? {}, ...navState ?? {} };
|
|
51453
51791
|
navLog.debug("handleNavigate", () => ({
|
|
51454
51792
|
path,
|
|
51455
51793
|
matched: match?.page.name ?? null,
|
|
51456
51794
|
params,
|
|
51795
|
+
navState: navState ? JSON.stringify(navState) : void 0,
|
|
51457
51796
|
availablePaths: pages.map((p) => p.page.path)
|
|
51458
51797
|
}));
|
|
51459
51798
|
if (match?.page.name) {
|
|
@@ -51468,9 +51807,9 @@ function OrbPreview({
|
|
|
51468
51807
|
}
|
|
51469
51808
|
}, [pages]);
|
|
51470
51809
|
const handleNavigateEffect = React85.useCallback(
|
|
51471
|
-
(path,
|
|
51810
|
+
(path, params, crumb) => {
|
|
51472
51811
|
navStackRef.current?.beginNavigate(path, crumb);
|
|
51473
|
-
handleNavigate(path);
|
|
51812
|
+
handleNavigate(path, params);
|
|
51474
51813
|
},
|
|
51475
51814
|
[handleNavigate]
|
|
51476
51815
|
);
|
|
@@ -51601,11 +51940,13 @@ function BrowserPlayground({
|
|
|
51601
51940
|
unregister: async () => {
|
|
51602
51941
|
runtime.unregisterAll();
|
|
51603
51942
|
},
|
|
51604
|
-
sendEvent: async (orbitalName, event, payload) => {
|
|
51943
|
+
sendEvent: async (orbitalName, event, payload, _clientId, tick, sourceTrait) => {
|
|
51605
51944
|
await registrationReady;
|
|
51606
51945
|
return runtime.processOrbitalEvent(orbitalName, {
|
|
51607
51946
|
event,
|
|
51608
|
-
payload
|
|
51947
|
+
payload,
|
|
51948
|
+
tick,
|
|
51949
|
+
sourceTrait
|
|
51609
51950
|
// @almadar/runtime OrbitalEventResponse.clientEffects uses a wider ClientEffectTuple than
|
|
51610
51951
|
// ServerBridge's local definition — cast at this boundary (upstream fix queued).
|
|
51611
51952
|
});
|
|
@@ -51623,17 +51964,9 @@ function BrowserPlayground({
|
|
|
51623
51964
|
}
|
|
51624
51965
|
);
|
|
51625
51966
|
}
|
|
51626
|
-
|
|
51627
|
-
|
|
51628
|
-
|
|
51629
|
-
var profilerOnRender = (id, phase, actualDuration, baseDuration, _startTime, commitTime) => {
|
|
51630
|
-
ui.pushPerfEntry({
|
|
51631
|
-
name: `profiler:${id}:${phase}`,
|
|
51632
|
-
durationMs: actualDuration,
|
|
51633
|
-
ts: commitTime,
|
|
51634
|
-
detail: { baseDuration }
|
|
51635
|
-
});
|
|
51636
|
-
};
|
|
51967
|
+
|
|
51968
|
+
// runtime/index.ts
|
|
51969
|
+
init_perf();
|
|
51637
51970
|
|
|
51638
51971
|
Object.defineProperty(exports, "EntitySchemaProvider", {
|
|
51639
51972
|
enumerable: true,
|
|
@@ -51711,7 +52044,6 @@ exports.BrowserPlayground = BrowserPlayground;
|
|
|
51711
52044
|
exports.OrbPreview = OrbPreview;
|
|
51712
52045
|
exports.clearSchemaCache = clearSchemaCache;
|
|
51713
52046
|
exports.createClientEffectHandlers = createClientEffectHandlers;
|
|
51714
|
-
exports.profilerOnRender = profilerOnRender;
|
|
51715
52047
|
exports.usePerfBuffer = usePerfBuffer;
|
|
51716
52048
|
exports.useResolvedSchema = useResolvedSchema;
|
|
51717
52049
|
exports.useTraitStateMachine = useTraitStateMachine;
|