@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.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import * as React85 from 'react';
|
|
2
|
-
import React85__default, { createContext, useContext, useMemo, useRef, useEffect, useCallback, Suspense, useState,
|
|
2
|
+
import React85__default, { createContext, useContext, useMemo, useRef, useEffect, useCallback, useSyncExternalStore, Suspense, useState, useLayoutEffect, lazy, useId } from 'react';
|
|
3
3
|
import { EventBusContext, useTraitScopeChain, RenderSlotProvider, useEntitySchemaOptional, useEntityBindingSnapshot, useTraitScope, useEntitySchema, getAllPages, matchPathAmong, CurrentPagePathProvider, NavStackProvider, OrbitalProvider, TraitScopeProvider, useNavStack, ServerBridgeProvider, useCurrentPagePath, useRenderSlot, useGameAudioContextOptional, VerificationProvider, EntitySchemaProvider, OrbitalThemeProvider, useServerBridge, EntityBindingContext } from '@almadar/ui/providers';
|
|
4
4
|
export { EntitySchemaProvider, ServerBridgeProvider, TraitContext, TraitProvider, useEntitySchema, useEntitySchemaOptional, useServerBridge, useTrait, useTraitContext } from '@almadar/ui/providers';
|
|
5
5
|
import { createLogger, setNamespaceLevel, isLogLevelEnabled } from '@almadar/logger';
|
|
6
|
+
import { perfStore, pushPerfEntry, wrapCallbackForEvent, perfStart, perfEnd, perfGauge, prepareSchemaForPreview, perfTimeAsync, collectTraitRefsFromResolvedTrait, buildOrbitalsByTrait, collectEmbeddedTraits } from '@almadar/runtime/ui';
|
|
7
|
+
export { PERF_NAMESPACE, adjustSchemaForMockData, buildMockData, clearPerf, perfEnd, perfStart, perfTime, prepareSchemaForPreview, wrapCallbackForEvent } from '@almadar/runtime/ui';
|
|
6
8
|
import { StateMachineManager, collectDeclaredConfigDefaults, resolveCallSitePayloadCaptures, createServerEffectHandlers, EffectExecutor, createContextFromBindings, createTickScheduler, isValidCronExpression, parseDurationString, InMemoryPersistence, normalizeCallSiteConfigToValues, interpolateValue } from '@almadar/runtime';
|
|
7
9
|
import { mergeEntityFrame, isCircuitEvent, applyListenPayloadMapping, schemaToIR, getPage, clearSchemaCache as clearSchemaCache$1, walkSExpr, buildResolvedTraitConfigs, isRenderBindingMarker, isFileValue, isInlineTrait, containsEntityBinding, isSExpr, isEventPayloadValue, RENDER_BINDING_MARKER, ANIMATION_NAMES } from '@almadar/core';
|
|
8
10
|
import { clsx } from 'clsx';
|
|
@@ -14,8 +16,6 @@ import { createPortal } from 'react-dom';
|
|
|
14
16
|
import { useTranslate } from '@almadar/ui/hooks';
|
|
15
17
|
import { useUISlots, UISlotProvider, useTheme } from '@almadar/ui/context';
|
|
16
18
|
import { evaluateGuard, evaluateListenPayloadExpr, evaluate, createMinimalContext, executeEffects } from '@almadar/evaluator';
|
|
17
|
-
import { wrapCallbackForEvent, prepareSchemaForPreview, perfStore, pushPerfEntry, collectTraitRefsFromResolvedTrait, buildOrbitalsByTrait, collectEmbeddedTraits } from '@almadar/runtime/ui';
|
|
18
|
-
export { PERF_NAMESPACE, adjustSchemaForMockData, buildMockData, clearPerf, perfEnd, perfStart, perfTime, prepareSchemaForPreview, wrapCallbackForEvent } from '@almadar/runtime/ui';
|
|
19
19
|
import { Link, Outlet, useLocation } from 'react-router-dom';
|
|
20
20
|
import ELK from 'elkjs/lib/elk.bundled.js';
|
|
21
21
|
import SyntaxHighlighter from 'react-syntax-highlighter/dist/esm/prism-light.js';
|
|
@@ -793,6 +793,22 @@ var init_useTapReveal = __esm({
|
|
|
793
793
|
"hooks/useTapReveal.ts"() {
|
|
794
794
|
}
|
|
795
795
|
});
|
|
796
|
+
function usePerfBuffer() {
|
|
797
|
+
return useSyncExternalStore(perfStore.subscribe, perfStore.getSnapshot, perfStore.getSnapshot);
|
|
798
|
+
}
|
|
799
|
+
var profilerOnRender;
|
|
800
|
+
var init_perf = __esm({
|
|
801
|
+
"lib/perf.ts"() {
|
|
802
|
+
profilerOnRender = (id, phase, actualDuration, baseDuration, _startTime, commitTime) => {
|
|
803
|
+
pushPerfEntry({
|
|
804
|
+
name: `profiler:${id}:${phase}`,
|
|
805
|
+
durationMs: actualDuration,
|
|
806
|
+
ts: commitTime,
|
|
807
|
+
detail: { baseDuration }
|
|
808
|
+
});
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
});
|
|
796
812
|
function resolveMarkerExpression(expression, entity, config, state) {
|
|
797
813
|
const ctx = createContextFromBindings({
|
|
798
814
|
entity,
|
|
@@ -810,11 +826,54 @@ function isPlainObject(value) {
|
|
|
810
826
|
if (typeof value === "function") return false;
|
|
811
827
|
return true;
|
|
812
828
|
}
|
|
829
|
+
function isEvaluatorResolvedData(value) {
|
|
830
|
+
return evaluatorResolvedData.has(value);
|
|
831
|
+
}
|
|
832
|
+
function brandResolved(value) {
|
|
833
|
+
if (value !== null && typeof value === "object" && !React85__default.isValidElement(value) && !(value instanceof Date)) {
|
|
834
|
+
resolvedMarkerFree.add(value);
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
function subtreeHasMarker(value) {
|
|
838
|
+
if (resolvedMarkerFree.has(value)) return false;
|
|
839
|
+
const cached = markerPresenceCache.get(value);
|
|
840
|
+
if (cached !== void 0) return cached;
|
|
841
|
+
let found = false;
|
|
842
|
+
const children = Array.isArray(value) ? value : Object.values(value);
|
|
843
|
+
for (const child of children) {
|
|
844
|
+
if (isRenderBindingMarker(child)) {
|
|
845
|
+
found = true;
|
|
846
|
+
break;
|
|
847
|
+
}
|
|
848
|
+
if (Array.isArray(child) || isPlainObject(child)) {
|
|
849
|
+
if (subtreeHasMarker(child)) {
|
|
850
|
+
found = true;
|
|
851
|
+
break;
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
markerPresenceCache.set(value, found);
|
|
856
|
+
return found;
|
|
857
|
+
}
|
|
813
858
|
function walkValue(value, scopeTrait, entity, config, state) {
|
|
814
859
|
if (isRenderBindingMarker(value)) {
|
|
815
|
-
|
|
860
|
+
const cached = markerResolutionCache.get(value);
|
|
861
|
+
if (cached !== void 0 && cached.entity === entity && cached.config === config && cached.state === state) {
|
|
862
|
+
return { resolved: cached.resolved, changed: false };
|
|
863
|
+
}
|
|
864
|
+
const resolved = resolveMarkerExpression(value.expression, entity, config, state);
|
|
865
|
+
markerResolutionCache.set(value, { entity, config, state, resolved });
|
|
866
|
+
if (resolved !== null && typeof resolved === "object" && !React85__default.isValidElement(resolved) && !(resolved instanceof Date)) {
|
|
867
|
+
resolvedMarkerFree.add(resolved);
|
|
868
|
+
evaluatorResolvedData.add(resolved);
|
|
869
|
+
}
|
|
870
|
+
return { resolved, changed: true };
|
|
816
871
|
}
|
|
817
872
|
if (Array.isArray(value)) {
|
|
873
|
+
if (!subtreeHasMarker(value)) {
|
|
874
|
+
brandResolved(value);
|
|
875
|
+
return { resolved: value, changed: false };
|
|
876
|
+
}
|
|
818
877
|
const out = [];
|
|
819
878
|
let changed = false;
|
|
820
879
|
for (const item of value) {
|
|
@@ -829,9 +888,14 @@ function walkValue(value, scopeTrait, entity, config, state) {
|
|
|
829
888
|
out.push(resolved);
|
|
830
889
|
if (itemChanged) changed = true;
|
|
831
890
|
}
|
|
891
|
+
brandResolved(out);
|
|
832
892
|
return changed ? { resolved: out, changed: true } : { resolved: value, changed: false };
|
|
833
893
|
}
|
|
834
894
|
if (isPlainObject(value)) {
|
|
895
|
+
if (!subtreeHasMarker(value)) {
|
|
896
|
+
brandResolved(value);
|
|
897
|
+
return { resolved: value, changed: false };
|
|
898
|
+
}
|
|
835
899
|
const sourceTrait = value._sourceTrait;
|
|
836
900
|
if (typeof sourceTrait === "string" && sourceTrait !== scopeTrait) {
|
|
837
901
|
return { resolved: value, changed: false };
|
|
@@ -843,11 +907,13 @@ function walkValue(value, scopeTrait, entity, config, state) {
|
|
|
843
907
|
out[key] = resolved;
|
|
844
908
|
if (itemChanged) changed = true;
|
|
845
909
|
}
|
|
910
|
+
brandResolved(out);
|
|
846
911
|
return changed ? { resolved: out, changed: true } : { resolved: value, changed: false };
|
|
847
912
|
}
|
|
848
913
|
return { resolved: value, changed: false };
|
|
849
914
|
}
|
|
850
915
|
function resolveRenderBindingMarkers(props, scopeTrait, entity, config, state) {
|
|
916
|
+
if (resolvedMarkerFree.has(props)) return props;
|
|
851
917
|
const out = {};
|
|
852
918
|
let changed = false;
|
|
853
919
|
for (const [key, value] of Object.entries(props)) {
|
|
@@ -855,11 +921,17 @@ function resolveRenderBindingMarkers(props, scopeTrait, entity, config, state) {
|
|
|
855
921
|
out[key] = resolved;
|
|
856
922
|
if (propChanged) changed = true;
|
|
857
923
|
}
|
|
924
|
+
brandResolved(out);
|
|
858
925
|
return changed ? out : props;
|
|
859
926
|
}
|
|
927
|
+
var markerPresenceCache, markerResolutionCache, resolvedMarkerFree, evaluatorResolvedData;
|
|
860
928
|
var init_resolve_render_bindings = __esm({
|
|
861
929
|
"lib/resolve-render-bindings.ts"() {
|
|
862
930
|
"use client";
|
|
931
|
+
markerPresenceCache = /* @__PURE__ */ new WeakMap();
|
|
932
|
+
markerResolutionCache = /* @__PURE__ */ new WeakMap();
|
|
933
|
+
resolvedMarkerFree = /* @__PURE__ */ new WeakSet();
|
|
934
|
+
evaluatorResolvedData = /* @__PURE__ */ new WeakSet();
|
|
863
935
|
}
|
|
864
936
|
});
|
|
865
937
|
function cn(...inputs) {
|
|
@@ -12184,6 +12256,7 @@ var init_LearningCanvas = __esm({
|
|
|
12184
12256
|
"components/learning/atoms/LearningCanvas.tsx"() {
|
|
12185
12257
|
"use client";
|
|
12186
12258
|
init_cn();
|
|
12259
|
+
init_perf();
|
|
12187
12260
|
init_useEventBus();
|
|
12188
12261
|
DASH_PATTERNS = { dashed: [6, 4], dotted: [2, 3] };
|
|
12189
12262
|
TRACE_SERIES_COLORS = ["#2563eb", "#dc2626", "#16a34a", "#f59e0b"];
|
|
@@ -12227,6 +12300,7 @@ var init_LearningCanvas = __esm({
|
|
|
12227
12300
|
return [...shapes, ...traceOut, ...readoutOut];
|
|
12228
12301
|
}, [shapes, traces, readouts, width, height]);
|
|
12229
12302
|
const draw = useCallback(() => {
|
|
12303
|
+
const _perfT = perfStart("learningcanvas:paint");
|
|
12230
12304
|
const canvas = canvasRef.current;
|
|
12231
12305
|
if (!canvas) return;
|
|
12232
12306
|
const ctx = canvas.getContext("2d");
|
|
@@ -12248,6 +12322,7 @@ var init_LearningCanvas = __esm({
|
|
|
12248
12322
|
for (const shape of derivedShapes) {
|
|
12249
12323
|
if (shape.type === "text") drawShape(ctx, shape, width, height, derivedShapes);
|
|
12250
12324
|
}
|
|
12325
|
+
perfEnd("learningcanvas:paint", _perfT);
|
|
12251
12326
|
}, [width, height, backgroundColor, derivedShapes]);
|
|
12252
12327
|
useEffect(() => {
|
|
12253
12328
|
draw();
|
|
@@ -26921,7 +26996,7 @@ function fileIcon(name) {
|
|
|
26921
26996
|
return "file";
|
|
26922
26997
|
}
|
|
26923
26998
|
}
|
|
26924
|
-
var TreeNodeItem, FileTree;
|
|
26999
|
+
var TreeNodeItem, FlatTreeNodeItem, FileTree;
|
|
26925
27000
|
var init_FileTree = __esm({
|
|
26926
27001
|
"components/core/molecules/FileTree.tsx"() {
|
|
26927
27002
|
"use client";
|
|
@@ -27006,14 +27081,101 @@ var init_FileTree = __esm({
|
|
|
27006
27081
|
)) })
|
|
27007
27082
|
] });
|
|
27008
27083
|
};
|
|
27084
|
+
FlatTreeNodeItem = ({
|
|
27085
|
+
item,
|
|
27086
|
+
depth,
|
|
27087
|
+
indent,
|
|
27088
|
+
childrenByParent,
|
|
27089
|
+
onNodeSelect,
|
|
27090
|
+
defaultExpanded = false
|
|
27091
|
+
}) => {
|
|
27092
|
+
const [expanded, setExpanded] = useState(defaultExpanded || depth < 1);
|
|
27093
|
+
const children = childrenByParent.get(item.id);
|
|
27094
|
+
const hasChildren = !!children && children.length > 0;
|
|
27095
|
+
const handleClick = useCallback(() => {
|
|
27096
|
+
if (hasChildren) setExpanded((prev) => !prev);
|
|
27097
|
+
onNodeSelect?.(item.id);
|
|
27098
|
+
}, [hasChildren, item.id, onNodeSelect]);
|
|
27099
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
27100
|
+
/* @__PURE__ */ jsxs(
|
|
27101
|
+
Box,
|
|
27102
|
+
{
|
|
27103
|
+
className: "flex items-center gap-1.5 py-0.5 px-2 cursor-pointer rounded-sm transition-colors hover:bg-muted",
|
|
27104
|
+
style: { paddingLeft: depth * indent + 8 },
|
|
27105
|
+
onClick: handleClick,
|
|
27106
|
+
role: "treeitem",
|
|
27107
|
+
"aria-expanded": hasChildren ? expanded : void 0,
|
|
27108
|
+
children: [
|
|
27109
|
+
hasChildren ? /* @__PURE__ */ jsx(
|
|
27110
|
+
Icon,
|
|
27111
|
+
{
|
|
27112
|
+
name: expanded ? "chevron-down" : "chevron-right",
|
|
27113
|
+
size: "xs",
|
|
27114
|
+
className: "text-[var(--color-muted-foreground)] flex-shrink-0"
|
|
27115
|
+
}
|
|
27116
|
+
) : /* @__PURE__ */ jsx(Box, { style: { width: 12, flexShrink: 0 } }),
|
|
27117
|
+
/* @__PURE__ */ jsx(
|
|
27118
|
+
Icon,
|
|
27119
|
+
{
|
|
27120
|
+
name: item.icon ?? (hasChildren ? expanded ? "folder-open" : "folder" : "file"),
|
|
27121
|
+
size: "xs",
|
|
27122
|
+
className: hasChildren ? "text-[var(--color-warning)]" : "text-[var(--color-muted-foreground)]"
|
|
27123
|
+
}
|
|
27124
|
+
),
|
|
27125
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", className: "truncate font-mono text-xs", children: item.label })
|
|
27126
|
+
]
|
|
27127
|
+
}
|
|
27128
|
+
),
|
|
27129
|
+
hasChildren && expanded && /* @__PURE__ */ jsx(Box, { role: "group", children: children.map((child) => /* @__PURE__ */ jsx(
|
|
27130
|
+
FlatTreeNodeItem,
|
|
27131
|
+
{
|
|
27132
|
+
item: child,
|
|
27133
|
+
depth: depth + 1,
|
|
27134
|
+
indent,
|
|
27135
|
+
childrenByParent,
|
|
27136
|
+
onNodeSelect
|
|
27137
|
+
},
|
|
27138
|
+
child.id
|
|
27139
|
+
)) })
|
|
27140
|
+
] });
|
|
27141
|
+
};
|
|
27009
27142
|
FileTree = ({
|
|
27010
27143
|
tree,
|
|
27144
|
+
items,
|
|
27011
27145
|
selectedPath,
|
|
27012
27146
|
onFileSelect,
|
|
27147
|
+
onNodeSelect,
|
|
27013
27148
|
className,
|
|
27014
27149
|
indent = 16
|
|
27015
27150
|
}) => {
|
|
27016
|
-
if (
|
|
27151
|
+
if (items) {
|
|
27152
|
+
if (items.length === 0) return null;
|
|
27153
|
+
const ids = new Set(items.map((node) => node.id));
|
|
27154
|
+
const childrenByParent = /* @__PURE__ */ new Map();
|
|
27155
|
+
const roots = [];
|
|
27156
|
+
for (const item of items) {
|
|
27157
|
+
if (item.parentId && ids.has(item.parentId)) {
|
|
27158
|
+
const siblings = childrenByParent.get(item.parentId);
|
|
27159
|
+
if (siblings) siblings.push(item);
|
|
27160
|
+
else childrenByParent.set(item.parentId, [item]);
|
|
27161
|
+
} else {
|
|
27162
|
+
roots.push(item);
|
|
27163
|
+
}
|
|
27164
|
+
}
|
|
27165
|
+
return /* @__PURE__ */ jsx(Box, { className: `py-1 overflow-y-auto ${className ?? ""}`, role: "tree", children: roots.map((item) => /* @__PURE__ */ jsx(
|
|
27166
|
+
FlatTreeNodeItem,
|
|
27167
|
+
{
|
|
27168
|
+
item,
|
|
27169
|
+
depth: 0,
|
|
27170
|
+
indent,
|
|
27171
|
+
childrenByParent,
|
|
27172
|
+
onNodeSelect,
|
|
27173
|
+
defaultExpanded: true
|
|
27174
|
+
},
|
|
27175
|
+
item.id
|
|
27176
|
+
)) });
|
|
27177
|
+
}
|
|
27178
|
+
if (!tree || tree.length === 0) return null;
|
|
27017
27179
|
return /* @__PURE__ */ jsx(Box, { className: `py-1 overflow-y-auto ${className ?? ""}`, role: "tree", children: tree.map((node) => /* @__PURE__ */ jsx(
|
|
27018
27180
|
TreeNodeItem,
|
|
27019
27181
|
{
|
|
@@ -28344,7 +28506,7 @@ var init_debug = __esm({
|
|
|
28344
28506
|
createLogger("almadar:ui:debug:game-state");
|
|
28345
28507
|
}
|
|
28346
28508
|
});
|
|
28347
|
-
var isRelationsDebugEnabled, RelationSelect;
|
|
28509
|
+
var isRelationsDebugEnabled, MANY_CARDINALITIES, RelationSelect;
|
|
28348
28510
|
var init_RelationSelect = __esm({
|
|
28349
28511
|
"components/core/molecules/RelationSelect.tsx"() {
|
|
28350
28512
|
"use client";
|
|
@@ -28358,6 +28520,11 @@ var init_RelationSelect = __esm({
|
|
|
28358
28520
|
init_Typography();
|
|
28359
28521
|
init_debug();
|
|
28360
28522
|
isRelationsDebugEnabled = () => isDebugEnabled();
|
|
28523
|
+
MANY_CARDINALITIES = [
|
|
28524
|
+
"many",
|
|
28525
|
+
"one-to-many",
|
|
28526
|
+
"many-to-many"
|
|
28527
|
+
];
|
|
28361
28528
|
RelationSelect = ({
|
|
28362
28529
|
value,
|
|
28363
28530
|
onChange,
|
|
@@ -29982,6 +30149,7 @@ var init_MathCanvas = __esm({
|
|
|
29982
30149
|
"components/learning/molecules/MathCanvas.tsx"() {
|
|
29983
30150
|
"use client";
|
|
29984
30151
|
init_useEventBus();
|
|
30152
|
+
init_perf();
|
|
29985
30153
|
init_atoms();
|
|
29986
30154
|
init_Stack();
|
|
29987
30155
|
init_LearningCanvas();
|
|
@@ -30022,17 +30190,21 @@ var init_MathCanvas = __esm({
|
|
|
30022
30190
|
error
|
|
30023
30191
|
}) => {
|
|
30024
30192
|
const eventBus = useEventBus();
|
|
30193
|
+
const keyMapKey = keyMap ? JSON.stringify(keyMap) : null;
|
|
30194
|
+
const keyUpMapKey = keyUpMap ? JSON.stringify(keyUpMap) : null;
|
|
30195
|
+
const stableKeyMap = useMemo(() => keyMap, [keyMapKey]);
|
|
30196
|
+
const stableKeyUpMap = useMemo(() => keyUpMap, [keyUpMapKey]);
|
|
30025
30197
|
useEffect(() => {
|
|
30026
|
-
if (!
|
|
30198
|
+
if (!stableKeyMap && !stableKeyUpMap) return;
|
|
30027
30199
|
const onDown = (e) => {
|
|
30028
|
-
const ev =
|
|
30200
|
+
const ev = stableKeyMap?.[e.code];
|
|
30029
30201
|
if (ev) {
|
|
30030
30202
|
eventBus.emit(`UI:${ev}`, {});
|
|
30031
30203
|
e.preventDefault();
|
|
30032
30204
|
}
|
|
30033
30205
|
};
|
|
30034
30206
|
const onUp = (e) => {
|
|
30035
|
-
const ev =
|
|
30207
|
+
const ev = stableKeyUpMap?.[e.code];
|
|
30036
30208
|
if (ev) eventBus.emit(`UI:${ev}`, {});
|
|
30037
30209
|
};
|
|
30038
30210
|
window.addEventListener("keydown", onDown);
|
|
@@ -30041,8 +30213,9 @@ var init_MathCanvas = __esm({
|
|
|
30041
30213
|
window.removeEventListener("keydown", onDown);
|
|
30042
30214
|
window.removeEventListener("keyup", onUp);
|
|
30043
30215
|
};
|
|
30044
|
-
}, [
|
|
30216
|
+
}, [stableKeyMap, stableKeyUpMap, eventBus]);
|
|
30045
30217
|
const derivedShapes = useMemo(() => {
|
|
30218
|
+
const _perfT = perfStart("mathcanvas:derive");
|
|
30046
30219
|
const out = [];
|
|
30047
30220
|
const margin = 24;
|
|
30048
30221
|
const plotW = width - margin * 2;
|
|
@@ -30286,6 +30459,7 @@ var init_MathCanvas = __esm({
|
|
|
30286
30459
|
}
|
|
30287
30460
|
}
|
|
30288
30461
|
out.push(...shapes);
|
|
30462
|
+
perfEnd("mathcanvas:derive", _perfT);
|
|
30289
30463
|
return out;
|
|
30290
30464
|
}, [
|
|
30291
30465
|
width,
|
|
@@ -36501,7 +36675,7 @@ var init_RichBlockEditor = __esm({
|
|
|
36501
36675
|
{
|
|
36502
36676
|
variant: "bordered",
|
|
36503
36677
|
padding: "none",
|
|
36504
|
-
className: cn("flex flex-col", className),
|
|
36678
|
+
className: cn("flex flex-col text-card-foreground", className),
|
|
36505
36679
|
children: [
|
|
36506
36680
|
enableBlocks && showToolbar && !readOnly && /* @__PURE__ */ jsx(
|
|
36507
36681
|
Box,
|
|
@@ -41729,6 +41903,7 @@ var init_DetailPanel = __esm({
|
|
|
41729
41903
|
"use client";
|
|
41730
41904
|
init_atoms();
|
|
41731
41905
|
init_Box();
|
|
41906
|
+
init_Input();
|
|
41732
41907
|
init_Stack();
|
|
41733
41908
|
init_SimpleGrid();
|
|
41734
41909
|
init_Menu();
|
|
@@ -41744,6 +41919,7 @@ var init_DetailPanel = __esm({
|
|
|
41744
41919
|
ReactMarkdown2 = lazy(() => import('react-markdown'));
|
|
41745
41920
|
DetailPanel = ({
|
|
41746
41921
|
title: propTitle,
|
|
41922
|
+
onTitleCommit,
|
|
41747
41923
|
subtitle,
|
|
41748
41924
|
status,
|
|
41749
41925
|
avatar,
|
|
@@ -41765,6 +41941,7 @@ var init_DetailPanel = __esm({
|
|
|
41765
41941
|
}) => {
|
|
41766
41942
|
const eventBus = useEventBus();
|
|
41767
41943
|
const { t } = useTranslate();
|
|
41944
|
+
const [titleDraft, setTitleDraft] = React85__default.useState(null);
|
|
41768
41945
|
const isFieldDefArray = (arr) => {
|
|
41769
41946
|
if (!arr || arr.length === 0) return false;
|
|
41770
41947
|
const first = arr[0];
|
|
@@ -41985,6 +42162,50 @@ var init_DetailPanel = __esm({
|
|
|
41985
42162
|
}),
|
|
41986
42163
|
status && /* @__PURE__ */ jsx(Badge, { variant: status.variant ?? "default", children: status.label })
|
|
41987
42164
|
] });
|
|
42165
|
+
const commitTitle = () => {
|
|
42166
|
+
if (!onTitleCommit) return;
|
|
42167
|
+
const next = (titleDraft ?? "").trim();
|
|
42168
|
+
setTitleDraft(null);
|
|
42169
|
+
if (!next || next === title) return;
|
|
42170
|
+
onTitleCommit(next, normalizedData?.id !== void 0 ? String(normalizedData.id) : "");
|
|
42171
|
+
};
|
|
42172
|
+
const titleNode = onTitleCommit && titleDraft !== null ? /* @__PURE__ */ jsx(
|
|
42173
|
+
Input,
|
|
42174
|
+
{
|
|
42175
|
+
value: titleDraft,
|
|
42176
|
+
autoFocus: true,
|
|
42177
|
+
"aria-label": t("common.title"),
|
|
42178
|
+
className: "h-auto py-1 text-3xl font-bold tracking-tight",
|
|
42179
|
+
onChange: (e) => setTitleDraft(e.target.value),
|
|
42180
|
+
onBlur: commitTitle,
|
|
42181
|
+
onKeyDown: (e) => {
|
|
42182
|
+
if (e.key === "Enter") {
|
|
42183
|
+
e.preventDefault();
|
|
42184
|
+
commitTitle();
|
|
42185
|
+
} else if (e.key === "Escape") {
|
|
42186
|
+
e.preventDefault();
|
|
42187
|
+
setTitleDraft(null);
|
|
42188
|
+
}
|
|
42189
|
+
},
|
|
42190
|
+
"data-testid": "detail-title-input"
|
|
42191
|
+
}
|
|
42192
|
+
) : onTitleCommit ? /* @__PURE__ */ jsx(
|
|
42193
|
+
Box,
|
|
42194
|
+
{
|
|
42195
|
+
role: "button",
|
|
42196
|
+
tabIndex: 0,
|
|
42197
|
+
className: "cursor-text rounded px-1 -mx-1 transition-colors hover:bg-muted/40",
|
|
42198
|
+
onClick: () => setTitleDraft(title ?? ""),
|
|
42199
|
+
onKeyDown: (e) => {
|
|
42200
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
42201
|
+
e.preventDefault();
|
|
42202
|
+
setTitleDraft(title ?? "");
|
|
42203
|
+
}
|
|
42204
|
+
},
|
|
42205
|
+
"data-testid": "detail-title-editable",
|
|
42206
|
+
children: /* @__PURE__ */ jsx(Typography, { variant: "h2", weight: "bold", children: title || "Details" })
|
|
42207
|
+
}
|
|
42208
|
+
) : /* @__PURE__ */ jsx(Typography, { variant: "h2", weight: "bold", children: title || "Details" });
|
|
41988
42209
|
const content = /* @__PURE__ */ jsx(Card, { variant: "elevated", children: /* @__PURE__ */ jsxs(VStack, { gap: "md", className: "p-6", children: [
|
|
41989
42210
|
/* @__PURE__ */ jsxs(HStack, { justify: "between", align: "start", gap: "md", children: [
|
|
41990
42211
|
/* @__PURE__ */ jsxs(HStack, { align: "start", gap: "sm", className: "min-w-0", children: [
|
|
@@ -42004,7 +42225,7 @@ var init_DetailPanel = __esm({
|
|
|
42004
42225
|
avatar,
|
|
42005
42226
|
/* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "min-w-0", children: [
|
|
42006
42227
|
/* @__PURE__ */ jsxs(HStack, { align: "center", gap: "sm", wrap: true, children: [
|
|
42007
|
-
|
|
42228
|
+
titleNode,
|
|
42008
42229
|
statusBadges
|
|
42009
42230
|
] }),
|
|
42010
42231
|
subtitle && /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: subtitle })
|
|
@@ -42340,6 +42561,9 @@ function determineInputType(field) {
|
|
|
42340
42561
|
if (field.type === "relation" || field.relation) {
|
|
42341
42562
|
return "relation";
|
|
42342
42563
|
}
|
|
42564
|
+
if (field.type === "array") {
|
|
42565
|
+
return "array";
|
|
42566
|
+
}
|
|
42343
42567
|
if (field.type === "enum" || field.values || getEnumOptions(field).length > 0) {
|
|
42344
42568
|
return "select";
|
|
42345
42569
|
}
|
|
@@ -42415,6 +42639,7 @@ var init_Form = __esm({
|
|
|
42415
42639
|
init_Typography();
|
|
42416
42640
|
init_Icon();
|
|
42417
42641
|
init_RelationSelect();
|
|
42642
|
+
init_TagInput();
|
|
42418
42643
|
init_UploadDropZone();
|
|
42419
42644
|
init_Alert();
|
|
42420
42645
|
init_useEventBus();
|
|
@@ -42494,7 +42719,7 @@ var init_Form = __esm({
|
|
|
42494
42719
|
values: "values" in f3 ? f3.values : void 0,
|
|
42495
42720
|
min: f3.min,
|
|
42496
42721
|
max: f3.max,
|
|
42497
|
-
relation: "relation" in f3 ? { entity: f3.relation.entity } : void 0
|
|
42722
|
+
relation: "relation" in f3 ? { entity: f3.relation.entity, cardinality: f3.relation.cardinality } : void 0
|
|
42498
42723
|
})
|
|
42499
42724
|
);
|
|
42500
42725
|
}, [entity, fields]);
|
|
@@ -42561,7 +42786,7 @@ var init_Form = __esm({
|
|
|
42561
42786
|
});
|
|
42562
42787
|
debug(
|
|
42563
42788
|
"forms",
|
|
42564
|
-
`Calculation triggered: ${calc.variableName} = ${value}`
|
|
42789
|
+
`Calculation triggered: ${calc.variableName} = ${String(value)}`
|
|
42565
42790
|
);
|
|
42566
42791
|
}
|
|
42567
42792
|
});
|
|
@@ -42729,7 +42954,7 @@ var init_Form = __esm({
|
|
|
42729
42954
|
values: "values" in entityField ? entityField.values : void 0,
|
|
42730
42955
|
min: entityField.min,
|
|
42731
42956
|
max: entityField.max,
|
|
42732
|
-
relation: "relation" in entityField ? { entity: entityField.relation.entity } : void 0
|
|
42957
|
+
relation: "relation" in entityField ? { entity: entityField.relation.entity, cardinality: entityField.relation.cardinality } : void 0
|
|
42733
42958
|
};
|
|
42734
42959
|
}
|
|
42735
42960
|
return { name: field, type: "string" };
|
|
@@ -42841,6 +43066,22 @@ var init_Form = __esm({
|
|
|
42841
43066
|
case "relation": {
|
|
42842
43067
|
const relationOptions = relationsData[fieldName] || [];
|
|
42843
43068
|
const relationLoading = relationsLoading[fieldName] || false;
|
|
43069
|
+
if (field.relation?.cardinality !== void 0 && MANY_CARDINALITIES.includes(field.relation.cardinality)) {
|
|
43070
|
+
const selectedValues = Array.isArray(currentValue) ? currentValue.map((v) => String(v)) : [];
|
|
43071
|
+
return /* @__PURE__ */ jsx(
|
|
43072
|
+
Select,
|
|
43073
|
+
{
|
|
43074
|
+
...commonProps,
|
|
43075
|
+
multiple: true,
|
|
43076
|
+
searchable: true,
|
|
43077
|
+
clearable: true,
|
|
43078
|
+
options: [...relationOptions],
|
|
43079
|
+
value: selectedValues,
|
|
43080
|
+
onValueChange: (value) => handleChange(fieldName, Array.isArray(value) ? value : [value]),
|
|
43081
|
+
placeholder: field.placeholder || `Select ${label}...`
|
|
43082
|
+
}
|
|
43083
|
+
);
|
|
43084
|
+
}
|
|
42844
43085
|
return /* @__PURE__ */ jsx(
|
|
42845
43086
|
RelationSelect,
|
|
42846
43087
|
{
|
|
@@ -42855,6 +43096,18 @@ var init_Form = __esm({
|
|
|
42855
43096
|
}
|
|
42856
43097
|
);
|
|
42857
43098
|
}
|
|
43099
|
+
case "array": {
|
|
43100
|
+
const arrayValue = Array.isArray(currentValue) ? currentValue.map((v) => String(v)) : currentValue != null && currentValue !== "" ? [String(currentValue)] : [];
|
|
43101
|
+
return /* @__PURE__ */ jsx(
|
|
43102
|
+
TagInput,
|
|
43103
|
+
{
|
|
43104
|
+
placeholder: field.placeholder,
|
|
43105
|
+
disabled: isLoading,
|
|
43106
|
+
value: arrayValue,
|
|
43107
|
+
onChange: (next) => handleChange(fieldName, [...next])
|
|
43108
|
+
}
|
|
43109
|
+
);
|
|
43110
|
+
}
|
|
42858
43111
|
case "number":
|
|
42859
43112
|
return /* @__PURE__ */ jsx(
|
|
42860
43113
|
Input,
|
|
@@ -48423,7 +48676,10 @@ function enrichFormFields(fields, entityDef) {
|
|
|
48423
48676
|
enriched.values = entityField.enumValues;
|
|
48424
48677
|
}
|
|
48425
48678
|
if (entityField.relation) {
|
|
48426
|
-
enriched.relation =
|
|
48679
|
+
enriched.relation = {
|
|
48680
|
+
entity: entityField.relation.entity,
|
|
48681
|
+
cardinality: entityField.relation.cardinality
|
|
48682
|
+
};
|
|
48427
48683
|
}
|
|
48428
48684
|
return enriched;
|
|
48429
48685
|
}
|
|
@@ -48451,7 +48707,10 @@ function enrichFormFields(fields, entityDef) {
|
|
|
48451
48707
|
}
|
|
48452
48708
|
}
|
|
48453
48709
|
if (!obj.relation && entityField.relation) {
|
|
48454
|
-
enriched.relation =
|
|
48710
|
+
enriched.relation = {
|
|
48711
|
+
entity: entityField.relation.entity,
|
|
48712
|
+
cardinality: entityField.relation.cardinality
|
|
48713
|
+
};
|
|
48455
48714
|
}
|
|
48456
48715
|
return enriched;
|
|
48457
48716
|
}
|
|
@@ -48466,7 +48725,12 @@ function enrichDetailFields(fields, entityDef) {
|
|
|
48466
48725
|
const meta = { type: entityField.type };
|
|
48467
48726
|
const values = entityField.values ?? entityField.enumValues;
|
|
48468
48727
|
if (values && values.length > 0) meta.values = values;
|
|
48469
|
-
if (entityField.relation)
|
|
48728
|
+
if (entityField.relation) {
|
|
48729
|
+
meta.relation = {
|
|
48730
|
+
entity: entityField.relation.entity,
|
|
48731
|
+
cardinality: entityField.relation.cardinality
|
|
48732
|
+
};
|
|
48733
|
+
}
|
|
48470
48734
|
return meta;
|
|
48471
48735
|
};
|
|
48472
48736
|
return fields.map((field) => {
|
|
@@ -49020,6 +49284,33 @@ function isPlainConfigObject(value) {
|
|
|
49020
49284
|
const proto = Object.getPrototypeOf(value);
|
|
49021
49285
|
return proto === Object.prototype || proto === null;
|
|
49022
49286
|
}
|
|
49287
|
+
function subtreeHasTraitRef(value) {
|
|
49288
|
+
if (isEvaluatorResolvedData(value)) return false;
|
|
49289
|
+
const cached = traitRefPresenceCache.get(value);
|
|
49290
|
+
if (cached !== void 0) return cached;
|
|
49291
|
+
let found = false;
|
|
49292
|
+
const children = Array.isArray(value) ? value : Object.values(value);
|
|
49293
|
+
for (const child of children) {
|
|
49294
|
+
if (typeof child === "string" && TRAIT_BINDING_RE.test(child)) {
|
|
49295
|
+
found = true;
|
|
49296
|
+
break;
|
|
49297
|
+
}
|
|
49298
|
+
if (isRenderBindingMarker(child)) continue;
|
|
49299
|
+
if (Array.isArray(child)) {
|
|
49300
|
+
if (subtreeHasTraitRef(child)) {
|
|
49301
|
+
found = true;
|
|
49302
|
+
break;
|
|
49303
|
+
}
|
|
49304
|
+
} else if (child !== null && typeof child === "object" && isPlainConfigObject(child)) {
|
|
49305
|
+
if (subtreeHasTraitRef(child)) {
|
|
49306
|
+
found = true;
|
|
49307
|
+
break;
|
|
49308
|
+
}
|
|
49309
|
+
}
|
|
49310
|
+
}
|
|
49311
|
+
traitRefPresenceCache.set(value, found);
|
|
49312
|
+
return found;
|
|
49313
|
+
}
|
|
49023
49314
|
function substituteTraitRefsDeep(value, pathKey) {
|
|
49024
49315
|
if (isRenderBindingMarker(value)) return value;
|
|
49025
49316
|
if (typeof value === "string") {
|
|
@@ -49034,11 +49325,13 @@ function substituteTraitRefsDeep(value, pathKey) {
|
|
|
49034
49325
|
return value;
|
|
49035
49326
|
}
|
|
49036
49327
|
if (Array.isArray(value)) {
|
|
49328
|
+
if (!subtreeHasTraitRef(value)) return value;
|
|
49037
49329
|
return value.map(
|
|
49038
49330
|
(item, i) => substituteTraitRefsDeep(item, `${pathKey}[${i}]`)
|
|
49039
49331
|
);
|
|
49040
49332
|
}
|
|
49041
49333
|
if (typeof value === "object" && isPlainConfigObject(value)) {
|
|
49334
|
+
if (!subtreeHasTraitRef(value)) return value;
|
|
49042
49335
|
const out = {};
|
|
49043
49336
|
for (const [k, v] of Object.entries(value)) {
|
|
49044
49337
|
out[k] = substituteTraitRefsDeep(v, `${pathKey}.${k}`);
|
|
@@ -49065,6 +49358,10 @@ function renderPatternProps(props, onDismiss, propsSchema) {
|
|
|
49065
49358
|
};
|
|
49066
49359
|
rendered[key] = /* @__PURE__ */ jsx(SlotContentRenderer, { content: childContent, onDismiss });
|
|
49067
49360
|
} else if (Array.isArray(value)) {
|
|
49361
|
+
if (!isEvaluatorResolvedData(value) && value.some((el) => isPatternConfig(el))) ; else if (!subtreeHasTraitRef(value)) {
|
|
49362
|
+
rendered[key] = value;
|
|
49363
|
+
continue;
|
|
49364
|
+
}
|
|
49068
49365
|
const isDataArray = propsSchema?.[key]?.items?.types?.includes("object") ?? false;
|
|
49069
49366
|
rendered[key] = value.map((item, i) => {
|
|
49070
49367
|
const el = item;
|
|
@@ -49327,7 +49624,7 @@ function UISlotRenderer({
|
|
|
49327
49624
|
}
|
|
49328
49625
|
return wrapped;
|
|
49329
49626
|
}
|
|
49330
|
-
var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SlotContainedContext, SLOT_SKELETON_MAP, SELF_OVERLAY_PATTERNS, CONTENT_NODE_SLOTS, PATTERNS_WITH_CHILDREN;
|
|
49627
|
+
var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SlotContainedContext, SLOT_SKELETON_MAP, SELF_OVERLAY_PATTERNS, CONTENT_NODE_SLOTS, PATTERNS_WITH_CHILDREN, traitRefPresenceCache;
|
|
49331
49628
|
var init_UISlotRenderer = __esm({
|
|
49332
49629
|
"components/core/organisms/UISlotRenderer.tsx"() {
|
|
49333
49630
|
"use client";
|
|
@@ -49401,6 +49698,7 @@ var init_UISlotRenderer = __esm({
|
|
|
49401
49698
|
"alert",
|
|
49402
49699
|
"dialog"
|
|
49403
49700
|
]);
|
|
49701
|
+
traitRefPresenceCache = /* @__PURE__ */ new WeakMap();
|
|
49404
49702
|
UISlotRenderer.displayName = "UISlotRenderer";
|
|
49405
49703
|
}
|
|
49406
49704
|
});
|
|
@@ -49528,6 +49826,23 @@ function createClientEffectHandlers(options) {
|
|
|
49528
49826
|
})
|
|
49529
49827
|
};
|
|
49530
49828
|
}
|
|
49829
|
+
|
|
49830
|
+
// lib/event-queue-coalesce.ts
|
|
49831
|
+
function enqueueEvent(queue, entry) {
|
|
49832
|
+
if (entry.tick !== void 0) {
|
|
49833
|
+
const pending = queue.find(
|
|
49834
|
+
(e) => e.tick !== void 0 && e.eventKey === entry.eventKey && e.targetTrait === entry.targetTrait
|
|
49835
|
+
);
|
|
49836
|
+
if (pending !== void 0) {
|
|
49837
|
+
pending.payload = entry.payload;
|
|
49838
|
+
return;
|
|
49839
|
+
}
|
|
49840
|
+
}
|
|
49841
|
+
queue.push(entry);
|
|
49842
|
+
}
|
|
49843
|
+
|
|
49844
|
+
// hooks/useTraitStateMachine.ts
|
|
49845
|
+
init_perf();
|
|
49531
49846
|
var lambdaLog = createLogger("almadar:ui:fn-form-lambda");
|
|
49532
49847
|
function isOperatorCall(value) {
|
|
49533
49848
|
const first = value[0];
|
|
@@ -50273,12 +50588,13 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
50273
50588
|
entityId
|
|
50274
50589
|
};
|
|
50275
50590
|
const emittedDuringExec = [];
|
|
50591
|
+
const tickName = flushEvent.startsWith("tick:") ? flushEvent.slice(5) : void 0;
|
|
50276
50592
|
const baseEmit = handlers.emit;
|
|
50277
50593
|
const trackingHandlers = {
|
|
50278
50594
|
...handlers,
|
|
50279
50595
|
emit: (event, eventPayload, source) => {
|
|
50280
50596
|
emittedDuringExec.push(event);
|
|
50281
|
-
baseEmit(event, eventPayload, source);
|
|
50597
|
+
baseEmit(event, eventPayload, tickName !== void 0 ? { ...source, tick: tickName } : source);
|
|
50282
50598
|
}
|
|
50283
50599
|
};
|
|
50284
50600
|
if (traitName === "Hero") {
|
|
@@ -50385,6 +50701,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
50385
50701
|
}, [eventBus]);
|
|
50386
50702
|
useEffect(() => {
|
|
50387
50703
|
const scheduler = createTickScheduler();
|
|
50704
|
+
const timedTick = (key, fn) => () => perfTimeAsync(key, fn);
|
|
50388
50705
|
const pureWriterTickKeys = /* @__PURE__ */ new Set();
|
|
50389
50706
|
for (const group of sharedGroups.values()) {
|
|
50390
50707
|
const ticksByInterval = /* @__PURE__ */ new Map();
|
|
@@ -50401,12 +50718,12 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
50401
50718
|
}
|
|
50402
50719
|
for (const entries of ticksByInterval.values()) {
|
|
50403
50720
|
const interval = entries[0].tick.interval;
|
|
50404
|
-
const onDue = () => {
|
|
50721
|
+
const onDue = timedTick(`tick:shared:${group.storeKey}@${String(interval)}`, () => {
|
|
50405
50722
|
const writers = entries.map(
|
|
50406
50723
|
({ binding, tick }) => createSharedEntityWriter(binding, tick, traitStatesRef, emitFromSharedWriter)
|
|
50407
50724
|
);
|
|
50408
50725
|
runTickFrame(group.storeKey, writers, sharedEntityStore);
|
|
50409
|
-
};
|
|
50726
|
+
});
|
|
50410
50727
|
if (interval === "frame") {
|
|
50411
50728
|
scheduler.add(0, onDue);
|
|
50412
50729
|
} else if (typeof interval === "number") {
|
|
@@ -50424,21 +50741,23 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
50424
50741
|
if (sharedKey !== void 0 && pureWriterTickKeys.has(`${binding.trait.name}::${tick.name}`)) {
|
|
50425
50742
|
continue;
|
|
50426
50743
|
}
|
|
50744
|
+
const tickKey = `tick:${binding.trait.name}::${tick.name}`;
|
|
50427
50745
|
if (tick.interval === "frame") {
|
|
50428
|
-
scheduler.add(0, () => runTickEffects(tick, binding));
|
|
50746
|
+
scheduler.add(0, timedTick(tickKey, () => runTickEffects(tick, binding)));
|
|
50429
50747
|
} else if (typeof tick.interval === "number") {
|
|
50430
|
-
scheduler.add(tick.interval, () => runTickEffects(tick, binding));
|
|
50748
|
+
scheduler.add(tick.interval, timedTick(tickKey, () => runTickEffects(tick, binding)));
|
|
50431
50749
|
} else if (isValidCronExpression(tick.interval)) {
|
|
50432
|
-
scheduler.addCron(tick.interval, () => runTickEffects(tick, binding));
|
|
50750
|
+
scheduler.addCron(tick.interval, timedTick(tickKey, () => runTickEffects(tick, binding)));
|
|
50433
50751
|
} else {
|
|
50434
|
-
scheduler.add(parseDurationString(tick.interval), () => runTickEffects(tick, binding));
|
|
50752
|
+
scheduler.add(parseDurationString(tick.interval), timedTick(tickKey, () => runTickEffects(tick, binding)));
|
|
50435
50753
|
}
|
|
50436
50754
|
}
|
|
50437
50755
|
}
|
|
50438
50756
|
return () => scheduler.stopAll();
|
|
50439
50757
|
}, [traitBindings, runTickEffects, sharedGroups, sharedEntityStore, emitFromSharedWriter]);
|
|
50440
|
-
const processEventQueued = useCallback(async (eventKey, payload, targetTrait) => {
|
|
50758
|
+
const processEventQueued = useCallback(async (eventKey, payload, targetTrait, tick, sourceTrait) => {
|
|
50441
50759
|
const normalizedEvent = normalizeEventKey(eventKey);
|
|
50760
|
+
const _perfT0 = perfStart("processEvent:total");
|
|
50442
50761
|
const bindings = traitBindingsRef.current;
|
|
50443
50762
|
const currentManager = managerRef.current;
|
|
50444
50763
|
crossTraitLog.debug("processEvent:enter", () => ({
|
|
@@ -50462,6 +50781,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
50462
50781
|
entityByTrait[name] = { ...sharedEntityStore.getSnapshot(sharedKey) };
|
|
50463
50782
|
}
|
|
50464
50783
|
}
|
|
50784
|
+
const _perfT1 = perfStart("processEvent:guardMatch");
|
|
50465
50785
|
const results = currentManager.sendEvent(
|
|
50466
50786
|
normalizedEvent,
|
|
50467
50787
|
payload,
|
|
@@ -50470,6 +50790,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
50470
50790
|
void 0,
|
|
50471
50791
|
targetTrait
|
|
50472
50792
|
);
|
|
50793
|
+
perfEnd("processEvent:guardMatch", _perfT1);
|
|
50473
50794
|
crossTraitLog.debug("processEvent:results", {
|
|
50474
50795
|
event: normalizedEvent,
|
|
50475
50796
|
executedCount: results.length,
|
|
@@ -50519,6 +50840,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
50519
50840
|
transition: `${result.previousState} -> ${result.newState}`,
|
|
50520
50841
|
effects: JSON.stringify(result.effects)
|
|
50521
50842
|
}));
|
|
50843
|
+
const _perfT2 = perfStart("processEvent:executeAll");
|
|
50522
50844
|
const emittedDuringExec = await executeTransitionEffects({
|
|
50523
50845
|
binding,
|
|
50524
50846
|
// upstream gap: /runtime TransitionResult.effects is unknown[] — they are SExpr at runtime (see Almadar_UI_Gaps.md)
|
|
@@ -50530,6 +50852,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
50530
50852
|
syncOnly: false,
|
|
50531
50853
|
log: stateLog
|
|
50532
50854
|
});
|
|
50855
|
+
perfEnd("processEvent:executeAll", _perfT2);
|
|
50533
50856
|
emittedByTrait.set(traitName, emittedDuringExec);
|
|
50534
50857
|
for (const emittedKey of emittedDuringExec) {
|
|
50535
50858
|
bridgeEchoPendingRef.current.set(
|
|
@@ -50626,23 +50949,31 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
50626
50949
|
if (orbital) dispatchedOrbitals.add(orbital);
|
|
50627
50950
|
}
|
|
50628
50951
|
const relayPayload = targetTrait !== void 0 ? { ...payload ?? {}, _targetTrait: targetTrait } : payload;
|
|
50629
|
-
|
|
50952
|
+
void onEventProcessed(normalizedEvent, relayPayload, dispatchedOrbitals, tick, sourceTrait);
|
|
50630
50953
|
}
|
|
50954
|
+
perfEnd("processEvent:total", _perfT0);
|
|
50955
|
+
perfEnd(`event:${normalizedEvent}`, _perfT0);
|
|
50631
50956
|
}, [entities, eventBus, sharedEntityStore]);
|
|
50632
50957
|
const drainEventQueue = useCallback(async () => {
|
|
50633
50958
|
if (processingRef.current) return;
|
|
50634
50959
|
processingRef.current = true;
|
|
50960
|
+
const _perfT = perfStart("drain:pass");
|
|
50961
|
+
let _perfN = 0;
|
|
50635
50962
|
try {
|
|
50636
50963
|
while (eventQueueRef.current.length > 0) {
|
|
50637
50964
|
const entry = eventQueueRef.current.shift();
|
|
50638
|
-
|
|
50965
|
+
_perfN++;
|
|
50966
|
+
await processEventQueued(entry.eventKey, entry.payload, entry.targetTrait, entry.tick, entry.sourceTrait);
|
|
50639
50967
|
}
|
|
50640
50968
|
} finally {
|
|
50641
50969
|
processingRef.current = false;
|
|
50970
|
+
perfEnd("drain:pass", _perfT);
|
|
50971
|
+
perfGauge("drain:passEntries", _perfN);
|
|
50642
50972
|
}
|
|
50643
50973
|
}, [processEventQueued]);
|
|
50644
|
-
const enqueueAndDrain = useCallback((eventKey, payload, targetTrait) => {
|
|
50645
|
-
eventQueueRef.current
|
|
50974
|
+
const enqueueAndDrain = useCallback((eventKey, payload, targetTrait, tick, sourceTrait) => {
|
|
50975
|
+
enqueueEvent(eventQueueRef.current, { eventKey, payload, targetTrait, tick, sourceTrait });
|
|
50976
|
+
perfGauge("queue:depthAtEnqueue", eventQueueRef.current.length);
|
|
50646
50977
|
void drainEventQueue();
|
|
50647
50978
|
}, [drainEventQueue]);
|
|
50648
50979
|
useCallback((eventKey, payload) => {
|
|
@@ -50695,7 +51026,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
50695
51026
|
crossTraitLog.debug("self:fire-server-cascade", { traitName, busKey: selfBusKey, eventKey });
|
|
50696
51027
|
}
|
|
50697
51028
|
crossTraitLog.debug("self:fire", { traitName, busKey: selfBusKey, eventKey });
|
|
50698
|
-
enqueueAndDrain(eventKey, event.payload, traitName);
|
|
51029
|
+
enqueueAndDrain(eventKey, event.payload, traitName, event.source?.tick, event.source?.trait);
|
|
50699
51030
|
});
|
|
50700
51031
|
unsubscribes.push(() => {
|
|
50701
51032
|
crossTraitLog.debug("self:unsubscribe", { traitName, busKey: selfBusKey, eventKey });
|
|
@@ -50713,7 +51044,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
50713
51044
|
const bareKey = `UI:${eventKey}`;
|
|
50714
51045
|
const unsub = eventBus.on(bareKey, (event) => {
|
|
50715
51046
|
crossTraitLog.debug("bare-cascade:fire", { bareKey, eventKey });
|
|
50716
|
-
enqueueAndDrain(eventKey, event.payload);
|
|
51047
|
+
enqueueAndDrain(eventKey, event.payload, void 0, event.source?.tick, event.source?.trait);
|
|
50717
51048
|
});
|
|
50718
51049
|
unsubscribes.push(() => {
|
|
50719
51050
|
crossTraitLog.debug("bare-cascade:unsubscribe", { bareKey, eventKey });
|
|
@@ -50747,7 +51078,9 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
50747
51078
|
enqueueAndDrain(
|
|
50748
51079
|
listen.triggers,
|
|
50749
51080
|
applyListenPayloadMapping(listen.payloadMapping, event.payload, evaluateListenPayloadExpr),
|
|
50750
|
-
binding.trait.name
|
|
51081
|
+
binding.trait.name,
|
|
51082
|
+
event.source?.tick,
|
|
51083
|
+
event.source?.trait
|
|
50751
51084
|
);
|
|
50752
51085
|
});
|
|
50753
51086
|
unsubscribes.push(() => {
|
|
@@ -51042,7 +51375,7 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
|
|
|
51042
51375
|
[serverActiveTraits]
|
|
51043
51376
|
);
|
|
51044
51377
|
const uiSlots = useUISlots();
|
|
51045
|
-
const onEventProcessed = useCallback(
|
|
51378
|
+
const onEventProcessed = useCallback((event, payload, dispatchedOrbitals, tick, sourceTrait) => {
|
|
51046
51379
|
if (!bridge.connected || !orbitalNames?.length) return;
|
|
51047
51380
|
const targets = dispatchedOrbitals && dispatchedOrbitals.size > 0 ? orbitalNames.filter((n) => dispatchedOrbitals.has(n)) : orbitalNames;
|
|
51048
51381
|
xOrbitalLog.debug("TraitInitializer:fanout", () => ({
|
|
@@ -51052,9 +51385,14 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
|
|
|
51052
51385
|
dispatchedOrbitalsSize: dispatchedOrbitals?.size ?? 0
|
|
51053
51386
|
}));
|
|
51054
51387
|
for (const name of targets) {
|
|
51055
|
-
|
|
51056
|
-
|
|
51057
|
-
|
|
51388
|
+
if (tick !== void 0) {
|
|
51389
|
+
void bridge.sendEvent(name, event, withActiveTraits(payload), tick, sourceTrait);
|
|
51390
|
+
continue;
|
|
51391
|
+
}
|
|
51392
|
+
void bridge.sendEvent(name, event, withActiveTraits(payload)).then(({ effects, meta }) => {
|
|
51393
|
+
recordServerResponse(name, event, meta);
|
|
51394
|
+
applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits, activeTraitNames, onNavigateBack);
|
|
51395
|
+
});
|
|
51058
51396
|
}
|
|
51059
51397
|
}, [bridge.connected, bridge.sendEvent, orbitalNames, uiSlots, onNavigate, onNavigateBack, embeddedTraits, activeTraitNames, withActiveTraits]);
|
|
51060
51398
|
const opts = orbitalNames ? { onEventProcessed, navigate: onNavigate, navigateBack: onNavigateBack, traitConfigsByName, orbitalsByTrait, embeddedTraits, initPayload: routeParams } : { navigate: onNavigate, navigateBack: onNavigateBack, persistence, traitConfigsByName, orbitalsByTrait, embeddedTraits, initPayload: routeParams };
|
|
@@ -51372,14 +51710,15 @@ function OrbPreview({
|
|
|
51372
51710
|
return pattern.replace(/:([A-Za-z0-9_]+)/g, (whole, key) => routeParams[key] ?? whole);
|
|
51373
51711
|
}, [currentPagePath, routeParams]);
|
|
51374
51712
|
const navStackRef = useRef(null);
|
|
51375
|
-
const handleNavigate = useCallback((path) => {
|
|
51713
|
+
const handleNavigate = useCallback((path, navState) => {
|
|
51376
51714
|
const hit = matchPathAmong(pages, path, (entry) => entry.page.path);
|
|
51377
51715
|
const match = hit?.candidate;
|
|
51378
|
-
const params = hit?.params ?? {};
|
|
51716
|
+
const params = { ...hit?.params ?? {}, ...navState ?? {} };
|
|
51379
51717
|
navLog.debug("handleNavigate", () => ({
|
|
51380
51718
|
path,
|
|
51381
51719
|
matched: match?.page.name ?? null,
|
|
51382
51720
|
params,
|
|
51721
|
+
navState: navState ? JSON.stringify(navState) : void 0,
|
|
51383
51722
|
availablePaths: pages.map((p) => p.page.path)
|
|
51384
51723
|
}));
|
|
51385
51724
|
if (match?.page.name) {
|
|
@@ -51394,9 +51733,9 @@ function OrbPreview({
|
|
|
51394
51733
|
}
|
|
51395
51734
|
}, [pages]);
|
|
51396
51735
|
const handleNavigateEffect = useCallback(
|
|
51397
|
-
(path,
|
|
51736
|
+
(path, params, crumb) => {
|
|
51398
51737
|
navStackRef.current?.beginNavigate(path, crumb);
|
|
51399
|
-
handleNavigate(path);
|
|
51738
|
+
handleNavigate(path, params);
|
|
51400
51739
|
},
|
|
51401
51740
|
[handleNavigate]
|
|
51402
51741
|
);
|
|
@@ -51527,11 +51866,13 @@ function BrowserPlayground({
|
|
|
51527
51866
|
unregister: async () => {
|
|
51528
51867
|
runtime.unregisterAll();
|
|
51529
51868
|
},
|
|
51530
|
-
sendEvent: async (orbitalName, event, payload) => {
|
|
51869
|
+
sendEvent: async (orbitalName, event, payload, _clientId, tick, sourceTrait) => {
|
|
51531
51870
|
await registrationReady;
|
|
51532
51871
|
return runtime.processOrbitalEvent(orbitalName, {
|
|
51533
51872
|
event,
|
|
51534
|
-
payload
|
|
51873
|
+
payload,
|
|
51874
|
+
tick,
|
|
51875
|
+
sourceTrait
|
|
51535
51876
|
// @almadar/runtime OrbitalEventResponse.clientEffects uses a wider ClientEffectTuple than
|
|
51536
51877
|
// ServerBridge's local definition — cast at this boundary (upstream fix queued).
|
|
51537
51878
|
});
|
|
@@ -51549,16 +51890,8 @@ function BrowserPlayground({
|
|
|
51549
51890
|
}
|
|
51550
51891
|
);
|
|
51551
51892
|
}
|
|
51552
|
-
|
|
51553
|
-
|
|
51554
|
-
|
|
51555
|
-
var profilerOnRender = (id, phase, actualDuration, baseDuration, _startTime, commitTime) => {
|
|
51556
|
-
pushPerfEntry({
|
|
51557
|
-
name: `profiler:${id}:${phase}`,
|
|
51558
|
-
durationMs: actualDuration,
|
|
51559
|
-
ts: commitTime,
|
|
51560
|
-
detail: { baseDuration }
|
|
51561
|
-
});
|
|
51562
|
-
};
|
|
51893
|
+
|
|
51894
|
+
// runtime/index.ts
|
|
51895
|
+
init_perf();
|
|
51563
51896
|
|
|
51564
51897
|
export { BrowserPlayground, OrbPreview, clearSchemaCache, createClientEffectHandlers, profilerOnRender, usePerfBuffer, useResolvedSchema, useTraitStateMachine };
|