@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/avl/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import { Loader2, X, Code, FileText, WrapText, Check, Copy, Lightbulb, CheckCirc
|
|
|
13
13
|
import { createPortal } from 'react-dom';
|
|
14
14
|
import { UISlotProvider, useUISlots, useTheme } from '@almadar/ui/context';
|
|
15
15
|
import { evaluateGuard, evaluateListenPayloadExpr, evaluate, createMinimalContext, executeEffects } from '@almadar/evaluator';
|
|
16
|
-
import { prepareSchemaForPreview, collectTraitRefsFromResolvedTrait, buildOrbitalsByTrait, collectEmbeddedTraits,
|
|
16
|
+
import { prepareSchemaForPreview, collectTraitRefsFromResolvedTrait, buildOrbitalsByTrait, collectEmbeddedTraits, perfStart, perfEnd, perfGauge, perfTimeAsync, wrapCallbackForEvent, pushPerfEntry } from '@almadar/runtime/ui';
|
|
17
17
|
import { Link, Outlet, useLocation } from 'react-router-dom';
|
|
18
18
|
import SyntaxHighlighter from 'react-syntax-highlighter/dist/esm/prism-light.js';
|
|
19
19
|
import dark from 'react-syntax-highlighter/dist/esm/styles/prism/vsc-dark-plus.js';
|
|
@@ -4588,11 +4588,54 @@ function isPlainObject(value) {
|
|
|
4588
4588
|
if (typeof value === "function") return false;
|
|
4589
4589
|
return true;
|
|
4590
4590
|
}
|
|
4591
|
+
function isEvaluatorResolvedData(value) {
|
|
4592
|
+
return evaluatorResolvedData.has(value);
|
|
4593
|
+
}
|
|
4594
|
+
function brandResolved(value) {
|
|
4595
|
+
if (value !== null && typeof value === "object" && !React94__default.isValidElement(value) && !(value instanceof Date)) {
|
|
4596
|
+
resolvedMarkerFree.add(value);
|
|
4597
|
+
}
|
|
4598
|
+
}
|
|
4599
|
+
function subtreeHasMarker(value) {
|
|
4600
|
+
if (resolvedMarkerFree.has(value)) return false;
|
|
4601
|
+
const cached = markerPresenceCache.get(value);
|
|
4602
|
+
if (cached !== void 0) return cached;
|
|
4603
|
+
let found = false;
|
|
4604
|
+
const children = Array.isArray(value) ? value : Object.values(value);
|
|
4605
|
+
for (const child of children) {
|
|
4606
|
+
if (isRenderBindingMarker(child)) {
|
|
4607
|
+
found = true;
|
|
4608
|
+
break;
|
|
4609
|
+
}
|
|
4610
|
+
if (Array.isArray(child) || isPlainObject(child)) {
|
|
4611
|
+
if (subtreeHasMarker(child)) {
|
|
4612
|
+
found = true;
|
|
4613
|
+
break;
|
|
4614
|
+
}
|
|
4615
|
+
}
|
|
4616
|
+
}
|
|
4617
|
+
markerPresenceCache.set(value, found);
|
|
4618
|
+
return found;
|
|
4619
|
+
}
|
|
4591
4620
|
function walkValue(value, scopeTrait, entity, config, state) {
|
|
4592
4621
|
if (isRenderBindingMarker(value)) {
|
|
4593
|
-
|
|
4622
|
+
const cached = markerResolutionCache.get(value);
|
|
4623
|
+
if (cached !== void 0 && cached.entity === entity && cached.config === config && cached.state === state) {
|
|
4624
|
+
return { resolved: cached.resolved, changed: false };
|
|
4625
|
+
}
|
|
4626
|
+
const resolved = resolveMarkerExpression(value.expression, entity, config, state);
|
|
4627
|
+
markerResolutionCache.set(value, { entity, config, state, resolved });
|
|
4628
|
+
if (resolved !== null && typeof resolved === "object" && !React94__default.isValidElement(resolved) && !(resolved instanceof Date)) {
|
|
4629
|
+
resolvedMarkerFree.add(resolved);
|
|
4630
|
+
evaluatorResolvedData.add(resolved);
|
|
4631
|
+
}
|
|
4632
|
+
return { resolved, changed: true };
|
|
4594
4633
|
}
|
|
4595
4634
|
if (Array.isArray(value)) {
|
|
4635
|
+
if (!subtreeHasMarker(value)) {
|
|
4636
|
+
brandResolved(value);
|
|
4637
|
+
return { resolved: value, changed: false };
|
|
4638
|
+
}
|
|
4596
4639
|
const out = [];
|
|
4597
4640
|
let changed = false;
|
|
4598
4641
|
for (const item of value) {
|
|
@@ -4607,9 +4650,14 @@ function walkValue(value, scopeTrait, entity, config, state) {
|
|
|
4607
4650
|
out.push(resolved);
|
|
4608
4651
|
if (itemChanged) changed = true;
|
|
4609
4652
|
}
|
|
4653
|
+
brandResolved(out);
|
|
4610
4654
|
return changed ? { resolved: out, changed: true } : { resolved: value, changed: false };
|
|
4611
4655
|
}
|
|
4612
4656
|
if (isPlainObject(value)) {
|
|
4657
|
+
if (!subtreeHasMarker(value)) {
|
|
4658
|
+
brandResolved(value);
|
|
4659
|
+
return { resolved: value, changed: false };
|
|
4660
|
+
}
|
|
4613
4661
|
const sourceTrait = value._sourceTrait;
|
|
4614
4662
|
if (typeof sourceTrait === "string" && sourceTrait !== scopeTrait) {
|
|
4615
4663
|
return { resolved: value, changed: false };
|
|
@@ -4621,11 +4669,13 @@ function walkValue(value, scopeTrait, entity, config, state) {
|
|
|
4621
4669
|
out[key] = resolved;
|
|
4622
4670
|
if (itemChanged) changed = true;
|
|
4623
4671
|
}
|
|
4672
|
+
brandResolved(out);
|
|
4624
4673
|
return changed ? { resolved: out, changed: true } : { resolved: value, changed: false };
|
|
4625
4674
|
}
|
|
4626
4675
|
return { resolved: value, changed: false };
|
|
4627
4676
|
}
|
|
4628
4677
|
function resolveRenderBindingMarkers(props, scopeTrait, entity, config, state) {
|
|
4678
|
+
if (resolvedMarkerFree.has(props)) return props;
|
|
4629
4679
|
const out = {};
|
|
4630
4680
|
let changed = false;
|
|
4631
4681
|
for (const [key, value] of Object.entries(props)) {
|
|
@@ -4633,11 +4683,17 @@ function resolveRenderBindingMarkers(props, scopeTrait, entity, config, state) {
|
|
|
4633
4683
|
out[key] = resolved;
|
|
4634
4684
|
if (propChanged) changed = true;
|
|
4635
4685
|
}
|
|
4686
|
+
brandResolved(out);
|
|
4636
4687
|
return changed ? out : props;
|
|
4637
4688
|
}
|
|
4689
|
+
var markerPresenceCache, markerResolutionCache, resolvedMarkerFree, evaluatorResolvedData;
|
|
4638
4690
|
var init_resolve_render_bindings = __esm({
|
|
4639
4691
|
"lib/resolve-render-bindings.ts"() {
|
|
4640
4692
|
"use client";
|
|
4693
|
+
markerPresenceCache = /* @__PURE__ */ new WeakMap();
|
|
4694
|
+
markerResolutionCache = /* @__PURE__ */ new WeakMap();
|
|
4695
|
+
resolvedMarkerFree = /* @__PURE__ */ new WeakSet();
|
|
4696
|
+
evaluatorResolvedData = /* @__PURE__ */ new WeakSet();
|
|
4641
4697
|
}
|
|
4642
4698
|
});
|
|
4643
4699
|
function getCurrentIconFamily() {
|
|
@@ -15242,6 +15298,19 @@ var init_molecules = __esm({
|
|
|
15242
15298
|
init_puzzleObject();
|
|
15243
15299
|
}
|
|
15244
15300
|
});
|
|
15301
|
+
var profilerOnRender;
|
|
15302
|
+
var init_perf = __esm({
|
|
15303
|
+
"lib/perf.ts"() {
|
|
15304
|
+
profilerOnRender = (id, phase, actualDuration, baseDuration, _startTime, commitTime) => {
|
|
15305
|
+
pushPerfEntry({
|
|
15306
|
+
name: `profiler:${id}:${phase}`,
|
|
15307
|
+
durationMs: actualDuration,
|
|
15308
|
+
ts: commitTime,
|
|
15309
|
+
detail: { baseDuration }
|
|
15310
|
+
});
|
|
15311
|
+
};
|
|
15312
|
+
}
|
|
15313
|
+
});
|
|
15245
15314
|
function themeBodyFont(el) {
|
|
15246
15315
|
if (typeof getComputedStyle !== "function") return "system-ui, sans-serif";
|
|
15247
15316
|
const v = getComputedStyle(el).getPropertyValue("--font-family-body").trim();
|
|
@@ -15590,6 +15659,7 @@ var init_LearningCanvas = __esm({
|
|
|
15590
15659
|
"components/learning/atoms/LearningCanvas.tsx"() {
|
|
15591
15660
|
"use client";
|
|
15592
15661
|
init_cn();
|
|
15662
|
+
init_perf();
|
|
15593
15663
|
init_useEventBus();
|
|
15594
15664
|
DASH_PATTERNS = { dashed: [6, 4], dotted: [2, 3] };
|
|
15595
15665
|
TRACE_SERIES_COLORS = ["#2563eb", "#dc2626", "#16a34a", "#f59e0b"];
|
|
@@ -15633,6 +15703,7 @@ var init_LearningCanvas = __esm({
|
|
|
15633
15703
|
return [...shapes, ...traceOut, ...readoutOut];
|
|
15634
15704
|
}, [shapes, traces, readouts, width, height]);
|
|
15635
15705
|
const draw = useCallback(() => {
|
|
15706
|
+
const _perfT = perfStart("learningcanvas:paint");
|
|
15636
15707
|
const canvas = canvasRef.current;
|
|
15637
15708
|
if (!canvas) return;
|
|
15638
15709
|
const ctx = canvas.getContext("2d");
|
|
@@ -15654,6 +15725,7 @@ var init_LearningCanvas = __esm({
|
|
|
15654
15725
|
for (const shape of derivedShapes) {
|
|
15655
15726
|
if (shape.type === "text") drawShape(ctx, shape, width, height, derivedShapes);
|
|
15656
15727
|
}
|
|
15728
|
+
perfEnd("learningcanvas:paint", _perfT);
|
|
15657
15729
|
}, [width, height, backgroundColor, derivedShapes]);
|
|
15658
15730
|
useEffect(() => {
|
|
15659
15731
|
draw();
|
|
@@ -29631,7 +29703,7 @@ function fileIcon(name) {
|
|
|
29631
29703
|
return "file";
|
|
29632
29704
|
}
|
|
29633
29705
|
}
|
|
29634
|
-
var TreeNodeItem, FileTree;
|
|
29706
|
+
var TreeNodeItem, FlatTreeNodeItem, FileTree;
|
|
29635
29707
|
var init_FileTree = __esm({
|
|
29636
29708
|
"components/core/molecules/FileTree.tsx"() {
|
|
29637
29709
|
"use client";
|
|
@@ -29716,14 +29788,101 @@ var init_FileTree = __esm({
|
|
|
29716
29788
|
)) })
|
|
29717
29789
|
] });
|
|
29718
29790
|
};
|
|
29791
|
+
FlatTreeNodeItem = ({
|
|
29792
|
+
item,
|
|
29793
|
+
depth,
|
|
29794
|
+
indent,
|
|
29795
|
+
childrenByParent,
|
|
29796
|
+
onNodeSelect,
|
|
29797
|
+
defaultExpanded = false
|
|
29798
|
+
}) => {
|
|
29799
|
+
const [expanded, setExpanded] = useState(defaultExpanded || depth < 1);
|
|
29800
|
+
const children = childrenByParent.get(item.id);
|
|
29801
|
+
const hasChildren = !!children && children.length > 0;
|
|
29802
|
+
const handleClick = useCallback(() => {
|
|
29803
|
+
if (hasChildren) setExpanded((prev) => !prev);
|
|
29804
|
+
onNodeSelect?.(item.id);
|
|
29805
|
+
}, [hasChildren, item.id, onNodeSelect]);
|
|
29806
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
29807
|
+
/* @__PURE__ */ jsxs(
|
|
29808
|
+
Box,
|
|
29809
|
+
{
|
|
29810
|
+
className: "flex items-center gap-1.5 py-0.5 px-2 cursor-pointer rounded-sm transition-colors hover:bg-muted",
|
|
29811
|
+
style: { paddingLeft: depth * indent + 8 },
|
|
29812
|
+
onClick: handleClick,
|
|
29813
|
+
role: "treeitem",
|
|
29814
|
+
"aria-expanded": hasChildren ? expanded : void 0,
|
|
29815
|
+
children: [
|
|
29816
|
+
hasChildren ? /* @__PURE__ */ jsx(
|
|
29817
|
+
Icon,
|
|
29818
|
+
{
|
|
29819
|
+
name: expanded ? "chevron-down" : "chevron-right",
|
|
29820
|
+
size: "xs",
|
|
29821
|
+
className: "text-[var(--color-muted-foreground)] flex-shrink-0"
|
|
29822
|
+
}
|
|
29823
|
+
) : /* @__PURE__ */ jsx(Box, { style: { width: 12, flexShrink: 0 } }),
|
|
29824
|
+
/* @__PURE__ */ jsx(
|
|
29825
|
+
Icon,
|
|
29826
|
+
{
|
|
29827
|
+
name: item.icon ?? (hasChildren ? expanded ? "folder-open" : "folder" : "file"),
|
|
29828
|
+
size: "xs",
|
|
29829
|
+
className: hasChildren ? "text-[var(--color-warning)]" : "text-[var(--color-muted-foreground)]"
|
|
29830
|
+
}
|
|
29831
|
+
),
|
|
29832
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", className: "truncate font-mono text-xs", children: item.label })
|
|
29833
|
+
]
|
|
29834
|
+
}
|
|
29835
|
+
),
|
|
29836
|
+
hasChildren && expanded && /* @__PURE__ */ jsx(Box, { role: "group", children: children.map((child) => /* @__PURE__ */ jsx(
|
|
29837
|
+
FlatTreeNodeItem,
|
|
29838
|
+
{
|
|
29839
|
+
item: child,
|
|
29840
|
+
depth: depth + 1,
|
|
29841
|
+
indent,
|
|
29842
|
+
childrenByParent,
|
|
29843
|
+
onNodeSelect
|
|
29844
|
+
},
|
|
29845
|
+
child.id
|
|
29846
|
+
)) })
|
|
29847
|
+
] });
|
|
29848
|
+
};
|
|
29719
29849
|
FileTree = ({
|
|
29720
29850
|
tree,
|
|
29851
|
+
items,
|
|
29721
29852
|
selectedPath,
|
|
29722
29853
|
onFileSelect,
|
|
29854
|
+
onNodeSelect,
|
|
29723
29855
|
className,
|
|
29724
29856
|
indent = 16
|
|
29725
29857
|
}) => {
|
|
29726
|
-
if (
|
|
29858
|
+
if (items) {
|
|
29859
|
+
if (items.length === 0) return null;
|
|
29860
|
+
const ids = new Set(items.map((node) => node.id));
|
|
29861
|
+
const childrenByParent = /* @__PURE__ */ new Map();
|
|
29862
|
+
const roots = [];
|
|
29863
|
+
for (const item of items) {
|
|
29864
|
+
if (item.parentId && ids.has(item.parentId)) {
|
|
29865
|
+
const siblings = childrenByParent.get(item.parentId);
|
|
29866
|
+
if (siblings) siblings.push(item);
|
|
29867
|
+
else childrenByParent.set(item.parentId, [item]);
|
|
29868
|
+
} else {
|
|
29869
|
+
roots.push(item);
|
|
29870
|
+
}
|
|
29871
|
+
}
|
|
29872
|
+
return /* @__PURE__ */ jsx(Box, { className: `py-1 overflow-y-auto ${className ?? ""}`, role: "tree", children: roots.map((item) => /* @__PURE__ */ jsx(
|
|
29873
|
+
FlatTreeNodeItem,
|
|
29874
|
+
{
|
|
29875
|
+
item,
|
|
29876
|
+
depth: 0,
|
|
29877
|
+
indent,
|
|
29878
|
+
childrenByParent,
|
|
29879
|
+
onNodeSelect,
|
|
29880
|
+
defaultExpanded: true
|
|
29881
|
+
},
|
|
29882
|
+
item.id
|
|
29883
|
+
)) });
|
|
29884
|
+
}
|
|
29885
|
+
if (!tree || tree.length === 0) return null;
|
|
29727
29886
|
return /* @__PURE__ */ jsx(Box, { className: `py-1 overflow-y-auto ${className ?? ""}`, role: "tree", children: tree.map((node) => /* @__PURE__ */ jsx(
|
|
29728
29887
|
TreeNodeItem,
|
|
29729
29888
|
{
|
|
@@ -31118,7 +31277,7 @@ var init_debug = __esm({
|
|
|
31118
31277
|
createLogger("almadar:ui:debug:game-state");
|
|
31119
31278
|
}
|
|
31120
31279
|
});
|
|
31121
|
-
var isRelationsDebugEnabled, RelationSelect;
|
|
31280
|
+
var isRelationsDebugEnabled, MANY_CARDINALITIES, RelationSelect;
|
|
31122
31281
|
var init_RelationSelect = __esm({
|
|
31123
31282
|
"components/core/molecules/RelationSelect.tsx"() {
|
|
31124
31283
|
"use client";
|
|
@@ -31132,6 +31291,11 @@ var init_RelationSelect = __esm({
|
|
|
31132
31291
|
init_Typography();
|
|
31133
31292
|
init_debug();
|
|
31134
31293
|
isRelationsDebugEnabled = () => isDebugEnabled();
|
|
31294
|
+
MANY_CARDINALITIES = [
|
|
31295
|
+
"many",
|
|
31296
|
+
"one-to-many",
|
|
31297
|
+
"many-to-many"
|
|
31298
|
+
];
|
|
31135
31299
|
RelationSelect = ({
|
|
31136
31300
|
value,
|
|
31137
31301
|
onChange,
|
|
@@ -32756,6 +32920,7 @@ var init_MathCanvas = __esm({
|
|
|
32756
32920
|
"components/learning/molecules/MathCanvas.tsx"() {
|
|
32757
32921
|
"use client";
|
|
32758
32922
|
init_useEventBus();
|
|
32923
|
+
init_perf();
|
|
32759
32924
|
init_atoms();
|
|
32760
32925
|
init_Stack();
|
|
32761
32926
|
init_LearningCanvas();
|
|
@@ -32796,17 +32961,21 @@ var init_MathCanvas = __esm({
|
|
|
32796
32961
|
error
|
|
32797
32962
|
}) => {
|
|
32798
32963
|
const eventBus = useEventBus();
|
|
32964
|
+
const keyMapKey = keyMap ? JSON.stringify(keyMap) : null;
|
|
32965
|
+
const keyUpMapKey = keyUpMap ? JSON.stringify(keyUpMap) : null;
|
|
32966
|
+
const stableKeyMap = useMemo(() => keyMap, [keyMapKey]);
|
|
32967
|
+
const stableKeyUpMap = useMemo(() => keyUpMap, [keyUpMapKey]);
|
|
32799
32968
|
useEffect(() => {
|
|
32800
|
-
if (!
|
|
32969
|
+
if (!stableKeyMap && !stableKeyUpMap) return;
|
|
32801
32970
|
const onDown = (e) => {
|
|
32802
|
-
const ev =
|
|
32971
|
+
const ev = stableKeyMap?.[e.code];
|
|
32803
32972
|
if (ev) {
|
|
32804
32973
|
eventBus.emit(`UI:${ev}`, {});
|
|
32805
32974
|
e.preventDefault();
|
|
32806
32975
|
}
|
|
32807
32976
|
};
|
|
32808
32977
|
const onUp = (e) => {
|
|
32809
|
-
const ev =
|
|
32978
|
+
const ev = stableKeyUpMap?.[e.code];
|
|
32810
32979
|
if (ev) eventBus.emit(`UI:${ev}`, {});
|
|
32811
32980
|
};
|
|
32812
32981
|
window.addEventListener("keydown", onDown);
|
|
@@ -32815,8 +32984,9 @@ var init_MathCanvas = __esm({
|
|
|
32815
32984
|
window.removeEventListener("keydown", onDown);
|
|
32816
32985
|
window.removeEventListener("keyup", onUp);
|
|
32817
32986
|
};
|
|
32818
|
-
}, [
|
|
32987
|
+
}, [stableKeyMap, stableKeyUpMap, eventBus]);
|
|
32819
32988
|
const derivedShapes = useMemo(() => {
|
|
32989
|
+
const _perfT = perfStart("mathcanvas:derive");
|
|
32820
32990
|
const out = [];
|
|
32821
32991
|
const margin = 24;
|
|
32822
32992
|
const plotW = width - margin * 2;
|
|
@@ -33060,6 +33230,7 @@ var init_MathCanvas = __esm({
|
|
|
33060
33230
|
}
|
|
33061
33231
|
}
|
|
33062
33232
|
out.push(...shapes);
|
|
33233
|
+
perfEnd("mathcanvas:derive", _perfT);
|
|
33063
33234
|
return out;
|
|
33064
33235
|
}, [
|
|
33065
33236
|
width,
|
|
@@ -39413,7 +39584,7 @@ var init_RichBlockEditor = __esm({
|
|
|
39413
39584
|
{
|
|
39414
39585
|
variant: "bordered",
|
|
39415
39586
|
padding: "none",
|
|
39416
|
-
className: cn("flex flex-col", className),
|
|
39587
|
+
className: cn("flex flex-col text-card-foreground", className),
|
|
39417
39588
|
children: [
|
|
39418
39589
|
enableBlocks && showToolbar && !readOnly && /* @__PURE__ */ jsx(
|
|
39419
39590
|
Box,
|
|
@@ -44232,6 +44403,7 @@ var init_DetailPanel = __esm({
|
|
|
44232
44403
|
"use client";
|
|
44233
44404
|
init_atoms();
|
|
44234
44405
|
init_Box();
|
|
44406
|
+
init_Input();
|
|
44235
44407
|
init_Stack();
|
|
44236
44408
|
init_SimpleGrid();
|
|
44237
44409
|
init_Menu();
|
|
@@ -44247,6 +44419,7 @@ var init_DetailPanel = __esm({
|
|
|
44247
44419
|
ReactMarkdown2 = lazy(() => import('react-markdown'));
|
|
44248
44420
|
DetailPanel = ({
|
|
44249
44421
|
title: propTitle,
|
|
44422
|
+
onTitleCommit,
|
|
44250
44423
|
subtitle,
|
|
44251
44424
|
status,
|
|
44252
44425
|
avatar,
|
|
@@ -44268,6 +44441,7 @@ var init_DetailPanel = __esm({
|
|
|
44268
44441
|
}) => {
|
|
44269
44442
|
const eventBus = useEventBus();
|
|
44270
44443
|
const { t } = useTranslate();
|
|
44444
|
+
const [titleDraft, setTitleDraft] = React94__default.useState(null);
|
|
44271
44445
|
const isFieldDefArray = (arr) => {
|
|
44272
44446
|
if (!arr || arr.length === 0) return false;
|
|
44273
44447
|
const first = arr[0];
|
|
@@ -44488,6 +44662,50 @@ var init_DetailPanel = __esm({
|
|
|
44488
44662
|
}),
|
|
44489
44663
|
status && /* @__PURE__ */ jsx(Badge, { variant: status.variant ?? "default", children: status.label })
|
|
44490
44664
|
] });
|
|
44665
|
+
const commitTitle = () => {
|
|
44666
|
+
if (!onTitleCommit) return;
|
|
44667
|
+
const next = (titleDraft ?? "").trim();
|
|
44668
|
+
setTitleDraft(null);
|
|
44669
|
+
if (!next || next === title) return;
|
|
44670
|
+
onTitleCommit(next, normalizedData?.id !== void 0 ? String(normalizedData.id) : "");
|
|
44671
|
+
};
|
|
44672
|
+
const titleNode = onTitleCommit && titleDraft !== null ? /* @__PURE__ */ jsx(
|
|
44673
|
+
Input,
|
|
44674
|
+
{
|
|
44675
|
+
value: titleDraft,
|
|
44676
|
+
autoFocus: true,
|
|
44677
|
+
"aria-label": t("common.title"),
|
|
44678
|
+
className: "h-auto py-1 text-3xl font-bold tracking-tight",
|
|
44679
|
+
onChange: (e) => setTitleDraft(e.target.value),
|
|
44680
|
+
onBlur: commitTitle,
|
|
44681
|
+
onKeyDown: (e) => {
|
|
44682
|
+
if (e.key === "Enter") {
|
|
44683
|
+
e.preventDefault();
|
|
44684
|
+
commitTitle();
|
|
44685
|
+
} else if (e.key === "Escape") {
|
|
44686
|
+
e.preventDefault();
|
|
44687
|
+
setTitleDraft(null);
|
|
44688
|
+
}
|
|
44689
|
+
},
|
|
44690
|
+
"data-testid": "detail-title-input"
|
|
44691
|
+
}
|
|
44692
|
+
) : onTitleCommit ? /* @__PURE__ */ jsx(
|
|
44693
|
+
Box,
|
|
44694
|
+
{
|
|
44695
|
+
role: "button",
|
|
44696
|
+
tabIndex: 0,
|
|
44697
|
+
className: "cursor-text rounded px-1 -mx-1 transition-colors hover:bg-muted/40",
|
|
44698
|
+
onClick: () => setTitleDraft(title ?? ""),
|
|
44699
|
+
onKeyDown: (e) => {
|
|
44700
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
44701
|
+
e.preventDefault();
|
|
44702
|
+
setTitleDraft(title ?? "");
|
|
44703
|
+
}
|
|
44704
|
+
},
|
|
44705
|
+
"data-testid": "detail-title-editable",
|
|
44706
|
+
children: /* @__PURE__ */ jsx(Typography, { variant: "h2", weight: "bold", children: title || "Details" })
|
|
44707
|
+
}
|
|
44708
|
+
) : /* @__PURE__ */ jsx(Typography, { variant: "h2", weight: "bold", children: title || "Details" });
|
|
44491
44709
|
const content = /* @__PURE__ */ jsx(Card, { variant: "elevated", children: /* @__PURE__ */ jsxs(VStack, { gap: "md", className: "p-6", children: [
|
|
44492
44710
|
/* @__PURE__ */ jsxs(HStack, { justify: "between", align: "start", gap: "md", children: [
|
|
44493
44711
|
/* @__PURE__ */ jsxs(HStack, { align: "start", gap: "sm", className: "min-w-0", children: [
|
|
@@ -44507,7 +44725,7 @@ var init_DetailPanel = __esm({
|
|
|
44507
44725
|
avatar,
|
|
44508
44726
|
/* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "min-w-0", children: [
|
|
44509
44727
|
/* @__PURE__ */ jsxs(HStack, { align: "center", gap: "sm", wrap: true, children: [
|
|
44510
|
-
|
|
44728
|
+
titleNode,
|
|
44511
44729
|
statusBadges
|
|
44512
44730
|
] }),
|
|
44513
44731
|
subtitle && /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: subtitle })
|
|
@@ -44843,6 +45061,9 @@ function determineInputType(field) {
|
|
|
44843
45061
|
if (field.type === "relation" || field.relation) {
|
|
44844
45062
|
return "relation";
|
|
44845
45063
|
}
|
|
45064
|
+
if (field.type === "array") {
|
|
45065
|
+
return "array";
|
|
45066
|
+
}
|
|
44846
45067
|
if (field.type === "enum" || field.values || getEnumOptions(field).length > 0) {
|
|
44847
45068
|
return "select";
|
|
44848
45069
|
}
|
|
@@ -44918,6 +45139,7 @@ var init_Form = __esm({
|
|
|
44918
45139
|
init_Typography();
|
|
44919
45140
|
init_Icon();
|
|
44920
45141
|
init_RelationSelect();
|
|
45142
|
+
init_TagInput();
|
|
44921
45143
|
init_UploadDropZone();
|
|
44922
45144
|
init_Alert();
|
|
44923
45145
|
init_useEventBus();
|
|
@@ -44997,7 +45219,7 @@ var init_Form = __esm({
|
|
|
44997
45219
|
values: "values" in f3 ? f3.values : void 0,
|
|
44998
45220
|
min: f3.min,
|
|
44999
45221
|
max: f3.max,
|
|
45000
|
-
relation: "relation" in f3 ? { entity: f3.relation.entity } : void 0
|
|
45222
|
+
relation: "relation" in f3 ? { entity: f3.relation.entity, cardinality: f3.relation.cardinality } : void 0
|
|
45001
45223
|
})
|
|
45002
45224
|
);
|
|
45003
45225
|
}, [entity, fields]);
|
|
@@ -45064,7 +45286,7 @@ var init_Form = __esm({
|
|
|
45064
45286
|
});
|
|
45065
45287
|
debug(
|
|
45066
45288
|
"forms",
|
|
45067
|
-
`Calculation triggered: ${calc.variableName} = ${value}`
|
|
45289
|
+
`Calculation triggered: ${calc.variableName} = ${String(value)}`
|
|
45068
45290
|
);
|
|
45069
45291
|
}
|
|
45070
45292
|
});
|
|
@@ -45232,7 +45454,7 @@ var init_Form = __esm({
|
|
|
45232
45454
|
values: "values" in entityField ? entityField.values : void 0,
|
|
45233
45455
|
min: entityField.min,
|
|
45234
45456
|
max: entityField.max,
|
|
45235
|
-
relation: "relation" in entityField ? { entity: entityField.relation.entity } : void 0
|
|
45457
|
+
relation: "relation" in entityField ? { entity: entityField.relation.entity, cardinality: entityField.relation.cardinality } : void 0
|
|
45236
45458
|
};
|
|
45237
45459
|
}
|
|
45238
45460
|
return { name: field, type: "string" };
|
|
@@ -45344,6 +45566,22 @@ var init_Form = __esm({
|
|
|
45344
45566
|
case "relation": {
|
|
45345
45567
|
const relationOptions = relationsData[fieldName] || [];
|
|
45346
45568
|
const relationLoading = relationsLoading[fieldName] || false;
|
|
45569
|
+
if (field.relation?.cardinality !== void 0 && MANY_CARDINALITIES.includes(field.relation.cardinality)) {
|
|
45570
|
+
const selectedValues = Array.isArray(currentValue) ? currentValue.map((v) => String(v)) : [];
|
|
45571
|
+
return /* @__PURE__ */ jsx(
|
|
45572
|
+
Select,
|
|
45573
|
+
{
|
|
45574
|
+
...commonProps,
|
|
45575
|
+
multiple: true,
|
|
45576
|
+
searchable: true,
|
|
45577
|
+
clearable: true,
|
|
45578
|
+
options: [...relationOptions],
|
|
45579
|
+
value: selectedValues,
|
|
45580
|
+
onValueChange: (value) => handleChange(fieldName, Array.isArray(value) ? value : [value]),
|
|
45581
|
+
placeholder: field.placeholder || `Select ${label}...`
|
|
45582
|
+
}
|
|
45583
|
+
);
|
|
45584
|
+
}
|
|
45347
45585
|
return /* @__PURE__ */ jsx(
|
|
45348
45586
|
RelationSelect,
|
|
45349
45587
|
{
|
|
@@ -45358,6 +45596,18 @@ var init_Form = __esm({
|
|
|
45358
45596
|
}
|
|
45359
45597
|
);
|
|
45360
45598
|
}
|
|
45599
|
+
case "array": {
|
|
45600
|
+
const arrayValue = Array.isArray(currentValue) ? currentValue.map((v) => String(v)) : currentValue != null && currentValue !== "" ? [String(currentValue)] : [];
|
|
45601
|
+
return /* @__PURE__ */ jsx(
|
|
45602
|
+
TagInput,
|
|
45603
|
+
{
|
|
45604
|
+
placeholder: field.placeholder,
|
|
45605
|
+
disabled: isLoading,
|
|
45606
|
+
value: arrayValue,
|
|
45607
|
+
onChange: (next) => handleChange(fieldName, [...next])
|
|
45608
|
+
}
|
|
45609
|
+
);
|
|
45610
|
+
}
|
|
45361
45611
|
case "number":
|
|
45362
45612
|
return /* @__PURE__ */ jsx(
|
|
45363
45613
|
Input,
|
|
@@ -50926,7 +51176,10 @@ function enrichFormFields(fields, entityDef) {
|
|
|
50926
51176
|
enriched.values = entityField.enumValues;
|
|
50927
51177
|
}
|
|
50928
51178
|
if (entityField.relation) {
|
|
50929
|
-
enriched.relation =
|
|
51179
|
+
enriched.relation = {
|
|
51180
|
+
entity: entityField.relation.entity,
|
|
51181
|
+
cardinality: entityField.relation.cardinality
|
|
51182
|
+
};
|
|
50930
51183
|
}
|
|
50931
51184
|
return enriched;
|
|
50932
51185
|
}
|
|
@@ -50954,7 +51207,10 @@ function enrichFormFields(fields, entityDef) {
|
|
|
50954
51207
|
}
|
|
50955
51208
|
}
|
|
50956
51209
|
if (!obj.relation && entityField.relation) {
|
|
50957
|
-
enriched.relation =
|
|
51210
|
+
enriched.relation = {
|
|
51211
|
+
entity: entityField.relation.entity,
|
|
51212
|
+
cardinality: entityField.relation.cardinality
|
|
51213
|
+
};
|
|
50958
51214
|
}
|
|
50959
51215
|
return enriched;
|
|
50960
51216
|
}
|
|
@@ -50969,7 +51225,12 @@ function enrichDetailFields(fields, entityDef) {
|
|
|
50969
51225
|
const meta = { type: entityField.type };
|
|
50970
51226
|
const values = entityField.values ?? entityField.enumValues;
|
|
50971
51227
|
if (values && values.length > 0) meta.values = values;
|
|
50972
|
-
if (entityField.relation)
|
|
51228
|
+
if (entityField.relation) {
|
|
51229
|
+
meta.relation = {
|
|
51230
|
+
entity: entityField.relation.entity,
|
|
51231
|
+
cardinality: entityField.relation.cardinality
|
|
51232
|
+
};
|
|
51233
|
+
}
|
|
50973
51234
|
return meta;
|
|
50974
51235
|
};
|
|
50975
51236
|
return fields.map((field) => {
|
|
@@ -51523,6 +51784,33 @@ function isPlainConfigObject(value) {
|
|
|
51523
51784
|
const proto = Object.getPrototypeOf(value);
|
|
51524
51785
|
return proto === Object.prototype || proto === null;
|
|
51525
51786
|
}
|
|
51787
|
+
function subtreeHasTraitRef(value) {
|
|
51788
|
+
if (isEvaluatorResolvedData(value)) return false;
|
|
51789
|
+
const cached = traitRefPresenceCache.get(value);
|
|
51790
|
+
if (cached !== void 0) return cached;
|
|
51791
|
+
let found = false;
|
|
51792
|
+
const children = Array.isArray(value) ? value : Object.values(value);
|
|
51793
|
+
for (const child of children) {
|
|
51794
|
+
if (typeof child === "string" && TRAIT_BINDING_RE.test(child)) {
|
|
51795
|
+
found = true;
|
|
51796
|
+
break;
|
|
51797
|
+
}
|
|
51798
|
+
if (isRenderBindingMarker(child)) continue;
|
|
51799
|
+
if (Array.isArray(child)) {
|
|
51800
|
+
if (subtreeHasTraitRef(child)) {
|
|
51801
|
+
found = true;
|
|
51802
|
+
break;
|
|
51803
|
+
}
|
|
51804
|
+
} else if (child !== null && typeof child === "object" && isPlainConfigObject(child)) {
|
|
51805
|
+
if (subtreeHasTraitRef(child)) {
|
|
51806
|
+
found = true;
|
|
51807
|
+
break;
|
|
51808
|
+
}
|
|
51809
|
+
}
|
|
51810
|
+
}
|
|
51811
|
+
traitRefPresenceCache.set(value, found);
|
|
51812
|
+
return found;
|
|
51813
|
+
}
|
|
51526
51814
|
function substituteTraitRefsDeep(value, pathKey) {
|
|
51527
51815
|
if (isRenderBindingMarker(value)) return value;
|
|
51528
51816
|
if (typeof value === "string") {
|
|
@@ -51537,11 +51825,13 @@ function substituteTraitRefsDeep(value, pathKey) {
|
|
|
51537
51825
|
return value;
|
|
51538
51826
|
}
|
|
51539
51827
|
if (Array.isArray(value)) {
|
|
51828
|
+
if (!subtreeHasTraitRef(value)) return value;
|
|
51540
51829
|
return value.map(
|
|
51541
51830
|
(item, i) => substituteTraitRefsDeep(item, `${pathKey}[${i}]`)
|
|
51542
51831
|
);
|
|
51543
51832
|
}
|
|
51544
51833
|
if (typeof value === "object" && isPlainConfigObject(value)) {
|
|
51834
|
+
if (!subtreeHasTraitRef(value)) return value;
|
|
51545
51835
|
const out = {};
|
|
51546
51836
|
for (const [k, v] of Object.entries(value)) {
|
|
51547
51837
|
out[k] = substituteTraitRefsDeep(v, `${pathKey}.${k}`);
|
|
@@ -51568,6 +51858,10 @@ function renderPatternProps(props, onDismiss, propsSchema) {
|
|
|
51568
51858
|
};
|
|
51569
51859
|
rendered[key] = /* @__PURE__ */ jsx(SlotContentRenderer, { content: childContent, onDismiss });
|
|
51570
51860
|
} else if (Array.isArray(value)) {
|
|
51861
|
+
if (!isEvaluatorResolvedData(value) && value.some((el) => isPatternConfig(el))) ; else if (!subtreeHasTraitRef(value)) {
|
|
51862
|
+
rendered[key] = value;
|
|
51863
|
+
continue;
|
|
51864
|
+
}
|
|
51571
51865
|
const isDataArray = propsSchema?.[key]?.items?.types?.includes("object") ?? false;
|
|
51572
51866
|
rendered[key] = value.map((item, i) => {
|
|
51573
51867
|
const el = item;
|
|
@@ -51830,7 +52124,7 @@ function UISlotRenderer({
|
|
|
51830
52124
|
}
|
|
51831
52125
|
return wrapped;
|
|
51832
52126
|
}
|
|
51833
|
-
var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SlotContainedContext, SLOT_SKELETON_MAP, SELF_OVERLAY_PATTERNS, CONTENT_NODE_SLOTS, PATTERNS_WITH_CHILDREN;
|
|
52127
|
+
var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SlotContainedContext, SLOT_SKELETON_MAP, SELF_OVERLAY_PATTERNS, CONTENT_NODE_SLOTS, PATTERNS_WITH_CHILDREN, traitRefPresenceCache;
|
|
51834
52128
|
var init_UISlotRenderer = __esm({
|
|
51835
52129
|
"components/core/organisms/UISlotRenderer.tsx"() {
|
|
51836
52130
|
"use client";
|
|
@@ -51904,6 +52198,7 @@ var init_UISlotRenderer = __esm({
|
|
|
51904
52198
|
"alert",
|
|
51905
52199
|
"dialog"
|
|
51906
52200
|
]);
|
|
52201
|
+
traitRefPresenceCache = /* @__PURE__ */ new WeakMap();
|
|
51907
52202
|
UISlotRenderer.displayName = "UISlotRenderer";
|
|
51908
52203
|
}
|
|
51909
52204
|
});
|
|
@@ -55578,7 +55873,22 @@ function createClientEffectHandlers(options) {
|
|
|
55578
55873
|
};
|
|
55579
55874
|
}
|
|
55580
55875
|
|
|
55876
|
+
// lib/event-queue-coalesce.ts
|
|
55877
|
+
function enqueueEvent(queue, entry) {
|
|
55878
|
+
if (entry.tick !== void 0) {
|
|
55879
|
+
const pending = queue.find(
|
|
55880
|
+
(e) => e.tick !== void 0 && e.eventKey === entry.eventKey && e.targetTrait === entry.targetTrait
|
|
55881
|
+
);
|
|
55882
|
+
if (pending !== void 0) {
|
|
55883
|
+
pending.payload = entry.payload;
|
|
55884
|
+
return;
|
|
55885
|
+
}
|
|
55886
|
+
}
|
|
55887
|
+
queue.push(entry);
|
|
55888
|
+
}
|
|
55889
|
+
|
|
55581
55890
|
// hooks/useTraitStateMachine.ts
|
|
55891
|
+
init_perf();
|
|
55582
55892
|
init_traitRegistry();
|
|
55583
55893
|
init_verificationRegistry();
|
|
55584
55894
|
var crossTraitLog = createLogger("almadar:ui:cross-trait");
|
|
@@ -56152,12 +56462,13 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
56152
56462
|
entityId
|
|
56153
56463
|
};
|
|
56154
56464
|
const emittedDuringExec = [];
|
|
56465
|
+
const tickName = flushEvent.startsWith("tick:") ? flushEvent.slice(5) : void 0;
|
|
56155
56466
|
const baseEmit = handlers.emit;
|
|
56156
56467
|
const trackingHandlers = {
|
|
56157
56468
|
...handlers,
|
|
56158
56469
|
emit: (event, eventPayload, source) => {
|
|
56159
56470
|
emittedDuringExec.push(event);
|
|
56160
|
-
baseEmit(event, eventPayload, source);
|
|
56471
|
+
baseEmit(event, eventPayload, tickName !== void 0 ? { ...source, tick: tickName } : source);
|
|
56161
56472
|
}
|
|
56162
56473
|
};
|
|
56163
56474
|
if (traitName === "Hero") {
|
|
@@ -56264,6 +56575,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
56264
56575
|
}, [eventBus]);
|
|
56265
56576
|
useEffect(() => {
|
|
56266
56577
|
const scheduler = createTickScheduler();
|
|
56578
|
+
const timedTick = (key, fn) => () => perfTimeAsync(key, fn);
|
|
56267
56579
|
const pureWriterTickKeys = /* @__PURE__ */ new Set();
|
|
56268
56580
|
for (const group of sharedGroups.values()) {
|
|
56269
56581
|
const ticksByInterval = /* @__PURE__ */ new Map();
|
|
@@ -56280,12 +56592,12 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
56280
56592
|
}
|
|
56281
56593
|
for (const entries of ticksByInterval.values()) {
|
|
56282
56594
|
const interval = entries[0].tick.interval;
|
|
56283
|
-
const onDue = () => {
|
|
56595
|
+
const onDue = timedTick(`tick:shared:${group.storeKey}@${String(interval)}`, () => {
|
|
56284
56596
|
const writers = entries.map(
|
|
56285
56597
|
({ binding, tick }) => createSharedEntityWriter(binding, tick, traitStatesRef, emitFromSharedWriter)
|
|
56286
56598
|
);
|
|
56287
56599
|
runTickFrame(group.storeKey, writers, sharedEntityStore);
|
|
56288
|
-
};
|
|
56600
|
+
});
|
|
56289
56601
|
if (interval === "frame") {
|
|
56290
56602
|
scheduler.add(0, onDue);
|
|
56291
56603
|
} else if (typeof interval === "number") {
|
|
@@ -56303,21 +56615,23 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
56303
56615
|
if (sharedKey !== void 0 && pureWriterTickKeys.has(`${binding.trait.name}::${tick.name}`)) {
|
|
56304
56616
|
continue;
|
|
56305
56617
|
}
|
|
56618
|
+
const tickKey = `tick:${binding.trait.name}::${tick.name}`;
|
|
56306
56619
|
if (tick.interval === "frame") {
|
|
56307
|
-
scheduler.add(0, () => runTickEffects(tick, binding));
|
|
56620
|
+
scheduler.add(0, timedTick(tickKey, () => runTickEffects(tick, binding)));
|
|
56308
56621
|
} else if (typeof tick.interval === "number") {
|
|
56309
|
-
scheduler.add(tick.interval, () => runTickEffects(tick, binding));
|
|
56622
|
+
scheduler.add(tick.interval, timedTick(tickKey, () => runTickEffects(tick, binding)));
|
|
56310
56623
|
} else if (isValidCronExpression(tick.interval)) {
|
|
56311
|
-
scheduler.addCron(tick.interval, () => runTickEffects(tick, binding));
|
|
56624
|
+
scheduler.addCron(tick.interval, timedTick(tickKey, () => runTickEffects(tick, binding)));
|
|
56312
56625
|
} else {
|
|
56313
|
-
scheduler.add(parseDurationString(tick.interval), () => runTickEffects(tick, binding));
|
|
56626
|
+
scheduler.add(parseDurationString(tick.interval), timedTick(tickKey, () => runTickEffects(tick, binding)));
|
|
56314
56627
|
}
|
|
56315
56628
|
}
|
|
56316
56629
|
}
|
|
56317
56630
|
return () => scheduler.stopAll();
|
|
56318
56631
|
}, [traitBindings, runTickEffects, sharedGroups, sharedEntityStore, emitFromSharedWriter]);
|
|
56319
|
-
const processEventQueued = useCallback(async (eventKey, payload, targetTrait) => {
|
|
56632
|
+
const processEventQueued = useCallback(async (eventKey, payload, targetTrait, tick, sourceTrait) => {
|
|
56320
56633
|
const normalizedEvent = normalizeEventKey(eventKey);
|
|
56634
|
+
const _perfT0 = perfStart("processEvent:total");
|
|
56321
56635
|
const bindings = traitBindingsRef.current;
|
|
56322
56636
|
const currentManager = managerRef.current;
|
|
56323
56637
|
crossTraitLog.debug("processEvent:enter", () => ({
|
|
@@ -56341,6 +56655,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
56341
56655
|
entityByTrait[name] = { ...sharedEntityStore.getSnapshot(sharedKey) };
|
|
56342
56656
|
}
|
|
56343
56657
|
}
|
|
56658
|
+
const _perfT1 = perfStart("processEvent:guardMatch");
|
|
56344
56659
|
const results = currentManager.sendEvent(
|
|
56345
56660
|
normalizedEvent,
|
|
56346
56661
|
payload,
|
|
@@ -56349,6 +56664,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
56349
56664
|
void 0,
|
|
56350
56665
|
targetTrait
|
|
56351
56666
|
);
|
|
56667
|
+
perfEnd("processEvent:guardMatch", _perfT1);
|
|
56352
56668
|
crossTraitLog.debug("processEvent:results", {
|
|
56353
56669
|
event: normalizedEvent,
|
|
56354
56670
|
executedCount: results.length,
|
|
@@ -56398,6 +56714,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
56398
56714
|
transition: `${result.previousState} -> ${result.newState}`,
|
|
56399
56715
|
effects: JSON.stringify(result.effects)
|
|
56400
56716
|
}));
|
|
56717
|
+
const _perfT2 = perfStart("processEvent:executeAll");
|
|
56401
56718
|
const emittedDuringExec = await executeTransitionEffects({
|
|
56402
56719
|
binding,
|
|
56403
56720
|
// upstream gap: /runtime TransitionResult.effects is unknown[] — they are SExpr at runtime (see Almadar_UI_Gaps.md)
|
|
@@ -56409,6 +56726,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
56409
56726
|
syncOnly: false,
|
|
56410
56727
|
log: stateLog
|
|
56411
56728
|
});
|
|
56729
|
+
perfEnd("processEvent:executeAll", _perfT2);
|
|
56412
56730
|
emittedByTrait.set(traitName, emittedDuringExec);
|
|
56413
56731
|
for (const emittedKey of emittedDuringExec) {
|
|
56414
56732
|
bridgeEchoPendingRef.current.set(
|
|
@@ -56505,23 +56823,31 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
56505
56823
|
if (orbital) dispatchedOrbitals.add(orbital);
|
|
56506
56824
|
}
|
|
56507
56825
|
const relayPayload = targetTrait !== void 0 ? { ...payload ?? {}, _targetTrait: targetTrait } : payload;
|
|
56508
|
-
|
|
56826
|
+
void onEventProcessed(normalizedEvent, relayPayload, dispatchedOrbitals, tick, sourceTrait);
|
|
56509
56827
|
}
|
|
56828
|
+
perfEnd("processEvent:total", _perfT0);
|
|
56829
|
+
perfEnd(`event:${normalizedEvent}`, _perfT0);
|
|
56510
56830
|
}, [entities, eventBus, sharedEntityStore]);
|
|
56511
56831
|
const drainEventQueue = useCallback(async () => {
|
|
56512
56832
|
if (processingRef.current) return;
|
|
56513
56833
|
processingRef.current = true;
|
|
56834
|
+
const _perfT = perfStart("drain:pass");
|
|
56835
|
+
let _perfN = 0;
|
|
56514
56836
|
try {
|
|
56515
56837
|
while (eventQueueRef.current.length > 0) {
|
|
56516
56838
|
const entry = eventQueueRef.current.shift();
|
|
56517
|
-
|
|
56839
|
+
_perfN++;
|
|
56840
|
+
await processEventQueued(entry.eventKey, entry.payload, entry.targetTrait, entry.tick, entry.sourceTrait);
|
|
56518
56841
|
}
|
|
56519
56842
|
} finally {
|
|
56520
56843
|
processingRef.current = false;
|
|
56844
|
+
perfEnd("drain:pass", _perfT);
|
|
56845
|
+
perfGauge("drain:passEntries", _perfN);
|
|
56521
56846
|
}
|
|
56522
56847
|
}, [processEventQueued]);
|
|
56523
|
-
const enqueueAndDrain = useCallback((eventKey, payload, targetTrait) => {
|
|
56524
|
-
eventQueueRef.current
|
|
56848
|
+
const enqueueAndDrain = useCallback((eventKey, payload, targetTrait, tick, sourceTrait) => {
|
|
56849
|
+
enqueueEvent(eventQueueRef.current, { eventKey, payload, targetTrait, tick, sourceTrait });
|
|
56850
|
+
perfGauge("queue:depthAtEnqueue", eventQueueRef.current.length);
|
|
56525
56851
|
void drainEventQueue();
|
|
56526
56852
|
}, [drainEventQueue]);
|
|
56527
56853
|
useCallback((eventKey, payload) => {
|
|
@@ -56574,7 +56900,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
56574
56900
|
crossTraitLog.debug("self:fire-server-cascade", { traitName, busKey: selfBusKey, eventKey });
|
|
56575
56901
|
}
|
|
56576
56902
|
crossTraitLog.debug("self:fire", { traitName, busKey: selfBusKey, eventKey });
|
|
56577
|
-
enqueueAndDrain(eventKey, event.payload, traitName);
|
|
56903
|
+
enqueueAndDrain(eventKey, event.payload, traitName, event.source?.tick, event.source?.trait);
|
|
56578
56904
|
});
|
|
56579
56905
|
unsubscribes.push(() => {
|
|
56580
56906
|
crossTraitLog.debug("self:unsubscribe", { traitName, busKey: selfBusKey, eventKey });
|
|
@@ -56592,7 +56918,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
56592
56918
|
const bareKey = `UI:${eventKey}`;
|
|
56593
56919
|
const unsub = eventBus.on(bareKey, (event) => {
|
|
56594
56920
|
crossTraitLog.debug("bare-cascade:fire", { bareKey, eventKey });
|
|
56595
|
-
enqueueAndDrain(eventKey, event.payload);
|
|
56921
|
+
enqueueAndDrain(eventKey, event.payload, void 0, event.source?.tick, event.source?.trait);
|
|
56596
56922
|
});
|
|
56597
56923
|
unsubscribes.push(() => {
|
|
56598
56924
|
crossTraitLog.debug("bare-cascade:unsubscribe", { bareKey, eventKey });
|
|
@@ -56626,7 +56952,9 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
56626
56952
|
enqueueAndDrain(
|
|
56627
56953
|
listen.triggers,
|
|
56628
56954
|
applyListenPayloadMapping(listen.payloadMapping, event.payload, evaluateListenPayloadExpr),
|
|
56629
|
-
binding.trait.name
|
|
56955
|
+
binding.trait.name,
|
|
56956
|
+
event.source?.tick,
|
|
56957
|
+
event.source?.trait
|
|
56630
56958
|
);
|
|
56631
56959
|
});
|
|
56632
56960
|
unsubscribes.push(() => {
|
|
@@ -56818,7 +57146,7 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
|
|
|
56818
57146
|
[serverActiveTraits]
|
|
56819
57147
|
);
|
|
56820
57148
|
const uiSlots = useUISlots();
|
|
56821
|
-
const onEventProcessed = useCallback(
|
|
57149
|
+
const onEventProcessed = useCallback((event, payload, dispatchedOrbitals, tick, sourceTrait) => {
|
|
56822
57150
|
if (!bridge.connected || !orbitalNames?.length) return;
|
|
56823
57151
|
const targets = dispatchedOrbitals && dispatchedOrbitals.size > 0 ? orbitalNames.filter((n) => dispatchedOrbitals.has(n)) : orbitalNames;
|
|
56824
57152
|
xOrbitalLog.debug("TraitInitializer:fanout", () => ({
|
|
@@ -56828,9 +57156,14 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
|
|
|
56828
57156
|
dispatchedOrbitalsSize: dispatchedOrbitals?.size ?? 0
|
|
56829
57157
|
}));
|
|
56830
57158
|
for (const name of targets) {
|
|
56831
|
-
|
|
56832
|
-
|
|
56833
|
-
|
|
57159
|
+
if (tick !== void 0) {
|
|
57160
|
+
void bridge.sendEvent(name, event, withActiveTraits(payload), tick, sourceTrait);
|
|
57161
|
+
continue;
|
|
57162
|
+
}
|
|
57163
|
+
void bridge.sendEvent(name, event, withActiveTraits(payload)).then(({ effects, meta }) => {
|
|
57164
|
+
recordServerResponse(name, event, meta);
|
|
57165
|
+
applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits, activeTraitNames, onNavigateBack);
|
|
57166
|
+
});
|
|
56834
57167
|
}
|
|
56835
57168
|
}, [bridge.connected, bridge.sendEvent, orbitalNames, uiSlots, onNavigate, onNavigateBack, embeddedTraits, activeTraitNames, withActiveTraits]);
|
|
56836
57169
|
const opts = orbitalNames ? { onEventProcessed, navigate: onNavigate, navigateBack: onNavigateBack, traitConfigsByName, orbitalsByTrait, embeddedTraits, initPayload: routeParams } : { navigate: onNavigate, navigateBack: onNavigateBack, persistence, traitConfigsByName, orbitalsByTrait, embeddedTraits, initPayload: routeParams };
|
|
@@ -57148,14 +57481,15 @@ function OrbPreview({
|
|
|
57148
57481
|
return pattern.replace(/:([A-Za-z0-9_]+)/g, (whole, key) => routeParams[key] ?? whole);
|
|
57149
57482
|
}, [currentPagePath, routeParams]);
|
|
57150
57483
|
const navStackRef = useRef(null);
|
|
57151
|
-
const handleNavigate = useCallback((path) => {
|
|
57484
|
+
const handleNavigate = useCallback((path, navState) => {
|
|
57152
57485
|
const hit = matchPathAmong(pages, path, (entry) => entry.page.path);
|
|
57153
57486
|
const match = hit?.candidate;
|
|
57154
|
-
const params = hit?.params ?? {};
|
|
57487
|
+
const params = { ...hit?.params ?? {}, ...navState ?? {} };
|
|
57155
57488
|
navLog.debug("handleNavigate", () => ({
|
|
57156
57489
|
path,
|
|
57157
57490
|
matched: match?.page.name ?? null,
|
|
57158
57491
|
params,
|
|
57492
|
+
navState: navState ? JSON.stringify(navState) : void 0,
|
|
57159
57493
|
availablePaths: pages.map((p) => p.page.path)
|
|
57160
57494
|
}));
|
|
57161
57495
|
if (match?.page.name) {
|
|
@@ -57170,9 +57504,9 @@ function OrbPreview({
|
|
|
57170
57504
|
}
|
|
57171
57505
|
}, [pages]);
|
|
57172
57506
|
const handleNavigateEffect = useCallback(
|
|
57173
|
-
(path,
|
|
57507
|
+
(path, params, crumb) => {
|
|
57174
57508
|
navStackRef.current?.beginNavigate(path, crumb);
|
|
57175
|
-
handleNavigate(path);
|
|
57509
|
+
handleNavigate(path, params);
|
|
57176
57510
|
},
|
|
57177
57511
|
[handleNavigate]
|
|
57178
57512
|
);
|
|
@@ -57303,11 +57637,13 @@ function BrowserPlayground({
|
|
|
57303
57637
|
unregister: async () => {
|
|
57304
57638
|
runtime.unregisterAll();
|
|
57305
57639
|
},
|
|
57306
|
-
sendEvent: async (orbitalName, event, payload) => {
|
|
57640
|
+
sendEvent: async (orbitalName, event, payload, _clientId, tick, sourceTrait) => {
|
|
57307
57641
|
await registrationReady;
|
|
57308
57642
|
return runtime.processOrbitalEvent(orbitalName, {
|
|
57309
57643
|
event,
|
|
57310
|
-
payload
|
|
57644
|
+
payload,
|
|
57645
|
+
tick,
|
|
57646
|
+
sourceTrait
|
|
57311
57647
|
// @almadar/runtime OrbitalEventResponse.clientEffects uses a wider ClientEffectTuple than
|
|
57312
57648
|
// ServerBridge's local definition — cast at this boundary (upstream fix queued).
|
|
57313
57649
|
});
|
|
@@ -59487,14 +59823,7 @@ TraitCardNode.displayName = "TraitCardNode";
|
|
|
59487
59823
|
|
|
59488
59824
|
// components/avl/organisms/FlowCanvas.tsx
|
|
59489
59825
|
init_useEventBus();
|
|
59490
|
-
|
|
59491
|
-
pushPerfEntry({
|
|
59492
|
-
name: `profiler:${id}:${phase}`,
|
|
59493
|
-
durationMs: actualDuration,
|
|
59494
|
-
ts: commitTime,
|
|
59495
|
-
detail: { baseDuration }
|
|
59496
|
-
});
|
|
59497
|
-
};
|
|
59826
|
+
init_perf();
|
|
59498
59827
|
var flowCanvasLog = createLogger("almadar:ui:flow-canvas");
|
|
59499
59828
|
var NODE_TYPES = {
|
|
59500
59829
|
preview: OrbPreviewNode,
|