@almadar/ui 6.28.0 → 6.29.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.
@@ -2263,6 +2263,13 @@ var init_slot_types = __esm({
2263
2263
  nextRefId = 1;
2264
2264
  }
2265
2265
  });
2266
+ var SlotContainedContext;
2267
+ var init_slotContained = __esm({
2268
+ "lib/slotContained.ts"() {
2269
+ "use client";
2270
+ SlotContainedContext = createContext(false);
2271
+ }
2272
+ });
2266
2273
  function buildForkPaths(x, y, branches, scale) {
2267
2274
  const inLength = 30 * scale;
2268
2275
  const outLength = 30 * scale;
@@ -35845,7 +35852,6 @@ function TableView({
35845
35852
  columns,
35846
35853
  fields,
35847
35854
  itemActions,
35848
- maxInlineActions,
35849
35855
  itemClickEvent = "",
35850
35856
  selectable = false,
35851
35857
  selectEvent,
@@ -35879,8 +35885,7 @@ function TableView({
35879
35885
  const [localSelected, setLocalSelected] = React89__default.useState(/* @__PURE__ */ new Set());
35880
35886
  const colDefs = (Array.isArray(columns) ? columns : void 0) ?? (Array.isArray(fields) ? fields : void 0) ?? [];
35881
35887
  const actionDefs = Array.isArray(itemActions) ? itemActions : [];
35882
- const inlineActions = maxInlineActions != null ? actionDefs.slice(0, maxInlineActions) : [];
35883
- const overflowActions = maxInlineActions != null ? actionDefs.slice(maxInlineActions) : actionDefs;
35888
+ const overflowActions = actionDefs;
35884
35889
  const fireAction = (action, row) => eventBus.emit(`UI:${action.event}`, {
35885
35890
  id: row.id,
35886
35891
  row
@@ -36062,7 +36067,7 @@ function TableView({
36062
36067
  }
36063
36068
  return /* @__PURE__ */ jsx(Box, { role: "cell", className: cellBase, children: /* @__PURE__ */ jsx("span", { className: "truncate text-foreground", children: formatCell(raw, col.format, relationsData?.[col.field ?? col.key]) }) }, col.key);
36064
36069
  }),
36065
- hasActions && /* @__PURE__ */ jsxs(
36070
+ hasActions && /* @__PURE__ */ jsx(
36066
36071
  HStack,
36067
36072
  {
36068
36073
  gap: "xs",
@@ -36076,38 +36081,20 @@ function TableView({
36076
36081
  "border-l border-[var(--color-border)]",
36077
36082
  lk.striped && index % 2 === 1 ? "bg-[var(--color-surface-subtle)]" : "bg-[var(--color-card)] group-hover:bg-[var(--color-surface-subtle)]"
36078
36083
  ),
36079
- children: [
36080
- inlineActions.map((action) => /* @__PURE__ */ jsxs(
36081
- Button,
36082
- {
36083
- variant: action.variant ?? "ghost",
36084
- size: "sm",
36085
- onClick: () => fireAction(action, row),
36086
- "data-testid": `action-${action.event}`,
36087
- "data-row-id": String(row.id),
36088
- className: cn(action.variant === "danger" && "text-error hover:bg-error/10"),
36089
- children: [
36090
- action.icon && renderIconInput3(action.icon, { size: "xs", className: "mr-1" }),
36091
- action.label
36092
- ]
36093
- },
36094
- action.event
36095
- )),
36096
- overflowActions.length > 0 && /* @__PURE__ */ jsx(
36097
- Menu,
36098
- {
36099
- position: "bottom-end",
36100
- trigger: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", "data-row-id": String(row.id), children: /* @__PURE__ */ jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
36101
- items: overflowActions.map((action) => ({
36102
- label: action.label,
36103
- icon: action.icon,
36104
- event: action.event,
36105
- variant: action.variant === "danger" ? "danger" : "default",
36106
- onClick: () => fireAction(action, row)
36107
- }))
36108
- }
36109
- )
36110
- ]
36084
+ children: overflowActions.length > 0 && /* @__PURE__ */ jsx(
36085
+ Menu,
36086
+ {
36087
+ position: "bottom-end",
36088
+ trigger: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", "data-row-id": String(row.id), children: /* @__PURE__ */ jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
36089
+ items: overflowActions.map((action) => ({
36090
+ label: action.label,
36091
+ icon: action.icon,
36092
+ event: action.event,
36093
+ variant: action.variant === "danger" ? "danger" : "default",
36094
+ onClick: () => fireAction(action, row)
36095
+ }))
36096
+ }
36097
+ )
36111
36098
  }
36112
36099
  )
36113
36100
  ]
@@ -45533,6 +45520,7 @@ var init_DetailPanel = __esm({
45533
45520
  init_EmptyState();
45534
45521
  init_cn();
45535
45522
  init_portalRoot();
45523
+ init_slotContained();
45536
45524
  init_format();
45537
45525
  init_getNestedValue();
45538
45526
  init_relationLabel();
@@ -45564,6 +45552,7 @@ var init_DetailPanel = __esm({
45564
45552
  }) => {
45565
45553
  const eventBus = useEventBus();
45566
45554
  const { t } = useTranslate();
45555
+ const contained = useContext(SlotContainedContext);
45567
45556
  const [titleDraft, setTitleDraft] = React89__default.useState(null);
45568
45557
  const isFieldDefArray = (arr) => {
45569
45558
  if (!arr || arr.length === 0) return false;
@@ -45951,8 +45940,9 @@ var init_DetailPanel = __esm({
45951
45940
  if (!slideOver) {
45952
45941
  return /* @__PURE__ */ jsx(Box, { className, children: content });
45953
45942
  }
45954
- const panel = /* @__PURE__ */ jsx(Box, { className: cn("fixed inset-y-0 right-0 w-full max-w-2xl bg-card shadow-lg z-50 overflow-y-auto p-6", className), children: content });
45955
- return typeof document === "undefined" ? panel : createPortal(panel, getOrCreatePortalRoot());
45943
+ const panel = /* @__PURE__ */ jsx(Box, { className: cn(contained ? "absolute" : "fixed", "inset-y-0 right-0 w-full max-w-2xl bg-card shadow-lg z-50 overflow-y-auto p-6", className), children: content });
45944
+ if (contained || typeof document === "undefined") return panel;
45945
+ return createPortal(panel, getOrCreatePortalRoot());
45956
45946
  };
45957
45947
  DetailPanel.displayName = "DetailPanel";
45958
45948
  }
@@ -52430,6 +52420,7 @@ var init_component_registry_generated = __esm({
52430
52420
  // components/core/organisms/UISlotRenderer.tsx
52431
52421
  var UISlotRenderer_exports = {};
52432
52422
  __export(UISlotRenderer_exports, {
52423
+ SlotContainedContext: () => SlotContainedContext,
52433
52424
  SlotContentRenderer: () => SlotContentRenderer,
52434
52425
  SuspenseConfigProvider: () => SuspenseConfigProvider,
52435
52426
  UISlotComponent: () => UISlotComponent,
@@ -52602,6 +52593,25 @@ function renderContainedPortal(t, slot, content, onDismiss) {
52602
52593
  }
52603
52594
  );
52604
52595
  case "drawer":
52596
+ if (content.pattern === "detail-panel" && content.props.slideOver === true) {
52597
+ return /* @__PURE__ */ jsx(
52598
+ Box,
52599
+ {
52600
+ id: slotId,
52601
+ className: "absolute inset-0 z-50 overflow-hidden",
52602
+ style: { backgroundColor: "rgba(0, 0, 0, 0.5)" },
52603
+ onClick: onDismiss,
52604
+ children: /* @__PURE__ */ jsx(
52605
+ Box,
52606
+ {
52607
+ className: "absolute inset-y-0 right-0 pointer-events-auto",
52608
+ onClick: (e) => e.stopPropagation(),
52609
+ children: slotContent
52610
+ }
52611
+ )
52612
+ }
52613
+ );
52614
+ }
52605
52615
  return /* @__PURE__ */ jsx(
52606
52616
  Box,
52607
52617
  {
@@ -53453,7 +53463,7 @@ function UISlotRenderer({
53453
53463
  }
53454
53464
  return wrapped;
53455
53465
  }
53456
- var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SlotContainedContext, SLOT_SKELETON_MAP, CONTENT_NODE_SLOTS, PATTERNS_WITH_CHILDREN, traitRefPresenceCache;
53466
+ var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SLOT_SKELETON_MAP, CONTENT_NODE_SLOTS, PATTERNS_WITH_CHILDREN, traitRefPresenceCache;
53457
53467
  var init_UISlotRenderer = __esm({
53458
53468
  "components/core/organisms/UISlotRenderer.tsx"() {
53459
53469
  "use client";
@@ -53468,6 +53478,7 @@ var init_UISlotRenderer = __esm({
53468
53478
  init_cn();
53469
53479
  init_format();
53470
53480
  init_portalRoot();
53481
+ init_slotContained();
53471
53482
  init_ErrorBoundary();
53472
53483
  init_Skeleton();
53473
53484
  init_renderer();
@@ -53477,7 +53488,6 @@ var init_UISlotRenderer = __esm({
53477
53488
  scopeWrapLog = createLogger("almadar:ui:scope-wrap");
53478
53489
  TRAIT_BINDING_RE = /^@trait\.([A-Z][A-Za-z0-9]*)$/;
53479
53490
  SuspenseConfigContext = createContext({ enabled: false });
53480
- SlotContainedContext = createContext(false);
53481
53491
  SuspenseConfigProvider.displayName = "SuspenseConfigProvider";
53482
53492
  SLOT_SKELETON_MAP = {
53483
53493
  main: "table",
@@ -54923,6 +54933,7 @@ function ServerBridgeProvider({
54923
54933
  clientEffects: result.clientEffects?.length ?? 0,
54924
54934
  dataEntities,
54925
54935
  data: responseData,
54936
+ entityByTrait: result.entityByTrait,
54926
54937
  emittedEvents: result.emittedEvents?.map((e) => e.event) ?? [],
54927
54938
  emitted: result.emittedEvents?.map((e) => ({ event: e.event, ...e.payload !== void 0 && { payload: e.payload } })) ?? [],
54928
54939
  effectResults: result.effectResults,
@@ -2936,6 +2936,13 @@ var init_slot_types = __esm({
2936
2936
  nextRefId = 1;
2937
2937
  }
2938
2938
  });
2939
+ var SlotContainedContext;
2940
+ var init_slotContained = __esm({
2941
+ "lib/slotContained.ts"() {
2942
+ "use client";
2943
+ SlotContainedContext = React87.createContext(false);
2944
+ }
2945
+ });
2939
2946
  function buildForkPaths(x, y, branches, scale) {
2940
2947
  const inLength = 30 * scale;
2941
2948
  const outLength = 30 * scale;
@@ -35697,7 +35704,6 @@ function TableView({
35697
35704
  columns,
35698
35705
  fields,
35699
35706
  itemActions,
35700
- maxInlineActions,
35701
35707
  itemClickEvent = "",
35702
35708
  selectable = false,
35703
35709
  selectEvent,
@@ -35731,8 +35737,7 @@ function TableView({
35731
35737
  const [localSelected, setLocalSelected] = React87__namespace.default.useState(/* @__PURE__ */ new Set());
35732
35738
  const colDefs = (Array.isArray(columns) ? columns : void 0) ?? (Array.isArray(fields) ? fields : void 0) ?? [];
35733
35739
  const actionDefs = Array.isArray(itemActions) ? itemActions : [];
35734
- const inlineActions = maxInlineActions != null ? actionDefs.slice(0, maxInlineActions) : [];
35735
- const overflowActions = maxInlineActions != null ? actionDefs.slice(maxInlineActions) : actionDefs;
35740
+ const overflowActions = actionDefs;
35736
35741
  const fireAction = (action, row) => eventBus.emit(`UI:${action.event}`, {
35737
35742
  id: row.id,
35738
35743
  row
@@ -35914,7 +35919,7 @@ function TableView({
35914
35919
  }
35915
35920
  return /* @__PURE__ */ jsxRuntime.jsx(Box, { role: "cell", className: cellBase, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-foreground", children: formatCell(raw, col.format, relationsData?.[col.field ?? col.key]) }) }, col.key);
35916
35921
  }),
35917
- hasActions && /* @__PURE__ */ jsxRuntime.jsxs(
35922
+ hasActions && /* @__PURE__ */ jsxRuntime.jsx(
35918
35923
  HStack,
35919
35924
  {
35920
35925
  gap: "xs",
@@ -35928,38 +35933,20 @@ function TableView({
35928
35933
  "border-l border-[var(--color-border)]",
35929
35934
  lk.striped && index % 2 === 1 ? "bg-[var(--color-surface-subtle)]" : "bg-[var(--color-card)] group-hover:bg-[var(--color-surface-subtle)]"
35930
35935
  ),
35931
- children: [
35932
- inlineActions.map((action) => /* @__PURE__ */ jsxRuntime.jsxs(
35933
- Button,
35934
- {
35935
- variant: action.variant ?? "ghost",
35936
- size: "sm",
35937
- onClick: () => fireAction(action, row),
35938
- "data-testid": `action-${action.event}`,
35939
- "data-row-id": String(row.id),
35940
- className: cn(action.variant === "danger" && "text-error hover:bg-error/10"),
35941
- children: [
35942
- action.icon && renderIconInput3(action.icon, { size: "xs", className: "mr-1" }),
35943
- action.label
35944
- ]
35945
- },
35946
- action.event
35947
- )),
35948
- overflowActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
35949
- Menu,
35950
- {
35951
- position: "bottom-end",
35952
- trigger: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", "data-row-id": String(row.id), children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
35953
- items: overflowActions.map((action) => ({
35954
- label: action.label,
35955
- icon: action.icon,
35956
- event: action.event,
35957
- variant: action.variant === "danger" ? "danger" : "default",
35958
- onClick: () => fireAction(action, row)
35959
- }))
35960
- }
35961
- )
35962
- ]
35936
+ children: overflowActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
35937
+ Menu,
35938
+ {
35939
+ position: "bottom-end",
35940
+ trigger: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", "data-row-id": String(row.id), children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
35941
+ items: overflowActions.map((action) => ({
35942
+ label: action.label,
35943
+ icon: action.icon,
35944
+ event: action.event,
35945
+ variant: action.variant === "danger" ? "danger" : "default",
35946
+ onClick: () => fireAction(action, row)
35947
+ }))
35948
+ }
35949
+ )
35963
35950
  }
35964
35951
  )
35965
35952
  ]
@@ -45247,6 +45234,7 @@ var init_DetailPanel = __esm({
45247
45234
  init_EmptyState();
45248
45235
  init_cn();
45249
45236
  init_portalRoot();
45237
+ init_slotContained();
45250
45238
  init_format();
45251
45239
  init_getNestedValue();
45252
45240
  init_relationLabel();
@@ -45278,6 +45266,7 @@ var init_DetailPanel = __esm({
45278
45266
  }) => {
45279
45267
  const eventBus = useEventBus();
45280
45268
  const { t } = hooks.useTranslate();
45269
+ const contained = React87.useContext(SlotContainedContext);
45281
45270
  const [titleDraft, setTitleDraft] = React87__namespace.default.useState(null);
45282
45271
  const isFieldDefArray = (arr) => {
45283
45272
  if (!arr || arr.length === 0) return false;
@@ -45665,8 +45654,9 @@ var init_DetailPanel = __esm({
45665
45654
  if (!slideOver) {
45666
45655
  return /* @__PURE__ */ jsxRuntime.jsx(Box, { className, children: content });
45667
45656
  }
45668
- const panel = /* @__PURE__ */ jsxRuntime.jsx(Box, { className: cn("fixed inset-y-0 right-0 w-full max-w-2xl bg-card shadow-lg z-50 overflow-y-auto p-6", className), children: content });
45669
- return typeof document === "undefined" ? panel : reactDom.createPortal(panel, getOrCreatePortalRoot());
45657
+ const panel = /* @__PURE__ */ jsxRuntime.jsx(Box, { className: cn(contained ? "absolute" : "fixed", "inset-y-0 right-0 w-full max-w-2xl bg-card shadow-lg z-50 overflow-y-auto p-6", className), children: content });
45658
+ if (contained || typeof document === "undefined") return panel;
45659
+ return reactDom.createPortal(panel, getOrCreatePortalRoot());
45670
45660
  };
45671
45661
  DetailPanel.displayName = "DetailPanel";
45672
45662
  }
@@ -52163,6 +52153,7 @@ var init_component_registry_generated = __esm({
52163
52153
  // components/core/organisms/UISlotRenderer.tsx
52164
52154
  var UISlotRenderer_exports = {};
52165
52155
  __export(UISlotRenderer_exports, {
52156
+ SlotContainedContext: () => SlotContainedContext,
52166
52157
  SlotContentRenderer: () => SlotContentRenderer,
52167
52158
  SuspenseConfigProvider: () => SuspenseConfigProvider,
52168
52159
  UISlotComponent: () => UISlotComponent,
@@ -52335,6 +52326,25 @@ function renderContainedPortal(t, slot, content, onDismiss) {
52335
52326
  }
52336
52327
  );
52337
52328
  case "drawer":
52329
+ if (content.pattern === "detail-panel" && content.props.slideOver === true) {
52330
+ return /* @__PURE__ */ jsxRuntime.jsx(
52331
+ Box,
52332
+ {
52333
+ id: slotId,
52334
+ className: "absolute inset-0 z-50 overflow-hidden",
52335
+ style: { backgroundColor: "rgba(0, 0, 0, 0.5)" },
52336
+ onClick: onDismiss,
52337
+ children: /* @__PURE__ */ jsxRuntime.jsx(
52338
+ Box,
52339
+ {
52340
+ className: "absolute inset-y-0 right-0 pointer-events-auto",
52341
+ onClick: (e) => e.stopPropagation(),
52342
+ children: slotContent
52343
+ }
52344
+ )
52345
+ }
52346
+ );
52347
+ }
52338
52348
  return /* @__PURE__ */ jsxRuntime.jsx(
52339
52349
  Box,
52340
52350
  {
@@ -53186,7 +53196,7 @@ function UISlotRenderer({
53186
53196
  }
53187
53197
  return wrapped;
53188
53198
  }
53189
- var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SlotContainedContext, SLOT_SKELETON_MAP, CONTENT_NODE_SLOTS, PATTERNS_WITH_CHILDREN, traitRefPresenceCache;
53199
+ var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SLOT_SKELETON_MAP, CONTENT_NODE_SLOTS, PATTERNS_WITH_CHILDREN, traitRefPresenceCache;
53190
53200
  var init_UISlotRenderer = __esm({
53191
53201
  "components/core/organisms/UISlotRenderer.tsx"() {
53192
53202
  "use client";
@@ -53201,6 +53211,7 @@ var init_UISlotRenderer = __esm({
53201
53211
  init_cn();
53202
53212
  init_format();
53203
53213
  init_portalRoot();
53214
+ init_slotContained();
53204
53215
  init_ErrorBoundary();
53205
53216
  init_Skeleton();
53206
53217
  init_renderer();
@@ -53210,7 +53221,6 @@ var init_UISlotRenderer = __esm({
53210
53221
  scopeWrapLog = logger.createLogger("almadar:ui:scope-wrap");
53211
53222
  TRAIT_BINDING_RE = /^@trait\.([A-Z][A-Za-z0-9]*)$/;
53212
53223
  SuspenseConfigContext = React87.createContext({ enabled: false });
53213
- SlotContainedContext = React87.createContext(false);
53214
53224
  SuspenseConfigProvider.displayName = "SuspenseConfigProvider";
53215
53225
  SLOT_SKELETON_MAP = {
53216
53226
  main: "table",
@@ -54678,6 +54688,9 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
54678
54688
  const normalizedEvent = normalizeEventKey(eventKey);
54679
54689
  return managerRef.current.canHandleEvent(traitName, normalizedEvent);
54680
54690
  }, []);
54691
+ const commitServerEntity = React87.useCallback((traitName, entity) => {
54692
+ traitFieldStatesRef.current.set(traitName, entity);
54693
+ }, []);
54681
54694
  React87.useEffect(() => {
54682
54695
  const allEvents = /* @__PURE__ */ new Set();
54683
54696
  for (const binding of traitBindings) {
@@ -54841,7 +54854,8 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
54841
54854
  sendEvent,
54842
54855
  getTraitState,
54843
54856
  canHandleEvent,
54844
- entityBindingSource
54857
+ entityBindingSource,
54858
+ commitServerEntity
54845
54859
  };
54846
54860
  }
54847
54861
  var resolvedSchemaLog = logger.createLogger("almadar:ui:resolved-schema");
@@ -55080,6 +55094,8 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
55080
55094
  [serverActiveTraits]
55081
55095
  );
55082
55096
  const uiSlots = context.useUISlots();
55097
+ const commitServerEntityRef = React87.useRef(() => {
55098
+ });
55083
55099
  const onEventProcessed = React87.useCallback((event, payload, dispatchedOrbitals, tick, sourceTrait, locallyEmitted, results, entityByTrait) => {
55084
55100
  if (!bridge.connected || !orbitalNames?.length) return;
55085
55101
  const targets = dispatchedOrbitals && dispatchedOrbitals.size > 0 ? orbitalNames.filter((n) => dispatchedOrbitals.has(n)) : orbitalNames;
@@ -55096,12 +55112,18 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
55096
55112
  }
55097
55113
  void bridge.sendEvent(name, event, withActiveTraits(payload), void 0, void 0, locallyEmitted, results, entityByTrait, user ?? void 0).then(({ effects, meta }) => {
55098
55114
  recordServerResponse(name, event, { ...meta, effectResults: effectResultsToTraces(meta.effectResults) });
55115
+ if (meta.entityByTrait) {
55116
+ for (const [traitName, entity] of Object.entries(meta.entityByTrait)) {
55117
+ commitServerEntityRef.current(traitName, entity);
55118
+ }
55119
+ }
55099
55120
  applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits, activeTraitNamesRef.current, onNavigateBack);
55100
55121
  });
55101
55122
  }
55102
55123
  }, [bridge.connected, bridge.sendEvent, orbitalNames, uiSlots, onNavigate, onNavigateBack, embeddedTraits, activeTraitNames, withActiveTraits, user]);
55103
55124
  const opts = orbitalNames ? { onEventProcessed, navigate: onNavigate, navigateBack: onNavigateBack, traitConfigsByName, orbitalsByTrait, embeddedTraits, callsiteCaptureChildrenByTrait, initPayload: routeParams } : { navigate: onNavigate, navigateBack: onNavigateBack, persistence, traitConfigsByName, orbitalsByTrait, embeddedTraits, callsiteCaptureChildrenByTrait, initPayload: routeParams };
55104
- const { sendEvent, entityBindingSource } = useTraitStateMachine(traits2, uiSlots, opts);
55125
+ const { sendEvent, entityBindingSource, commitServerEntity } = useTraitStateMachine(traits2, uiSlots, opts);
55126
+ commitServerEntityRef.current = commitServerEntity;
55105
55127
  const initSentRef = React87.useRef(false);
55106
55128
  const prevTraitsRef = React87.useRef(void 0);
55107
55129
  const paramsKey = JSON.stringify(routeParams ?? {});
@@ -55153,6 +55175,11 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
55153
55175
  user ?? void 0
55154
55176
  );
55155
55177
  recordServerResponse(name, "INIT", { ...meta, effectResults: effectResultsToTraces(meta.effectResults) });
55178
+ if (meta.entityByTrait) {
55179
+ for (const [traitName, entity] of Object.entries(meta.entityByTrait)) {
55180
+ commitServerEntityRef.current(traitName, entity);
55181
+ }
55182
+ }
55156
55183
  const effectTraces = [
55157
55184
  { type: "fetch", args: [], status: "executed" },
55158
55185
  ...effects.map((eff) => ({
@@ -5,8 +5,8 @@ import * as _almadar_runtime from '@almadar/runtime';
5
5
  import { TraitState, TransitionResult, EffectHandlers } from '@almadar/runtime';
6
6
  import { K as KeyCaptureTable } from '../useKeyboardRouter-CVn8lfiX.cjs';
7
7
  import { c as useUISlots } from '../UISlotContext-BlRDbHDy.cjs';
8
- import { a as EntityBindingSource, h as ServerBridgeTransport, A as AccessTokenProvider } from '../EntityBindingContext-C6FgxdfG.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-C6FgxdfG.cjs';
8
+ import { a as EntityBindingSource, h as ServerBridgeTransport, A as AccessTokenProvider } from '../EntityBindingContext-UyeCfEBS.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-UyeCfEBS.cjs';
10
10
  import '../verificationRegistry-DTrKDRoa.cjs';
11
11
  export { PERF_NAMESPACE, PerfEntry, PreparedPreviewSchema, adjustSchemaForMockData, buildMockData, clearPerf, perfEnd, perfStart, perfTime, prepareSchemaForPreview, wrapCallbackForEvent } from '@almadar/runtime/ui';
12
12
  import React__default, { ReactNode } from 'react';
@@ -30,6 +30,20 @@ interface TraitStateMachineResult {
30
30
  /** Live per-trait binding surface for `EntityBindingContext` — the
31
31
  * renderer resolves `RenderBindingMarker` prop leaves against it. */
32
32
  entityBindingSource: EntityBindingSource;
33
+ /**
34
+ * Commit a trait's authoritative entity row, as returned by a stateless
35
+ * server response's `entityByTrait[traitName]` (Fix C, the entity
36
+ * round-trip). The stateless deployment has no server-held memory
37
+ * across requests, so a `set`-only field a trait wrote on a PRIOR
38
+ * request would otherwise vanish on the next one (`traitFieldStatesRef`
39
+ * only ever reflects THIS client's own local writes) — replacing it
40
+ * here with the server's own post-effects row keeps the two in sync,
41
+ * the same way a fresh `getById` already does within a single request.
42
+ * A full replace, not a merge: the server sends the whole row after its
43
+ * own effects ran, the same authoritative shape a `fetch`/`getById`
44
+ * would return.
45
+ */
46
+ commitServerEntity: (traitName: string, entity: EntityRow) => void;
33
47
  }
34
48
  interface UseTraitStateMachineOptions {
35
49
  /**
@@ -5,8 +5,8 @@ import * as _almadar_runtime from '@almadar/runtime';
5
5
  import { TraitState, TransitionResult, EffectHandlers } from '@almadar/runtime';
6
6
  import { K as KeyCaptureTable } from '../useKeyboardRouter-B1pIi9jo.js';
7
7
  import { c as useUISlots } from '../UISlotContext-CB89mv7N.js';
8
- import { a as EntityBindingSource, h as ServerBridgeTransport, A as AccessTokenProvider } from '../EntityBindingContext-C6FgxdfG.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-C6FgxdfG.js';
8
+ import { a as EntityBindingSource, h as ServerBridgeTransport, A as AccessTokenProvider } from '../EntityBindingContext-UyeCfEBS.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-UyeCfEBS.js';
10
10
  import '../verificationRegistry-Cwa52VyK.js';
11
11
  export { PERF_NAMESPACE, PerfEntry, PreparedPreviewSchema, adjustSchemaForMockData, buildMockData, clearPerf, perfEnd, perfStart, perfTime, prepareSchemaForPreview, wrapCallbackForEvent } from '@almadar/runtime/ui';
12
12
  import React__default, { ReactNode } from 'react';
@@ -30,6 +30,20 @@ interface TraitStateMachineResult {
30
30
  /** Live per-trait binding surface for `EntityBindingContext` — the
31
31
  * renderer resolves `RenderBindingMarker` prop leaves against it. */
32
32
  entityBindingSource: EntityBindingSource;
33
+ /**
34
+ * Commit a trait's authoritative entity row, as returned by a stateless
35
+ * server response's `entityByTrait[traitName]` (Fix C, the entity
36
+ * round-trip). The stateless deployment has no server-held memory
37
+ * across requests, so a `set`-only field a trait wrote on a PRIOR
38
+ * request would otherwise vanish on the next one (`traitFieldStatesRef`
39
+ * only ever reflects THIS client's own local writes) — replacing it
40
+ * here with the server's own post-effects row keeps the two in sync,
41
+ * the same way a fresh `getById` already does within a single request.
42
+ * A full replace, not a merge: the server sends the whole row after its
43
+ * own effects ran, the same authoritative shape a `fetch`/`getById`
44
+ * would return.
45
+ */
46
+ commitServerEntity: (traitName: string, entity: EntityRow) => void;
33
47
  }
34
48
  interface UseTraitStateMachineOptions {
35
49
  /**