@almadar/ui 5.121.2 → 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.
@@ -139,9 +139,9 @@ function getGlobalEventBus() {
139
139
  function useEventBus() {
140
140
  const context = React83.useContext(providers.EventBusContext);
141
141
  const baseBus = context ?? getGlobalEventBus() ?? fallbackEventBus;
142
- const scope = providers.useTraitScope();
142
+ const chain = providers.useTraitScopeChain();
143
143
  return React83.useMemo(() => {
144
- if (!scope) {
144
+ if (chain.length === 0) {
145
145
  return {
146
146
  ...baseBus,
147
147
  emit: (type, payload, source) => {
@@ -157,22 +157,31 @@ function useEventBus() {
157
157
  emit: (type, payload, source) => {
158
158
  if (typeof type === "string" && type.startsWith("UI:")) {
159
159
  const tail = type.slice(3);
160
- const qualified = tail.includes(".") ? type : `UI:${scope.orbital}.${scope.trait}.${tail}`;
161
- if (qualified !== type) {
162
- scopeLog.info("emit:qualified", {
160
+ const isQualified = tail.includes(".");
161
+ const event = isQualified ? tail.split(".").slice(2).join(".") : tail;
162
+ if (!event) {
163
+ baseBus.emit(type, payload, source);
164
+ return;
165
+ }
166
+ const keys = /* @__PURE__ */ new Set();
167
+ if (isQualified) keys.add(type);
168
+ for (const sc of chain) {
169
+ keys.add(`UI:${sc.orbital}.${sc.trait}.${event}`);
170
+ }
171
+ if (keys.size > 1) {
172
+ scopeLog.info("emit:fan-out", {
163
173
  from: type,
164
- to: qualified,
165
- scopeOrbital: scope.orbital,
166
- scopeTrait: scope.trait
174
+ keys: Array.from(keys),
175
+ chainDepth: chain.length
167
176
  });
168
177
  }
169
- baseBus.emit(qualified, payload, source);
178
+ for (const key of keys) baseBus.emit(key, payload, source);
170
179
  return;
171
180
  }
172
181
  baseBus.emit(type, payload, source);
173
182
  }
174
183
  };
175
- }, [baseBus, scope]);
184
+ }, [baseBus, chain]);
176
185
  }
177
186
  function useEventListener(event, handler) {
178
187
  const eventBus = useEventBus();
@@ -714,13 +723,13 @@ var init_Icon = __esm({
714
723
  style
715
724
  }) => {
716
725
  const directIcon = typeof icon === "string" ? void 0 : icon;
717
- const effectiveName = typeof icon === "string" ? icon : name;
726
+ const effectiveName = typeof icon === "string" && icon !== "" ? icon : name;
727
+ const effectiveStrokeWidth = strokeWidth != null && strokeWidth > 0 ? strokeWidth : void 0;
718
728
  const family = useIconFamily();
719
729
  const RenderedComponent = React83__namespace.default.useMemo(() => {
720
730
  if (directIcon) return null;
721
731
  return effectiveName ? resolveIconForFamily(effectiveName) : null;
722
732
  }, [directIcon, effectiveName, family]);
723
- const effectiveStrokeWidth = strokeWidth ?? void 0;
724
733
  const inlineStyle = {
725
734
  ...effectiveStrokeWidth === void 0 ? { strokeWidth: "var(--icon-stroke-width, 2)" } : {},
726
735
  ...style
@@ -1320,6 +1329,15 @@ var init_Modal = __esm({
1320
1329
  const [dragY, setDragY] = React83.useState(0);
1321
1330
  const dragStartY = React83.useRef(0);
1322
1331
  const isDragging = React83.useRef(false);
1332
+ const [closing, setClosing] = React83.useState(false);
1333
+ const wasOpenRef = React83.useRef(isOpen);
1334
+ React83.useEffect(() => {
1335
+ if (wasOpenRef.current && !isOpen) setClosing(true);
1336
+ wasOpenRef.current = isOpen;
1337
+ }, [isOpen]);
1338
+ const handleAnimEnd = (e) => {
1339
+ if (closing && e.target === e.currentTarget) setClosing(false);
1340
+ };
1323
1341
  React83.useEffect(() => {
1324
1342
  if (isOpen) {
1325
1343
  previousActiveElement.current = document.activeElement;
@@ -1353,7 +1371,11 @@ var init_Modal = __esm({
1353
1371
  document.body.style.overflow = "";
1354
1372
  };
1355
1373
  }, [isOpen]);
1356
- if (!isOpen || typeof document === "undefined") return null;
1374
+ if (typeof document === "undefined") return null;
1375
+ const renderOpen = isOpen || closing;
1376
+ if (!renderOpen) return null;
1377
+ const dialogAnim = closing ? "animate-modal-out" : "animate-modal-in";
1378
+ const overlayAnim = closing ? "animate-overlay-out" : "animate-overlay-in";
1357
1379
  const handleClose = () => {
1358
1380
  if (closeEvent) eventBus.emit(`UI:${closeEvent}`, {});
1359
1381
  onClose();
@@ -1370,7 +1392,8 @@ var init_Modal = __esm({
1370
1392
  className: cn(
1371
1393
  "fixed inset-0 z-[1000]",
1372
1394
  "flex items-start justify-center px-4 pb-4 pt-[10vh]",
1373
- "max-sm:items-stretch max-sm:p-0 max-sm:pt-0"
1395
+ "max-sm:items-stretch max-sm:p-0 max-sm:pt-0",
1396
+ overlayAnim
1374
1397
  ),
1375
1398
  style: { backgroundColor: "rgba(0, 0, 0, 0.6)" },
1376
1399
  onClick: handleOverlayClick,
@@ -1398,8 +1421,10 @@ var init_Modal = __esm({
1398
1421
  // full height, no rounded corners, no min-width.
1399
1422
  "max-sm:max-w-none max-sm:max-h-none max-sm:w-full max-sm:h-full max-sm:rounded-none",
1400
1423
  lookStyles[look],
1401
- className
1424
+ className,
1425
+ dialogAnim
1402
1426
  ),
1427
+ onAnimationEnd: handleAnimEnd,
1403
1428
  style: dragY > 0 ? {
1404
1429
  transform: `translateY(${dragY}px)`,
1405
1430
  transition: isDragging.current ? "none" : "transform 200ms ease-out"
@@ -1508,6 +1533,7 @@ var init_Overlay = __esm({
1508
1533
  className: cn(
1509
1534
  "fixed inset-0 z-40",
1510
1535
  blur && "backdrop-blur-sm",
1536
+ "animate-overlay-in",
1511
1537
  className
1512
1538
  ),
1513
1539
  style: { backgroundColor: "rgba(0, 0, 0, 0.6)" },
@@ -2920,7 +2946,7 @@ var init_Input = __esm({
2920
2946
  eventBus.emit(`UI:${action}`, { value: e.currentTarget.value });
2921
2947
  }
2922
2948
  };
2923
- const wrapField = (field) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full", children: [
2949
+ const wrapField = (field, fullWidth = true) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: fullWidth ? "w-full" : "w-fit", children: [
2924
2950
  label && /* @__PURE__ */ jsxRuntime.jsx("label", { className: "block text-sm font-medium text-foreground mb-1", children: label }),
2925
2951
  field,
2926
2952
  (helperText || error) && /* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("mt-1 text-xs", error ? "text-error" : "text-muted-foreground"), children: error ?? helperText })
@@ -2980,7 +3006,8 @@ var init_Input = __esm({
2980
3006
  ),
2981
3007
  ...props
2982
3008
  }
2983
- )
3009
+ ),
3010
+ false
2984
3011
  );
2985
3012
  }
2986
3013
  return wrapField(
@@ -5308,6 +5335,18 @@ var init_RangeSlider = __esm({
5308
5335
  function easeOut(t) {
5309
5336
  return t * (2 - t);
5310
5337
  }
5338
+ function formatDisplay(value, format, decimals) {
5339
+ switch (format) {
5340
+ case "currency":
5341
+ return `$${value.toFixed(2)}`;
5342
+ case "percent":
5343
+ return `${Math.round(value)}%`;
5344
+ case "number":
5345
+ return value.toLocaleString();
5346
+ default:
5347
+ return value.toFixed(decimals);
5348
+ }
5349
+ }
5311
5350
  var AnimatedCounter;
5312
5351
  var init_AnimatedCounter = __esm({
5313
5352
  "components/marketing/atoms/AnimatedCounter.tsx"() {
@@ -5319,6 +5358,7 @@ var init_AnimatedCounter = __esm({
5319
5358
  duration = 600,
5320
5359
  prefix,
5321
5360
  suffix,
5361
+ format,
5322
5362
  className
5323
5363
  }) => {
5324
5364
  const numericRaw = typeof rawValue === "number" ? rawValue : Number.parseFloat(String(rawValue ?? ""));
@@ -5334,6 +5374,10 @@ var init_AnimatedCounter = __esm({
5334
5374
  setDisplayValue(to);
5335
5375
  return;
5336
5376
  }
5377
+ if (window.matchMedia?.("(prefers-reduced-motion: reduce)").matches) {
5378
+ setDisplayValue(to);
5379
+ return;
5380
+ }
5337
5381
  const startTime = performance.now();
5338
5382
  const diff = to - from;
5339
5383
  function animate(currentTime) {
@@ -5355,7 +5399,7 @@ var init_AnimatedCounter = __esm({
5355
5399
  };
5356
5400
  }, [value, duration]);
5357
5401
  const decimalPlaces = Number.isInteger(value) ? 0 : String(value).split(".")[1]?.length ?? 0;
5358
- const formattedValue = displayValue.toFixed(decimalPlaces);
5402
+ const formattedValue = formatDisplay(displayValue, format, decimalPlaces);
5359
5403
  return /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "h3", className: cn("tabular-nums", className), children: [
5360
5404
  prefix,
5361
5405
  formattedValue,
@@ -6634,14 +6678,29 @@ function recordTransition(trace) {
6634
6678
  "pass"
6635
6679
  );
6636
6680
  } else {
6637
- const hasRenderUI = entry.effects.some((e) => e.type === "render-ui");
6638
- if (hasRenderUI) {
6639
- registerCheck(
6640
- checkId,
6641
- `INIT transition for "${entry.traitName}" missing fetch effect`,
6642
- "fail",
6643
- "Entity-bound render-ui without a fetch effect will show empty data"
6681
+ const rendersEntityData = entry.effects.some(
6682
+ (e) => e.type === "render-ui" && JSON.stringify(e.args).includes("@entity.")
6683
+ );
6684
+ if (rendersEntityData) {
6685
+ const siblingSeeds = getState().transitions.some(
6686
+ (t) => t.event === "INIT" && t.effects.some(
6687
+ (e) => e.type === "fetch" || e.type === "set" && typeof e.args[0] === "string" && e.args[0].startsWith("@entity.")
6688
+ )
6644
6689
  );
6690
+ if (siblingSeeds) {
6691
+ registerCheck(
6692
+ checkId,
6693
+ `INIT transition for "${entry.traitName}" has sibling entity-seed (shared entity)`,
6694
+ "pass"
6695
+ );
6696
+ } else {
6697
+ registerCheck(
6698
+ checkId,
6699
+ `INIT transition for "${entry.traitName}" missing fetch effect`,
6700
+ "fail",
6701
+ "Entity-bound render-ui without a fetch effect will show empty data"
6702
+ );
6703
+ }
6645
6704
  }
6646
6705
  }
6647
6706
  }
@@ -6759,19 +6818,32 @@ function bindEventBus(eventBus) {
6759
6818
  log3.debug("sendEvent", { event: prefixed, traitScope, payloadKeys: payload ? Object.keys(payload) : [] });
6760
6819
  eventBus.emit(prefixed, payload);
6761
6820
  };
6821
+ const MAX_EVENT_LOG = 5e3;
6762
6822
  const eventLog = [];
6823
+ let eventLogDropped = 0;
6824
+ const bumpEpoch = () => {
6825
+ window.__orbitalVerification.eventLogEpoch = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
6826
+ };
6763
6827
  window.__orbitalVerification.eventLog = eventLog;
6828
+ window.__orbitalVerification.eventLogDropped = 0;
6829
+ bumpEpoch();
6764
6830
  window.__orbitalVerification.clearEventLog = () => {
6765
6831
  eventLog.length = 0;
6832
+ eventLogDropped = 0;
6833
+ window.__orbitalVerification.eventLogDropped = 0;
6834
+ bumpEpoch();
6766
6835
  };
6767
6836
  if (eventBus.onAny) {
6768
6837
  const verificationRegistryEventLogger = (event) => {
6769
- if (eventLog.length < 200) {
6770
- eventLog.push({
6771
- type: event.type,
6772
- payload: event.payload,
6773
- timestamp: Date.now()
6774
- });
6838
+ eventLog.push({
6839
+ type: event.type,
6840
+ payload: event.payload,
6841
+ timestamp: Date.now()
6842
+ });
6843
+ if (eventLog.length > MAX_EVENT_LOG) {
6844
+ eventLog.shift();
6845
+ eventLogDropped += 1;
6846
+ window.__orbitalVerification.eventLogDropped = eventLogDropped;
6775
6847
  }
6776
6848
  };
6777
6849
  Object.defineProperty(verificationRegistryEventLogger, "name", {
@@ -7774,7 +7846,7 @@ function GameMenu({
7774
7846
  logo,
7775
7847
  className
7776
7848
  }) {
7777
- const resolvedOptions = options ?? menuItems ?? DEFAULT_MENU_OPTIONS;
7849
+ const resolvedOptions = (options?.length ? options : void 0) ?? (menuItems?.length ? menuItems : void 0) ?? DEFAULT_MENU_OPTIONS;
7778
7850
  const eventBus = useEventBus();
7779
7851
  const handleOptionClick = React83__namespace.useCallback(
7780
7852
  (option) => {
@@ -9172,6 +9244,10 @@ function Canvas2D({
9172
9244
  window.removeEventListener("keyup", onUp);
9173
9245
  };
9174
9246
  }, [keyMap, keyUpMap, eventBus]);
9247
+ React83.useEffect(() => {
9248
+ if (!keyMap && !keyUpMap) return;
9249
+ canvasRef.current?.focus();
9250
+ }, [keyMap, keyUpMap]);
9175
9251
  if (error) {
9176
9252
  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: [
9177
9253
  /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "alert-circle", size: "xl" }),
@@ -9220,7 +9296,7 @@ function Canvas2D({
9220
9296
  onWheel: gestureHandlers.onWheel,
9221
9297
  onContextMenu: (e) => e.preventDefault(),
9222
9298
  className: "cursor-pointer touch-none",
9223
- tabIndex: isFree ? 0 : void 0,
9299
+ tabIndex: isFree || keyMap || keyUpMap ? 0 : void 0,
9224
9300
  style: {
9225
9301
  width: viewportSize.width,
9226
9302
  height: viewportSize.height
@@ -14121,7 +14197,8 @@ var init_LoadingState = __esm({
14121
14197
  LoadingState = ({
14122
14198
  title,
14123
14199
  message,
14124
- className
14200
+ className,
14201
+ fullPage = false
14125
14202
  }) => {
14126
14203
  const { t } = hooks.useTranslate();
14127
14204
  const displayMessage = message ?? t("common.loading");
@@ -14130,7 +14207,8 @@ var init_LoadingState = __esm({
14130
14207
  {
14131
14208
  align: "center",
14132
14209
  className: cn(
14133
- "justify-center py-12",
14210
+ "justify-center",
14211
+ fullPage ? "fixed inset-0 z-[1000] py-12 bg-background/80 backdrop-blur-sm animate-overlay-in" : "py-12",
14134
14212
  className
14135
14213
  ),
14136
14214
  children: [
@@ -17332,7 +17410,7 @@ var init_BookCoverPage = __esm({
17332
17410
  size: "lg",
17333
17411
  action: "BOOK_START",
17334
17412
  className: "mt-8",
17335
- children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: t("book.startReading") })
17413
+ children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", color: "inherit", children: t("book.startReading") })
17336
17414
  }
17337
17415
  )
17338
17416
  ]
@@ -19644,8 +19722,9 @@ var init_Chart = __esm({
19644
19722
  align: "center",
19645
19723
  flex: true,
19646
19724
  className: "min-w-0",
19725
+ style: { height: "100%" },
19647
19726
  children: [
19648
- /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: histogram ? "none" : "xs", align: "end", className: "w-full", style: { height: "100%" }, children: series.map((s, sIdx) => {
19727
+ /* @__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) => {
19649
19728
  const value = valueAt(s, label);
19650
19729
  const barHeight = value / maxValue * 100;
19651
19730
  const color = seriesColor(s, sIdx);
@@ -19658,6 +19737,8 @@ var init_Chart = __esm({
19658
19737
  ),
19659
19738
  style: {
19660
19739
  height: `${barHeight}%`,
19740
+ // Cap width so a lone category doesn't paint the whole plot as one solid block; narrow columns are unaffected (flex-1 binds first).
19741
+ ...!histogram && { maxWidth: 72 },
19661
19742
  backgroundColor: color
19662
19743
  },
19663
19744
  onClick: () => onPointClick?.(
@@ -19692,8 +19773,9 @@ var init_Chart = __esm({
19692
19773
  align: "center",
19693
19774
  flex: true,
19694
19775
  className: "min-w-0",
19776
+ style: { height: "100%" },
19695
19777
  children: [
19696
- /* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "none", className: "w-full", style: { height: "100%" }, justify: "end", children: series.map((s, sIdx) => {
19778
+ /* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "none", className: "w-full flex-1 min-h-0", justify: "end", children: series.map((s, sIdx) => {
19697
19779
  const value = valueAt(s, label);
19698
19780
  const ratio = stack === "normalize" ? total === 0 ? 0 : value / total * 100 : value / maxValue * 100;
19699
19781
  const color = seriesColor(s, sIdx);
@@ -19738,6 +19820,7 @@ var init_Chart = __esm({
19738
19820
  const innerRadius = donut ? radius * 0.6 : 0;
19739
19821
  const center = size / 2;
19740
19822
  const segments = React83.useMemo(() => {
19823
+ if (!Number.isFinite(total) || total <= 0) return [];
19741
19824
  let currentAngle = -Math.PI / 2;
19742
19825
  return data.map((point, idx) => {
19743
19826
  const angle = point.value / total * 2 * Math.PI;
@@ -19749,13 +19832,25 @@ var init_Chart = __esm({
19749
19832
  const y1 = center + radius * Math.sin(startAngle);
19750
19833
  const x2 = center + radius * Math.cos(endAngle);
19751
19834
  const y2 = center + radius * Math.sin(endAngle);
19835
+ const fullCircle = angle >= 2 * Math.PI - 1e-9;
19836
+ const midAngle = startAngle + angle / 2;
19837
+ const xm = center + radius * Math.cos(midAngle);
19838
+ const ym = center + radius * Math.sin(midAngle);
19752
19839
  let d;
19753
19840
  if (innerRadius > 0) {
19754
19841
  const ix1 = center + innerRadius * Math.cos(startAngle);
19755
19842
  const iy1 = center + innerRadius * Math.sin(startAngle);
19756
19843
  const ix2 = center + innerRadius * Math.cos(endAngle);
19757
19844
  const iy2 = center + innerRadius * Math.sin(endAngle);
19758
- 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`;
19845
+ if (fullCircle) {
19846
+ const ixm = center + innerRadius * Math.cos(midAngle);
19847
+ const iym = center + innerRadius * Math.sin(midAngle);
19848
+ 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`;
19849
+ } else {
19850
+ 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`;
19851
+ }
19852
+ } else if (fullCircle) {
19853
+ d = `M ${center} ${center} L ${x1} ${y1} A ${radius} ${radius} 0 1 1 ${xm} ${ym} A ${radius} ${radius} 0 1 1 ${x2} ${y2} Z`;
19759
19854
  } else {
19760
19855
  d = `M ${center} ${center} L ${x1} ${y1} A ${radius} ${radius} 0 ${largeArc} 1 ${x2} ${y2} Z`;
19761
19856
  }
@@ -22782,10 +22877,10 @@ function DataGrid({
22782
22877
  ] }),
22783
22878
  badgeFields.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "xs", className: "flex-wrap", children: badgeFields.map((field) => {
22784
22879
  const val = getNestedValue(itemData, field.name);
22785
- if (val === void 0 || val === null) return null;
22880
+ if (val === void 0 || val === null || val === "") return null;
22786
22881
  return /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center", children: [
22787
22882
  field.icon && renderIconInput(field.icon, { size: "xs" }),
22788
- /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: resolveBadgeVariant(field, String(val)), children: String(val) })
22883
+ /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: resolveBadgeVariant(field, String(val)), children: formatValue(val, field.format) })
22789
22884
  ] }, field.name);
22790
22885
  }) })
22791
22886
  ] }),
@@ -30275,6 +30370,11 @@ var init_VoteStack = __esm({
30275
30370
  {
30276
30371
  className: cn(
30277
30372
  "inline-flex items-center justify-center",
30373
+ // Shrink-wrap in stretch contexts (slot/sidecar wrappers are
30374
+ // flex-column with stretch alignment): without this the root spans
30375
+ // the full wrapper width and the count row's `w-full` turns the
30376
+ // compact pill into a page-wide band.
30377
+ "w-fit",
30278
30378
  variant === "vertical" ? "flex-col" : "flex-row",
30279
30379
  "rounded-sm",
30280
30380
  "border-[length:var(--border-width)] border-border",
@@ -34180,7 +34280,7 @@ var init_Sidebar = __esm({
34180
34280
  isActive ? [
34181
34281
  "bg-primary text-primary-foreground",
34182
34282
  "font-medium shadow-sm",
34183
- "border-primary translate-x-1 -translate-y-0.5"
34283
+ "border-primary translate-x-1 rtl:-translate-x-1 -translate-y-0.5"
34184
34284
  ].join(" ") : [
34185
34285
  "text-foreground",
34186
34286
  "hover:bg-muted hover:border-border",
@@ -34190,10 +34290,10 @@ var init_Sidebar = __esm({
34190
34290
  title: collapsed ? item.label : void 0,
34191
34291
  children: [
34192
34292
  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") })),
34193
- !collapsed && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", color: isActive ? "inherit" : "primary", className: "font-medium truncate flex-1 text-left", children: item.label }),
34293
+ !collapsed && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", color: isActive ? "inherit" : "primary", className: "font-medium truncate flex-1 text-start", children: item.label }),
34194
34294
  !collapsed && item.badge !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "danger", size: "sm", children: item.badge }),
34195
34295
  collapsed && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: cn(
34196
- "absolute left-full ml-2 px-2 py-1 text-xs opacity-0 group-hover:opacity-100",
34296
+ "absolute start-full ms-2 px-2 py-1 text-xs opacity-0 group-hover:opacity-100",
34197
34297
  "pointer-events-none whitespace-nowrap z-50 transition-opacity",
34198
34298
  "bg-primary text-primary-foreground",
34199
34299
  "border-[length:var(--border-width-thin)] border-border",
@@ -34248,7 +34348,7 @@ var init_Sidebar = __esm({
34248
34348
  as: "aside",
34249
34349
  className: cn(
34250
34350
  "flex flex-col h-full",
34251
- "bg-card border-r border-border",
34351
+ "bg-card border-e border-border",
34252
34352
  "transition-all duration-300 ease-in-out",
34253
34353
  collapsed ? "w-20" : "w-64",
34254
34354
  className
@@ -35409,7 +35509,7 @@ function resolveColor3(color, el) {
35409
35509
  function truncateLabel(label) {
35410
35510
  return label.length > MAX_LABEL_CHARS ? label.slice(0, MAX_LABEL_CHARS - 1) + "\u2026" : label;
35411
35511
  }
35412
- var GROUP_COLORS2, labelMeasureCtx, MAX_LABEL_CHARS, GraphCanvas;
35512
+ var GROUP_COLORS2, GROUP_GRAVITY, UNGROUPED_GRAVITY, labelMeasureCtx, MAX_LABEL_CHARS, NO_NODES, NO_EDGES, NO_SIM, GraphCanvas;
35413
35513
  var init_GraphCanvas = __esm({
35414
35514
  "components/core/molecules/GraphCanvas.tsx"() {
35415
35515
  "use client";
@@ -35429,13 +35529,18 @@ var init_GraphCanvas = __esm({
35429
35529
  "var(--color-info)",
35430
35530
  "var(--color-accent)"
35431
35531
  ];
35532
+ GROUP_GRAVITY = 0.3;
35533
+ UNGROUPED_GRAVITY = 0.02;
35432
35534
  labelMeasureCtx = null;
35433
35535
  MAX_LABEL_CHARS = 22;
35536
+ NO_NODES = [];
35537
+ NO_EDGES = [];
35538
+ NO_SIM = [];
35434
35539
  GraphCanvas = ({
35435
35540
  title,
35436
- nodes: propNodes = [],
35437
- edges: propEdges = [],
35438
- similarity: propSimilarity = [],
35541
+ nodes: propNodes = NO_NODES,
35542
+ edges: propEdges = NO_EDGES,
35543
+ similarity: propSimilarity = NO_SIM,
35439
35544
  height = 400,
35440
35545
  showLabels = true,
35441
35546
  interactive = true,
@@ -35485,6 +35590,7 @@ var init_GraphCanvas = __esm({
35485
35590
  const interactionRef = React83.useRef({
35486
35591
  mode: "none",
35487
35592
  dragNodeId: null,
35593
+ pressedNodeId: null,
35488
35594
  startMouse: { x: 0, y: 0 },
35489
35595
  startOffset: { x: 0, y: 0 },
35490
35596
  downPos: { x: 0, y: 0 }
@@ -35532,6 +35638,11 @@ var init_GraphCanvas = __esm({
35532
35638
  () => [...new Set(propNodes.map((n) => n.group).filter(Boolean))],
35533
35639
  [propNodes]
35534
35640
  );
35641
+ const nodesKey = React83.useMemo(() => propNodes.map((n) => n.id).join(""), [propNodes]);
35642
+ const edgesKey = React83.useMemo(
35643
+ () => propEdges.map((e) => `${e.source}${e.target}`).join(""),
35644
+ [propEdges]
35645
+ );
35535
35646
  React83.useEffect(() => {
35536
35647
  const canvas = canvasRef.current;
35537
35648
  if (!canvas || propNodes.length === 0) return;
@@ -35615,7 +35726,7 @@ var init_GraphCanvas = __esm({
35615
35726
  const edgeLinks = propEdges.filter((e) => present.has(e.source) && present.has(e.target)).map((e) => ({ source: e.source, target: e.target, weight: clamp01(e.weight ?? 1) }));
35616
35727
  const simLinks = activeSimilarity.filter((p) => present.has(p.source) && present.has(p.target)).map((p) => ({ source: p.source, target: p.target, weight: clamp01(p.weight) }));
35617
35728
  const collideRadius = (n) => Math.max(n.size || 8, (n.labelW ?? 0) / 2) + nodeSpacing / 2;
35618
- const simulation = d3Force.forceSimulation(simNodes).force("edge", d3Force.forceLink(edgeLinks).id((d) => d.id).distance((l) => linkDistance * (0.35 + (1 - l.weight) * 0.3)).strength(0.9)).force("similarity", d3Force.forceLink(simLinks).id((d) => d.id).distance((l) => linkDistance * (1.35 - 0.55 * l.weight)).strength(0.03)).force("charge", d3Force.forceManyBody().strength(-repulsion * 0.5)).force("collide", d3Force.forceCollide().radius(collideRadius).strength(0.9)).force("x", d3Force.forceX((n) => groupTarget.get(n.group ?? "")?.x ?? w / 2).strength((n) => multiCluster && n.group ? 0.14 : 0.02)).force("y", d3Force.forceY((n) => groupTarget.get(n.group ?? "")?.y ?? h / 2).strength((n) => multiCluster && n.group ? 0.14 : 0.02)).stop();
35729
+ const simulation = d3Force.forceSimulation(simNodes).force("edge", d3Force.forceLink(edgeLinks).id((d) => d.id).distance((l) => linkDistance * (0.35 + (1 - l.weight) * 0.3)).strength(0.9)).force("similarity", d3Force.forceLink(simLinks).id((d) => d.id).distance((l) => linkDistance * (1.35 - 0.55 * l.weight)).strength(0.03)).force("charge", d3Force.forceManyBody().strength(-repulsion * 0.5)).force("collide", d3Force.forceCollide().radius(collideRadius).strength(0.9)).force("x", d3Force.forceX((n) => groupTarget.get(n.group ?? "")?.x ?? w / 2).strength((n) => multiCluster && n.group ? GROUP_GRAVITY : UNGROUPED_GRAVITY)).force("y", d3Force.forceY((n) => groupTarget.get(n.group ?? "")?.y ?? h / 2).strength((n) => multiCluster && n.group ? GROUP_GRAVITY : UNGROUPED_GRAVITY)).stop();
35619
35730
  for (let i = 0; i < 300; i++) simulation.tick();
35620
35731
  const pad = nodeSpacing / 2;
35621
35732
  const rectsOf = (n) => {
@@ -35712,7 +35823,7 @@ var init_GraphCanvas = __esm({
35712
35823
  return () => {
35713
35824
  cancelAnimationFrame(animRef.current);
35714
35825
  };
35715
- }, [propNodes, propEdges, propSimilarity, layout, repulsion, linkDistance, nodeSpacing, showLabels]);
35826
+ }, [nodesKey, edgesKey, propSimilarity, layout, repulsion, linkDistance, nodeSpacing, showLabels]);
35716
35827
  React83.useEffect(() => {
35717
35828
  const canvas = canvasRef.current;
35718
35829
  if (!canvas) return;
@@ -35842,6 +35953,7 @@ var init_GraphCanvas = __esm({
35842
35953
  const cancelSinglePointer = React83.useCallback(() => {
35843
35954
  interactionRef.current.mode = "none";
35844
35955
  interactionRef.current.dragNodeId = null;
35956
+ interactionRef.current.pressedNodeId = null;
35845
35957
  }, []);
35846
35958
  const handlePointerDown = React83.useCallback(
35847
35959
  (e) => {
@@ -35852,6 +35964,7 @@ var init_GraphCanvas = __esm({
35852
35964
  state.downPos = { x: e.clientX, y: e.clientY };
35853
35965
  state.startMouse = { x: e.clientX, y: e.clientY };
35854
35966
  state.startOffset = { ...offset };
35967
+ state.pressedNodeId = node?.id ?? null;
35855
35968
  if (draggable && node) {
35856
35969
  state.mode = "dragging";
35857
35970
  state.dragNodeId = node.id;
@@ -35903,7 +36016,8 @@ var init_GraphCanvas = __esm({
35903
36016
  if (moved < 4) {
35904
36017
  const coords = toCoords(e);
35905
36018
  if (!coords) return;
35906
- const node = nodeAt(coords.graphX, coords.graphY);
36019
+ const node = (state.pressedNodeId ? nodesRef.current.find((n) => n.id === state.pressedNodeId) : void 0) ?? nodeAt(coords.graphX, coords.graphY);
36020
+ state.pressedNodeId = null;
35907
36021
  if (node) {
35908
36022
  if (node.badge && node.badge > 1 && onBadgeClick) {
35909
36023
  const r = (node.size || 8) + (selectedNodeId === node.id ? 4 : 0);
@@ -35923,6 +36037,7 @@ var init_GraphCanvas = __esm({
35923
36037
  );
35924
36038
  const handlePointerLeave = React83.useCallback(() => {
35925
36039
  setHoveredNode(null);
36040
+ interactionRef.current.pressedNodeId = null;
35926
36041
  }, []);
35927
36042
  const gestureHandlers = useCanvasGestures({
35928
36043
  canvasRef,
@@ -38874,8 +38989,17 @@ var init_MediaGallery = __esm({
38874
38989
  const eventBus = useEventBus();
38875
38990
  const { t } = hooks.useTranslate();
38876
38991
  const [lightboxItem, setLightboxItem] = React83.useState(null);
38992
+ const [failedIds, setFailedIds] = React83.useState(/* @__PURE__ */ new Set());
38877
38993
  const closeLightbox = React83.useCallback(() => setLightboxItem(null), []);
38878
38994
  useEventListener("UI:LIGHTBOX_CLOSE", closeLightbox);
38995
+ const handleImageError = React83.useCallback((id) => {
38996
+ setFailedIds((prev) => {
38997
+ if (prev.has(id)) return prev;
38998
+ const next = new Set(prev);
38999
+ next.add(id);
39000
+ return next;
39001
+ });
39002
+ }, []);
38879
39003
  const handleItemClick = React83.useCallback(
38880
39004
  (item) => {
38881
39005
  if (selectable) {
@@ -38891,7 +39015,7 @@ var init_MediaGallery = __esm({
38891
39015
  );
38892
39016
  const entityData = Array.isArray(entity) ? entity : [];
38893
39017
  const items = React83__namespace.default.useMemo(() => {
38894
- if (propItems) return propItems;
39018
+ if (propItems && propItems.length > 0) return propItems;
38895
39019
  if (entityData.length === 0) return [];
38896
39020
  return entityData.map((record, idx) => {
38897
39021
  return {
@@ -38974,13 +39098,14 @@ var init_MediaGallery = __esm({
38974
39098
  ),
38975
39099
  onClick: () => handleItemClick(item),
38976
39100
  children: [
38977
- /* @__PURE__ */ jsxRuntime.jsx(
39101
+ 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(
38978
39102
  "img",
38979
39103
  {
38980
39104
  src: item.thumbnail || item.src,
38981
39105
  alt: item.alt || item.caption || "",
38982
39106
  className: "w-full h-full object-cover",
38983
- loading: "lazy"
39107
+ loading: "lazy",
39108
+ onError: () => handleImageError(item.id)
38984
39109
  }
38985
39110
  ),
38986
39111
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -42468,6 +42593,11 @@ var init_TeamOrganism = __esm({
42468
42593
  TeamOrganism.displayName = "TeamOrganism";
42469
42594
  }
42470
42595
  });
42596
+ function formatDate4(value) {
42597
+ const d = new Date(value);
42598
+ if (isNaN(d.getTime())) return value;
42599
+ return d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
42600
+ }
42471
42601
  var lookStyles10, STATUS_STYLES2, Timeline;
42472
42602
  var init_Timeline = __esm({
42473
42603
  "components/core/organisms/Timeline.tsx"() {
@@ -42595,7 +42725,7 @@ var init_Timeline = __esm({
42595
42725
  /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", className: cn("flex-1 min-w-0", !isLast && "pb-6"), children: [
42596
42726
  /* @__PURE__ */ jsxRuntime.jsxs(HStack, { justify: "between", align: "start", wrap: true, children: [
42597
42727
  /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "semibold", children: item.title }),
42598
- item.date && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", className: "flex-shrink-0", children: item.date })
42728
+ item.date && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", className: "flex-shrink-0", children: formatDate4(item.date) })
42599
42729
  ] }),
42600
42730
  item.description && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "secondary", children: item.description }),
42601
42731
  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)) }),
@@ -43807,7 +43937,7 @@ function substituteTraitRefsDeep(value, pathKey) {
43807
43937
  }
43808
43938
  return value;
43809
43939
  }
43810
- function renderPatternProps(props, onDismiss) {
43940
+ function renderPatternProps(props, onDismiss, propsSchema) {
43811
43941
  const rendered = {};
43812
43942
  for (const [key, value] of Object.entries(props)) {
43813
43943
  if (key === "children") {
@@ -43825,9 +43955,10 @@ function renderPatternProps(props, onDismiss) {
43825
43955
  };
43826
43956
  rendered[key] = /* @__PURE__ */ jsxRuntime.jsx(SlotContentRenderer, { content: childContent, onDismiss });
43827
43957
  } else if (Array.isArray(value)) {
43958
+ const isDataArray = propsSchema?.[key]?.items?.types?.includes("object") ?? false;
43828
43959
  rendered[key] = value.map((item, i) => {
43829
43960
  const el = item;
43830
- if (isPatternConfig(el)) {
43961
+ if (!isDataArray && isPatternConfig(el)) {
43831
43962
  const nestedProps = {};
43832
43963
  for (const [k, v] of Object.entries(el)) {
43833
43964
  if (k !== "type") nestedProps[k] = v;
@@ -43915,14 +44046,15 @@ function SlotContentRenderer({
43915
44046
  );
43916
44047
  }
43917
44048
  }
43918
- const renderedProps = renderPatternProps(restProps, onDismiss);
43919
44049
  const patternDef = patterns.getPatternDefinition(content.pattern);
43920
44050
  const propsSchema = patternDef?.propsSchema;
44051
+ const renderedProps = renderPatternProps(restProps, onDismiss, propsSchema);
43921
44052
  if (propsSchema) {
43922
44053
  for (const [propKey, propValue] of Object.entries(renderedProps)) {
43923
44054
  if (typeof propValue !== "string") continue;
43924
44055
  const propDef = propsSchema[propKey];
43925
44056
  if (!propDef || propDef.kind !== "callback") continue;
44057
+ if (propValue === "") continue;
43926
44058
  renderedProps[propKey] = ui.wrapCallbackForEvent(
43927
44059
  `UI:${propValue}`,
43928
44060
  propDef.callbackArgs,
@@ -44208,7 +44340,7 @@ function EventBusProvider({ children, isolated = false }) {
44208
44340
  const listenerCount = (listeners7?.size ?? 0) + anyListenersRef.current.size;
44209
44341
  busLog.debug("emit", { type, payloadKeys: payload ? Object.keys(payload).length : 0, listenerCount });
44210
44342
  if (listenerCount === 0) {
44211
- busLog.warn("emit:no-listeners", { type });
44343
+ busLog.debug("emit:no-listeners", { type });
44212
44344
  }
44213
44345
  if (listeners7) {
44214
44346
  const listenersCopy = Array.from(listeners7);
@@ -45473,17 +45605,27 @@ function useTrait(traitName) {
45473
45605
  const context = useTraitContext();
45474
45606
  return context.getTrait(traitName);
45475
45607
  }
45608
+ var EMPTY_CHAIN = Object.freeze([]);
45476
45609
  var TraitScopeContext = React83.createContext(null);
45477
45610
  function TraitScopeProvider3({
45478
45611
  orbital,
45479
45612
  trait,
45480
45613
  children
45481
45614
  }) {
45482
- const value = React83.useMemo(() => ({ orbital, trait }), [orbital, trait]);
45615
+ const parentChain = React83.useContext(TraitScopeContext);
45616
+ const value = React83.useMemo(() => {
45617
+ const self = { orbital, trait };
45618
+ return parentChain && parentChain.length > 0 ? [self, ...parentChain] : [self];
45619
+ }, [orbital, trait, parentChain]);
45483
45620
  return /* @__PURE__ */ jsxRuntime.jsx(TraitScopeContext.Provider, { value, children });
45484
45621
  }
45485
- function useTraitScope2() {
45486
- return React83.useContext(TraitScopeContext);
45622
+ function useTraitScopeChain2() {
45623
+ const chain = React83.useContext(TraitScopeContext);
45624
+ return chain ?? EMPTY_CHAIN;
45625
+ }
45626
+ function useTraitScope() {
45627
+ const chain = React83.useContext(TraitScopeContext);
45628
+ return chain && chain.length > 0 ? chain[0] : null;
45487
45629
  }
45488
45630
 
45489
45631
  // providers/OfflineModeProvider.tsx
@@ -45633,6 +45775,7 @@ exports.useSelectionOptional = useSelectionOptional;
45633
45775
  exports.useServerBridge = useServerBridge;
45634
45776
  exports.useTrait = useTrait;
45635
45777
  exports.useTraitContext = useTraitContext;
45636
- exports.useTraitScope = useTraitScope2;
45778
+ exports.useTraitScope = useTraitScope;
45779
+ exports.useTraitScopeChain = useTraitScopeChain2;
45637
45780
  exports.useUser = useUser;
45638
45781
  exports.useUserForEvaluation = useUserForEvaluation;