@almadar/ui 5.121.3 → 5.121.4

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.
@@ -142,9 +142,9 @@ function getGlobalEventBus() {
142
142
  function useEventBus() {
143
143
  const context = React81.useContext(providers.EventBusContext);
144
144
  const baseBus = context ?? getGlobalEventBus() ?? fallbackEventBus;
145
- const scope = providers.useTraitScope();
145
+ const chain = providers.useTraitScopeChain();
146
146
  return React81.useMemo(() => {
147
- if (!scope) {
147
+ if (chain.length === 0) {
148
148
  return {
149
149
  ...baseBus,
150
150
  emit: (type, payload, source) => {
@@ -160,22 +160,31 @@ function useEventBus() {
160
160
  emit: (type, payload, source) => {
161
161
  if (typeof type === "string" && type.startsWith("UI:")) {
162
162
  const tail = type.slice(3);
163
- const qualified = tail.includes(".") ? type : `UI:${scope.orbital}.${scope.trait}.${tail}`;
164
- if (qualified !== type) {
165
- scopeLog.info("emit:qualified", {
163
+ const isQualified = tail.includes(".");
164
+ const event = isQualified ? tail.split(".").slice(2).join(".") : tail;
165
+ if (!event) {
166
+ baseBus.emit(type, payload, source);
167
+ return;
168
+ }
169
+ const keys = /* @__PURE__ */ new Set();
170
+ if (isQualified) keys.add(type);
171
+ for (const sc of chain) {
172
+ keys.add(`UI:${sc.orbital}.${sc.trait}.${event}`);
173
+ }
174
+ if (keys.size > 1) {
175
+ scopeLog.info("emit:fan-out", {
166
176
  from: type,
167
- to: qualified,
168
- scopeOrbital: scope.orbital,
169
- scopeTrait: scope.trait
177
+ keys: Array.from(keys),
178
+ chainDepth: chain.length
170
179
  });
171
180
  }
172
- baseBus.emit(qualified, payload, source);
181
+ for (const key of keys) baseBus.emit(key, payload, source);
173
182
  return;
174
183
  }
175
184
  baseBus.emit(type, payload, source);
176
185
  }
177
186
  };
178
- }, [baseBus, scope]);
187
+ }, [baseBus, chain]);
179
188
  }
180
189
  function useEventListener(event, handler) {
181
190
  const eventBus = useEventBus();
@@ -1192,13 +1201,13 @@ var init_Icon = __esm({
1192
1201
  style
1193
1202
  }) => {
1194
1203
  const directIcon = typeof icon === "string" ? void 0 : icon;
1195
- const effectiveName = typeof icon === "string" ? icon : name;
1204
+ const effectiveName = typeof icon === "string" && icon !== "" ? icon : name;
1205
+ const effectiveStrokeWidth = strokeWidth != null && strokeWidth > 0 ? strokeWidth : void 0;
1196
1206
  const family = useIconFamily();
1197
1207
  const RenderedComponent = React81__namespace.default.useMemo(() => {
1198
1208
  if (directIcon) return null;
1199
1209
  return effectiveName ? resolveIconForFamily(effectiveName) : null;
1200
1210
  }, [directIcon, effectiveName, family]);
1201
- const effectiveStrokeWidth = strokeWidth ?? void 0;
1202
1211
  const inlineStyle = {
1203
1212
  ...effectiveStrokeWidth === void 0 ? { strokeWidth: "var(--icon-stroke-width, 2)" } : {},
1204
1213
  ...style
@@ -1798,6 +1807,15 @@ var init_Modal = __esm({
1798
1807
  const [dragY, setDragY] = React81.useState(0);
1799
1808
  const dragStartY = React81.useRef(0);
1800
1809
  const isDragging = React81.useRef(false);
1810
+ const [closing, setClosing] = React81.useState(false);
1811
+ const wasOpenRef = React81.useRef(isOpen);
1812
+ React81.useEffect(() => {
1813
+ if (wasOpenRef.current && !isOpen) setClosing(true);
1814
+ wasOpenRef.current = isOpen;
1815
+ }, [isOpen]);
1816
+ const handleAnimEnd = (e) => {
1817
+ if (closing && e.target === e.currentTarget) setClosing(false);
1818
+ };
1801
1819
  React81.useEffect(() => {
1802
1820
  if (isOpen) {
1803
1821
  previousActiveElement.current = document.activeElement;
@@ -1831,7 +1849,11 @@ var init_Modal = __esm({
1831
1849
  document.body.style.overflow = "";
1832
1850
  };
1833
1851
  }, [isOpen]);
1834
- if (!isOpen || typeof document === "undefined") return null;
1852
+ if (typeof document === "undefined") return null;
1853
+ const renderOpen = isOpen || closing;
1854
+ if (!renderOpen) return null;
1855
+ const dialogAnim = closing ? "animate-modal-out" : "animate-modal-in";
1856
+ const overlayAnim = closing ? "animate-overlay-out" : "animate-overlay-in";
1835
1857
  const handleClose = () => {
1836
1858
  if (closeEvent) eventBus.emit(`UI:${closeEvent}`, {});
1837
1859
  onClose();
@@ -1848,7 +1870,8 @@ var init_Modal = __esm({
1848
1870
  className: cn(
1849
1871
  "fixed inset-0 z-[1000]",
1850
1872
  "flex items-start justify-center px-4 pb-4 pt-[10vh]",
1851
- "max-sm:items-stretch max-sm:p-0 max-sm:pt-0"
1873
+ "max-sm:items-stretch max-sm:p-0 max-sm:pt-0",
1874
+ overlayAnim
1852
1875
  ),
1853
1876
  style: { backgroundColor: "rgba(0, 0, 0, 0.6)" },
1854
1877
  onClick: handleOverlayClick,
@@ -1876,8 +1899,10 @@ var init_Modal = __esm({
1876
1899
  // full height, no rounded corners, no min-width.
1877
1900
  "max-sm:max-w-none max-sm:max-h-none max-sm:w-full max-sm:h-full max-sm:rounded-none",
1878
1901
  lookStyles[look],
1879
- className
1902
+ className,
1903
+ dialogAnim
1880
1904
  ),
1905
+ onAnimationEnd: handleAnimEnd,
1881
1906
  style: dragY > 0 ? {
1882
1907
  transform: `translateY(${dragY}px)`,
1883
1908
  transition: isDragging.current ? "none" : "transform 200ms ease-out"
@@ -1986,6 +2011,7 @@ var init_Overlay = __esm({
1986
2011
  className: cn(
1987
2012
  "fixed inset-0 z-40",
1988
2013
  blur && "backdrop-blur-sm",
2014
+ "animate-overlay-in",
1989
2015
  className
1990
2016
  ),
1991
2017
  style: { backgroundColor: "rgba(0, 0, 0, 0.6)" },
@@ -3398,7 +3424,7 @@ var init_Input = __esm({
3398
3424
  eventBus.emit(`UI:${action}`, { value: e.currentTarget.value });
3399
3425
  }
3400
3426
  };
3401
- const wrapField = (field) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full", children: [
3427
+ const wrapField = (field, fullWidth = true) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: fullWidth ? "w-full" : "w-fit", children: [
3402
3428
  label && /* @__PURE__ */ jsxRuntime.jsx("label", { className: "block text-sm font-medium text-foreground mb-1", children: label }),
3403
3429
  field,
3404
3430
  (helperText || error) && /* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("mt-1 text-xs", error ? "text-error" : "text-muted-foreground"), children: error ?? helperText })
@@ -3458,7 +3484,8 @@ var init_Input = __esm({
3458
3484
  ),
3459
3485
  ...props
3460
3486
  }
3461
- )
3487
+ ),
3488
+ false
3462
3489
  );
3463
3490
  }
3464
3491
  return wrapField(
@@ -5786,6 +5813,18 @@ var init_RangeSlider = __esm({
5786
5813
  function easeOut(t) {
5787
5814
  return t * (2 - t);
5788
5815
  }
5816
+ function formatDisplay(value, format, decimals) {
5817
+ switch (format) {
5818
+ case "currency":
5819
+ return `$${value.toFixed(2)}`;
5820
+ case "percent":
5821
+ return `${Math.round(value)}%`;
5822
+ case "number":
5823
+ return value.toLocaleString();
5824
+ default:
5825
+ return value.toFixed(decimals);
5826
+ }
5827
+ }
5789
5828
  var AnimatedCounter;
5790
5829
  var init_AnimatedCounter = __esm({
5791
5830
  "components/marketing/atoms/AnimatedCounter.tsx"() {
@@ -5797,6 +5836,7 @@ var init_AnimatedCounter = __esm({
5797
5836
  duration = 600,
5798
5837
  prefix,
5799
5838
  suffix,
5839
+ format,
5800
5840
  className
5801
5841
  }) => {
5802
5842
  const numericRaw = typeof rawValue === "number" ? rawValue : Number.parseFloat(String(rawValue ?? ""));
@@ -5812,6 +5852,10 @@ var init_AnimatedCounter = __esm({
5812
5852
  setDisplayValue(to);
5813
5853
  return;
5814
5854
  }
5855
+ if (window.matchMedia?.("(prefers-reduced-motion: reduce)").matches) {
5856
+ setDisplayValue(to);
5857
+ return;
5858
+ }
5815
5859
  const startTime = performance.now();
5816
5860
  const diff = to - from;
5817
5861
  function animate(currentTime) {
@@ -5833,7 +5877,7 @@ var init_AnimatedCounter = __esm({
5833
5877
  };
5834
5878
  }, [value, duration]);
5835
5879
  const decimalPlaces = Number.isInteger(value) ? 0 : String(value).split(".")[1]?.length ?? 0;
5836
- const formattedValue = displayValue.toFixed(decimalPlaces);
5880
+ const formattedValue = formatDisplay(displayValue, format, decimalPlaces);
5837
5881
  return /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "h3", className: cn("tabular-nums", className), children: [
5838
5882
  prefix,
5839
5883
  formattedValue,
@@ -7077,14 +7121,29 @@ function recordTransition(trace) {
7077
7121
  "pass"
7078
7122
  );
7079
7123
  } else {
7080
- const hasRenderUI = entry.effects.some((e) => e.type === "render-ui");
7081
- if (hasRenderUI) {
7082
- registerCheck(
7083
- checkId,
7084
- `INIT transition for "${entry.traitName}" missing fetch effect`,
7085
- "fail",
7086
- "Entity-bound render-ui without a fetch effect will show empty data"
7124
+ const rendersEntityData = entry.effects.some(
7125
+ (e) => e.type === "render-ui" && JSON.stringify(e.args).includes("@entity.")
7126
+ );
7127
+ if (rendersEntityData) {
7128
+ const siblingSeeds = getState().transitions.some(
7129
+ (t) => t.event === "INIT" && t.effects.some(
7130
+ (e) => e.type === "fetch" || e.type === "set" && typeof e.args[0] === "string" && e.args[0].startsWith("@entity.")
7131
+ )
7087
7132
  );
7133
+ if (siblingSeeds) {
7134
+ registerCheck(
7135
+ checkId,
7136
+ `INIT transition for "${entry.traitName}" has sibling entity-seed (shared entity)`,
7137
+ "pass"
7138
+ );
7139
+ } else {
7140
+ registerCheck(
7141
+ checkId,
7142
+ `INIT transition for "${entry.traitName}" missing fetch effect`,
7143
+ "fail",
7144
+ "Entity-bound render-ui without a fetch effect will show empty data"
7145
+ );
7146
+ }
7088
7147
  }
7089
7148
  }
7090
7149
  }
@@ -8229,7 +8288,7 @@ function GameMenu({
8229
8288
  logo,
8230
8289
  className
8231
8290
  }) {
8232
- const resolvedOptions = options ?? menuItems ?? DEFAULT_MENU_OPTIONS;
8291
+ const resolvedOptions = (options?.length ? options : void 0) ?? (menuItems?.length ? menuItems : void 0) ?? DEFAULT_MENU_OPTIONS;
8233
8292
  const eventBus = useEventBus();
8234
8293
  const handleOptionClick = React81__namespace.useCallback(
8235
8294
  (option) => {
@@ -9520,6 +9579,10 @@ function Canvas2D({
9520
9579
  window.removeEventListener("keyup", onUp);
9521
9580
  };
9522
9581
  }, [keyMap, keyUpMap, eventBus]);
9582
+ React81.useEffect(() => {
9583
+ if (!keyMap && !keyUpMap) return;
9584
+ canvasRef.current?.focus();
9585
+ }, [keyMap, keyUpMap]);
9523
9586
  if (error) {
9524
9587
  return /* @__PURE__ */ jsxRuntime.jsx(Box, { className: cn("flex items-center justify-center w-full h-full bg-[var(--color-card)] rounded-container", className), children: /* @__PURE__ */ jsxRuntime.jsxs(Stack, { direction: "vertical", gap: "md", align: "center", children: [
9525
9588
  /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "alert-circle", size: "xl" }),
@@ -9568,7 +9631,7 @@ function Canvas2D({
9568
9631
  onWheel: gestureHandlers.onWheel,
9569
9632
  onContextMenu: (e) => e.preventDefault(),
9570
9633
  className: "cursor-pointer touch-none",
9571
- tabIndex: isFree ? 0 : void 0,
9634
+ tabIndex: isFree || keyMap || keyUpMap ? 0 : void 0,
9572
9635
  style: {
9573
9636
  width: viewportSize.width,
9574
9637
  height: viewportSize.height
@@ -13819,7 +13882,8 @@ var init_LoadingState = __esm({
13819
13882
  LoadingState = ({
13820
13883
  title,
13821
13884
  message,
13822
- className
13885
+ className,
13886
+ fullPage = false
13823
13887
  }) => {
13824
13888
  const { t } = hooks.useTranslate();
13825
13889
  const displayMessage = message ?? t("common.loading");
@@ -13828,7 +13892,8 @@ var init_LoadingState = __esm({
13828
13892
  {
13829
13893
  align: "center",
13830
13894
  className: cn(
13831
- "justify-center py-12",
13895
+ "justify-center",
13896
+ fullPage ? "fixed inset-0 z-[1000] py-12 bg-background/80 backdrop-blur-sm animate-overlay-in" : "py-12",
13832
13897
  className
13833
13898
  ),
13834
13899
  children: [
@@ -16980,7 +17045,7 @@ var init_BookCoverPage = __esm({
16980
17045
  size: "lg",
16981
17046
  action: "BOOK_START",
16982
17047
  className: "mt-8",
16983
- children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: t("book.startReading") })
17048
+ children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", color: "inherit", children: t("book.startReading") })
16984
17049
  }
16985
17050
  )
16986
17051
  ]
@@ -19225,8 +19290,9 @@ var init_Chart = __esm({
19225
19290
  align: "center",
19226
19291
  flex: true,
19227
19292
  className: "min-w-0",
19293
+ style: { height: "100%" },
19228
19294
  children: [
19229
- /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: histogram ? "none" : "xs", align: "end", className: "w-full", style: { height: "100%" }, children: series.map((s, sIdx) => {
19295
+ /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: histogram ? "none" : "xs", align: "end", justify: histogram ? void 0 : "center", className: "w-full flex-1 min-h-0", children: series.map((s, sIdx) => {
19230
19296
  const value = valueAt(s, label);
19231
19297
  const barHeight = value / maxValue * 100;
19232
19298
  const color = seriesColor(s, sIdx);
@@ -19239,6 +19305,8 @@ var init_Chart = __esm({
19239
19305
  ),
19240
19306
  style: {
19241
19307
  height: `${barHeight}%`,
19308
+ // Cap width so a lone category doesn't paint the whole plot as one solid block; narrow columns are unaffected (flex-1 binds first).
19309
+ ...!histogram && { maxWidth: 72 },
19242
19310
  backgroundColor: color
19243
19311
  },
19244
19312
  onClick: () => onPointClick?.(
@@ -19273,8 +19341,9 @@ var init_Chart = __esm({
19273
19341
  align: "center",
19274
19342
  flex: true,
19275
19343
  className: "min-w-0",
19344
+ style: { height: "100%" },
19276
19345
  children: [
19277
- /* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "none", className: "w-full", style: { height: "100%" }, justify: "end", children: series.map((s, sIdx) => {
19346
+ /* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "none", className: "w-full flex-1 min-h-0", justify: "end", children: series.map((s, sIdx) => {
19278
19347
  const value = valueAt(s, label);
19279
19348
  const ratio = stack === "normalize" ? total === 0 ? 0 : value / total * 100 : value / maxValue * 100;
19280
19349
  const color = seriesColor(s, sIdx);
@@ -19319,6 +19388,7 @@ var init_Chart = __esm({
19319
19388
  const innerRadius = donut ? radius * 0.6 : 0;
19320
19389
  const center = size / 2;
19321
19390
  const segments = React81.useMemo(() => {
19391
+ if (!Number.isFinite(total) || total <= 0) return [];
19322
19392
  let currentAngle = -Math.PI / 2;
19323
19393
  return data.map((point, idx) => {
19324
19394
  const angle = point.value / total * 2 * Math.PI;
@@ -19330,13 +19400,25 @@ var init_Chart = __esm({
19330
19400
  const y1 = center + radius * Math.sin(startAngle);
19331
19401
  const x2 = center + radius * Math.cos(endAngle);
19332
19402
  const y2 = center + radius * Math.sin(endAngle);
19403
+ const fullCircle = angle >= 2 * Math.PI - 1e-9;
19404
+ const midAngle = startAngle + angle / 2;
19405
+ const xm = center + radius * Math.cos(midAngle);
19406
+ const ym = center + radius * Math.sin(midAngle);
19333
19407
  let d;
19334
19408
  if (innerRadius > 0) {
19335
19409
  const ix1 = center + innerRadius * Math.cos(startAngle);
19336
19410
  const iy1 = center + innerRadius * Math.sin(startAngle);
19337
19411
  const ix2 = center + innerRadius * Math.cos(endAngle);
19338
19412
  const iy2 = center + innerRadius * Math.sin(endAngle);
19339
- d = `M ${ix1} ${iy1} L ${x1} ${y1} A ${radius} ${radius} 0 ${largeArc} 1 ${x2} ${y2} L ${ix2} ${iy2} A ${innerRadius} ${innerRadius} 0 ${largeArc} 0 ${ix1} ${iy1} Z`;
19413
+ if (fullCircle) {
19414
+ const ixm = center + innerRadius * Math.cos(midAngle);
19415
+ const iym = center + innerRadius * Math.sin(midAngle);
19416
+ d = `M ${ix1} ${iy1} L ${x1} ${y1} A ${radius} ${radius} 0 1 1 ${xm} ${ym} A ${radius} ${radius} 0 1 1 ${x2} ${y2} L ${ix2} ${iy2} A ${innerRadius} ${innerRadius} 0 1 0 ${ixm} ${iym} A ${innerRadius} ${innerRadius} 0 1 0 ${ix1} ${iy1} Z`;
19417
+ } else {
19418
+ d = `M ${ix1} ${iy1} L ${x1} ${y1} A ${radius} ${radius} 0 ${largeArc} 1 ${x2} ${y2} L ${ix2} ${iy2} A ${innerRadius} ${innerRadius} 0 ${largeArc} 0 ${ix1} ${iy1} Z`;
19419
+ }
19420
+ } else if (fullCircle) {
19421
+ d = `M ${center} ${center} L ${x1} ${y1} A ${radius} ${radius} 0 1 1 ${xm} ${ym} A ${radius} ${radius} 0 1 1 ${x2} ${y2} Z`;
19340
19422
  } else {
19341
19423
  d = `M ${center} ${center} L ${x1} ${y1} A ${radius} ${radius} 0 ${largeArc} 1 ${x2} ${y2} Z`;
19342
19424
  }
@@ -22349,10 +22431,10 @@ function DataGrid({
22349
22431
  ] }),
22350
22432
  badgeFields.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "xs", className: "flex-wrap", children: badgeFields.map((field) => {
22351
22433
  const val = getNestedValue(itemData, field.name);
22352
- if (val === void 0 || val === null) return null;
22434
+ if (val === void 0 || val === null || val === "") return null;
22353
22435
  return /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center", children: [
22354
22436
  field.icon && renderIconInput(field.icon, { size: "xs" }),
22355
- /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: resolveBadgeVariant(field, String(val)), children: String(val) })
22437
+ /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: resolveBadgeVariant(field, String(val)), children: formatValue(val, field.format) })
22356
22438
  ] }, field.name);
22357
22439
  }) })
22358
22440
  ] }),
@@ -29640,6 +29722,11 @@ var init_VoteStack = __esm({
29640
29722
  {
29641
29723
  className: cn(
29642
29724
  "inline-flex items-center justify-center",
29725
+ // Shrink-wrap in stretch contexts (slot/sidecar wrappers are
29726
+ // flex-column with stretch alignment): without this the root spans
29727
+ // the full wrapper width and the count row's `w-full` turns the
29728
+ // compact pill into a page-wide band.
29729
+ "w-fit",
29643
29730
  variant === "vertical" ? "flex-col" : "flex-row",
29644
29731
  "rounded-sm",
29645
29732
  "border-[length:var(--border-width)] border-border",
@@ -33545,7 +33632,7 @@ var init_Sidebar = __esm({
33545
33632
  isActive ? [
33546
33633
  "bg-primary text-primary-foreground",
33547
33634
  "font-medium shadow-sm",
33548
- "border-primary translate-x-1 -translate-y-0.5"
33635
+ "border-primary translate-x-1 rtl:-translate-x-1 -translate-y-0.5"
33549
33636
  ].join(" ") : [
33550
33637
  "text-foreground",
33551
33638
  "hover:bg-muted hover:border-border",
@@ -33555,10 +33642,10 @@ var init_Sidebar = __esm({
33555
33642
  title: collapsed ? item.label : void 0,
33556
33643
  children: [
33557
33644
  item.icon && (typeof item.icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: item.icon, size: "sm", className: cn("min-w-[20px] flex-shrink-0", isActive && "text-primary-foreground") }) : /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: item.icon, size: "sm", className: cn("min-w-[20px] flex-shrink-0", isActive && "text-primary-foreground") })),
33558
- !collapsed && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", color: isActive ? "inherit" : "primary", className: "font-medium truncate flex-1 text-left", children: item.label }),
33645
+ !collapsed && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", color: isActive ? "inherit" : "primary", className: "font-medium truncate flex-1 text-start", children: item.label }),
33559
33646
  !collapsed && item.badge !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "danger", size: "sm", children: item.badge }),
33560
33647
  collapsed && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: cn(
33561
- "absolute left-full ml-2 px-2 py-1 text-xs opacity-0 group-hover:opacity-100",
33648
+ "absolute start-full ms-2 px-2 py-1 text-xs opacity-0 group-hover:opacity-100",
33562
33649
  "pointer-events-none whitespace-nowrap z-50 transition-opacity",
33563
33650
  "bg-primary text-primary-foreground",
33564
33651
  "border-[length:var(--border-width-thin)] border-border",
@@ -33613,7 +33700,7 @@ var init_Sidebar = __esm({
33613
33700
  as: "aside",
33614
33701
  className: cn(
33615
33702
  "flex flex-col h-full",
33616
- "bg-card border-r border-border",
33703
+ "bg-card border-e border-border",
33617
33704
  "transition-all duration-300 ease-in-out",
33618
33705
  collapsed ? "w-20" : "w-64",
33619
33706
  className
@@ -34774,7 +34861,7 @@ function resolveColor3(color, el) {
34774
34861
  function truncateLabel(label) {
34775
34862
  return label.length > MAX_LABEL_CHARS ? label.slice(0, MAX_LABEL_CHARS - 1) + "\u2026" : label;
34776
34863
  }
34777
- var GROUP_COLORS2, GROUP_GRAVITY, UNGROUPED_GRAVITY, labelMeasureCtx, MAX_LABEL_CHARS, GraphCanvas;
34864
+ var GROUP_COLORS2, GROUP_GRAVITY, UNGROUPED_GRAVITY, labelMeasureCtx, MAX_LABEL_CHARS, NO_NODES, NO_EDGES, NO_SIM, GraphCanvas;
34778
34865
  var init_GraphCanvas = __esm({
34779
34866
  "components/core/molecules/GraphCanvas.tsx"() {
34780
34867
  "use client";
@@ -34798,11 +34885,14 @@ var init_GraphCanvas = __esm({
34798
34885
  UNGROUPED_GRAVITY = 0.02;
34799
34886
  labelMeasureCtx = null;
34800
34887
  MAX_LABEL_CHARS = 22;
34888
+ NO_NODES = [];
34889
+ NO_EDGES = [];
34890
+ NO_SIM = [];
34801
34891
  GraphCanvas = ({
34802
34892
  title,
34803
- nodes: propNodes = [],
34804
- edges: propEdges = [],
34805
- similarity: propSimilarity = [],
34893
+ nodes: propNodes = NO_NODES,
34894
+ edges: propEdges = NO_EDGES,
34895
+ similarity: propSimilarity = NO_SIM,
34806
34896
  height = 400,
34807
34897
  showLabels = true,
34808
34898
  interactive = true,
@@ -34852,6 +34942,7 @@ var init_GraphCanvas = __esm({
34852
34942
  const interactionRef = React81.useRef({
34853
34943
  mode: "none",
34854
34944
  dragNodeId: null,
34945
+ pressedNodeId: null,
34855
34946
  startMouse: { x: 0, y: 0 },
34856
34947
  startOffset: { x: 0, y: 0 },
34857
34948
  downPos: { x: 0, y: 0 }
@@ -34899,6 +34990,11 @@ var init_GraphCanvas = __esm({
34899
34990
  () => [...new Set(propNodes.map((n) => n.group).filter(Boolean))],
34900
34991
  [propNodes]
34901
34992
  );
34993
+ const nodesKey = React81.useMemo(() => propNodes.map((n) => n.id).join(""), [propNodes]);
34994
+ const edgesKey = React81.useMemo(
34995
+ () => propEdges.map((e) => `${e.source}${e.target}`).join(""),
34996
+ [propEdges]
34997
+ );
34902
34998
  React81.useEffect(() => {
34903
34999
  const canvas = canvasRef.current;
34904
35000
  if (!canvas || propNodes.length === 0) return;
@@ -35079,7 +35175,7 @@ var init_GraphCanvas = __esm({
35079
35175
  return () => {
35080
35176
  cancelAnimationFrame(animRef.current);
35081
35177
  };
35082
- }, [propNodes, propEdges, propSimilarity, layout, repulsion, linkDistance, nodeSpacing, showLabels]);
35178
+ }, [nodesKey, edgesKey, propSimilarity, layout, repulsion, linkDistance, nodeSpacing, showLabels]);
35083
35179
  React81.useEffect(() => {
35084
35180
  const canvas = canvasRef.current;
35085
35181
  if (!canvas) return;
@@ -35209,6 +35305,7 @@ var init_GraphCanvas = __esm({
35209
35305
  const cancelSinglePointer = React81.useCallback(() => {
35210
35306
  interactionRef.current.mode = "none";
35211
35307
  interactionRef.current.dragNodeId = null;
35308
+ interactionRef.current.pressedNodeId = null;
35212
35309
  }, []);
35213
35310
  const handlePointerDown = React81.useCallback(
35214
35311
  (e) => {
@@ -35219,6 +35316,7 @@ var init_GraphCanvas = __esm({
35219
35316
  state.downPos = { x: e.clientX, y: e.clientY };
35220
35317
  state.startMouse = { x: e.clientX, y: e.clientY };
35221
35318
  state.startOffset = { ...offset };
35319
+ state.pressedNodeId = node?.id ?? null;
35222
35320
  if (draggable && node) {
35223
35321
  state.mode = "dragging";
35224
35322
  state.dragNodeId = node.id;
@@ -35270,7 +35368,8 @@ var init_GraphCanvas = __esm({
35270
35368
  if (moved < 4) {
35271
35369
  const coords = toCoords(e);
35272
35370
  if (!coords) return;
35273
- const node = nodeAt(coords.graphX, coords.graphY);
35371
+ const node = (state.pressedNodeId ? nodesRef.current.find((n) => n.id === state.pressedNodeId) : void 0) ?? nodeAt(coords.graphX, coords.graphY);
35372
+ state.pressedNodeId = null;
35274
35373
  if (node) {
35275
35374
  if (node.badge && node.badge > 1 && onBadgeClick) {
35276
35375
  const r = (node.size || 8) + (selectedNodeId === node.id ? 4 : 0);
@@ -35290,6 +35389,7 @@ var init_GraphCanvas = __esm({
35290
35389
  );
35291
35390
  const handlePointerLeave = React81.useCallback(() => {
35292
35391
  setHoveredNode(null);
35392
+ interactionRef.current.pressedNodeId = null;
35293
35393
  }, []);
35294
35394
  const gestureHandlers = useCanvasGestures({
35295
35395
  canvasRef,
@@ -38241,8 +38341,17 @@ var init_MediaGallery = __esm({
38241
38341
  const eventBus = useEventBus();
38242
38342
  const { t } = hooks.useTranslate();
38243
38343
  const [lightboxItem, setLightboxItem] = React81.useState(null);
38344
+ const [failedIds, setFailedIds] = React81.useState(/* @__PURE__ */ new Set());
38244
38345
  const closeLightbox = React81.useCallback(() => setLightboxItem(null), []);
38245
38346
  useEventListener("UI:LIGHTBOX_CLOSE", closeLightbox);
38347
+ const handleImageError = React81.useCallback((id) => {
38348
+ setFailedIds((prev) => {
38349
+ if (prev.has(id)) return prev;
38350
+ const next = new Set(prev);
38351
+ next.add(id);
38352
+ return next;
38353
+ });
38354
+ }, []);
38246
38355
  const handleItemClick = React81.useCallback(
38247
38356
  (item) => {
38248
38357
  if (selectable) {
@@ -38258,7 +38367,7 @@ var init_MediaGallery = __esm({
38258
38367
  );
38259
38368
  const entityData = Array.isArray(entity) ? entity : [];
38260
38369
  const items = React81__namespace.default.useMemo(() => {
38261
- if (propItems) return propItems;
38370
+ if (propItems && propItems.length > 0) return propItems;
38262
38371
  if (entityData.length === 0) return [];
38263
38372
  return entityData.map((record, idx) => {
38264
38373
  return {
@@ -38341,13 +38450,14 @@ var init_MediaGallery = __esm({
38341
38450
  ),
38342
38451
  onClick: () => handleItemClick(item),
38343
38452
  children: [
38344
- /* @__PURE__ */ jsxRuntime.jsx(
38453
+ failedIds.has(item.id) ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-full flex items-center justify-center bg-muted text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Image, size: "lg" }) }) : /* @__PURE__ */ jsxRuntime.jsx(
38345
38454
  "img",
38346
38455
  {
38347
38456
  src: item.thumbnail || item.src,
38348
38457
  alt: item.alt || item.caption || "",
38349
38458
  className: "w-full h-full object-cover",
38350
- loading: "lazy"
38459
+ loading: "lazy",
38460
+ onError: () => handleImageError(item.id)
38351
38461
  }
38352
38462
  ),
38353
38463
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -41854,6 +41964,11 @@ var init_TeamOrganism = __esm({
41854
41964
  TeamOrganism.displayName = "TeamOrganism";
41855
41965
  }
41856
41966
  });
41967
+ function formatDate4(value) {
41968
+ const d = new Date(value);
41969
+ if (isNaN(d.getTime())) return value;
41970
+ return d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
41971
+ }
41857
41972
  var lookStyles10, STATUS_STYLES2, Timeline;
41858
41973
  var init_Timeline = __esm({
41859
41974
  "components/core/organisms/Timeline.tsx"() {
@@ -41981,7 +42096,7 @@ var init_Timeline = __esm({
41981
42096
  /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", className: cn("flex-1 min-w-0", !isLast && "pb-6"), children: [
41982
42097
  /* @__PURE__ */ jsxRuntime.jsxs(HStack, { justify: "between", align: "start", wrap: true, children: [
41983
42098
  /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "semibold", children: item.title }),
41984
- item.date && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", className: "flex-shrink-0", children: item.date })
42099
+ item.date && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", className: "flex-shrink-0", children: formatDate4(item.date) })
41985
42100
  ] }),
41986
42101
  item.description && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "secondary", children: item.description }),
41987
42102
  item.tags && item.tags.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "xs", wrap: true, children: item.tags.map((tag, tagIdx) => /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "default", children: tag }, tagIdx)) }),
@@ -43193,7 +43308,7 @@ function substituteTraitRefsDeep(value, pathKey) {
43193
43308
  }
43194
43309
  return value;
43195
43310
  }
43196
- function renderPatternProps(props, onDismiss) {
43311
+ function renderPatternProps(props, onDismiss, propsSchema) {
43197
43312
  const rendered = {};
43198
43313
  for (const [key, value] of Object.entries(props)) {
43199
43314
  if (key === "children") {
@@ -43211,9 +43326,10 @@ function renderPatternProps(props, onDismiss) {
43211
43326
  };
43212
43327
  rendered[key] = /* @__PURE__ */ jsxRuntime.jsx(SlotContentRenderer, { content: childContent, onDismiss });
43213
43328
  } else if (Array.isArray(value)) {
43329
+ const isDataArray = propsSchema?.[key]?.items?.types?.includes("object") ?? false;
43214
43330
  rendered[key] = value.map((item, i) => {
43215
43331
  const el = item;
43216
- if (isPatternConfig(el)) {
43332
+ if (!isDataArray && isPatternConfig(el)) {
43217
43333
  const nestedProps = {};
43218
43334
  for (const [k, v] of Object.entries(el)) {
43219
43335
  if (k !== "type") nestedProps[k] = v;
@@ -43301,14 +43417,15 @@ function SlotContentRenderer({
43301
43417
  );
43302
43418
  }
43303
43419
  }
43304
- const renderedProps = renderPatternProps(restProps, onDismiss);
43305
43420
  const patternDef = patterns.getPatternDefinition(content.pattern);
43306
43421
  const propsSchema = patternDef?.propsSchema;
43422
+ const renderedProps = renderPatternProps(restProps, onDismiss, propsSchema);
43307
43423
  if (propsSchema) {
43308
43424
  for (const [propKey, propValue] of Object.entries(renderedProps)) {
43309
43425
  if (typeof propValue !== "string") continue;
43310
43426
  const propDef = propsSchema[propKey];
43311
43427
  if (!propDef || propDef.kind !== "callback") continue;
43428
+ if (propValue === "") continue;
43312
43429
  renderedProps[propKey] = ui.wrapCallbackForEvent(
43313
43430
  `UI:${propValue}`,
43314
43431
  propDef.callbackArgs,
@@ -43591,6 +43708,7 @@ function useSharedEntityStore() {
43591
43708
  }
43592
43709
  return storeRef.current;
43593
43710
  }
43711
+ React81.createContext(null);
43594
43712
  function runTickFrame(entityId, orderedWriters, store) {
43595
43713
  let scratch = store.getSnapshot(entityId);
43596
43714
  for (const writer of orderedWriters) {
@@ -43826,6 +43944,11 @@ var SYNC_TICK_OPERATORS = /* @__PURE__ */ new Set([
43826
43944
  "do",
43827
43945
  "when"
43828
43946
  ]);
43947
+ var REACTIVE_REPAINT_PATTERN_TYPES = /* @__PURE__ */ new Set([
43948
+ "canvas",
43949
+ "game-hud",
43950
+ "game-shell"
43951
+ ]);
43829
43952
  var LIFECYCLE_EVENTS = ["INIT", "LOAD", "$MOUNT"];
43830
43953
  function toTraitDefinition(binding) {
43831
43954
  return {
@@ -44078,6 +44201,8 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
44078
44201
  }, [traitStates]);
44079
44202
  const traitSnapshotDataRef = React81.useRef(/* @__PURE__ */ new Map());
44080
44203
  const traitFieldStatesRef = React81.useRef(/* @__PURE__ */ new Map());
44204
+ const lastCanvasRenderUiRef = React81.useRef(/* @__PURE__ */ new Map());
44205
+ const executeTransitionEffectsRef = React81.useRef(null);
44081
44206
  React81.useEffect(() => {
44082
44207
  const mgr = managerRef.current;
44083
44208
  const bindings = traitBindingsRef.current;
@@ -44118,11 +44243,9 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
44118
44243
  bindTraitStateGetter((traitName) => {
44119
44244
  const allStates = newManager.getAllStates();
44120
44245
  if (allStates instanceof Map) {
44121
- const val = allStates.get(traitName);
44122
- return typeof val === "string" ? val : void 0;
44246
+ return allStates.get(traitName)?.currentState;
44123
44247
  }
44124
- const state = newManager.getState(traitName);
44125
- return typeof state === "string" ? state : void 0;
44248
+ return newManager.getState(traitName)?.currentState;
44126
44249
  });
44127
44250
  const snapshotUnregs = [];
44128
44251
  for (const binding of traitBindingsRef.current) {
@@ -44207,6 +44330,15 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
44207
44330
  const existing = pendingSlots.get(slot) || [];
44208
44331
  existing.push({ pattern, props: props || {} });
44209
44332
  pendingSlots.set(slot, existing);
44333
+ const patternType = pattern?.type;
44334
+ if (patternType !== void 0 && REACTIVE_REPAINT_PATTERN_TYPES.has(patternType)) {
44335
+ const rawForSlot = effects.filter(
44336
+ (e) => Array.isArray(e) && (e[0] === "render-ui" || e[0] === "render") && e[1] === slot
44337
+ );
44338
+ if (rawForSlot.length > 0) {
44339
+ lastCanvasRenderUiRef.current.set(traitName, rawForSlot);
44340
+ }
44341
+ }
44210
44342
  },
44211
44343
  clearSlot: (slot) => {
44212
44344
  pendingSlots.set(slot, []);
@@ -44277,11 +44409,15 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
44277
44409
  notify: clientHandlers.notify
44278
44410
  };
44279
44411
  }
44412
+ const sharedWrites = [];
44280
44413
  const baseSet = handlers.set;
44281
44414
  handlers = {
44282
44415
  ...handlers,
44283
44416
  set: async (targetId, field, value) => {
44284
44417
  if (baseSet) await baseSet(targetId, field, value);
44418
+ if (sharedKey !== void 0) {
44419
+ sharedWrites.push({ field, value });
44420
+ }
44285
44421
  log9.debug("set:write", {
44286
44422
  traitName,
44287
44423
  field,
@@ -44357,7 +44493,10 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
44357
44493
  });
44358
44494
  }
44359
44495
  if (sharedKey !== void 0) {
44360
- sharedEntityStore.commit(sharedKey, liveEntity);
44496
+ sharedEntityStore.commit(
44497
+ sharedKey,
44498
+ core.mergeEntityFrame(sharedEntityStore.getSnapshot(sharedKey), sharedWrites)
44499
+ );
44361
44500
  }
44362
44501
  log9.debug("effects:executed", () => ({
44363
44502
  traitName,
@@ -44383,6 +44522,38 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
44383
44522
  entity: binding.linkedEntity
44384
44523
  });
44385
44524
  }
44525
+ if (pendingSlots.size === 0 && effectsCallOp(effects, SHARED_ENTITY_WRITE_OPS)) {
44526
+ const stashed = lastCanvasRenderUiRef.current.get(traitName);
44527
+ if (stashed !== void 0 && stashed.length > 0) {
44528
+ await executor.executeAll(stashed);
44529
+ for (const [slot, patterns] of pendingSlots) {
44530
+ flushSlot(traitName, slot, patterns, {
44531
+ event: flushEvent,
44532
+ state: previousState,
44533
+ entity: binding.linkedEntity
44534
+ });
44535
+ }
44536
+ }
44537
+ if (sharedKey !== void 0 && executeTransitionEffectsRef.current !== null) {
44538
+ for (const sibling of traitBindingsRef.current) {
44539
+ const siblingName = sibling.trait.name;
44540
+ if (siblingName === traitName) continue;
44541
+ if (sharedKeyByTraitNameRef.current.get(siblingName) !== sharedKey) continue;
44542
+ const siblingStash = lastCanvasRenderUiRef.current.get(siblingName);
44543
+ if (siblingStash === void 0 || siblingStash.length === 0) continue;
44544
+ const siblingState = traitStatesRef.current.get(siblingName)?.currentState ?? "";
44545
+ await executeTransitionEffectsRef.current({
44546
+ binding: sibling,
44547
+ effects: siblingStash,
44548
+ previousState: siblingState,
44549
+ newState: siblingState,
44550
+ flushEvent: `${flushEvent}:repaint`,
44551
+ syncOnly,
44552
+ log: log9
44553
+ });
44554
+ }
44555
+ }
44556
+ }
44386
44557
  } catch (error) {
44387
44558
  log9.error("effects:error", {
44388
44559
  traitName,
@@ -44394,6 +44565,9 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
44394
44565
  }
44395
44566
  return emittedDuringExec;
44396
44567
  }, [eventBus, flushSlot, sharedEntityStore]);
44568
+ React81.useEffect(() => {
44569
+ executeTransitionEffectsRef.current = executeTransitionEffects;
44570
+ }, [executeTransitionEffects]);
44397
44571
  const runTickEffects = React81.useCallback((tick, binding) => {
44398
44572
  const traitName = binding.trait.name;
44399
44573
  const currentState = traitStatesRef.current.get(traitName)?.currentState ?? "";
@@ -44456,6 +44630,24 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
44456
44630
  ({ binding, tick }) => createSharedEntityWriter(binding, tick, traitStatesRef, emitFromSharedWriter)
44457
44631
  );
44458
44632
  runTickFrame(group.storeKey, writers, sharedEntityStore);
44633
+ const repaint = executeTransitionEffectsRef.current;
44634
+ if (repaint !== null) {
44635
+ for (const renderBinding of group.renderBindings) {
44636
+ const renderTraitName = renderBinding.trait.name;
44637
+ const stash = lastCanvasRenderUiRef.current.get(renderTraitName);
44638
+ if (stash === void 0 || stash.length === 0) continue;
44639
+ const renderState = traitStatesRef.current.get(renderTraitName)?.currentState ?? "";
44640
+ void repaint({
44641
+ binding: renderBinding,
44642
+ effects: stash,
44643
+ previousState: renderState,
44644
+ newState: renderState,
44645
+ flushEvent: "tick:repaint",
44646
+ syncOnly: true,
44647
+ log: sharedEntityLog
44648
+ });
44649
+ }
44650
+ }
44459
44651
  };
44460
44652
  if (interval === "frame") {
44461
44653
  scheduler.add(0, onDue);
@@ -44505,6 +44697,13 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
44505
44697
  entityByTrait[name] = fields;
44506
44698
  }
44507
44699
  }
44700
+ for (const binding of bindings) {
44701
+ const name = binding.trait.name;
44702
+ const sharedKey = sharedKeyByTraitNameRef.current.get(name);
44703
+ if (sharedKey !== void 0) {
44704
+ entityByTrait[name] = { ...sharedEntityStore.getSnapshot(sharedKey) };
44705
+ }
44706
+ }
44508
44707
  const results = currentManager.sendEvent(
44509
44708
  normalizedEvent,
44510
44709
  payload,
@@ -44658,7 +44857,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
44658
44857
  }
44659
44858
  await onEventProcessed(normalizedEvent, payload, dispatchedOrbitals);
44660
44859
  }
44661
- }, [entities, eventBus]);
44860
+ }, [entities, eventBus, sharedEntityStore]);
44662
44861
  const drainEventQueue = React81.useCallback(async () => {
44663
44862
  if (processingRef.current) return;
44664
44863
  processingRef.current = true;
@@ -44728,6 +44927,24 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
44728
44927
  });
44729
44928
  }
44730
44929
  }
44930
+ const bareCascadeKeys = /* @__PURE__ */ new Set();
44931
+ for (const binding of traitBindings) {
44932
+ for (const transition of binding.trait.transitions) {
44933
+ const eventKey = transition.event;
44934
+ if (LIFECYCLE_EVENTS.includes(eventKey)) continue;
44935
+ if (bareCascadeKeys.has(eventKey)) continue;
44936
+ bareCascadeKeys.add(eventKey);
44937
+ const bareKey = `UI:${eventKey}`;
44938
+ const unsub = eventBus.on(bareKey, (event) => {
44939
+ crossTraitLog.debug("bare-cascade:fire", { bareKey, eventKey });
44940
+ enqueueAndDrain(eventKey, event.payload);
44941
+ });
44942
+ unsubscribes.push(() => {
44943
+ crossTraitLog.debug("bare-cascade:unsubscribe", { bareKey, eventKey });
44944
+ unsub();
44945
+ });
44946
+ }
44947
+ }
44731
44948
  for (const binding of traitBindings) {
44732
44949
  const ownOrbital = orbitalsByTrait?.[binding.trait.name];
44733
44950
  const listens = binding.trait.listens ?? [];
@@ -44912,9 +45129,16 @@ function normalizeChild(child) {
44912
45129
  props: { ...rest, ...normalizedChildren !== void 0 ? { children: normalizedChildren } : {} }
44913
45130
  };
44914
45131
  }
44915
- function applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits) {
45132
+ function applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits, activeTraits) {
44916
45133
  for (const eff of effects) {
44917
45134
  if (eff.type === "render-ui" && eff.slot && eff.pattern) {
45135
+ if (eff.traitName && activeTraits && !activeTraits.has(eff.traitName)) {
45136
+ xOrbitalLog.debug("slot:off-page-trait-skipped", {
45137
+ sourceTrait: eff.traitName,
45138
+ slot: eff.slot
45139
+ });
45140
+ continue;
45141
+ }
44918
45142
  const patternRecord = eff.pattern;
44919
45143
  const { type: patternType, children, ...inlineProps } = patternRecord;
44920
45144
  const normalizedChildren = Array.isArray(children) ? children.map((c) => normalizeChild(c)) : children;
@@ -44955,8 +45179,38 @@ function applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits) {
44955
45179
  }
44956
45180
  }
44957
45181
  }
44958
- function TraitInitializer({ traits: traits2, orbitalNames, onNavigate, onLocalFallback, persistence, traitConfigsByName, orbitalsByTrait, embeddedTraits }) {
45182
+ function collectServerActiveTraits(ir, allTraits, mountedTraitNames) {
45183
+ if (!ir?.pages || ir.pages.size <= 1) return void 0;
45184
+ const pageBound = /* @__PURE__ */ new Set();
45185
+ for (const page of ir.pages.values()) {
45186
+ const queue = page.traits.map((b) => b.trait.name).filter((n) => !!n);
45187
+ for (const name of queue) {
45188
+ if (pageBound.has(name)) continue;
45189
+ pageBound.add(name);
45190
+ const rt = allTraits.get(name);
45191
+ if (!rt) continue;
45192
+ queue.push(...ui.collectTraitRefsFromResolvedTrait(rt));
45193
+ }
45194
+ }
45195
+ const active = new Set(mountedTraitNames);
45196
+ for (const name of allTraits.keys()) {
45197
+ if (!pageBound.has(name)) active.add(name);
45198
+ }
45199
+ return active;
45200
+ }
45201
+ function TraitInitializer({ traits: traits2, orbitalNames, onNavigate, onLocalFallback, persistence, traitConfigsByName, orbitalsByTrait, embeddedTraits, serverActiveTraits }) {
44959
45202
  const bridge = providers.useServerBridge();
45203
+ const activeTraitNames = React81.useMemo(
45204
+ () => new Set(traits2.map((b) => b.trait.name).filter((n) => !!n)),
45205
+ [traits2]
45206
+ );
45207
+ const withActiveTraits = React81.useCallback(
45208
+ (payload) => {
45209
+ if (!serverActiveTraits || serverActiveTraits.size === 0) return payload;
45210
+ return { ...payload ?? {}, _activeTraits: Array.from(serverActiveTraits) };
45211
+ },
45212
+ [serverActiveTraits]
45213
+ );
44960
45214
  const uiSlots = context.useUISlots();
44961
45215
  const onEventProcessed = React81.useCallback(async (event, payload, dispatchedOrbitals) => {
44962
45216
  if (!bridge.connected || !orbitalNames?.length) return;
@@ -44968,11 +45222,11 @@ function TraitInitializer({ traits: traits2, orbitalNames, onNavigate, onLocalFa
44968
45222
  dispatchedOrbitalsSize: dispatchedOrbitals?.size ?? 0
44969
45223
  }));
44970
45224
  for (const name of targets) {
44971
- const { effects, meta } = await bridge.sendEvent(name, event, payload);
45225
+ const { effects, meta } = await bridge.sendEvent(name, event, withActiveTraits(payload));
44972
45226
  recordServerResponse(name, event, meta);
44973
- applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits);
45227
+ applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits, activeTraitNames);
44974
45228
  }
44975
- }, [bridge.connected, bridge.sendEvent, orbitalNames, uiSlots, onNavigate, embeddedTraits]);
45229
+ }, [bridge.connected, bridge.sendEvent, orbitalNames, uiSlots, onNavigate, embeddedTraits, activeTraitNames, withActiveTraits]);
44976
45230
  const opts = orbitalNames ? { onEventProcessed, navigate: onNavigate, traitConfigsByName, orbitalsByTrait, embeddedTraits } : { navigate: onNavigate, persistence, traitConfigsByName, orbitalsByTrait, embeddedTraits };
44977
45231
  const { sendEvent } = useTraitStateMachine(traits2, uiSlots, opts);
44978
45232
  const initSentRef = React81.useRef(false);
@@ -45009,7 +45263,7 @@ function TraitInitializer({ traits: traits2, orbitalNames, onNavigate, onLocalFa
45009
45263
  initSentRef.current = true;
45010
45264
  (async () => {
45011
45265
  for (const name of orbitalNames) {
45012
- const { effects, meta } = await bridge.sendEvent(name, "INIT", {});
45266
+ const { effects, meta } = await bridge.sendEvent(name, "INIT", withActiveTraits({}));
45013
45267
  recordServerResponse(name, "INIT", meta);
45014
45268
  const effectTraces = [
45015
45269
  { type: "fetch", args: [], status: "executed" },
@@ -45027,10 +45281,10 @@ function TraitInitializer({ traits: traits2, orbitalNames, onNavigate, onLocalFa
45027
45281
  effects: effectTraces,
45028
45282
  timestamp: Date.now()
45029
45283
  });
45030
- applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits);
45284
+ applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits, activeTraitNames);
45031
45285
  }
45032
45286
  })();
45033
- }, [bridge.connected, orbitalNames, bridge.sendEvent, uiSlots, onNavigate, embeddedTraits]);
45287
+ }, [bridge.connected, orbitalNames, bridge.sendEvent, uiSlots, onNavigate, embeddedTraits, activeTraitNames, withActiveTraits]);
45034
45288
  return null;
45035
45289
  }
45036
45290
  function SchemaRunner({ schema, serverUrl, transport, mockData, pageName, onNavigate, onLocalFallback, persistence }) {
@@ -45117,6 +45371,14 @@ function SchemaRunner({ schema, serverUrl, transport, mockData, pageName, onNavi
45117
45371
  }
45118
45372
  return Array.from(set);
45119
45373
  }, [allPageTraits, orbitalsByTrait]);
45374
+ const serverActiveTraits = React81.useMemo(
45375
+ () => collectServerActiveTraits(
45376
+ ir,
45377
+ allTraits,
45378
+ new Set(allPageTraits.map((b) => b.trait.name).filter((n) => !!n))
45379
+ ),
45380
+ [ir, allTraits, allPageTraits]
45381
+ );
45120
45382
  React81.useEffect(() => {
45121
45383
  const traitNames = allPageTraits.map((b) => b.trait.name);
45122
45384
  const orbitalsByTraitForPage = {};
@@ -45126,7 +45388,7 @@ function SchemaRunner({ schema, serverUrl, transport, mockData, pageName, onNavi
45126
45388
  }
45127
45389
  xOrbitalLog.info("SchemaRunner:mount", {
45128
45390
  pageName,
45129
- traitNames,
45391
+ traitNames: traitNames.join(","),
45130
45392
  orbitalsByTraitForPage,
45131
45393
  pageOrbitalNames: pageOrbitalNames.join(",")
45132
45394
  });
@@ -45171,6 +45433,7 @@ function SchemaRunner({ schema, serverUrl, transport, mockData, pageName, onNavi
45171
45433
  traitConfigsByName,
45172
45434
  orbitalsByTrait,
45173
45435
  embeddedTraits,
45436
+ serverActiveTraits,
45174
45437
  onNavigate,
45175
45438
  onLocalFallback,
45176
45439
  persistence