@almadar/ui 5.158.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.
@@ -3,6 +3,7 @@
3
3
  var React85 = require('react');
4
4
  var providers = require('@almadar/ui/providers');
5
5
  var logger = require('@almadar/logger');
6
+ var ui = require('@almadar/runtime/ui');
6
7
  var runtime = require('@almadar/runtime');
7
8
  var core = require('@almadar/core');
8
9
  var clsx = require('clsx');
@@ -13,7 +14,6 @@ var reactDom = require('react-dom');
13
14
  var hooks = require('@almadar/ui/hooks');
14
15
  var context = require('@almadar/ui/context');
15
16
  var evaluator = require('@almadar/evaluator');
16
- var ui = require('@almadar/runtime/ui');
17
17
  var reactRouterDom = require('react-router-dom');
18
18
  var ELK = require('elkjs/lib/elk.bundled.js');
19
19
  var SyntaxHighlighter = require('react-syntax-highlighter/dist/esm/prism-light.js');
@@ -867,6 +867,22 @@ var init_useTapReveal = __esm({
867
867
  "hooks/useTapReveal.ts"() {
868
868
  }
869
869
  });
870
+ function usePerfBuffer() {
871
+ return React85.useSyncExternalStore(ui.perfStore.subscribe, ui.perfStore.getSnapshot, ui.perfStore.getSnapshot);
872
+ }
873
+ exports.profilerOnRender = void 0;
874
+ var init_perf = __esm({
875
+ "lib/perf.ts"() {
876
+ exports.profilerOnRender = (id, phase, actualDuration, baseDuration, _startTime, commitTime) => {
877
+ ui.pushPerfEntry({
878
+ name: `profiler:${id}:${phase}`,
879
+ durationMs: actualDuration,
880
+ ts: commitTime,
881
+ detail: { baseDuration }
882
+ });
883
+ };
884
+ }
885
+ });
870
886
  function resolveMarkerExpression(expression, entity, config, state) {
871
887
  const ctx = runtime.createContextFromBindings({
872
888
  entity,
@@ -884,7 +900,16 @@ function isPlainObject(value) {
884
900
  if (typeof value === "function") return false;
885
901
  return true;
886
902
  }
903
+ function isEvaluatorResolvedData(value) {
904
+ return evaluatorResolvedData.has(value);
905
+ }
906
+ function brandResolved(value) {
907
+ if (value !== null && typeof value === "object" && !React85__namespace.default.isValidElement(value) && !(value instanceof Date)) {
908
+ resolvedMarkerFree.add(value);
909
+ }
910
+ }
887
911
  function subtreeHasMarker(value) {
912
+ if (resolvedMarkerFree.has(value)) return false;
888
913
  const cached = markerPresenceCache.get(value);
889
914
  if (cached !== void 0) return cached;
890
915
  let found = false;
@@ -906,10 +931,23 @@ function subtreeHasMarker(value) {
906
931
  }
907
932
  function walkValue(value, scopeTrait, entity, config, state) {
908
933
  if (core.isRenderBindingMarker(value)) {
909
- return { resolved: resolveMarkerExpression(value.expression, entity, config, state), changed: true };
934
+ const cached = markerResolutionCache.get(value);
935
+ if (cached !== void 0 && cached.entity === entity && cached.config === config && cached.state === state) {
936
+ return { resolved: cached.resolved, changed: false };
937
+ }
938
+ const resolved = resolveMarkerExpression(value.expression, entity, config, state);
939
+ markerResolutionCache.set(value, { entity, config, state, resolved });
940
+ if (resolved !== null && typeof resolved === "object" && !React85__namespace.default.isValidElement(resolved) && !(resolved instanceof Date)) {
941
+ resolvedMarkerFree.add(resolved);
942
+ evaluatorResolvedData.add(resolved);
943
+ }
944
+ return { resolved, changed: true };
910
945
  }
911
946
  if (Array.isArray(value)) {
912
- if (!subtreeHasMarker(value)) return { resolved: value, changed: false };
947
+ if (!subtreeHasMarker(value)) {
948
+ brandResolved(value);
949
+ return { resolved: value, changed: false };
950
+ }
913
951
  const out = [];
914
952
  let changed = false;
915
953
  for (const item of value) {
@@ -924,10 +962,14 @@ function walkValue(value, scopeTrait, entity, config, state) {
924
962
  out.push(resolved);
925
963
  if (itemChanged) changed = true;
926
964
  }
965
+ brandResolved(out);
927
966
  return changed ? { resolved: out, changed: true } : { resolved: value, changed: false };
928
967
  }
929
968
  if (isPlainObject(value)) {
930
- if (!subtreeHasMarker(value)) return { resolved: value, changed: false };
969
+ if (!subtreeHasMarker(value)) {
970
+ brandResolved(value);
971
+ return { resolved: value, changed: false };
972
+ }
931
973
  const sourceTrait = value._sourceTrait;
932
974
  if (typeof sourceTrait === "string" && sourceTrait !== scopeTrait) {
933
975
  return { resolved: value, changed: false };
@@ -939,11 +981,13 @@ function walkValue(value, scopeTrait, entity, config, state) {
939
981
  out[key] = resolved;
940
982
  if (itemChanged) changed = true;
941
983
  }
984
+ brandResolved(out);
942
985
  return changed ? { resolved: out, changed: true } : { resolved: value, changed: false };
943
986
  }
944
987
  return { resolved: value, changed: false };
945
988
  }
946
989
  function resolveRenderBindingMarkers(props, scopeTrait, entity, config, state) {
990
+ if (resolvedMarkerFree.has(props)) return props;
947
991
  const out = {};
948
992
  let changed = false;
949
993
  for (const [key, value] of Object.entries(props)) {
@@ -951,13 +995,17 @@ function resolveRenderBindingMarkers(props, scopeTrait, entity, config, state) {
951
995
  out[key] = resolved;
952
996
  if (propChanged) changed = true;
953
997
  }
998
+ brandResolved(out);
954
999
  return changed ? out : props;
955
1000
  }
956
- var markerPresenceCache;
1001
+ var markerPresenceCache, markerResolutionCache, resolvedMarkerFree, evaluatorResolvedData;
957
1002
  var init_resolve_render_bindings = __esm({
958
1003
  "lib/resolve-render-bindings.ts"() {
959
1004
  "use client";
960
1005
  markerPresenceCache = /* @__PURE__ */ new WeakMap();
1006
+ markerResolutionCache = /* @__PURE__ */ new WeakMap();
1007
+ resolvedMarkerFree = /* @__PURE__ */ new WeakSet();
1008
+ evaluatorResolvedData = /* @__PURE__ */ new WeakSet();
961
1009
  }
962
1010
  });
963
1011
  function cn(...inputs) {
@@ -12282,6 +12330,7 @@ var init_LearningCanvas = __esm({
12282
12330
  "components/learning/atoms/LearningCanvas.tsx"() {
12283
12331
  "use client";
12284
12332
  init_cn();
12333
+ init_perf();
12285
12334
  init_useEventBus();
12286
12335
  DASH_PATTERNS = { dashed: [6, 4], dotted: [2, 3] };
12287
12336
  TRACE_SERIES_COLORS = ["#2563eb", "#dc2626", "#16a34a", "#f59e0b"];
@@ -12325,6 +12374,7 @@ var init_LearningCanvas = __esm({
12325
12374
  return [...shapes, ...traceOut, ...readoutOut];
12326
12375
  }, [shapes, traces, readouts, width, height]);
12327
12376
  const draw = React85.useCallback(() => {
12377
+ const _perfT = ui.perfStart("learningcanvas:paint");
12328
12378
  const canvas = canvasRef.current;
12329
12379
  if (!canvas) return;
12330
12380
  const ctx = canvas.getContext("2d");
@@ -12346,6 +12396,7 @@ var init_LearningCanvas = __esm({
12346
12396
  for (const shape of derivedShapes) {
12347
12397
  if (shape.type === "text") drawShape(ctx, shape, width, height, derivedShapes);
12348
12398
  }
12399
+ ui.perfEnd("learningcanvas:paint", _perfT);
12349
12400
  }, [width, height, backgroundColor, derivedShapes]);
12350
12401
  React85.useEffect(() => {
12351
12402
  draw();
@@ -30172,6 +30223,7 @@ var init_MathCanvas = __esm({
30172
30223
  "components/learning/molecules/MathCanvas.tsx"() {
30173
30224
  "use client";
30174
30225
  init_useEventBus();
30226
+ init_perf();
30175
30227
  init_atoms();
30176
30228
  init_Stack();
30177
30229
  init_LearningCanvas();
@@ -30237,6 +30289,7 @@ var init_MathCanvas = __esm({
30237
30289
  };
30238
30290
  }, [stableKeyMap, stableKeyUpMap, eventBus]);
30239
30291
  const derivedShapes = React85.useMemo(() => {
30292
+ const _perfT = ui.perfStart("mathcanvas:derive");
30240
30293
  const out = [];
30241
30294
  const margin = 24;
30242
30295
  const plotW = width - margin * 2;
@@ -30480,6 +30533,7 @@ var init_MathCanvas = __esm({
30480
30533
  }
30481
30534
  }
30482
30535
  out.push(...shapes);
30536
+ ui.perfEnd("mathcanvas:derive", _perfT);
30483
30537
  return out;
30484
30538
  }, [
30485
30539
  width,
@@ -36695,7 +36749,7 @@ var init_RichBlockEditor = __esm({
36695
36749
  {
36696
36750
  variant: "bordered",
36697
36751
  padding: "none",
36698
- className: cn("flex flex-col", className),
36752
+ className: cn("flex flex-col text-card-foreground", className),
36699
36753
  children: [
36700
36754
  enableBlocks && showToolbar && !readOnly && /* @__PURE__ */ jsxRuntime.jsx(
36701
36755
  Box,
@@ -41923,6 +41977,7 @@ var init_DetailPanel = __esm({
41923
41977
  "use client";
41924
41978
  init_atoms();
41925
41979
  init_Box();
41980
+ init_Input();
41926
41981
  init_Stack();
41927
41982
  init_SimpleGrid();
41928
41983
  init_Menu();
@@ -41938,6 +41993,7 @@ var init_DetailPanel = __esm({
41938
41993
  ReactMarkdown2 = React85.lazy(() => import('react-markdown'));
41939
41994
  DetailPanel = ({
41940
41995
  title: propTitle,
41996
+ onTitleCommit,
41941
41997
  subtitle,
41942
41998
  status,
41943
41999
  avatar,
@@ -41959,6 +42015,7 @@ var init_DetailPanel = __esm({
41959
42015
  }) => {
41960
42016
  const eventBus = useEventBus();
41961
42017
  const { t } = hooks.useTranslate();
42018
+ const [titleDraft, setTitleDraft] = React85__namespace.default.useState(null);
41962
42019
  const isFieldDefArray = (arr) => {
41963
42020
  if (!arr || arr.length === 0) return false;
41964
42021
  const first = arr[0];
@@ -42179,6 +42236,50 @@ var init_DetailPanel = __esm({
42179
42236
  }),
42180
42237
  status && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: status.variant ?? "default", children: status.label })
42181
42238
  ] });
42239
+ const commitTitle = () => {
42240
+ if (!onTitleCommit) return;
42241
+ const next = (titleDraft ?? "").trim();
42242
+ setTitleDraft(null);
42243
+ if (!next || next === title) return;
42244
+ onTitleCommit(next, normalizedData?.id !== void 0 ? String(normalizedData.id) : "");
42245
+ };
42246
+ const titleNode = onTitleCommit && titleDraft !== null ? /* @__PURE__ */ jsxRuntime.jsx(
42247
+ Input,
42248
+ {
42249
+ value: titleDraft,
42250
+ autoFocus: true,
42251
+ "aria-label": t("common.title"),
42252
+ className: "h-auto py-1 text-3xl font-bold tracking-tight",
42253
+ onChange: (e) => setTitleDraft(e.target.value),
42254
+ onBlur: commitTitle,
42255
+ onKeyDown: (e) => {
42256
+ if (e.key === "Enter") {
42257
+ e.preventDefault();
42258
+ commitTitle();
42259
+ } else if (e.key === "Escape") {
42260
+ e.preventDefault();
42261
+ setTitleDraft(null);
42262
+ }
42263
+ },
42264
+ "data-testid": "detail-title-input"
42265
+ }
42266
+ ) : onTitleCommit ? /* @__PURE__ */ jsxRuntime.jsx(
42267
+ Box,
42268
+ {
42269
+ role: "button",
42270
+ tabIndex: 0,
42271
+ className: "cursor-text rounded px-1 -mx-1 transition-colors hover:bg-muted/40",
42272
+ onClick: () => setTitleDraft(title ?? ""),
42273
+ onKeyDown: (e) => {
42274
+ if (e.key === "Enter" || e.key === " ") {
42275
+ e.preventDefault();
42276
+ setTitleDraft(title ?? "");
42277
+ }
42278
+ },
42279
+ "data-testid": "detail-title-editable",
42280
+ children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h2", weight: "bold", children: title || "Details" })
42281
+ }
42282
+ ) : /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h2", weight: "bold", children: title || "Details" });
42182
42283
  const content = /* @__PURE__ */ jsxRuntime.jsx(Card, { variant: "elevated", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "md", className: "p-6", children: [
42183
42284
  /* @__PURE__ */ jsxRuntime.jsxs(HStack, { justify: "between", align: "start", gap: "md", children: [
42184
42285
  /* @__PURE__ */ jsxRuntime.jsxs(HStack, { align: "start", gap: "sm", className: "min-w-0", children: [
@@ -42198,7 +42299,7 @@ var init_DetailPanel = __esm({
42198
42299
  avatar,
42199
42300
  /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", className: "min-w-0", children: [
42200
42301
  /* @__PURE__ */ jsxRuntime.jsxs(HStack, { align: "center", gap: "sm", wrap: true, children: [
42201
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h2", weight: "bold", children: title || "Details" }),
42302
+ titleNode,
42202
42303
  statusBadges
42203
42304
  ] }),
42204
42305
  subtitle && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", color: "secondary", children: subtitle })
@@ -42759,7 +42860,7 @@ var init_Form = __esm({
42759
42860
  });
42760
42861
  debug(
42761
42862
  "forms",
42762
- `Calculation triggered: ${calc.variableName} = ${value}`
42863
+ `Calculation triggered: ${calc.variableName} = ${String(value)}`
42763
42864
  );
42764
42865
  }
42765
42866
  });
@@ -49258,6 +49359,7 @@ function isPlainConfigObject(value) {
49258
49359
  return proto === Object.prototype || proto === null;
49259
49360
  }
49260
49361
  function subtreeHasTraitRef(value) {
49362
+ if (isEvaluatorResolvedData(value)) return false;
49261
49363
  const cached = traitRefPresenceCache.get(value);
49262
49364
  if (cached !== void 0) return cached;
49263
49365
  let found = false;
@@ -49330,6 +49432,10 @@ function renderPatternProps(props, onDismiss, propsSchema) {
49330
49432
  };
49331
49433
  rendered[key] = /* @__PURE__ */ jsxRuntime.jsx(SlotContentRenderer, { content: childContent, onDismiss });
49332
49434
  } else if (Array.isArray(value)) {
49435
+ if (!isEvaluatorResolvedData(value) && value.some((el) => isPatternConfig(el))) ; else if (!subtreeHasTraitRef(value)) {
49436
+ rendered[key] = value;
49437
+ continue;
49438
+ }
49333
49439
  const isDataArray = propsSchema?.[key]?.items?.types?.includes("object") ?? false;
49334
49440
  rendered[key] = value.map((item, i) => {
49335
49441
  const el = item;
@@ -49808,6 +49914,9 @@ function enqueueEvent(queue, entry) {
49808
49914
  }
49809
49915
  queue.push(entry);
49810
49916
  }
49917
+
49918
+ // hooks/useTraitStateMachine.ts
49919
+ init_perf();
49811
49920
  var lambdaLog = logger.createLogger("almadar:ui:fn-form-lambda");
49812
49921
  function isOperatorCall(value) {
49813
49922
  const first = value[0];
@@ -50666,6 +50775,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
50666
50775
  }, [eventBus]);
50667
50776
  React85.useEffect(() => {
50668
50777
  const scheduler = runtime.createTickScheduler();
50778
+ const timedTick = (key, fn) => () => ui.perfTimeAsync(key, fn);
50669
50779
  const pureWriterTickKeys = /* @__PURE__ */ new Set();
50670
50780
  for (const group of sharedGroups.values()) {
50671
50781
  const ticksByInterval = /* @__PURE__ */ new Map();
@@ -50682,12 +50792,12 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
50682
50792
  }
50683
50793
  for (const entries of ticksByInterval.values()) {
50684
50794
  const interval = entries[0].tick.interval;
50685
- const onDue = () => {
50795
+ const onDue = timedTick(`tick:shared:${group.storeKey}@${String(interval)}`, () => {
50686
50796
  const writers = entries.map(
50687
50797
  ({ binding, tick }) => createSharedEntityWriter(binding, tick, traitStatesRef, emitFromSharedWriter)
50688
50798
  );
50689
50799
  runTickFrame(group.storeKey, writers, sharedEntityStore);
50690
- };
50800
+ });
50691
50801
  if (interval === "frame") {
50692
50802
  scheduler.add(0, onDue);
50693
50803
  } else if (typeof interval === "number") {
@@ -50705,14 +50815,15 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
50705
50815
  if (sharedKey !== void 0 && pureWriterTickKeys.has(`${binding.trait.name}::${tick.name}`)) {
50706
50816
  continue;
50707
50817
  }
50818
+ const tickKey = `tick:${binding.trait.name}::${tick.name}`;
50708
50819
  if (tick.interval === "frame") {
50709
- scheduler.add(0, () => runTickEffects(tick, binding));
50820
+ scheduler.add(0, timedTick(tickKey, () => runTickEffects(tick, binding)));
50710
50821
  } else if (typeof tick.interval === "number") {
50711
- scheduler.add(tick.interval, () => runTickEffects(tick, binding));
50822
+ scheduler.add(tick.interval, timedTick(tickKey, () => runTickEffects(tick, binding)));
50712
50823
  } else if (runtime.isValidCronExpression(tick.interval)) {
50713
- scheduler.addCron(tick.interval, () => runTickEffects(tick, binding));
50824
+ scheduler.addCron(tick.interval, timedTick(tickKey, () => runTickEffects(tick, binding)));
50714
50825
  } else {
50715
- scheduler.add(runtime.parseDurationString(tick.interval), () => runTickEffects(tick, binding));
50826
+ scheduler.add(runtime.parseDurationString(tick.interval), timedTick(tickKey, () => runTickEffects(tick, binding)));
50716
50827
  }
50717
50828
  }
50718
50829
  }
@@ -50720,6 +50831,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
50720
50831
  }, [traitBindings, runTickEffects, sharedGroups, sharedEntityStore, emitFromSharedWriter]);
50721
50832
  const processEventQueued = React85.useCallback(async (eventKey, payload, targetTrait, tick, sourceTrait) => {
50722
50833
  const normalizedEvent = normalizeEventKey(eventKey);
50834
+ const _perfT0 = ui.perfStart("processEvent:total");
50723
50835
  const bindings = traitBindingsRef.current;
50724
50836
  const currentManager = managerRef.current;
50725
50837
  crossTraitLog.debug("processEvent:enter", () => ({
@@ -50743,6 +50855,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
50743
50855
  entityByTrait[name] = { ...sharedEntityStore.getSnapshot(sharedKey) };
50744
50856
  }
50745
50857
  }
50858
+ const _perfT1 = ui.perfStart("processEvent:guardMatch");
50746
50859
  const results = currentManager.sendEvent(
50747
50860
  normalizedEvent,
50748
50861
  payload,
@@ -50751,6 +50864,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
50751
50864
  void 0,
50752
50865
  targetTrait
50753
50866
  );
50867
+ ui.perfEnd("processEvent:guardMatch", _perfT1);
50754
50868
  crossTraitLog.debug("processEvent:results", {
50755
50869
  event: normalizedEvent,
50756
50870
  executedCount: results.length,
@@ -50800,6 +50914,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
50800
50914
  transition: `${result.previousState} -> ${result.newState}`,
50801
50915
  effects: JSON.stringify(result.effects)
50802
50916
  }));
50917
+ const _perfT2 = ui.perfStart("processEvent:executeAll");
50803
50918
  const emittedDuringExec = await executeTransitionEffects({
50804
50919
  binding,
50805
50920
  // upstream gap: /runtime TransitionResult.effects is unknown[] — they are SExpr at runtime (see Almadar_UI_Gaps.md)
@@ -50811,6 +50926,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
50811
50926
  syncOnly: false,
50812
50927
  log: stateLog
50813
50928
  });
50929
+ ui.perfEnd("processEvent:executeAll", _perfT2);
50814
50930
  emittedByTrait.set(traitName, emittedDuringExec);
50815
50931
  for (const emittedKey of emittedDuringExec) {
50816
50932
  bridgeEchoPendingRef.current.set(
@@ -50907,27 +51023,31 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
50907
51023
  if (orbital) dispatchedOrbitals.add(orbital);
50908
51024
  }
50909
51025
  const relayPayload = targetTrait !== void 0 ? { ...payload ?? {}, _targetTrait: targetTrait } : payload;
50910
- if (tick !== void 0) {
50911
- void onEventProcessed(normalizedEvent, relayPayload, dispatchedOrbitals, tick, sourceTrait);
50912
- } else {
50913
- await onEventProcessed(normalizedEvent, relayPayload, dispatchedOrbitals);
50914
- }
51026
+ void onEventProcessed(normalizedEvent, relayPayload, dispatchedOrbitals, tick, sourceTrait);
50915
51027
  }
51028
+ ui.perfEnd("processEvent:total", _perfT0);
51029
+ ui.perfEnd(`event:${normalizedEvent}`, _perfT0);
50916
51030
  }, [entities, eventBus, sharedEntityStore]);
50917
51031
  const drainEventQueue = React85.useCallback(async () => {
50918
51032
  if (processingRef.current) return;
50919
51033
  processingRef.current = true;
51034
+ const _perfT = ui.perfStart("drain:pass");
51035
+ let _perfN = 0;
50920
51036
  try {
50921
51037
  while (eventQueueRef.current.length > 0) {
50922
51038
  const entry = eventQueueRef.current.shift();
51039
+ _perfN++;
50923
51040
  await processEventQueued(entry.eventKey, entry.payload, entry.targetTrait, entry.tick, entry.sourceTrait);
50924
51041
  }
50925
51042
  } finally {
50926
51043
  processingRef.current = false;
51044
+ ui.perfEnd("drain:pass", _perfT);
51045
+ ui.perfGauge("drain:passEntries", _perfN);
50927
51046
  }
50928
51047
  }, [processEventQueued]);
50929
51048
  const enqueueAndDrain = React85.useCallback((eventKey, payload, targetTrait, tick, sourceTrait) => {
50930
51049
  enqueueEvent(eventQueueRef.current, { eventKey, payload, targetTrait, tick, sourceTrait });
51050
+ ui.perfGauge("queue:depthAtEnqueue", eventQueueRef.current.length);
50931
51051
  void drainEventQueue();
50932
51052
  }, [drainEventQueue]);
50933
51053
  React85.useCallback((eventKey, payload) => {
@@ -51329,7 +51449,7 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
51329
51449
  [serverActiveTraits]
51330
51450
  );
51331
51451
  const uiSlots = context.useUISlots();
51332
- const onEventProcessed = React85.useCallback(async (event, payload, dispatchedOrbitals, tick, sourceTrait) => {
51452
+ const onEventProcessed = React85.useCallback((event, payload, dispatchedOrbitals, tick, sourceTrait) => {
51333
51453
  if (!bridge.connected || !orbitalNames?.length) return;
51334
51454
  const targets = dispatchedOrbitals && dispatchedOrbitals.size > 0 ? orbitalNames.filter((n) => dispatchedOrbitals.has(n)) : orbitalNames;
51335
51455
  xOrbitalLog.debug("TraitInitializer:fanout", () => ({
@@ -51343,9 +51463,10 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
51343
51463
  void bridge.sendEvent(name, event, withActiveTraits(payload), tick, sourceTrait);
51344
51464
  continue;
51345
51465
  }
51346
- const { effects, meta } = await bridge.sendEvent(name, event, withActiveTraits(payload));
51347
- recordServerResponse(name, event, meta);
51348
- applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits, activeTraitNames, onNavigateBack);
51466
+ void bridge.sendEvent(name, event, withActiveTraits(payload)).then(({ effects, meta }) => {
51467
+ recordServerResponse(name, event, meta);
51468
+ applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits, activeTraitNames, onNavigateBack);
51469
+ });
51349
51470
  }
51350
51471
  }, [bridge.connected, bridge.sendEvent, orbitalNames, uiSlots, onNavigate, onNavigateBack, embeddedTraits, activeTraitNames, withActiveTraits]);
51351
51472
  const opts = orbitalNames ? { onEventProcessed, navigate: onNavigate, navigateBack: onNavigateBack, traitConfigsByName, orbitalsByTrait, embeddedTraits, initPayload: routeParams } : { navigate: onNavigate, navigateBack: onNavigateBack, persistence, traitConfigsByName, orbitalsByTrait, embeddedTraits, initPayload: routeParams };
@@ -51663,14 +51784,15 @@ function OrbPreview({
51663
51784
  return pattern.replace(/:([A-Za-z0-9_]+)/g, (whole, key) => routeParams[key] ?? whole);
51664
51785
  }, [currentPagePath, routeParams]);
51665
51786
  const navStackRef = React85.useRef(null);
51666
- const handleNavigate = React85.useCallback((path) => {
51787
+ const handleNavigate = React85.useCallback((path, navState) => {
51667
51788
  const hit = providers.matchPathAmong(pages, path, (entry) => entry.page.path);
51668
51789
  const match = hit?.candidate;
51669
- const params = hit?.params ?? {};
51790
+ const params = { ...hit?.params ?? {}, ...navState ?? {} };
51670
51791
  navLog.debug("handleNavigate", () => ({
51671
51792
  path,
51672
51793
  matched: match?.page.name ?? null,
51673
51794
  params,
51795
+ navState: navState ? JSON.stringify(navState) : void 0,
51674
51796
  availablePaths: pages.map((p) => p.page.path)
51675
51797
  }));
51676
51798
  if (match?.page.name) {
@@ -51685,9 +51807,9 @@ function OrbPreview({
51685
51807
  }
51686
51808
  }, [pages]);
51687
51809
  const handleNavigateEffect = React85.useCallback(
51688
- (path, _params, crumb) => {
51810
+ (path, params, crumb) => {
51689
51811
  navStackRef.current?.beginNavigate(path, crumb);
51690
- handleNavigate(path);
51812
+ handleNavigate(path, params);
51691
51813
  },
51692
51814
  [handleNavigate]
51693
51815
  );
@@ -51842,17 +51964,9 @@ function BrowserPlayground({
51842
51964
  }
51843
51965
  );
51844
51966
  }
51845
- function usePerfBuffer() {
51846
- return React85.useSyncExternalStore(ui.perfStore.subscribe, ui.perfStore.getSnapshot, ui.perfStore.getSnapshot);
51847
- }
51848
- var profilerOnRender = (id, phase, actualDuration, baseDuration, _startTime, commitTime) => {
51849
- ui.pushPerfEntry({
51850
- name: `profiler:${id}:${phase}`,
51851
- durationMs: actualDuration,
51852
- ts: commitTime,
51853
- detail: { baseDuration }
51854
- });
51855
- };
51967
+
51968
+ // runtime/index.ts
51969
+ init_perf();
51856
51970
 
51857
51971
  Object.defineProperty(exports, "EntitySchemaProvider", {
51858
51972
  enumerable: true,
@@ -51930,7 +52044,6 @@ exports.BrowserPlayground = BrowserPlayground;
51930
52044
  exports.OrbPreview = OrbPreview;
51931
52045
  exports.clearSchemaCache = clearSchemaCache;
51932
52046
  exports.createClientEffectHandlers = createClientEffectHandlers;
51933
- exports.profilerOnRender = profilerOnRender;
51934
52047
  exports.usePerfBuffer = usePerfBuffer;
51935
52048
  exports.useResolvedSchema = useResolvedSchema;
51936
52049
  exports.useTraitStateMachine = useTraitStateMachine;
@@ -5,11 +5,11 @@ import * as _almadar_runtime from '@almadar/runtime';
5
5
  import { TraitState, EffectHandlers } from '@almadar/runtime';
6
6
  import '../useEventBus-Ckr4wqW3.cjs';
7
7
  import { c as useUISlots } from '../UISlotContext-BlRDbHDy.cjs';
8
- import { a as EntityBindingSource, h as ServerBridgeTransport } from '../EntityBindingContext-Bn3ePJQC.cjs';
9
- export { b as EntitySchemaContextValue, c as EntitySchemaProvider, d as EntitySchemaProviderProps, e as ServerBridgeContextValue, f as ServerBridgeProvider, i as ServerClientEffect, T as TraitContext, k as TraitContextValue, l as TraitInstance, m as TraitProvider, n as TraitProviderProps, o as useEntitySchema, p as useEntitySchemaOptional, q as useServerBridge, r as useTrait, s as useTraitContext } from '../EntityBindingContext-Bn3ePJQC.cjs';
10
- import { PerfEntry } from '@almadar/runtime/ui';
8
+ import { E as EntityBindingSource, S as ServerBridgeTransport } from '../EntityBindingContext-0Evn_LcT.cjs';
9
+ export { a as EntitySchemaContextValue, b as EntitySchemaProvider, c as EntitySchemaProviderProps, d as ServerBridgeContextValue, e as ServerBridgeProvider, f as ServerClientEffect, T as TraitContext, g as TraitContextValue, h as TraitInstance, i as TraitProvider, j as TraitProviderProps, u as useEntitySchema, k as useEntitySchemaOptional, l as useServerBridge, m as useTrait, n as useTraitContext } from '../EntityBindingContext-0Evn_LcT.cjs';
11
10
  export { PERF_NAMESPACE, PerfEntry, PreparedPreviewSchema, adjustSchemaForMockData, buildMockData, clearPerf, perfEnd, perfStart, perfTime, prepareSchemaForPreview, wrapCallbackForEvent } from '@almadar/runtime/ui';
12
- import React__default, { ProfilerOnRenderCallback } from 'react';
11
+ import React__default from 'react';
12
+ export { p as profilerOnRender, u as usePerfBuffer } from '../perf-DaVdsbU0.cjs';
13
13
  import '../event-bus-types-Bl78kokd.cjs';
14
14
  import '../useUISlots-GNwGLlW2.cjs';
15
15
  import '@almadar/core/patterns';
@@ -312,21 +312,4 @@ interface BrowserPlaygroundProps {
312
312
  }
313
313
  declare function BrowserPlayground({ schema, mode, initialPagePath, height, className, }: BrowserPlaygroundProps): React__default.ReactElement;
314
314
 
315
- /**
316
- * @almadar/ui/runtime — perf instrumentation
317
- *
318
- * React-specific consumption layer on top of the renderer-agnostic perf ring
319
- * now living in `@almadar/runtime/ui/perf`. Re-exports the framework-free
320
- * timing primitives and adds `useSyncExternalStore` / `React.Profiler` hooks.
321
- */
322
-
323
- /**
324
- * React hook: returns the current perf ring snapshot, re-renders on push.
325
- */
326
- declare function usePerfBuffer(): readonly PerfEntry[];
327
- /**
328
- * React.Profiler `onRender` callback. Records `actualDuration` per commit.
329
- */
330
- declare const profilerOnRender: ProfilerOnRenderCallback;
331
-
332
- export { BrowserPlayground, type BrowserPlaygroundProps, type ClientEventBus, type CreateClientEffectHandlersOptions, OrbPreview, type OrbPreviewProps, type ResolvedSchemaResult, ServerBridgeTransport, type SlotPatternEntry, type SlotSetter, type SlotSource, type TraitStateMachineResult, type UseTraitStateMachineOptions, clearSchemaCache, createClientEffectHandlers, profilerOnRender, usePerfBuffer, useResolvedSchema, useTraitStateMachine };
315
+ export { BrowserPlayground, type BrowserPlaygroundProps, type ClientEventBus, type CreateClientEffectHandlersOptions, OrbPreview, type OrbPreviewProps, type ResolvedSchemaResult, ServerBridgeTransport, type SlotPatternEntry, type SlotSetter, type SlotSource, type TraitStateMachineResult, type UseTraitStateMachineOptions, clearSchemaCache, createClientEffectHandlers, useResolvedSchema, useTraitStateMachine };
@@ -5,11 +5,11 @@ import * as _almadar_runtime from '@almadar/runtime';
5
5
  import { TraitState, EffectHandlers } from '@almadar/runtime';
6
6
  import '../useEventBus-CQWyAWpK.js';
7
7
  import { c as useUISlots } from '../UISlotContext-CB89mv7N.js';
8
- import { a as EntityBindingSource, h as ServerBridgeTransport } from '../EntityBindingContext-Bn3ePJQC.js';
9
- export { b as EntitySchemaContextValue, c as EntitySchemaProvider, d as EntitySchemaProviderProps, e as ServerBridgeContextValue, f as ServerBridgeProvider, i as ServerClientEffect, T as TraitContext, k as TraitContextValue, l as TraitInstance, m as TraitProvider, n as TraitProviderProps, o as useEntitySchema, p as useEntitySchemaOptional, q as useServerBridge, r as useTrait, s as useTraitContext } from '../EntityBindingContext-Bn3ePJQC.js';
10
- import { PerfEntry } from '@almadar/runtime/ui';
8
+ import { E as EntityBindingSource, S as ServerBridgeTransport } from '../EntityBindingContext-0Evn_LcT.js';
9
+ export { a as EntitySchemaContextValue, b as EntitySchemaProvider, c as EntitySchemaProviderProps, d as ServerBridgeContextValue, e as ServerBridgeProvider, f as ServerClientEffect, T as TraitContext, g as TraitContextValue, h as TraitInstance, i as TraitProvider, j as TraitProviderProps, u as useEntitySchema, k as useEntitySchemaOptional, l as useServerBridge, m as useTrait, n as useTraitContext } from '../EntityBindingContext-0Evn_LcT.js';
11
10
  export { PERF_NAMESPACE, PerfEntry, PreparedPreviewSchema, adjustSchemaForMockData, buildMockData, clearPerf, perfEnd, perfStart, perfTime, prepareSchemaForPreview, wrapCallbackForEvent } from '@almadar/runtime/ui';
12
- import React__default, { ProfilerOnRenderCallback } from 'react';
11
+ import React__default from 'react';
12
+ export { p as profilerOnRender, u as usePerfBuffer } from '../perf-DaVdsbU0.js';
13
13
  import '../event-bus-types-Bl78kokd.js';
14
14
  import '../useUISlots-GNwGLlW2.js';
15
15
  import '@almadar/core/patterns';
@@ -312,21 +312,4 @@ interface BrowserPlaygroundProps {
312
312
  }
313
313
  declare function BrowserPlayground({ schema, mode, initialPagePath, height, className, }: BrowserPlaygroundProps): React__default.ReactElement;
314
314
 
315
- /**
316
- * @almadar/ui/runtime — perf instrumentation
317
- *
318
- * React-specific consumption layer on top of the renderer-agnostic perf ring
319
- * now living in `@almadar/runtime/ui/perf`. Re-exports the framework-free
320
- * timing primitives and adds `useSyncExternalStore` / `React.Profiler` hooks.
321
- */
322
-
323
- /**
324
- * React hook: returns the current perf ring snapshot, re-renders on push.
325
- */
326
- declare function usePerfBuffer(): readonly PerfEntry[];
327
- /**
328
- * React.Profiler `onRender` callback. Records `actualDuration` per commit.
329
- */
330
- declare const profilerOnRender: ProfilerOnRenderCallback;
331
-
332
- export { BrowserPlayground, type BrowserPlaygroundProps, type ClientEventBus, type CreateClientEffectHandlersOptions, OrbPreview, type OrbPreviewProps, type ResolvedSchemaResult, ServerBridgeTransport, type SlotPatternEntry, type SlotSetter, type SlotSource, type TraitStateMachineResult, type UseTraitStateMachineOptions, clearSchemaCache, createClientEffectHandlers, profilerOnRender, usePerfBuffer, useResolvedSchema, useTraitStateMachine };
315
+ export { BrowserPlayground, type BrowserPlaygroundProps, type ClientEventBus, type CreateClientEffectHandlersOptions, OrbPreview, type OrbPreviewProps, type ResolvedSchemaResult, ServerBridgeTransport, type SlotPatternEntry, type SlotSetter, type SlotSource, type TraitStateMachineResult, type UseTraitStateMachineOptions, clearSchemaCache, createClientEffectHandlers, useResolvedSchema, useTraitStateMachine };