@almadar/ui 5.135.0 → 5.136.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.
@@ -1,8 +1,10 @@
1
- import * as React82 from 'react';
2
- import React82__default, { createContext, useContext, useMemo, useRef, useEffect, useCallback, Suspense, useState, useSyncExternalStore, useLayoutEffect, lazy, useId } from 'react';
3
- import { EventBusContext, useTraitScopeChain, useEntitySchemaOptional, useEntitySchema, getAllPages, matchPathAmong, OrbitalProvider, TraitScopeProvider, ServerBridgeProvider, useCurrentPagePath, useGameAudioContextOptional, VerificationProvider, EntitySchemaProvider, OrbitalThemeProvider, useServerBridge } from '@almadar/ui/providers';
1
+ import * as React83 from 'react';
2
+ import React83__default, { createContext, useContext, useMemo, useRef, useEffect, useCallback, Suspense, useState, useSyncExternalStore, useLayoutEffect, lazy, useId } from 'react';
3
+ import { EventBusContext, useTraitScopeChain, useEntitySchemaOptional, useEntityBindingSnapshot, useTraitScope, useEntitySchema, getAllPages, matchPathAmong, OrbitalProvider, TraitScopeProvider, ServerBridgeProvider, useCurrentPagePath, useGameAudioContextOptional, VerificationProvider, EntitySchemaProvider, OrbitalThemeProvider, useServerBridge, EntityBindingContext } from '@almadar/ui/providers';
4
4
  export { EntitySchemaProvider, ServerBridgeProvider, TraitContext, TraitProvider, useEntitySchema, useEntitySchemaOptional, useServerBridge, useTrait, useTraitContext } from '@almadar/ui/providers';
5
5
  import { createLogger, setNamespaceLevel, isLogLevelEnabled } from '@almadar/logger';
6
+ import { StateMachineManager, collectDeclaredConfigDefaults, resolveCallSitePayloadCaptures, createServerEffectHandlers, EffectExecutor, createContextFromBindings, createTickScheduler, isValidCronExpression, parseDurationString, InMemoryPersistence, normalizeCallSiteConfigToValues, interpolateValue } from '@almadar/runtime';
7
+ import { mergeEntityFrame, isCircuitEvent, applyListenPayloadMapping, schemaToIR, getPage, clearSchemaCache as clearSchemaCache$1, walkSExpr, buildResolvedTraitConfigs, isRenderBindingMarker, isInlineTrait, containsEntityBinding, isSExpr, isEventPayloadValue, RENDER_BINDING_MARKER } from '@almadar/core';
6
8
  import { clsx } from 'clsx';
7
9
  import { twMerge } from 'tailwind-merge';
8
10
  import * as LucideIcons2 from 'lucide-react';
@@ -69,14 +71,13 @@ import ReactMarkdown from 'react-markdown';
69
71
  import remarkGfm from 'remark-gfm';
70
72
  import remarkMath from 'remark-math';
71
73
  import rehypeKatex from 'rehype-katex';
72
- import { mergeEntityFrame, isCircuitEvent, applyListenPayloadMapping, schemaToIR, getPage, clearSchemaCache as clearSchemaCache$1, walkSExpr, buildResolvedTraitConfigs, isInlineTrait, isSExpr, isEventPayloadValue } from '@almadar/core';
73
74
  import { DndContext, pointerWithin, rectIntersection, closestCorners, useSensors, useSensor, PointerSensor, KeyboardSensor, useDroppable } from '@dnd-kit/core';
74
75
  import { useSortable, arrayMove, sortableKeyboardCoordinates, SortableContext, rectSortingStrategy, verticalListSortingStrategy } from '@dnd-kit/sortable';
75
76
  import { CSS } from '@dnd-kit/utilities';
77
+ import { ordered, lib } from 'emojilib';
76
78
  import { useNodeId, ReactFlowProvider, Handle, Position } from '@xyflow/react';
77
79
  import { forceSimulation, forceLink, forceManyBody, forceCollide, forceX, forceY } from 'd3-force';
78
80
  import { isDrawHostPattern, getPatternDefinition, getComponentForPattern as getComponentForPattern$1 } from '@almadar/core/patterns';
79
- import { StateMachineManager, collectDeclaredConfigDefaults, resolveCallSitePayloadCaptures, createServerEffectHandlers, EffectExecutor, createContextFromBindings, createTickScheduler, isValidCronExpression, parseDurationString, InMemoryPersistence, normalizeCallSiteConfigToValues } from '@almadar/runtime';
80
81
  import { isKnownStdOperator } from '@almadar/std/registry';
81
82
  import { OrbitalServerRuntime } from '@almadar/runtime/OrbitalServerRuntime';
82
83
 
@@ -812,6 +813,75 @@ var init_useTapReveal = __esm({
812
813
  "hooks/useTapReveal.ts"() {
813
814
  }
814
815
  });
816
+ function resolveMarkerExpression(expression, entity, config, state) {
817
+ const ctx = createContextFromBindings({
818
+ entity,
819
+ payload: {},
820
+ state,
821
+ ...config !== void 0 ? { config } : {}
822
+ });
823
+ return interpolateValue(expression, ctx);
824
+ }
825
+ function isPlainObject(value) {
826
+ if (value === null || value === void 0 || typeof value !== "object") return false;
827
+ if (Array.isArray(value)) return false;
828
+ if (React83__default.isValidElement(value)) return false;
829
+ if (value instanceof Date) return false;
830
+ if (typeof value === "function") return false;
831
+ return true;
832
+ }
833
+ function walkValue(value, scopeTrait, entity, config, state) {
834
+ if (isRenderBindingMarker(value)) {
835
+ return { resolved: resolveMarkerExpression(value.expression, entity, config, state), changed: true };
836
+ }
837
+ if (Array.isArray(value)) {
838
+ const out = [];
839
+ let changed = false;
840
+ for (const item of value) {
841
+ const element = item;
842
+ const wasMarker = isRenderBindingMarker(element);
843
+ const { resolved, changed: itemChanged } = walkValue(element, scopeTrait, entity, config, state);
844
+ if (wasMarker && Array.isArray(resolved)) {
845
+ out.push(...resolved);
846
+ changed = true;
847
+ continue;
848
+ }
849
+ out.push(resolved);
850
+ if (itemChanged) changed = true;
851
+ }
852
+ return changed ? { resolved: out, changed: true } : { resolved: value, changed: false };
853
+ }
854
+ if (isPlainObject(value)) {
855
+ const sourceTrait = value._sourceTrait;
856
+ if (typeof sourceTrait === "string" && sourceTrait !== scopeTrait) {
857
+ return { resolved: value, changed: false };
858
+ }
859
+ const out = {};
860
+ let changed = false;
861
+ for (const [key, item] of Object.entries(value)) {
862
+ const { resolved, changed: itemChanged } = walkValue(item, scopeTrait, entity, config, state);
863
+ out[key] = resolved;
864
+ if (itemChanged) changed = true;
865
+ }
866
+ return changed ? { resolved: out, changed: true } : { resolved: value, changed: false };
867
+ }
868
+ return { resolved: value, changed: false };
869
+ }
870
+ function resolveRenderBindingMarkers(props, scopeTrait, entity, config, state) {
871
+ const out = {};
872
+ let changed = false;
873
+ for (const [key, value] of Object.entries(props)) {
874
+ const { resolved, changed: propChanged } = walkValue(value, scopeTrait, entity, config, state);
875
+ out[key] = resolved;
876
+ if (propChanged) changed = true;
877
+ }
878
+ return changed ? out : props;
879
+ }
880
+ var init_resolve_render_bindings = __esm({
881
+ "lib/resolve-render-bindings.ts"() {
882
+ "use client";
883
+ }
884
+ });
815
885
  function cn(...inputs) {
816
886
  return twMerge(clsx(inputs));
817
887
  }
@@ -928,7 +998,7 @@ var init_Box = __esm({
928
998
  fixed: "fixed",
929
999
  sticky: "sticky"
930
1000
  };
931
- Box = React82__default.forwardRef(
1001
+ Box = React83__default.forwardRef(
932
1002
  ({
933
1003
  padding,
934
1004
  paddingX,
@@ -993,7 +1063,7 @@ var init_Box = __esm({
993
1063
  onPointerDown?.(e);
994
1064
  }, [hoverEvent, tapReveal, triggerProps, onPointerDown]);
995
1065
  const isClickable = action || onClick;
996
- return React82__default.createElement(
1066
+ return React83__default.createElement(
997
1067
  Component,
998
1068
  {
999
1069
  ref,
@@ -1210,7 +1280,7 @@ var init_Icon = __esm({
1210
1280
  const effectiveName = typeof icon === "string" && icon !== "" ? icon : name;
1211
1281
  const effectiveStrokeWidth = strokeWidth != null && strokeWidth > 0 ? strokeWidth : void 0;
1212
1282
  const family = useIconFamily();
1213
- const RenderedComponent = React82__default.useMemo(() => {
1283
+ const RenderedComponent = React83__default.useMemo(() => {
1214
1284
  if (directIcon) return null;
1215
1285
  return effectiveName ? resolveIconForFamily(effectiveName) : null;
1216
1286
  }, [directIcon, effectiveName, family]);
@@ -1272,9 +1342,13 @@ function getAtlas(url, onReady) {
1272
1342
  onReady();
1273
1343
  }).catch(() => {
1274
1344
  atlasCache.set(url, null);
1345
+ onReady();
1275
1346
  });
1276
1347
  return void 0;
1277
1348
  }
1349
+ function atlasFailed(url) {
1350
+ return atlasCache.get(url) === null;
1351
+ }
1278
1352
  function subRectFor(atlas, sprite) {
1279
1353
  if (isTilesheet(atlas)) {
1280
1354
  let col;
@@ -1330,7 +1404,7 @@ var init_atlasSlice = __esm({
1330
1404
  }
1331
1405
  });
1332
1406
  function useAtlasSliceDataUrl(asset) {
1333
- const [, bump] = React82.useReducer((x) => x + 1, 0);
1407
+ const [, bump] = React83.useReducer((x) => x + 1, 0);
1334
1408
  if (!isAtlasAsset(asset)) return void 0;
1335
1409
  const key = `${asset.atlas}#${asset.sprite}`;
1336
1410
  const cached = sliceDataUrlCache.get(key);
@@ -1393,13 +1467,13 @@ function AtlasImage({
1393
1467
  style,
1394
1468
  "aria-hidden": ariaHidden
1395
1469
  }) {
1396
- const [, bump] = React82.useReducer((x) => x + 1, 0);
1397
- const canvasRef = React82.useRef(null);
1470
+ const [, bump] = React83.useReducer((x) => x + 1, 0);
1471
+ const canvasRef = React83.useRef(null);
1398
1472
  const sliced = isAtlasAsset(asset);
1399
1473
  const atlas = sliced ? getAtlas(asset.atlas, bump) : void 0;
1400
1474
  const img = sliced && asset?.url ? getSheetImage(asset.url, bump) : null;
1401
1475
  const rect = sliced && atlas ? subRectFor(atlas, asset.sprite) : null;
1402
- React82.useEffect(() => {
1476
+ React83.useEffect(() => {
1403
1477
  const canvas = canvasRef.current;
1404
1478
  if (!canvas || !img || !rect) return;
1405
1479
  canvas.width = rect.sw;
@@ -1475,7 +1549,7 @@ function resolveIconProp(value, sizeClass) {
1475
1549
  const IconComp = value;
1476
1550
  return /* @__PURE__ */ jsx(IconComp, { className: sizeClass });
1477
1551
  }
1478
- if (React82__default.isValidElement(value)) {
1552
+ if (React83__default.isValidElement(value)) {
1479
1553
  return value;
1480
1554
  }
1481
1555
  if (typeof value === "object" && value !== null && isIconLike(value)) {
@@ -1552,7 +1626,7 @@ var init_Button = __esm({
1552
1626
  md: "h-icon-default w-icon-default",
1553
1627
  lg: "h-icon-default w-icon-default"
1554
1628
  };
1555
- Button = React82__default.forwardRef(
1629
+ Button = React83__default.forwardRef(
1556
1630
  ({
1557
1631
  className,
1558
1632
  variant = "primary",
@@ -1622,7 +1696,7 @@ var Dialog;
1622
1696
  var init_Dialog = __esm({
1623
1697
  "components/core/atoms/Dialog.tsx"() {
1624
1698
  init_cn();
1625
- Dialog = React82__default.forwardRef(
1699
+ Dialog = React83__default.forwardRef(
1626
1700
  ({
1627
1701
  role = "dialog",
1628
1702
  "aria-modal": ariaModal = true,
@@ -1833,7 +1907,7 @@ var init_Typography = __esm({
1833
1907
  if (format !== void 0 && format !== "none" && (typeof body === "string" || typeof body === "number" || body instanceof Date)) {
1834
1908
  body = formatValue(body, format);
1835
1909
  }
1836
- return React82__default.createElement(
1910
+ return React83__default.createElement(
1837
1911
  Component,
1838
1912
  {
1839
1913
  id,
@@ -2396,7 +2470,7 @@ var init_Badge = __esm({
2396
2470
  md: "px-2.5 py-1 text-sm",
2397
2471
  lg: "px-3 py-1.5 text-base"
2398
2472
  };
2399
- Badge = React82__default.forwardRef(
2473
+ Badge = React83__default.forwardRef(
2400
2474
  ({ className, variant = "default", size = "sm", amount, label, icon, iconAsset, children, onRemove, removeLabel, ...props }, ref) => {
2401
2475
  const iconSizes3 = {
2402
2476
  sm: "h-icon-default w-icon-default",
@@ -2746,7 +2820,7 @@ var init_SvgFlow = __esm({
2746
2820
  width = 100,
2747
2821
  height = 100
2748
2822
  }) => {
2749
- const markerId = React82__default.useMemo(() => {
2823
+ const markerId = React83__default.useMemo(() => {
2750
2824
  flowIdCounter += 1;
2751
2825
  return `almadar-flow-arrow-${flowIdCounter}`;
2752
2826
  }, []);
@@ -3339,7 +3413,7 @@ var init_SvgRing = __esm({
3339
3413
  width = 100,
3340
3414
  height = 100
3341
3415
  }) => {
3342
- const gradientId = React82__default.useMemo(() => {
3416
+ const gradientId = React83__default.useMemo(() => {
3343
3417
  ringIdCounter += 1;
3344
3418
  return `almadar-ring-glow-${ringIdCounter}`;
3345
3419
  }, []);
@@ -3520,7 +3594,7 @@ var init_Input = __esm({
3520
3594
  init_cn();
3521
3595
  init_Icon();
3522
3596
  init_useEventBus();
3523
- Input = React82__default.forwardRef(
3597
+ Input = React83__default.forwardRef(
3524
3598
  ({
3525
3599
  className,
3526
3600
  inputType,
@@ -3543,6 +3617,20 @@ var init_Input = __esm({
3543
3617
  const { t } = useTranslate();
3544
3618
  const eventBus = useEventBus();
3545
3619
  const type = inputType || htmlType || "text";
3620
+ const isDeclarative = typeof onChange === "string";
3621
+ const [localValue, setLocalValue] = React83__default.useState(value);
3622
+ const pendingEchoRef = React83__default.useRef(/* @__PURE__ */ new Set());
3623
+ React83__default.useEffect(() => {
3624
+ if (!isDeclarative) return;
3625
+ const incoming = value == null ? "" : String(value);
3626
+ if (pendingEchoRef.current.has(incoming)) {
3627
+ pendingEchoRef.current.delete(incoming);
3628
+ return;
3629
+ }
3630
+ pendingEchoRef.current.clear();
3631
+ setLocalValue(value);
3632
+ }, [value, isDeclarative]);
3633
+ const displayValue = isDeclarative ? localValue : value;
3546
3634
  const resolveIconNode = (i, cls) => {
3547
3635
  if (!i) return null;
3548
3636
  if (typeof i === "string") return /* @__PURE__ */ jsx(Icon, { name: i, className: cls });
@@ -3552,7 +3640,7 @@ var init_Input = __esm({
3552
3640
  const iconCls = "h-icon-default w-icon-default";
3553
3641
  const IconComponent = typeof iconProp === "string" ? resolveIcon(iconProp) : iconProp;
3554
3642
  const resolvedLeftIcon = (leftIcon ? resolveIconNode(leftIcon, iconCls) : null) || IconComponent && /* @__PURE__ */ jsx(IconComponent, { className: iconCls });
3555
- const showClearButton = clearable && value && String(value).length > 0;
3643
+ const showClearButton = clearable && displayValue && String(displayValue).length > 0;
3556
3644
  const isMultiline = type === "textarea";
3557
3645
  const baseClassName = cn(
3558
3646
  "block w-full rounded-sm transition-all duration-fast",
@@ -3571,6 +3659,10 @@ var init_Input = __esm({
3571
3659
  if (typeof onChange === "string") {
3572
3660
  const target = e.target;
3573
3661
  const payload = type === "checkbox" ? { checked: target.checked } : { value: target.value };
3662
+ if (type !== "checkbox") {
3663
+ pendingEchoRef.current.add(target.value);
3664
+ setLocalValue(target.value);
3665
+ }
3574
3666
  eventBus.emit(`UI:${onChange}`, payload);
3575
3667
  } else {
3576
3668
  onChange?.(e);
@@ -3601,7 +3693,7 @@ var init_Input = __esm({
3601
3693
  "select",
3602
3694
  {
3603
3695
  ref,
3604
- value,
3696
+ value: displayValue,
3605
3697
  onChange: handleChange,
3606
3698
  className: cn(baseClassName, "appearance-none pr-10", className),
3607
3699
  ...props,
@@ -3621,7 +3713,7 @@ var init_Input = __esm({
3621
3713
  "textarea",
3622
3714
  {
3623
3715
  ref,
3624
- value,
3716
+ value: displayValue,
3625
3717
  onChange: handleChange,
3626
3718
  rows,
3627
3719
  className: baseClassName,
@@ -3660,7 +3752,7 @@ var init_Input = __esm({
3660
3752
  {
3661
3753
  ref,
3662
3754
  type,
3663
- value,
3755
+ value: displayValue,
3664
3756
  onChange: handleChange,
3665
3757
  onKeyDown: handleKeyDown,
3666
3758
  className: baseClassName,
@@ -3688,7 +3780,7 @@ var Label;
3688
3780
  var init_Label = __esm({
3689
3781
  "components/core/atoms/Label.tsx"() {
3690
3782
  init_cn();
3691
- Label = React82__default.forwardRef(
3783
+ Label = React83__default.forwardRef(
3692
3784
  ({ className, required, children, ...props }, ref) => {
3693
3785
  return /* @__PURE__ */ jsxs(
3694
3786
  "label",
@@ -3715,7 +3807,7 @@ var init_Textarea = __esm({
3715
3807
  "components/core/atoms/Textarea.tsx"() {
3716
3808
  init_cn();
3717
3809
  init_useEventBus();
3718
- Textarea = React82__default.forwardRef(
3810
+ Textarea = React83__default.forwardRef(
3719
3811
  ({ className, error, onChange, ...props }, ref) => {
3720
3812
  const eventBus = useEventBus();
3721
3813
  const handleChange = (e) => {
@@ -3954,7 +4046,7 @@ var init_Select = __esm({
3954
4046
  init_cn();
3955
4047
  init_Icon();
3956
4048
  init_useEventBus();
3957
- Select = React82__default.forwardRef(
4049
+ Select = React83__default.forwardRef(
3958
4050
  (props, _ref) => {
3959
4051
  const { multiple, searchable, clearable } = props;
3960
4052
  if (multiple || searchable || clearable) {
@@ -3971,7 +4063,7 @@ var init_Checkbox = __esm({
3971
4063
  "components/core/atoms/Checkbox.tsx"() {
3972
4064
  init_cn();
3973
4065
  init_useEventBus();
3974
- Checkbox = React82__default.forwardRef(
4066
+ Checkbox = React83__default.forwardRef(
3975
4067
  ({ className, label, id, onChange, ...props }, ref) => {
3976
4068
  const inputId = id || `checkbox-${Math.random().toString(36).substr(2, 9)}`;
3977
4069
  const eventBus = useEventBus();
@@ -4025,7 +4117,7 @@ var init_Spinner = __esm({
4025
4117
  md: "h-6 w-6",
4026
4118
  lg: "h-8 w-8"
4027
4119
  };
4028
- Spinner = React82__default.forwardRef(
4120
+ Spinner = React83__default.forwardRef(
4029
4121
  ({ className, size = "md", overlay, ...props }, ref) => {
4030
4122
  if (overlay) {
4031
4123
  return /* @__PURE__ */ jsx(
@@ -4115,7 +4207,7 @@ var init_Card = __esm({
4115
4207
  chip: "shadow-none rounded-pill border-[length:var(--border-width)] border-border",
4116
4208
  "tile-image-first": "p-0 overflow-hidden"
4117
4209
  };
4118
- Card = React82__default.forwardRef(
4210
+ Card = React83__default.forwardRef(
4119
4211
  ({
4120
4212
  className,
4121
4213
  variant = "bordered",
@@ -4164,9 +4256,9 @@ var init_Card = __esm({
4164
4256
  }
4165
4257
  );
4166
4258
  Card.displayName = "Card";
4167
- CardHeader = React82__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
4259
+ CardHeader = React83__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
4168
4260
  CardHeader.displayName = "CardHeader";
4169
- CardTitle = React82__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4261
+ CardTitle = React83__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4170
4262
  "h3",
4171
4263
  {
4172
4264
  ref,
@@ -4179,11 +4271,11 @@ var init_Card = __esm({
4179
4271
  }
4180
4272
  ));
4181
4273
  CardTitle.displayName = "CardTitle";
4182
- CardContent = React82__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
4274
+ CardContent = React83__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
4183
4275
  CardContent.displayName = "CardContent";
4184
4276
  CardBody = CardContent;
4185
4277
  CardBody.displayName = "CardBody";
4186
- CardFooter = React82__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4278
+ CardFooter = React83__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4187
4279
  "div",
4188
4280
  {
4189
4281
  ref,
@@ -4270,7 +4362,7 @@ var init_FilterPill = __esm({
4270
4362
  md: "w-3.5 h-3.5",
4271
4363
  lg: "w-4 h-4"
4272
4364
  };
4273
- FilterPill = React82__default.forwardRef(
4365
+ FilterPill = React83__default.forwardRef(
4274
4366
  ({
4275
4367
  className,
4276
4368
  variant = "default",
@@ -4399,8 +4491,8 @@ var init_Avatar = __esm({
4399
4491
  actionPayload
4400
4492
  }) => {
4401
4493
  const eventBus = useEventBus();
4402
- const [imgFailed, setImgFailed] = React82__default.useState(false);
4403
- React82__default.useEffect(() => {
4494
+ const [imgFailed, setImgFailed] = React83__default.useState(false);
4495
+ React83__default.useEffect(() => {
4404
4496
  setImgFailed(false);
4405
4497
  }, [src]);
4406
4498
  const initials = providedInitials ?? (name ? generateInitials(name) : void 0);
@@ -4513,7 +4605,7 @@ var init_Center = __esm({
4513
4605
  as: Component = "div"
4514
4606
  }) => {
4515
4607
  const mergedStyle = minHeight ? { minHeight, ...style } : style;
4516
- return React82__default.createElement(Component, {
4608
+ return React83__default.createElement(Component, {
4517
4609
  className: cn(
4518
4610
  inline ? "inline-flex" : "flex",
4519
4611
  horizontal && "justify-center",
@@ -4781,7 +4873,7 @@ var init_Radio = __esm({
4781
4873
  md: "w-2.5 h-2.5",
4782
4874
  lg: "w-3 h-3"
4783
4875
  };
4784
- Radio = React82__default.forwardRef(
4876
+ Radio = React83__default.forwardRef(
4785
4877
  ({
4786
4878
  label,
4787
4879
  helperText,
@@ -4798,12 +4890,12 @@ var init_Radio = __esm({
4798
4890
  onChange,
4799
4891
  ...props
4800
4892
  }, ref) => {
4801
- const reactId = React82__default.useId();
4893
+ const reactId = React83__default.useId();
4802
4894
  const baseId = id || `radio-${reactId}`;
4803
4895
  const hasError = !!error;
4804
4896
  const eventBus = useEventBus();
4805
- const [selected, setSelected] = React82__default.useState(value);
4806
- React82__default.useEffect(() => {
4897
+ const [selected, setSelected] = React83__default.useState(value);
4898
+ React83__default.useEffect(() => {
4807
4899
  if (value !== void 0) setSelected(value);
4808
4900
  }, [value]);
4809
4901
  const pick = (next, e) => {
@@ -4985,7 +5077,7 @@ var init_Switch = __esm({
4985
5077
  "components/core/atoms/Switch.tsx"() {
4986
5078
  "use client";
4987
5079
  init_cn();
4988
- Switch = React82.forwardRef(
5080
+ Switch = React83.forwardRef(
4989
5081
  ({
4990
5082
  checked,
4991
5083
  defaultChecked = false,
@@ -4996,10 +5088,10 @@ var init_Switch = __esm({
4996
5088
  name,
4997
5089
  className
4998
5090
  }, ref) => {
4999
- const [isChecked, setIsChecked] = React82.useState(
5091
+ const [isChecked, setIsChecked] = React83.useState(
5000
5092
  checked !== void 0 ? checked : defaultChecked
5001
5093
  );
5002
- React82.useEffect(() => {
5094
+ React83.useEffect(() => {
5003
5095
  if (checked !== void 0) {
5004
5096
  setIsChecked(checked);
5005
5097
  }
@@ -5162,7 +5254,7 @@ var init_Stack = __esm({
5162
5254
  };
5163
5255
  const isHorizontal = direction === "horizontal";
5164
5256
  const directionClass = responsive && isHorizontal ? reverse ? "flex-col-reverse md:flex-row-reverse" : "flex-col md:flex-row" : isHorizontal ? reverse ? "flex-row-reverse" : "flex-row" : reverse ? "flex-col-reverse" : "flex-col";
5165
- return React82__default.createElement(
5257
+ return React83__default.createElement(
5166
5258
  Component,
5167
5259
  {
5168
5260
  className: cn(
@@ -5362,7 +5454,7 @@ var Aside;
5362
5454
  var init_Aside = __esm({
5363
5455
  "components/core/atoms/Aside.tsx"() {
5364
5456
  init_cn();
5365
- Aside = React82__default.forwardRef(
5457
+ Aside = React83__default.forwardRef(
5366
5458
  ({ className, children, ...rest }, ref) => /* @__PURE__ */ jsx("aside", { ref, className: cn(className), ...rest, children })
5367
5459
  );
5368
5460
  Aside.displayName = "Aside";
@@ -5441,9 +5533,9 @@ var init_LawReferenceTooltip = __esm({
5441
5533
  className
5442
5534
  }) => {
5443
5535
  const { t } = useTranslate();
5444
- const [isVisible, setIsVisible] = React82__default.useState(false);
5445
- const timeoutRef = React82__default.useRef(null);
5446
- const triggerRef = React82__default.useRef(null);
5536
+ const [isVisible, setIsVisible] = React83__default.useState(false);
5537
+ const timeoutRef = React83__default.useRef(null);
5538
+ const triggerRef = React83__default.useRef(null);
5447
5539
  const handleMouseEnter = () => {
5448
5540
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
5449
5541
  timeoutRef.current = setTimeout(() => setIsVisible(true), 200);
@@ -5454,7 +5546,7 @@ var init_LawReferenceTooltip = __esm({
5454
5546
  };
5455
5547
  const { revealed, triggerProps } = useTapReveal({ refs: [triggerRef] });
5456
5548
  const open = isVisible || revealed;
5457
- React82__default.useEffect(() => {
5549
+ React83__default.useEffect(() => {
5458
5550
  return () => {
5459
5551
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
5460
5552
  };
@@ -5664,7 +5756,7 @@ var init_StatusDot = __esm({
5664
5756
  md: "w-2.5 h-2.5",
5665
5757
  lg: "w-3 h-3"
5666
5758
  };
5667
- StatusDot = React82__default.forwardRef(
5759
+ StatusDot = React83__default.forwardRef(
5668
5760
  ({ className, status = "offline", pulse = false, size = "md", label, ...props }, ref) => {
5669
5761
  return /* @__PURE__ */ jsx(
5670
5762
  "span",
@@ -5718,7 +5810,7 @@ var init_TrendIndicator = __esm({
5718
5810
  down: "trending-down",
5719
5811
  flat: "arrow-right"
5720
5812
  };
5721
- TrendIndicator = React82__default.forwardRef(
5813
+ TrendIndicator = React83__default.forwardRef(
5722
5814
  ({
5723
5815
  className,
5724
5816
  value,
@@ -5787,7 +5879,7 @@ var init_RangeSlider = __esm({
5787
5879
  md: "w-4 h-4",
5788
5880
  lg: "w-5 h-5"
5789
5881
  };
5790
- RangeSlider = React82__default.forwardRef(
5882
+ RangeSlider = React83__default.forwardRef(
5791
5883
  ({
5792
5884
  className,
5793
5885
  min = 0,
@@ -6363,7 +6455,7 @@ var init_ContentSection = __esm({
6363
6455
  md: "py-16",
6364
6456
  lg: "py-24"
6365
6457
  };
6366
- ContentSection = React82__default.forwardRef(
6458
+ ContentSection = React83__default.forwardRef(
6367
6459
  ({ children, background = "default", padding = "lg", id, className }, ref) => {
6368
6460
  return /* @__PURE__ */ jsx(
6369
6461
  Box,
@@ -6897,7 +6989,7 @@ var init_AnimatedReveal = __esm({
6897
6989
  "scale-up": { opacity: 1, transform: "scale(1) translateY(0)" },
6898
6990
  "none": {}
6899
6991
  };
6900
- AnimatedReveal = React82__default.forwardRef(
6992
+ AnimatedReveal = React83__default.forwardRef(
6901
6993
  ({
6902
6994
  trigger = "scroll",
6903
6995
  animation = "fade-up",
@@ -7057,7 +7149,7 @@ var init_AnimatedGraphic = __esm({
7057
7149
  "components/marketing/atoms/AnimatedGraphic.tsx"() {
7058
7150
  "use client";
7059
7151
  init_cn();
7060
- AnimatedGraphic = React82__default.forwardRef(
7152
+ AnimatedGraphic = React83__default.forwardRef(
7061
7153
  ({
7062
7154
  src,
7063
7155
  svgContent,
@@ -7080,7 +7172,7 @@ var init_AnimatedGraphic = __esm({
7080
7172
  const fetchedSvg = useFetchedSvg(svgContent ? void 0 : src);
7081
7173
  const resolvedSvg = svgContent ?? fetchedSvg;
7082
7174
  const prevAnimateRef = useRef(animate);
7083
- const setRef = React82__default.useCallback(
7175
+ const setRef = React83__default.useCallback(
7084
7176
  (node) => {
7085
7177
  containerRef.current = node;
7086
7178
  if (typeof ref === "function") ref(node);
@@ -7547,46 +7639,45 @@ var init_useImageCache = __esm({
7547
7639
  });
7548
7640
 
7549
7641
  // lib/isometric.ts
7550
- function isoToScreen(tileX, tileY, scale, baseOffsetX, layout = "isometric") {
7551
- const scaledTileWidth = TILE_WIDTH * scale;
7552
- const scaledFloorHeight = FLOOR_HEIGHT * scale;
7642
+ function isoToScreen(tileX, tileY, cellWidth, baseOffsetX, layout = "isometric") {
7643
+ const w = cellWidth;
7644
+ const fh = cellWidth / 2;
7553
7645
  if (layout === "hex") {
7554
- const screenX2 = tileX * scaledTileWidth + (tileY & 1) * (scaledTileWidth / 2) + baseOffsetX;
7555
- const screenY2 = tileY * (scaledFloorHeight * 0.75);
7646
+ const screenX2 = tileX * w + (tileY & 1) * (w / 2) + baseOffsetX;
7647
+ const screenY2 = tileY * (fh * 0.75);
7556
7648
  return { x: screenX2, y: screenY2 };
7557
7649
  }
7558
7650
  if (layout === "flat") {
7559
- const screenX2 = tileX * scaledTileWidth + baseOffsetX;
7560
- const screenY2 = tileY * scaledTileWidth;
7651
+ const screenX2 = tileX * w + baseOffsetX;
7652
+ const screenY2 = tileY * w;
7561
7653
  return { x: screenX2, y: screenY2 };
7562
7654
  }
7563
- const screenX = (tileX - tileY) * (scaledTileWidth / 2) + baseOffsetX;
7564
- const screenY = (tileX + tileY) * (scaledFloorHeight / 2);
7655
+ const screenX = (tileX - tileY) * (w / 2) + baseOffsetX;
7656
+ const screenY = (tileX + tileY) * (fh / 2);
7565
7657
  return { x: screenX, y: screenY };
7566
7658
  }
7567
- function screenToIso(screenX, screenY, scale, baseOffsetX, layout = "isometric") {
7568
- const scaledTileWidth = TILE_WIDTH * scale;
7569
- const scaledFloorHeight = FLOOR_HEIGHT * scale;
7659
+ function screenToIso(screenX, screenY, cellWidth, baseOffsetX, layout = "isometric") {
7660
+ const w = cellWidth;
7661
+ const fh = cellWidth / 2;
7570
7662
  if (layout === "hex") {
7571
- const row = Math.round(screenY / (scaledFloorHeight * 0.75));
7572
- const col = Math.round((screenX - (row & 1) * (scaledTileWidth / 2) - baseOffsetX) / scaledTileWidth);
7663
+ const row = Math.round(screenY / (fh * 0.75));
7664
+ const col = Math.round((screenX - (row & 1) * (w / 2) - baseOffsetX) / w);
7573
7665
  return { x: col, y: row };
7574
7666
  }
7575
7667
  if (layout === "flat") {
7576
- const col = Math.round((screenX - baseOffsetX) / scaledTileWidth);
7577
- const row = Math.round(screenY / scaledTileWidth);
7668
+ const col = Math.round((screenX - baseOffsetX) / w);
7669
+ const row = Math.round(screenY / w);
7578
7670
  return { x: col, y: row };
7579
7671
  }
7580
7672
  const adjustedX = screenX - baseOffsetX;
7581
- const tileX = (adjustedX / (scaledTileWidth / 2) + screenY / (scaledFloorHeight / 2)) / 2;
7582
- const tileY = (screenY / (scaledFloorHeight / 2) - adjustedX / (scaledTileWidth / 2)) / 2;
7673
+ const tileX = (adjustedX / (w / 2) + screenY / (fh / 2)) / 2;
7674
+ const tileY = (screenY / (fh / 2) - adjustedX / (w / 2)) / 2;
7583
7675
  return { x: Math.round(tileX), y: Math.round(tileY) };
7584
7676
  }
7585
- var TILE_WIDTH, FLOOR_HEIGHT, DIAMOND_TOP_Y, BACKGROUND_FALLBACK_COLOR, MINIMAP_TERRAIN_COLORS;
7677
+ var TILE_WIDTH, DIAMOND_TOP_Y, BACKGROUND_FALLBACK_COLOR, MINIMAP_TERRAIN_COLORS;
7586
7678
  var init_isometric = __esm({
7587
7679
  "lib/isometric.ts"() {
7588
7680
  TILE_WIDTH = 256;
7589
- FLOOR_HEIGHT = 128;
7590
7681
  DIAMOND_TOP_Y = 374;
7591
7682
  BACKGROUND_FALLBACK_COLOR = "#1a1a2e";
7592
7683
  MINIMAP_TERRAIN_COLORS = {
@@ -7808,9 +7899,9 @@ function ControlButton({
7808
7899
  className
7809
7900
  }) {
7810
7901
  const eventBus = useEventBus();
7811
- const [isPressed, setIsPressed] = React82.useState(false);
7902
+ const [isPressed, setIsPressed] = React83.useState(false);
7812
7903
  const actualPressed = pressed ?? isPressed;
7813
- const handlePointerDown = React82.useCallback(
7904
+ const handlePointerDown = React83.useCallback(
7814
7905
  (e) => {
7815
7906
  e.preventDefault();
7816
7907
  if (disabled) return;
@@ -7820,7 +7911,7 @@ function ControlButton({
7820
7911
  },
7821
7912
  [disabled, pressEvent, eventBus, onPress]
7822
7913
  );
7823
- const handlePointerUp = React82.useCallback(
7914
+ const handlePointerUp = React83.useCallback(
7824
7915
  (e) => {
7825
7916
  e.preventDefault();
7826
7917
  if (disabled) return;
@@ -7830,7 +7921,7 @@ function ControlButton({
7830
7921
  },
7831
7922
  [disabled, releaseEvent, eventBus, onRelease]
7832
7923
  );
7833
- const handlePointerLeave = React82.useCallback(
7924
+ const handlePointerLeave = React83.useCallback(
7834
7925
  (e) => {
7835
7926
  if (isPressed) {
7836
7927
  setIsPressed(false);
@@ -8088,8 +8179,8 @@ function ControlGrid({
8088
8179
  className
8089
8180
  }) {
8090
8181
  const eventBus = useEventBus();
8091
- const [active, setActive] = React82.useState(/* @__PURE__ */ new Set());
8092
- const handlePress = React82.useCallback(
8182
+ const [active, setActive] = React83.useState(/* @__PURE__ */ new Set());
8183
+ const handlePress = React83.useCallback(
8093
8184
  (id) => {
8094
8185
  setActive((prev) => new Set(prev).add(id));
8095
8186
  if (actionEvent) eventBus.emit(`UI:${actionEvent}`, { id, pressed: true });
@@ -8103,7 +8194,7 @@ function ControlGrid({
8103
8194
  },
8104
8195
  [kind, actionEvent, directionEvent, directionEvents, eventBus, onAction, onDirection]
8105
8196
  );
8106
- const handleRelease = React82.useCallback(
8197
+ const handleRelease = React83.useCallback(
8107
8198
  (id) => {
8108
8199
  setActive((prev) => {
8109
8200
  const next = new Set(prev);
@@ -8461,7 +8552,7 @@ function GameMenu({
8461
8552
  }) {
8462
8553
  const resolvedOptions = (options?.length ? options : void 0) ?? (menuItems?.length ? menuItems : void 0) ?? DEFAULT_MENU_OPTIONS;
8463
8554
  const eventBus = useEventBus();
8464
- const handleOptionClick = React82.useCallback(
8555
+ const handleOptionClick = React83.useCallback(
8465
8556
  (option) => {
8466
8557
  if (option.event) {
8467
8558
  eventBus.emit(`UI:${option.event}`, { option });
@@ -8697,7 +8788,7 @@ function StateGraph({
8697
8788
  }) {
8698
8789
  const eventBus = useEventBus();
8699
8790
  const nodes = states ?? [];
8700
- const positions = React82.useMemo(() => layoutStates(nodes, width, height), [nodes, width, height]);
8791
+ const positions = React83.useMemo(() => layoutStates(nodes, width, height), [nodes, width, height]);
8701
8792
  return /* @__PURE__ */ jsxs(
8702
8793
  Box,
8703
8794
  {
@@ -8768,12 +8859,13 @@ function MiniMap({
8768
8859
  tileAssets,
8769
8860
  unitAssets
8770
8861
  }) {
8771
- const canvasRef = React82.useRef(null);
8772
- const imgCacheRef = React82.useRef(/* @__PURE__ */ new Map());
8862
+ const canvasRef = React83.useRef(null);
8863
+ const imgCacheRef = React83.useRef(/* @__PURE__ */ new Map());
8773
8864
  function loadImg(url) {
8774
8865
  const cached = imgCacheRef.current.get(url);
8775
8866
  if (cached) return cached.complete ? cached : null;
8776
8867
  const img = new Image();
8868
+ img.crossOrigin = "anonymous";
8777
8869
  img.src = url;
8778
8870
  img.onload = () => {
8779
8871
  const canvas = canvasRef.current;
@@ -8784,7 +8876,7 @@ function MiniMap({
8784
8876
  imgCacheRef.current.set(url, img);
8785
8877
  return null;
8786
8878
  }
8787
- React82.useEffect(() => {
8879
+ React83.useEffect(() => {
8788
8880
  const canvas = canvasRef.current;
8789
8881
  if (!canvas) return;
8790
8882
  const ctx = canvas.getContext("2d");
@@ -8941,7 +9033,7 @@ function useCamera(initial) {
8941
9033
  const handleWheel = useCallback((e, drawFn) => {
8942
9034
  e.preventDefault();
8943
9035
  const zoomDelta = e.deltaY > 0 ? 0.9 : 1.1;
8944
- cameraRef.current.zoom = Math.max(0.5, Math.min(3, cameraRef.current.zoom * zoomDelta));
9036
+ cameraRef.current.zoom = Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, cameraRef.current.zoom * zoomDelta));
8945
9037
  drawFn?.();
8946
9038
  }, []);
8947
9039
  const handlePointerDown = useCallback((e) => {
@@ -8962,7 +9054,7 @@ function useCamera(initial) {
8962
9054
  const zoomAtPoint = useCallback((factor, centerX, centerY, viewportSize, drawFn) => {
8963
9055
  const cam = cameraRef.current;
8964
9056
  const oldZoom = cam.zoom;
8965
- const newZoom = Math.max(0.5, Math.min(3, oldZoom * factor));
9057
+ const newZoom = Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, oldZoom * factor));
8966
9058
  if (newZoom === oldZoom) {
8967
9059
  drawFn?.();
8968
9060
  return;
@@ -9014,9 +9106,12 @@ function useCamera(initial) {
9014
9106
  lerpToTarget
9015
9107
  };
9016
9108
  }
9109
+ var MIN_ZOOM, MAX_ZOOM;
9017
9110
  var init_useCamera = __esm({
9018
9111
  "hooks/useCamera.ts"() {
9019
9112
  "use client";
9113
+ MIN_ZOOM = 0.05;
9114
+ MAX_ZOOM = 10;
9020
9115
  }
9021
9116
  });
9022
9117
 
@@ -9030,6 +9125,7 @@ function getOrLoadImage(url, onReady) {
9030
9125
  return null;
9031
9126
  }
9032
9127
  const img = new Image();
9128
+ img.crossOrigin = "anonymous";
9033
9129
  const entry = { img, status: "pending", onReady };
9034
9130
  cache.set(url, entry);
9035
9131
  updateAssetStatus(url, "pending");
@@ -9041,10 +9137,14 @@ function getOrLoadImage(url, onReady) {
9041
9137
  img.onerror = () => {
9042
9138
  entry.status = "failed";
9043
9139
  updateAssetStatus(url, "failed");
9140
+ entry.onReady?.();
9044
9141
  };
9045
9142
  img.src = url;
9046
9143
  return null;
9047
9144
  }
9145
+ function getImageStatus(url) {
9146
+ return cache.get(url)?.status;
9147
+ }
9048
9148
  var cache;
9049
9149
  var init_imageCache = __esm({
9050
9150
  "lib/imageCache.ts"() {
@@ -9183,12 +9283,13 @@ var init_webPainter2d = __esm({
9183
9283
 
9184
9284
  // lib/drawable/projector.ts
9185
9285
  function create2DProjector(opts) {
9186
- const { scale, baseOffsetX, layout } = opts;
9187
- const tileWidth = layout === "free" ? 1 : TILE_WIDTH * scale;
9188
- const floorHeight = layout === "free" ? 1 : FLOOR_HEIGHT * scale;
9189
- const diamondTopY = layout === "free" ? 0 : (opts.diamondTopY ?? DIAMOND_TOP_Y) * scale;
9286
+ const { baseOffsetX, layout } = opts;
9287
+ const tw = opts.tileWidth ?? TILE_WIDTH;
9288
+ const tileWidth = layout === "free" ? 1 : tw;
9289
+ const floorHeight = layout === "free" ? 1 : tw / 2;
9290
+ const diamondTopY = layout === "free" ? 0 : opts.diamondTopY ?? tw * (DIAMOND_TOP_Y / TILE_WIDTH);
9190
9291
  const squareGrid = layout === "flat" || layout === "free";
9191
- const project = (pos) => layout === "free" ? { x: pos.x, y: pos.y } : isoToScreen(pos.x, pos.y, scale, baseOffsetX, layout);
9292
+ const project = (pos) => layout === "free" ? { x: pos.x, y: pos.y } : isoToScreen(pos.x, pos.y, tw, baseOffsetX, layout);
9192
9293
  const anchorPoint = (pos, anchor) => {
9193
9294
  const base = project(pos);
9194
9295
  if (anchor === "top-left") return base;
@@ -9219,7 +9320,7 @@ function create2DProjector(opts) {
9219
9320
  { x: base.x, y: topY + floorHeight / 2 }
9220
9321
  ];
9221
9322
  };
9222
- return { project, anchorPoint, cellPath, tileWidth, floorHeight, diamondTopY, scale, squareGrid };
9323
+ return { project, anchorPoint, cellPath, tileWidth, floorHeight, diamondTopY, squareGrid, worldPixelDirect: layout === "free" };
9223
9324
  }
9224
9325
  var init_projector = __esm({
9225
9326
  "lib/drawable/projector.ts"() {
@@ -9235,32 +9336,67 @@ var init_contract = __esm({
9235
9336
  "lib/drawable/contract.ts"() {
9236
9337
  }
9237
9338
  });
9238
-
9239
- // components/game/atoms/DrawSprite.tsx
9339
+ function warnMissingOnce(reason, node) {
9340
+ const key = `${reason}:${node.asset.url}:${String(node.asset.atlas)}:${String(node.asset.sprite)}`;
9341
+ if (loggedMissing.has(key)) return;
9342
+ loggedMissing.add(key);
9343
+ spriteLog.warn("draw-sprite asset unresolvable \u2014 painting fallback square", { reason, url: node.asset.url, atlas: node.asset.atlas, sprite: node.asset.sprite });
9344
+ }
9345
+ function paintFallbackSquare(painter, node, dctx, reason) {
9346
+ warnMissingOnce(reason, node);
9347
+ const tw = dctx.projector.tileWidth;
9348
+ const natural = dctx.projector.worldPixelDirect ? FALLBACK_WORLD_PX : tw;
9349
+ const w = node.width !== void 0 ? node.width * tw : natural;
9350
+ const h = node.height !== void 0 ? node.height * tw : natural;
9351
+ const anchor = node.anchor ?? "top-left";
9352
+ const p = dctx.projector.anchorPoint(node.position, anchor);
9353
+ const dx = anchor === "top-left" ? p.x : p.x - w / 2;
9354
+ const dy = anchor === "ground" ? p.y - h : anchor === "center" ? p.y - h / 2 : p.y;
9355
+ painter.save();
9356
+ if (node.opacity !== void 0 && node.opacity !== 1) painter.setAlpha(node.opacity);
9357
+ painter.fillRect(dx, dy, w, h, "#9b8f7f");
9358
+ painter.strokeRect(dx, dy, w, h, "#5e564b", Math.max(1, tw / 32));
9359
+ painter.restore();
9360
+ }
9240
9361
  function DrawSprite(_props) {
9241
9362
  return null;
9242
9363
  }
9243
- var paintSprite;
9364
+ var spriteLog, loggedMissing, FALLBACK_WORLD_PX, paintSprite;
9244
9365
  var init_DrawSprite = __esm({
9245
9366
  "components/game/atoms/DrawSprite.tsx"() {
9246
9367
  "use client";
9247
9368
  init_atlasSlice();
9369
+ init_imageCache();
9248
9370
  init_contract();
9371
+ spriteLog = createLogger("almadar:ui:draw-sprite");
9372
+ loggedMissing = /* @__PURE__ */ new Set();
9373
+ FALLBACK_WORLD_PX = 32;
9249
9374
  paintSprite = (painter, node, dctx) => {
9250
9375
  if (!node.asset?.url || !isValidScenePos(node.position)) return;
9251
9376
  const tex = painter.resolveTexture(node.asset.url);
9252
- if (!tex) return;
9377
+ if (!tex) {
9378
+ if (getImageStatus(node.asset.url) === "failed") paintFallbackSquare(painter, node, dctx, "texture-failed");
9379
+ return;
9380
+ }
9253
9381
  let src = typeof node.frame === "object" ? node.frame : void 0;
9254
9382
  if (!src && isAtlasAsset(node.asset)) {
9255
9383
  const atlas = getAtlas(node.asset.atlas, dctx.invalidate);
9256
- if (!atlas) return;
9384
+ if (!atlas) {
9385
+ if (atlasFailed(node.asset.atlas)) paintFallbackSquare(painter, node, dctx, "atlas-failed");
9386
+ return;
9387
+ }
9257
9388
  const r = subRectFor(atlas, node.asset.sprite);
9258
- if (!r) return;
9389
+ if (!r) {
9390
+ paintFallbackSquare(painter, node, dctx, "sprite-missing");
9391
+ return;
9392
+ }
9259
9393
  src = { x: r.sx, y: r.sy, w: r.sw, h: r.sh };
9260
9394
  }
9261
9395
  const tw = dctx.projector.tileWidth;
9262
- const w = node.width !== void 0 ? node.width * tw : src ? src.w : tex.width;
9263
- const h = node.height !== void 0 ? node.height * tw : src ? src.h : tex.height;
9396
+ const fallbackW = dctx.projector.worldPixelDirect ? src ? src.w : tex.width : tw;
9397
+ const fallbackH = dctx.projector.worldPixelDirect ? src ? src.h : tex.height : tw;
9398
+ const w = node.width !== void 0 ? node.width * tw : fallbackW;
9399
+ const h = node.height !== void 0 ? node.height * tw : fallbackH;
9264
9400
  const anchor = node.anchor ?? "top-left";
9265
9401
  const p = dctx.projector.anchorPoint(node.position, anchor);
9266
9402
  const dx = anchor === "top-left" ? p.x : p.x - w / 2;
@@ -9526,6 +9662,8 @@ function Canvas2D({
9526
9662
  keyUpMap,
9527
9663
  camera = "pan-zoom",
9528
9664
  scale = 0.4,
9665
+ tileWidth,
9666
+ fit = false,
9529
9667
  showMinimap = true,
9530
9668
  followTarget,
9531
9669
  cameraPos,
@@ -9568,9 +9706,32 @@ function Canvas2D({
9568
9706
  observer2.observe(el);
9569
9707
  return () => observer2.disconnect();
9570
9708
  }, []);
9571
- const scaledTileWidth = TILE_WIDTH * scale;
9572
- const scaledFloorHeight = FLOOR_HEIGHT * scale;
9573
- const scaledDiamondTopY = DIAMOND_TOP_Y * scale;
9709
+ const [atlasVersion, setAtlasVersion] = useState(0);
9710
+ const bumpAtlas = useCallback(() => setAtlasVersion((v) => v + 1), []);
9711
+ const detectedTileWidth = useMemo(() => {
9712
+ for (const n of drawables ?? []) {
9713
+ const refs = [];
9714
+ if (n.type === "draw-sprite") refs.push(n.asset);
9715
+ else if (n.type === "draw-sprite-layer") for (const it of n.items) refs.push(it.asset);
9716
+ for (const a of refs) {
9717
+ if (a && isAtlasAsset(a) && a.atlas) {
9718
+ const atlas = getAtlas(a.atlas, bumpAtlas);
9719
+ if (atlas) {
9720
+ if ("tileWidth" in atlas) return atlas.tileWidth;
9721
+ if ("subTextures" in atlas) {
9722
+ const first = Object.values(atlas.subTextures)[0];
9723
+ if (first && typeof first.width === "number") return first.width;
9724
+ }
9725
+ }
9726
+ }
9727
+ }
9728
+ }
9729
+ return void 0;
9730
+ }, [drawables, atlasVersion]);
9731
+ const nativeTileW = tileWidth ?? detectedTileWidth ?? TILE_WIDTH;
9732
+ const scaledTileWidth = nativeTileW;
9733
+ const scaledFloorHeight = nativeTileW / 2;
9734
+ const scaledDiamondTopY = nativeTileW * (DIAMOND_TOP_Y / TILE_WIDTH);
9574
9735
  const drawnItems = useMemo(() => collectDrawnItems(drawables ?? []), [drawables]);
9575
9736
  const scenePositions = useMemo(() => drawnItems.map((i) => i.pos), [drawnItems]);
9576
9737
  const hitIndex = useMemo(() => buildHitIndex(drawnItems), [drawnItems]);
@@ -9588,14 +9749,36 @@ function Canvas2D({
9588
9749
  if (isFree || projection === "flat" || projection === "side") return 0;
9589
9750
  return (gridExtent.height - 1) * (scaledTileWidth / 2);
9590
9751
  }, [isFree, projection, gridExtent.height, scaledTileWidth]);
9752
+ const effectiveZoom = useMemo(() => {
9753
+ if (isFree || projection === "side") return scale;
9754
+ if (!fit) {
9755
+ const z2 = TILE_WIDTH * scale * scale / nativeTileW;
9756
+ return Number.isFinite(z2) && z2 > 0 ? z2 : scale;
9757
+ }
9758
+ if (!viewportSize.width || gridExtent.width < 2 || gridExtent.height < 2) return scale;
9759
+ let boardW;
9760
+ let boardH;
9761
+ if (projection === "flat") {
9762
+ boardW = gridExtent.width * nativeTileW;
9763
+ boardH = gridExtent.height * nativeTileW;
9764
+ } else if (projection === "hex") {
9765
+ boardW = (gridExtent.width + 0.5) * nativeTileW;
9766
+ boardH = gridExtent.height * (nativeTileW / 2) * 0.75 + nativeTileW / 2;
9767
+ } else {
9768
+ boardW = (gridExtent.width + gridExtent.height) * (nativeTileW / 2);
9769
+ boardH = (gridExtent.width + gridExtent.height) * (nativeTileW / 4);
9770
+ }
9771
+ const z = Math.min(viewportSize.width * 0.85 / boardW, viewportSize.height * 0.85 / boardH);
9772
+ return Number.isFinite(z) && z > 0 ? z : scale;
9773
+ }, [isFree, projection, fit, viewportSize, gridExtent, nativeTileW, scale]);
9591
9774
  const projector = useMemo(
9592
- () => create2DProjector({ scale, baseOffsetX, layout }),
9593
- [scale, baseOffsetX, layout]
9775
+ () => create2DProjector({ tileWidth: nativeTileW, baseOffsetX, layout }),
9776
+ [nativeTileW, baseOffsetX, layout]
9594
9777
  );
9595
9778
  const unproject = useCallback((screenX, screenY) => {
9596
9779
  if (projection === "free" || projection === "side") return { x: Math.round(screenX), y: Math.round(screenY) };
9597
- return screenToIso(screenX, screenY, scale, baseOffsetX, projection);
9598
- }, [projection, scale, baseOffsetX]);
9780
+ return screenToIso(screenX, screenY, nativeTileW, baseOffsetX, projection);
9781
+ }, [projection, nativeTileW, baseOffsetX]);
9599
9782
  const bgUrls = useMemo(() => backgroundImage ? [backgroundImage.url] : [], [backgroundImage]);
9600
9783
  const { getImage, pendingCount: _imagePendingCount } = useImageCache(bgUrls);
9601
9784
  useEffect(() => {
@@ -9622,9 +9805,7 @@ function Canvas2D({
9622
9805
  zoomAtPoint,
9623
9806
  screenToWorld,
9624
9807
  lerpToTarget
9625
- } = useCamera({ zoom: scale });
9626
- const [atlasVersion, setAtlasVersion] = useState(0);
9627
- const bumpAtlas = useCallback(() => setAtlasVersion((v) => v + 1), []);
9808
+ } = useCamera({ zoom: effectiveZoom });
9628
9809
  const miniMapTiles = useMemo(() => {
9629
9810
  if (!showMinimap) return [];
9630
9811
  const color = MINIMAP_TERRAIN_COLORS.default;
@@ -9699,6 +9880,13 @@ function Canvas2D({
9699
9880
  useEffect(() => {
9700
9881
  draw();
9701
9882
  }, [_imagePendingCount, draw]);
9883
+ const userZoomedRef = useRef(false);
9884
+ useEffect(() => {
9885
+ if (userZoomedRef.current) return;
9886
+ if (cameraRef.current.zoom === effectiveZoom) return;
9887
+ cameraRef.current.zoom = effectiveZoom;
9888
+ draw();
9889
+ }, [effectiveZoom, cameraRef, draw]);
9702
9890
  useEffect(() => {
9703
9891
  draw();
9704
9892
  }, [atlasVersion, draw]);
@@ -9755,7 +9943,9 @@ function Canvas2D({
9755
9943
  if (tileLeaveEvent) eventBus.emit(`UI:${tileLeaveEvent}`, {});
9756
9944
  }, [handleMouseLeave, tileLeaveEvent, eventBus]);
9757
9945
  const applyZoom = useCallback((factor, centerX, centerY) => {
9758
- if (enableCamera) zoomAtPoint(factor, centerX, centerY, viewportSize, () => draw());
9946
+ if (!enableCamera) return;
9947
+ userZoomedRef.current = true;
9948
+ zoomAtPoint(factor, centerX, centerY, viewportSize, () => draw());
9759
9949
  }, [enableCamera, zoomAtPoint, viewportSize, draw]);
9760
9950
  const applyPanDelta = useCallback((dx, dy) => {
9761
9951
  if (enableCamera) panBy(dx, dy, () => draw());
@@ -9940,6 +10130,8 @@ function Canvas({
9940
10130
  isLoading,
9941
10131
  unitScale,
9942
10132
  showMinimap,
10133
+ fit,
10134
+ tileWidth,
9943
10135
  backgroundImage,
9944
10136
  backgroundColor,
9945
10137
  worldWidth,
@@ -9997,6 +10189,8 @@ function Canvas({
9997
10189
  projection,
9998
10190
  camera: to2DCamera(camera?.mode),
9999
10191
  ...zoom !== void 0 ? { scale: zoom } : {},
10192
+ ...fit !== void 0 ? { fit } : {},
10193
+ ...tileWidth !== void 0 ? { tileWidth } : {},
10000
10194
  ...camera?.target !== void 0 ? { followTarget: camera.target } : {},
10001
10195
  ...camera?.pos !== void 0 ? { cameraPos: camera.pos } : {},
10002
10196
  showMinimap,
@@ -10139,7 +10333,7 @@ function LinearView({
10139
10333
  /* @__PURE__ */ jsx(HStack, { className: "flex-wrap items-center", gap: "xs", children: trait.states.map((state, i) => {
10140
10334
  const isDone = i < currentIdx;
10141
10335
  const isCurrent = i === currentIdx;
10142
- return /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
10336
+ return /* @__PURE__ */ jsxs(React83__default.Fragment, { children: [
10143
10337
  i > 0 && /* @__PURE__ */ jsx(
10144
10338
  Typography,
10145
10339
  {
@@ -10674,7 +10868,7 @@ function SequenceBar({
10674
10868
  else onSlotRemove?.(index);
10675
10869
  }, [emit, slotRemoveEvent, onSlotRemove, playing]);
10676
10870
  const paddedSlots = Array.from({ length: maxSlots }, (_, i) => slots[i]);
10677
- return /* @__PURE__ */ jsx(HStack, { className: cn("items-center", className), gap: "sm", children: paddedSlots.map((slot, i) => /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
10871
+ return /* @__PURE__ */ jsx(HStack, { className: cn("items-center", className), gap: "sm", children: paddedSlots.map((slot, i) => /* @__PURE__ */ jsxs(React83__default.Fragment, { children: [
10678
10872
  i > 0 && /* @__PURE__ */ jsx(
10679
10873
  Typography,
10680
10874
  {
@@ -11323,7 +11517,7 @@ var init_ErrorBoundary = __esm({
11323
11517
  }
11324
11518
  );
11325
11519
  };
11326
- ErrorBoundary = class extends React82__default.Component {
11520
+ ErrorBoundary = class extends React83__default.Component {
11327
11521
  constructor(props) {
11328
11522
  super(props);
11329
11523
  __publicField(this, "reset", () => {
@@ -11592,7 +11786,7 @@ var init_Container = __esm({
11592
11786
  as: Component = "div"
11593
11787
  }) => {
11594
11788
  const resolvedSize = maxWidth ?? size ?? "lg";
11595
- return React82__default.createElement(
11789
+ return React83__default.createElement(
11596
11790
  Component,
11597
11791
  {
11598
11792
  className: cn(
@@ -14557,7 +14751,7 @@ var init_CodeBlock = __esm({
14557
14751
  DIFF_STYLE_FALLBACK = { bg: "", prefix: " ", text: "text-foreground" };
14558
14752
  LINE_PROPS_FN = (n) => ({ "data-line": String(n - 1) });
14559
14753
  HIDDEN_LINE_NUMBERS = { display: "none" };
14560
- CodeBlock = React82__default.memo(
14754
+ CodeBlock = React83__default.memo(
14561
14755
  ({
14562
14756
  code: rawCode,
14563
14757
  language = "text",
@@ -15145,7 +15339,7 @@ var init_MarkdownContent = __esm({
15145
15339
  init_Box();
15146
15340
  init_CodeBlock();
15147
15341
  init_cn();
15148
- MarkdownContent = React82__default.memo(
15342
+ MarkdownContent = React83__default.memo(
15149
15343
  ({ content, direction = "ltr", className }) => {
15150
15344
  const { t: _t } = useTranslate();
15151
15345
  const safeContent = typeof content === "string" ? content : String(content ?? "");
@@ -16422,7 +16616,7 @@ var init_StateMachineView = __esm({
16422
16616
  style: { top: title ? 30 : 0 },
16423
16617
  children: [
16424
16618
  entity && /* @__PURE__ */ jsx(EntityBox, { entity, config }),
16425
- states.map((state) => renderStateNode ? /* @__PURE__ */ jsx(React82__default.Fragment, { children: renderStateNode(state, config) }, state.id) : /* @__PURE__ */ jsx(
16619
+ states.map((state) => renderStateNode ? /* @__PURE__ */ jsx(React83__default.Fragment, { children: renderStateNode(state, config) }, state.id) : /* @__PURE__ */ jsx(
16426
16620
  StateNode2,
16427
16621
  {
16428
16622
  state,
@@ -22163,8 +22357,8 @@ var init_Menu = __esm({
22163
22357
  "bottom-end": "bottom-start"
22164
22358
  };
22165
22359
  const effectivePosition = direction === "rtl" ? rtlMirror[position] ?? position : position;
22166
- const triggerChild = React82__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx(Typography, { variant: "small", as: "span", children: trigger });
22167
- const triggerElement = React82__default.cloneElement(
22360
+ const triggerChild = React83__default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsx(Typography, { variant: "small", as: "span", children: trigger });
22361
+ const triggerElement = React83__default.cloneElement(
22168
22362
  triggerChild,
22169
22363
  {
22170
22364
  ref: triggerRef,
@@ -22259,14 +22453,14 @@ function useDataDnd(args) {
22259
22453
  const isZone = Boolean(dragGroup || accepts || sortable);
22260
22454
  const enabled = isZone || Boolean(dndRoot);
22261
22455
  const eventBus = useEventBus();
22262
- const parentRoot = React82__default.useContext(RootCtx);
22456
+ const parentRoot = React83__default.useContext(RootCtx);
22263
22457
  const isRoot = enabled && parentRoot === null;
22264
- const zoneId = React82__default.useId();
22458
+ const zoneId = React83__default.useId();
22265
22459
  const ownGroup = dragGroup ?? accepts ?? zoneId;
22266
- const [optimisticOrders, setOptimisticOrders] = React82__default.useState(() => /* @__PURE__ */ new Map());
22267
- const optimisticOrdersRef = React82__default.useRef(optimisticOrders);
22460
+ const [optimisticOrders, setOptimisticOrders] = React83__default.useState(() => /* @__PURE__ */ new Map());
22461
+ const optimisticOrdersRef = React83__default.useRef(optimisticOrders);
22268
22462
  optimisticOrdersRef.current = optimisticOrders;
22269
- const clearOptimisticOrder = React82__default.useCallback((group) => {
22463
+ const clearOptimisticOrder = React83__default.useCallback((group) => {
22270
22464
  setOptimisticOrders((prev) => {
22271
22465
  if (!prev.has(group)) return prev;
22272
22466
  const next = new Map(prev);
@@ -22291,7 +22485,7 @@ function useDataDnd(args) {
22291
22485
  const raw = it[dndItemIdField];
22292
22486
  return raw != null ? String(raw) : `__idx_${idx}`;
22293
22487
  }).join("|");
22294
- const itemIds = React82__default.useMemo(
22488
+ const itemIds = React83__default.useMemo(
22295
22489
  () => orderedItems.map((it, idx) => {
22296
22490
  const raw = it[dndItemIdField];
22297
22491
  return raw != null ? String(raw) : `__idx_${idx}`;
@@ -22302,7 +22496,7 @@ function useDataDnd(args) {
22302
22496
  const raw = it[dndItemIdField];
22303
22497
  return raw != null ? String(raw) : `__${idx}`;
22304
22498
  }).join("|");
22305
- React82__default.useEffect(() => {
22499
+ React83__default.useEffect(() => {
22306
22500
  const root = isRoot ? null : parentRoot;
22307
22501
  if (root) {
22308
22502
  root.clearOptimisticOrder(ownGroup);
@@ -22310,20 +22504,20 @@ function useDataDnd(args) {
22310
22504
  clearOptimisticOrder(ownGroup);
22311
22505
  }
22312
22506
  }, [itemsContentSig, ownGroup]);
22313
- const zonesRef = React82__default.useRef(/* @__PURE__ */ new Map());
22314
- const registerZone = React82__default.useCallback((zoneId2, meta2) => {
22507
+ const zonesRef = React83__default.useRef(/* @__PURE__ */ new Map());
22508
+ const registerZone = React83__default.useCallback((zoneId2, meta2) => {
22315
22509
  zonesRef.current.set(zoneId2, meta2);
22316
22510
  }, []);
22317
- const unregisterZone = React82__default.useCallback((zoneId2) => {
22511
+ const unregisterZone = React83__default.useCallback((zoneId2) => {
22318
22512
  zonesRef.current.delete(zoneId2);
22319
22513
  }, []);
22320
- const [activeDrag, setActiveDrag] = React82__default.useState(null);
22321
- const [overZoneGroup, setOverZoneGroup] = React82__default.useState(null);
22322
- const meta = React82__default.useMemo(
22514
+ const [activeDrag, setActiveDrag] = React83__default.useState(null);
22515
+ const [overZoneGroup, setOverZoneGroup] = React83__default.useState(null);
22516
+ const meta = React83__default.useMemo(
22323
22517
  () => ({ group: ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, rawItems: items, idField: dndItemIdField }),
22324
22518
  [ownGroup, dropEvent, reorderEvent, positionEvent, itemIds, items, dndItemIdField]
22325
22519
  );
22326
- React82__default.useEffect(() => {
22520
+ React83__default.useEffect(() => {
22327
22521
  const target = isRoot ? null : parentRoot;
22328
22522
  if (!target) {
22329
22523
  zonesRef.current.set(zoneId, meta);
@@ -22342,7 +22536,7 @@ function useDataDnd(args) {
22342
22536
  }, [parentRoot, isRoot, zoneId, meta]);
22343
22537
  const sensors = useAlmadarDndSensors(true);
22344
22538
  const collisionDetection = almadarDndCollisionDetection;
22345
- const findZoneByItem = React82__default.useCallback(
22539
+ const findZoneByItem = React83__default.useCallback(
22346
22540
  (id) => {
22347
22541
  for (const z of zonesRef.current.values()) {
22348
22542
  if (z.itemIds.includes(id)) return z;
@@ -22351,7 +22545,7 @@ function useDataDnd(args) {
22351
22545
  },
22352
22546
  []
22353
22547
  );
22354
- React82__default.useCallback(
22548
+ React83__default.useCallback(
22355
22549
  (group) => {
22356
22550
  for (const z of zonesRef.current.values()) {
22357
22551
  if (z.group === group) return z;
@@ -22360,7 +22554,7 @@ function useDataDnd(args) {
22360
22554
  },
22361
22555
  []
22362
22556
  );
22363
- const handleDragEnd = React82__default.useCallback(
22557
+ const handleDragEnd = React83__default.useCallback(
22364
22558
  (event) => {
22365
22559
  const { active, over } = event;
22366
22560
  const activeIdStr = String(active.id);
@@ -22451,8 +22645,8 @@ function useDataDnd(args) {
22451
22645
  },
22452
22646
  [eventBus]
22453
22647
  );
22454
- const sortableData = React82__default.useMemo(() => ({ dndGroup: ownGroup }), [ownGroup]);
22455
- const SortableItem = React82__default.useCallback(
22648
+ const sortableData = React83__default.useMemo(() => ({ dndGroup: ownGroup }), [ownGroup]);
22649
+ const SortableItem = React83__default.useCallback(
22456
22650
  ({ id, children }) => {
22457
22651
  const {
22458
22652
  attributes,
@@ -22492,7 +22686,7 @@ function useDataDnd(args) {
22492
22686
  id: droppableId,
22493
22687
  data: sortableData
22494
22688
  });
22495
- const ctx = React82__default.useContext(RootCtx);
22689
+ const ctx = React83__default.useContext(RootCtx);
22496
22690
  const activeDrag2 = ctx?.activeDrag ?? null;
22497
22691
  const overZoneGroup2 = ctx?.overZoneGroup ?? null;
22498
22692
  const isThisZoneOver = overZoneGroup2 === ownGroup;
@@ -22507,7 +22701,7 @@ function useDataDnd(args) {
22507
22701
  showForeignPlaceholder,
22508
22702
  ctxAvailable: ctx != null
22509
22703
  });
22510
- React82__default.useEffect(() => {
22704
+ React83__default.useEffect(() => {
22511
22705
  dndLog.info("dropzone:isOver:change", { droppableId, group: ownGroup, isOver, isThisZoneOver, showForeignPlaceholder, activeDragSourceGroup: activeDrag2?.sourceGroup ?? null });
22512
22706
  }, [droppableId, isOver, isThisZoneOver, showForeignPlaceholder]);
22513
22707
  return /* @__PURE__ */ jsx(
@@ -22521,11 +22715,11 @@ function useDataDnd(args) {
22521
22715
  }
22522
22716
  );
22523
22717
  };
22524
- const rootContextValue = React82__default.useMemo(
22718
+ const rootContextValue = React83__default.useMemo(
22525
22719
  () => ({ registerZone, unregisterZone, activeDrag, overZoneGroup, optimisticOrders, clearOptimisticOrder }),
22526
22720
  [registerZone, unregisterZone, activeDrag, overZoneGroup, optimisticOrders, clearOptimisticOrder]
22527
22721
  );
22528
- const handleDragStart = React82__default.useCallback((event) => {
22722
+ const handleDragStart = React83__default.useCallback((event) => {
22529
22723
  const sourceZone = findZoneByItem(event.active.id);
22530
22724
  const rect = event.active.rect.current.initial;
22531
22725
  const height = rect?.height && rect.height > 0 ? rect.height : 64;
@@ -22544,7 +22738,7 @@ function useDataDnd(args) {
22544
22738
  isRoot
22545
22739
  });
22546
22740
  }, [findZoneByItem, isRoot, zoneId]);
22547
- const handleDragOver = React82__default.useCallback((event) => {
22741
+ const handleDragOver = React83__default.useCallback((event) => {
22548
22742
  const { active, over } = event;
22549
22743
  const overData = over?.data?.current;
22550
22744
  const overGroup = overData?.dndGroup ?? null;
@@ -22614,7 +22808,7 @@ function useDataDnd(args) {
22614
22808
  return next;
22615
22809
  });
22616
22810
  }, []);
22617
- const handleDragCancel = React82__default.useCallback((event) => {
22811
+ const handleDragCancel = React83__default.useCallback((event) => {
22618
22812
  setActiveDrag(null);
22619
22813
  setOverZoneGroup(null);
22620
22814
  dndLog.warn("dragCancel", {
@@ -22622,12 +22816,12 @@ function useDataDnd(args) {
22622
22816
  reason: "dnd-kit cancelled the drag (escape key, pointer interrupted, or external)"
22623
22817
  });
22624
22818
  }, []);
22625
- const handleDragEndWithCleanup = React82__default.useCallback((event) => {
22819
+ const handleDragEndWithCleanup = React83__default.useCallback((event) => {
22626
22820
  handleDragEnd(event);
22627
22821
  setActiveDrag(null);
22628
22822
  setOverZoneGroup(null);
22629
22823
  }, [handleDragEnd]);
22630
- const wrapContainer = React82__default.useCallback(
22824
+ const wrapContainer = React83__default.useCallback(
22631
22825
  (children) => {
22632
22826
  if (!enabled) return children;
22633
22827
  const strategy = layout === "grid" ? rectSortingStrategy : verticalListSortingStrategy;
@@ -22681,7 +22875,7 @@ var init_useDataDnd = __esm({
22681
22875
  init_useAlmadarDndCollision();
22682
22876
  init_Box();
22683
22877
  dndLog = createLogger("almadar:ui:dnd");
22684
- RootCtx = React82__default.createContext(null);
22878
+ RootCtx = React83__default.createContext(null);
22685
22879
  }
22686
22880
  });
22687
22881
  function renderIconInput(icon, props) {
@@ -23223,7 +23417,7 @@ function DataList({
23223
23417
  }) {
23224
23418
  const eventBus = useEventBus();
23225
23419
  const { t } = useTranslate();
23226
- const [visibleCount, setVisibleCount] = React82__default.useState(pageSize || Infinity);
23420
+ const [visibleCount, setVisibleCount] = React83__default.useState(pageSize || Infinity);
23227
23421
  const fieldDefs = fields ?? columns ?? [];
23228
23422
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
23229
23423
  const dnd = useDataDnd({
@@ -23239,14 +23433,14 @@ function DataList({
23239
23433
  dndRoot
23240
23434
  });
23241
23435
  const orderedData = dnd.orderedItems;
23242
- const allData = React82__default.useMemo(
23436
+ const allData = React83__default.useMemo(
23243
23437
  () => sortRows(orderedData, sortBy, sortDirection),
23244
23438
  [orderedData, sortBy, sortDirection]
23245
23439
  );
23246
23440
  const data = pageSize > 0 ? allData.slice(0, visibleCount) : allData;
23247
23441
  const hasMoreLocal = pageSize > 0 && visibleCount < allData.length;
23248
23442
  const hasRenderProp = typeof children === "function";
23249
- React82__default.useEffect(() => {
23443
+ React83__default.useEffect(() => {
23250
23444
  const renderItemTypeOf = typeof schemaRenderItem;
23251
23445
  const childrenTypeOf = typeof children;
23252
23446
  if (data.length > 0 && !hasRenderProp) {
@@ -23361,7 +23555,7 @@ function DataList({
23361
23555
  return v === void 0 || v === null || v === "" ? raw : String(v);
23362
23556
  };
23363
23557
  return /* @__PURE__ */ jsxs(VStack, { gap: "sm", className: cn("py-2", className), children: [
23364
- groups2.map((group, gi) => /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
23558
+ groups2.map((group, gi) => /* @__PURE__ */ jsxs(React83__default.Fragment, { children: [
23365
23559
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: "my-2" }),
23366
23560
  group.items.map((itemData, index) => {
23367
23561
  const id = itemData.id || `${gi}-${index}`;
@@ -23397,7 +23591,11 @@ function DataList({
23397
23591
  metaFields.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "mt-1 flex-wrap", children: metaFields.map((f3) => {
23398
23592
  const v = getNestedValue(itemData, f3.name);
23399
23593
  if (v === void 0 || v === null || v === "") return null;
23400
- return f3.variant === "badge" ? /* @__PURE__ */ jsx(Badge, { variant: statusVariant3(String(v)), children: String(v) }, f3.name) : /* @__PURE__ */ jsx(
23594
+ return f3.variant === "badge" ? (
23595
+ // `format` applies here too — a boolean field badged
23596
+ // without it renders the raw "false" instead of "No".
23597
+ /* @__PURE__ */ jsx(Badge, { variant: statusVariant3(String(v)), children: formatValue2(v, f3.format) }, f3.name)
23598
+ ) : /* @__PURE__ */ jsx(
23401
23599
  Typography,
23402
23600
  {
23403
23601
  variant: "caption",
@@ -23509,7 +23707,7 @@ function DataList({
23509
23707
  if (val === void 0 || val === null) return null;
23510
23708
  return /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center flex-shrink-0", children: [
23511
23709
  field.icon && renderIconInput2(field.icon, { size: "xs" }),
23512
- /* @__PURE__ */ jsx(Badge, { variant: statusVariant3(String(val)), children: String(val) })
23710
+ /* @__PURE__ */ jsx(Badge, { variant: statusVariant3(String(val)), children: formatValue2(val, field.format) })
23513
23711
  ] }, field.name);
23514
23712
  })
23515
23713
  ] }),
@@ -23556,7 +23754,7 @@ function DataList({
23556
23754
  className
23557
23755
  ),
23558
23756
  children: [
23559
- groups.map((group, gi) => /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
23757
+ groups.map((group, gi) => /* @__PURE__ */ jsxs(React83__default.Fragment, { children: [
23560
23758
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-4" : "mt-0" }),
23561
23759
  group.items.map(
23562
23760
  (itemData, index) => renderItem(itemData, index, gi === groups.length - 1 && index === group.items.length - 1)
@@ -23643,7 +23841,7 @@ var init_FormSection = __esm({
23643
23841
  columns = 1,
23644
23842
  className
23645
23843
  }) => {
23646
- const [collapsed, setCollapsed] = React82__default.useState(defaultCollapsed);
23844
+ const [collapsed, setCollapsed] = React83__default.useState(defaultCollapsed);
23647
23845
  const { t } = useTranslate();
23648
23846
  const eventBus = useEventBus();
23649
23847
  const gridClass = {
@@ -23651,7 +23849,7 @@ var init_FormSection = __esm({
23651
23849
  2: "grid-cols-1 md:grid-cols-2",
23652
23850
  3: "grid-cols-1 md:grid-cols-2 lg:grid-cols-3"
23653
23851
  }[columns];
23654
- React82__default.useCallback(() => {
23852
+ React83__default.useCallback(() => {
23655
23853
  if (collapsible) {
23656
23854
  setCollapsed((prev) => !prev);
23657
23855
  eventBus.emit("UI:TOGGLE_COLLAPSE", { collapsed: !collapsed });
@@ -23748,6 +23946,182 @@ var init_FormSection = __esm({
23748
23946
  FormActions.displayName = "FormActions";
23749
23947
  }
23750
23948
  });
23949
+ var ALL_CATEGORY, MAX_RENDERED, GridPicker;
23950
+ var init_GridPicker = __esm({
23951
+ "components/core/molecules/GridPicker.tsx"() {
23952
+ "use client";
23953
+ init_cn();
23954
+ init_Input();
23955
+ init_Badge();
23956
+ init_Stack();
23957
+ ALL_CATEGORY = "__all__";
23958
+ MAX_RENDERED = 300;
23959
+ GridPicker = ({
23960
+ items,
23961
+ value,
23962
+ onChange,
23963
+ categories,
23964
+ searchPlaceholder,
23965
+ renderThumbnail,
23966
+ cellSize = 32,
23967
+ className
23968
+ }) => {
23969
+ const [search, setSearch] = useState("");
23970
+ const [activeCategory, setActiveCategory] = useState(ALL_CATEGORY);
23971
+ const gridRef = useRef(null);
23972
+ const categoryChips = useMemo(() => {
23973
+ if (categories !== void 0) return categories;
23974
+ const seen = [];
23975
+ for (const item of items) {
23976
+ if (!seen.includes(item.category)) seen.push(item.category);
23977
+ }
23978
+ return seen;
23979
+ }, [categories, items]);
23980
+ const filtered = useMemo(() => {
23981
+ const needle = search.trim().toLowerCase();
23982
+ return items.filter((item) => {
23983
+ const matchesCategory = activeCategory === ALL_CATEGORY || item.category === activeCategory;
23984
+ const matchesSearch = needle === "" || item.label.toLowerCase().includes(needle) || item.keywords !== void 0 && item.keywords.some((k) => k.toLowerCase().includes(needle));
23985
+ return matchesCategory && matchesSearch;
23986
+ });
23987
+ }, [items, search, activeCategory]);
23988
+ const visible = useMemo(() => filtered.slice(0, MAX_RENDERED), [filtered]);
23989
+ const truncated = filtered.length - visible.length;
23990
+ const select = useCallback(
23991
+ (item) => {
23992
+ onChange(item.id);
23993
+ },
23994
+ [onChange]
23995
+ );
23996
+ const handleKeyDown = useCallback(
23997
+ (e, index) => {
23998
+ const cells = gridRef.current?.querySelectorAll(
23999
+ "[data-gridpicker-cell]"
24000
+ );
24001
+ if (cells === void 0 || cells.length === 0) return;
24002
+ const columns = (() => {
24003
+ const grid = gridRef.current;
24004
+ if (grid === null) return 1;
24005
+ const style = window.getComputedStyle(grid);
24006
+ const cols = style.gridTemplateColumns.split(" ").filter(Boolean).length;
24007
+ return cols > 0 ? cols : 1;
24008
+ })();
24009
+ let next = -1;
24010
+ if (e.key === "ArrowRight") next = index + 1;
24011
+ else if (e.key === "ArrowLeft") next = index - 1;
24012
+ else if (e.key === "ArrowDown") next = index + columns;
24013
+ else if (e.key === "ArrowUp") next = index - columns;
24014
+ else if (e.key === "Enter" || e.key === " ") {
24015
+ e.preventDefault();
24016
+ select(filtered[index]);
24017
+ return;
24018
+ } else {
24019
+ return;
24020
+ }
24021
+ e.preventDefault();
24022
+ if (next >= 0 && next < cells.length) {
24023
+ cells[next].focus();
24024
+ }
24025
+ },
24026
+ [filtered, select]
24027
+ );
24028
+ return /* @__PURE__ */ jsxs(VStack, { gap: "sm", className: cn("w-full", className), children: [
24029
+ /* @__PURE__ */ jsx(
24030
+ Input,
24031
+ {
24032
+ type: "search",
24033
+ icon: "search",
24034
+ value: search,
24035
+ placeholder: searchPlaceholder,
24036
+ clearable: true,
24037
+ onClear: () => setSearch(""),
24038
+ onChange: (e) => setSearch(e.target.value)
24039
+ }
24040
+ ),
24041
+ categoryChips.length > 0 && /* @__PURE__ */ jsxs(HStack, { gap: "xs", wrap: true, children: [
24042
+ /* @__PURE__ */ jsx(
24043
+ Badge,
24044
+ {
24045
+ variant: activeCategory === ALL_CATEGORY ? "primary" : "neutral",
24046
+ size: "sm",
24047
+ role: "button",
24048
+ tabIndex: 0,
24049
+ "aria-pressed": activeCategory === ALL_CATEGORY,
24050
+ className: "cursor-pointer",
24051
+ onClick: () => setActiveCategory(ALL_CATEGORY),
24052
+ onKeyDown: (e) => {
24053
+ if (e.key === "Enter" || e.key === " ") {
24054
+ e.preventDefault();
24055
+ setActiveCategory(ALL_CATEGORY);
24056
+ }
24057
+ },
24058
+ children: "All"
24059
+ }
24060
+ ),
24061
+ categoryChips.map((category) => /* @__PURE__ */ jsx(
24062
+ Badge,
24063
+ {
24064
+ variant: activeCategory === category ? "primary" : "neutral",
24065
+ size: "sm",
24066
+ role: "button",
24067
+ tabIndex: 0,
24068
+ "aria-pressed": activeCategory === category,
24069
+ className: "cursor-pointer",
24070
+ onClick: () => setActiveCategory(category),
24071
+ onKeyDown: (e) => {
24072
+ if (e.key === "Enter" || e.key === " ") {
24073
+ e.preventDefault();
24074
+ setActiveCategory(category);
24075
+ }
24076
+ },
24077
+ children: category
24078
+ },
24079
+ category
24080
+ ))
24081
+ ] }),
24082
+ /* @__PURE__ */ jsx(
24083
+ "div",
24084
+ {
24085
+ ref: gridRef,
24086
+ role: "listbox",
24087
+ className: "grid gap-1 overflow-y-auto max-h-64 p-1",
24088
+ style: {
24089
+ gridTemplateColumns: `repeat(auto-fill, minmax(${cellSize}px, 1fr))`
24090
+ },
24091
+ children: visible.map((item, index) => {
24092
+ const selected = item.id === value;
24093
+ return /* @__PURE__ */ jsx(
24094
+ "button",
24095
+ {
24096
+ type: "button",
24097
+ role: "option",
24098
+ "aria-selected": selected,
24099
+ "aria-label": item.label,
24100
+ title: item.label,
24101
+ "data-gridpicker-cell": true,
24102
+ tabIndex: selected || value === void 0 && index === 0 ? 0 : -1,
24103
+ onClick: () => select(item),
24104
+ onKeyDown: (e) => handleKeyDown(e, index),
24105
+ className: cn(
24106
+ "flex items-center justify-center rounded-sm",
24107
+ "transition-colors hover:bg-muted",
24108
+ "focus:outline-none focus:ring-1 focus:ring-ring",
24109
+ selected && "bg-primary/10 ring-1 ring-primary"
24110
+ ),
24111
+ style: { width: cellSize, height: cellSize },
24112
+ children: renderThumbnail(item)
24113
+ },
24114
+ item.id
24115
+ );
24116
+ })
24117
+ }
24118
+ ),
24119
+ truncated > 0 && /* @__PURE__ */ jsx("div", { className: "px-1 text-xs text-muted-foreground", children: `+${truncated} more \u2014 refine your search` })
24120
+ ] });
24121
+ };
24122
+ GridPicker.displayName = "GridPicker";
24123
+ }
24124
+ });
23751
24125
  function fileIcon(name) {
23752
24126
  const ext = name.split(".").pop()?.toLowerCase() ?? "";
23753
24127
  switch (ext) {
@@ -24456,7 +24830,7 @@ var init_Flex = __esm({
24456
24830
  flexStyle.flexBasis = typeof basis === "number" ? `${basis}px` : basis;
24457
24831
  }
24458
24832
  }
24459
- return React82__default.createElement(Component, {
24833
+ return React83__default.createElement(Component, {
24460
24834
  className: cn(
24461
24835
  inline ? "inline-flex" : "flex",
24462
24836
  directionStyles[direction],
@@ -24575,7 +24949,7 @@ var init_Grid = __esm({
24575
24949
  as: Component = "div"
24576
24950
  }) => {
24577
24951
  const mergedStyle = rows ? { gridTemplateRows: `repeat(${rows}, minmax(0, 1fr))`, ...style } : style;
24578
- return React82__default.createElement(
24952
+ return React83__default.createElement(
24579
24953
  Component,
24580
24954
  {
24581
24955
  className: cn(
@@ -24712,9 +25086,16 @@ var init_Popover = __esm({
24712
25086
  position = "bottom",
24713
25087
  trigger = "click",
24714
25088
  showArrow = true,
25089
+ open,
25090
+ onOpenChange,
24715
25091
  className
24716
25092
  }) => {
24717
- const [isOpen, setIsOpen] = useState(false);
25093
+ const [uncontrolledOpen, setUncontrolledOpen] = useState(false);
25094
+ const isOpen = open !== void 0 ? open : uncontrolledOpen;
25095
+ const setIsOpen = (next) => {
25096
+ if (open === void 0) setUncontrolledOpen(next);
25097
+ onOpenChange?.(next);
25098
+ };
24718
25099
  const [triggerRect, setTriggerRect] = useState(null);
24719
25100
  const [popoverWidth, setPopoverWidth] = useState(0);
24720
25101
  const triggerRef = useRef(null);
@@ -24747,6 +25128,23 @@ var init_Popover = __esm({
24747
25128
  updatePosition();
24748
25129
  }
24749
25130
  }, [isOpen]);
25131
+ useEffect(() => {
25132
+ if (!isOpen) return;
25133
+ let raf = 0;
25134
+ let lastTop = Number.NaN;
25135
+ let lastLeft = Number.NaN;
25136
+ const track = () => {
25137
+ const rect = triggerRef.current?.getBoundingClientRect();
25138
+ if (rect && (rect.top !== lastTop || rect.left !== lastLeft)) {
25139
+ lastTop = rect.top;
25140
+ lastLeft = rect.left;
25141
+ updatePosition();
25142
+ }
25143
+ raf = requestAnimationFrame(track);
25144
+ };
25145
+ raf = requestAnimationFrame(track);
25146
+ return () => cancelAnimationFrame(raf);
25147
+ }, [isOpen]);
24750
25148
  useEffect(() => {
24751
25149
  if (!mounted) setPopoverWidth(0);
24752
25150
  }, [mounted]);
@@ -24783,9 +25181,9 @@ var init_Popover = __esm({
24783
25181
  onMouseLeave: handleClose,
24784
25182
  onPointerDown: tapTriggerProps.onPointerDown
24785
25183
  };
24786
- const childElement = React82__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
25184
+ const childElement = React83__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
24787
25185
  const childPointerDown = childElement.props.onPointerDown;
24788
- const triggerElement = React82__default.cloneElement(
25186
+ const triggerElement = React83__default.cloneElement(
24789
25187
  childElement,
24790
25188
  {
24791
25189
  ref: triggerRef,
@@ -25394,9 +25792,9 @@ var init_Tooltip = __esm({
25394
25792
  if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
25395
25793
  };
25396
25794
  }, []);
25397
- const triggerElement = React82__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
25795
+ const triggerElement = React83__default.isValidElement(children) ? children : /* @__PURE__ */ jsx("span", { children });
25398
25796
  const childPointerDown = triggerElement.props.onPointerDown;
25399
- const trigger = React82__default.cloneElement(triggerElement, {
25797
+ const trigger = React83__default.cloneElement(triggerElement, {
25400
25798
  ref: triggerRef,
25401
25799
  onMouseEnter: handleMouseEnter,
25402
25800
  onMouseLeave: handleMouseLeave,
@@ -25486,7 +25884,7 @@ var init_WizardProgress = __esm({
25486
25884
  children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: normalizedSteps.map((step, index) => {
25487
25885
  const isActive = index === currentStep;
25488
25886
  const isCompleted = index < currentStep;
25489
- return /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
25887
+ return /* @__PURE__ */ jsxs(React83__default.Fragment, { children: [
25490
25888
  /* @__PURE__ */ jsx(
25491
25889
  "button",
25492
25890
  {
@@ -26095,6 +26493,80 @@ var init_FlipCard = __esm({
26095
26493
  FlipCard.displayName = "FlipCard";
26096
26494
  }
26097
26495
  });
26496
+ var EMOJI_ITEMS, EmojiPicker;
26497
+ var init_EmojiPicker = __esm({
26498
+ "components/core/molecules/EmojiPicker.tsx"() {
26499
+ "use client";
26500
+ init_useEventBus();
26501
+ init_Button();
26502
+ init_GridPicker();
26503
+ init_Popover();
26504
+ EMOJI_ITEMS = (() => {
26505
+ const items = [];
26506
+ for (const name of ordered) {
26507
+ const entry = lib[name];
26508
+ if (entry === void 0 || entry.char === null || entry.char === "") continue;
26509
+ items.push({
26510
+ id: entry.char,
26511
+ label: name.replace(/_/g, " "),
26512
+ category: entry.category.replace(/_/g, " "),
26513
+ keywords: entry.keywords
26514
+ });
26515
+ }
26516
+ return items;
26517
+ })();
26518
+ EmojiPicker = ({
26519
+ pickEvent,
26520
+ position = "top",
26521
+ triggerIcon = "smile",
26522
+ triggerLabel = "Add emoji",
26523
+ className
26524
+ }) => {
26525
+ const eventBus = useEventBus();
26526
+ const [open, setOpen] = useState(false);
26527
+ const handlePick = (glyph) => {
26528
+ if (pickEvent !== void 0) {
26529
+ const payload = { emoji: glyph };
26530
+ eventBus.emit(`UI:${pickEvent}`, payload);
26531
+ }
26532
+ setOpen(false);
26533
+ };
26534
+ return /* @__PURE__ */ jsx(
26535
+ Popover,
26536
+ {
26537
+ position,
26538
+ trigger: "click",
26539
+ showArrow: false,
26540
+ open,
26541
+ onOpenChange: setOpen,
26542
+ content: /* @__PURE__ */ jsx(
26543
+ GridPicker,
26544
+ {
26545
+ items: EMOJI_ITEMS,
26546
+ onChange: handlePick,
26547
+ searchPlaceholder: "Search emoji\u2026",
26548
+ renderThumbnail: (item) => /* @__PURE__ */ jsx("span", { className: "text-xl leading-none", "aria-hidden": "true", children: item.id }),
26549
+ cellSize: 32,
26550
+ className: "w-80"
26551
+ }
26552
+ ),
26553
+ children: /* @__PURE__ */ jsx(
26554
+ Button,
26555
+ {
26556
+ variant: "ghost",
26557
+ icon: triggerIcon,
26558
+ "aria-label": triggerLabel,
26559
+ title: triggerLabel,
26560
+ className,
26561
+ "data-testid": "emoji-picker-trigger"
26562
+ }
26563
+ )
26564
+ }
26565
+ );
26566
+ };
26567
+ EmojiPicker.displayName = "EmojiPicker";
26568
+ }
26569
+ });
26098
26570
  function toISODate(d) {
26099
26571
  return d.toISOString().slice(0, 10);
26100
26572
  }
@@ -27047,12 +27519,12 @@ var init_MapView = __esm({
27047
27519
  shadowSize: [41, 41]
27048
27520
  });
27049
27521
  L.Marker.prototype.options.icon = defaultIcon;
27050
- const { useEffect: useEffect59, useRef: useRef60, useCallback: useCallback88, useState: useState89 } = React82__default;
27522
+ const { useEffect: useEffect59, useRef: useRef61, useCallback: useCallback89, useState: useState91 } = React83__default;
27051
27523
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
27052
27524
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
27053
27525
  function MapUpdater({ centerLat, centerLng, zoom }) {
27054
27526
  const map = useMap();
27055
- const prevRef = useRef60({ centerLat, centerLng, zoom });
27527
+ const prevRef = useRef61({ centerLat, centerLng, zoom });
27056
27528
  useEffect59(() => {
27057
27529
  const prev = prevRef.current;
27058
27530
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
@@ -27092,8 +27564,8 @@ var init_MapView = __esm({
27092
27564
  showAttribution = true
27093
27565
  }) {
27094
27566
  const eventBus = useEventBus2();
27095
- const [clickedPosition, setClickedPosition] = useState89(null);
27096
- const handleMapClick = useCallback88((lat, lng) => {
27567
+ const [clickedPosition, setClickedPosition] = useState91(null);
27568
+ const handleMapClick = useCallback89((lat, lng) => {
27097
27569
  if (showClickedPin) {
27098
27570
  setClickedPosition({ lat, lng });
27099
27571
  }
@@ -27102,7 +27574,7 @@ var init_MapView = __esm({
27102
27574
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
27103
27575
  }
27104
27576
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
27105
- const handleMarkerClick = useCallback88((marker) => {
27577
+ const handleMarkerClick = useCallback89((marker) => {
27106
27578
  onMarkerClick?.(marker);
27107
27579
  if (markerClickEvent) {
27108
27580
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -27917,6 +28389,7 @@ function TableView({
27917
28389
  fields,
27918
28390
  itemActions,
27919
28391
  maxInlineActions,
28392
+ itemClickEvent,
27920
28393
  selectable = false,
27921
28394
  selectEvent,
27922
28395
  selectedIds,
@@ -27944,8 +28417,8 @@ function TableView({
27944
28417
  }) {
27945
28418
  const eventBus = useEventBus();
27946
28419
  const { t } = useTranslate();
27947
- const [visibleCount, setVisibleCount] = React82__default.useState(pageSize > 0 ? pageSize : Infinity);
27948
- const [localSelected, setLocalSelected] = React82__default.useState(/* @__PURE__ */ new Set());
28420
+ const [visibleCount, setVisibleCount] = React83__default.useState(pageSize > 0 ? pageSize : Infinity);
28421
+ const [localSelected, setLocalSelected] = React83__default.useState(/* @__PURE__ */ new Set());
27949
28422
  const colDefs = (Array.isArray(columns) ? columns : void 0) ?? (Array.isArray(fields) ? fields : void 0) ?? [];
27950
28423
  const actionDefs = Array.isArray(itemActions) ? itemActions : [];
27951
28424
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
@@ -27961,13 +28434,13 @@ function TableView({
27961
28434
  dndItemIdField,
27962
28435
  dndRoot
27963
28436
  });
27964
- const ordered = dnd.orderedItems;
27965
- const data = pageSize > 0 ? ordered.slice(0, visibleCount) : ordered;
27966
- const hasMore = pageSize > 0 && visibleCount < ordered.length;
28437
+ const ordered2 = dnd.orderedItems;
28438
+ const data = pageSize > 0 ? ordered2.slice(0, visibleCount) : ordered2;
28439
+ const hasMore = pageSize > 0 && visibleCount < ordered2.length;
27967
28440
  const hasRenderProp = typeof children === "function";
27968
28441
  const idField = dndItemIdField ?? "id";
27969
28442
  const isCoarsePointer = useMediaQuery("(pointer: coarse)");
27970
- React82__default.useEffect(() => {
28443
+ React83__default.useEffect(() => {
27971
28444
  tableViewLog.debug("render", {
27972
28445
  rowCount: data.length,
27973
28446
  colCount: colDefs.length,
@@ -28016,7 +28489,15 @@ function TableView({
28016
28489
  };
28017
28490
  eventBus.emit(`UI:${action.event}`, payload);
28018
28491
  };
28019
- const colFloors = React82__default.useMemo(
28492
+ const handleRowClick = (row) => () => {
28493
+ if (!itemClickEvent) return;
28494
+ const payload = {
28495
+ id: row.id,
28496
+ row
28497
+ };
28498
+ eventBus.emit(`UI:${itemClickEvent}`, payload);
28499
+ };
28500
+ const colFloors = React83__default.useMemo(
28020
28501
  () => colDefs.map((col) => {
28021
28502
  const longest = data.reduce((widest, row) => {
28022
28503
  const cell = formatCell(asFieldValue(getNestedValue(row, col.field ?? col.key)), col.format);
@@ -28092,10 +28573,12 @@ function TableView({
28092
28573
  role: "row",
28093
28574
  "data-entity-row": true,
28094
28575
  "data-entity-id": id,
28576
+ onClick: itemClickEvent ? handleRowClick(row) : void 0,
28095
28577
  style: !hasRenderProp ? { gridTemplateColumns } : void 0,
28096
28578
  className: cn(
28097
28579
  "group items-center gap-3 transition-colors duration-fast",
28098
28580
  hasRenderProp ? "flex" : "grid",
28581
+ itemClickEvent && "cursor-pointer",
28099
28582
  lk.rowPad,
28100
28583
  lk.divider && "border-b border-[var(--color-border)]",
28101
28584
  lk.striped && index % 2 === 1 && "bg-[var(--color-surface-subtle)]",
@@ -28103,7 +28586,7 @@ function TableView({
28103
28586
  look === "bordered" && "[&>*]:border-r [&>*]:border-[var(--color-border)] [&>*:last-child]:border-r-0"
28104
28587
  ),
28105
28588
  children: [
28106
- selectable && /* @__PURE__ */ jsx(Box, { className: "flex items-center", children: /* @__PURE__ */ jsx(
28589
+ selectable && /* @__PURE__ */ jsx(Box, { className: "flex items-center", onClick: itemClickEvent ? (e) => e.stopPropagation() : void 0, children: /* @__PURE__ */ jsx(
28107
28590
  Checkbox,
28108
28591
  {
28109
28592
  checked: selected.has(id),
@@ -28128,6 +28611,7 @@ function TableView({
28128
28611
  HStack,
28129
28612
  {
28130
28613
  gap: "xs",
28614
+ onClick: itemClickEvent ? (e) => e.stopPropagation() : void 0,
28131
28615
  className: cn(
28132
28616
  // Pinned: the fixed column tracks routinely overflow the caller's
28133
28617
  // scroll container, which used to leave the actions off-screen.
@@ -28175,12 +28659,12 @@ function TableView({
28175
28659
  ]
28176
28660
  }
28177
28661
  );
28178
- return dnd.isZone ? /* @__PURE__ */ jsx(dnd.SortableItem, { id: row[idField] ?? id, children: rowInner }, id) : /* @__PURE__ */ jsx(React82__default.Fragment, { children: rowInner }, id);
28662
+ return dnd.isZone ? /* @__PURE__ */ jsx(dnd.SortableItem, { id: row[idField] ?? id, children: rowInner }, id) : /* @__PURE__ */ jsx(React83__default.Fragment, { children: rowInner }, id);
28179
28663
  };
28180
28664
  const items = Array.from(data);
28181
28665
  const groups = groupBy ? groupData2(items, groupBy) : [{ label: "", items }];
28182
28666
  let runningIndex = 0;
28183
- const body = /* @__PURE__ */ jsx(Box, { role: "rowgroup", children: groups.map((group, gi) => /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
28667
+ const body = /* @__PURE__ */ jsx(Box, { role: "rowgroup", children: groups.map((group, gi) => /* @__PURE__ */ jsxs(React83__default.Fragment, { children: [
28184
28668
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-3" : "mt-0" }),
28185
28669
  group.items.map((row) => renderRow(row, runningIndex++))
28186
28670
  ] }, gi)) });
@@ -28197,7 +28681,7 @@ function TableView({
28197
28681
  /* @__PURE__ */ jsx(Icon, { name: "chevron-down", size: "xs", className: "mr-1" }),
28198
28682
  t("common.showMore"),
28199
28683
  " (",
28200
- t("common.remaining", { count: ordered.length - visibleCount }),
28684
+ t("common.remaining", { count: ordered2.length - visibleCount }),
28201
28685
  ")"
28202
28686
  ] }) })
28203
28687
  ]
@@ -29405,7 +29889,7 @@ var init_StepFlow = __esm({
29405
29889
  className
29406
29890
  }) => {
29407
29891
  if (orientation === "vertical") {
29408
- return /* @__PURE__ */ jsx(VStack, { gap: "none", className: cn("w-full", className), children: steps.map((step, index) => /* @__PURE__ */ jsx(React82__default.Fragment, { children: /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "start", className: "w-full", children: [
29892
+ return /* @__PURE__ */ jsx(VStack, { gap: "none", className: cn("w-full", className), children: steps.map((step, index) => /* @__PURE__ */ jsx(React83__default.Fragment, { children: /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "start", className: "w-full", children: [
29409
29893
  /* @__PURE__ */ jsxs(VStack, { gap: "none", align: "center", children: [
29410
29894
  /* @__PURE__ */ jsx(StepCircle, { step, index }),
29411
29895
  showConnectors && index < steps.length - 1 && /* @__PURE__ */ jsx(Box, { className: "w-px h-8 bg-border" })
@@ -29416,7 +29900,7 @@ var init_StepFlow = __esm({
29416
29900
  ] })
29417
29901
  ] }) }, index)) });
29418
29902
  }
29419
- return /* @__PURE__ */ jsx(Box, { className: cn("w-full flex flex-col md:flex-row items-start gap-0", className), children: steps.map((step, index) => /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
29903
+ return /* @__PURE__ */ jsx(Box, { className: cn("w-full flex flex-col md:flex-row items-start gap-0", className), children: steps.map((step, index) => /* @__PURE__ */ jsxs(React83__default.Fragment, { children: [
29420
29904
  /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", className: "flex-1 w-full md:w-auto", children: [
29421
29905
  /* @__PURE__ */ jsx(StepCircle, { step, index }),
29422
29906
  /* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-center", children: step.title }),
@@ -30406,7 +30890,7 @@ var init_LikertScale = __esm({
30406
30890
  md: "text-base",
30407
30891
  lg: "text-lg"
30408
30892
  };
30409
- LikertScale = React82__default.forwardRef(
30893
+ LikertScale = React83__default.forwardRef(
30410
30894
  ({
30411
30895
  question,
30412
30896
  options = DEFAULT_LIKERT_OPTIONS,
@@ -30418,7 +30902,7 @@ var init_LikertScale = __esm({
30418
30902
  variant = "radios",
30419
30903
  className
30420
30904
  }, ref) => {
30421
- const groupId = React82__default.useId();
30905
+ const groupId = React83__default.useId();
30422
30906
  const eventBus = useEventBus();
30423
30907
  const handleSelect = useCallback(
30424
30908
  (next) => {
@@ -32707,7 +33191,7 @@ var init_DocBreadcrumb = __esm({
32707
33191
  "aria-label": t("aria.breadcrumb"),
32708
33192
  children: /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "center", wrap: true, children: items.map((item, idx) => {
32709
33193
  const isLast = idx === items.length - 1;
32710
- return /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
33194
+ return /* @__PURE__ */ jsxs(React83__default.Fragment, { children: [
32711
33195
  idx > 0 && /* @__PURE__ */ jsx(
32712
33196
  Icon,
32713
33197
  {
@@ -33576,7 +34060,7 @@ var init_MiniStateMachine = __esm({
33576
34060
  const x = 2 + i * (NODE_W + GAP + ARROW_W + GAP);
33577
34061
  const tc = transitionCounts[s.name] ?? 0;
33578
34062
  const role = getStateRole(s.name, s.isInitial ?? void 0, s.isTerminal ?? void 0, tc, maxTC);
33579
- return /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
34063
+ return /* @__PURE__ */ jsxs(React83__default.Fragment, { children: [
33580
34064
  /* @__PURE__ */ jsx(
33581
34065
  AvlState,
33582
34066
  {
@@ -33780,7 +34264,7 @@ var init_PageHeader = __esm({
33780
34264
  info: "bg-info/10 text-info"
33781
34265
  };
33782
34266
  return /* @__PURE__ */ jsxs(Box, { className: cn("mb-6", className), children: [
33783
- breadcrumbs && breadcrumbs.length > 0 && /* @__PURE__ */ jsx(Box, { as: "nav", className: "mb-4", children: /* @__PURE__ */ jsx(Box, { as: "ol", className: "flex items-center gap-2 text-sm", children: breadcrumbs.map((crumb, idx) => /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
34267
+ breadcrumbs && breadcrumbs.length > 0 && /* @__PURE__ */ jsx(Box, { as: "nav", className: "mb-4", children: /* @__PURE__ */ jsx(Box, { as: "ol", className: "flex items-center gap-2 text-sm", children: breadcrumbs.map((crumb, idx) => /* @__PURE__ */ jsxs(React83__default.Fragment, { children: [
33784
34268
  idx > 0 && /* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: "/" }),
33785
34269
  crumb.href ? /* @__PURE__ */ jsx(
33786
34270
  "a",
@@ -34138,7 +34622,7 @@ var init_Section = __esm({
34138
34622
  as: Component = "section"
34139
34623
  }) => {
34140
34624
  const hasHeader = title || description || action;
34141
- return React82__default.createElement(
34625
+ return React83__default.createElement(
34142
34626
  Component,
34143
34627
  {
34144
34628
  className: cn(
@@ -34512,7 +34996,7 @@ var init_WizardContainer = __esm({
34512
34996
  const isCompleted = index < currentStep;
34513
34997
  const stepKey = step.id ?? step.tabId ?? `step-${index}`;
34514
34998
  const stepTitle = step.title ?? step.name ?? `Step ${index + 1}`;
34515
- return /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
34999
+ return /* @__PURE__ */ jsxs(React83__default.Fragment, { children: [
34516
35000
  /* @__PURE__ */ jsx(
34517
35001
  Button,
34518
35002
  {
@@ -36299,7 +36783,7 @@ var init_ImportPreviewTree = __esm({
36299
36783
  const renderUnit = (unit, childrenByParent, depth) => {
36300
36784
  const summary = fieldSummary(unit);
36301
36785
  const children = childrenByParent.get(unit.ref) ?? [];
36302
- return /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
36786
+ return /* @__PURE__ */ jsxs(React83__default.Fragment, { children: [
36303
36787
  /* @__PURE__ */ jsxs(
36304
36788
  Box,
36305
36789
  {
@@ -36396,7 +36880,7 @@ var init_ImportProgress = __esm({
36396
36880
  PIPELINE.map((key, index) => {
36397
36881
  const isComplete = index < currentIndex;
36398
36882
  const isActive = index === currentIndex;
36399
- return /* @__PURE__ */ jsxs(React82__default.Fragment, { children: [
36883
+ return /* @__PURE__ */ jsxs(React83__default.Fragment, { children: [
36400
36884
  index > 0 ? /* @__PURE__ */ jsx(Box, { className: "h-px w-4 bg-border" }) : null,
36401
36885
  /* @__PURE__ */ jsxs(Box, { className: "flex items-center gap-1", "data-testid": `import-progress-step-${key}`, children: [
36402
36886
  /* @__PURE__ */ jsx(
@@ -37509,7 +37993,7 @@ var init_DrawGroup = __esm({
37509
37993
  }
37510
37994
  });
37511
37995
  function extractTitle(children) {
37512
- if (!React82__default.isValidElement(children)) return void 0;
37996
+ if (!React83__default.isValidElement(children)) return void 0;
37513
37997
  const props = children.props;
37514
37998
  if (typeof props.title === "string") {
37515
37999
  return props.title;
@@ -37859,12 +38343,12 @@ var init_Form = __esm({
37859
38343
  const isSchemaEntity = isOrbitalEntitySchema(entity);
37860
38344
  const resolvedEntity = isSchemaEntity ? entity : void 0;
37861
38345
  const entityName = typeof entity === "string" ? entity : resolvedEntity?.name;
37862
- const normalizedInitialData = React82__default.useMemo(() => {
38346
+ const normalizedInitialData = React83__default.useMemo(() => {
37863
38347
  const entityRowAsInitial = isPlainEntityRow(entity) ? entity : void 0;
37864
38348
  const callerInitial = initialData !== null && typeof initialData === "object" && !Array.isArray(initialData) ? initialData : {};
37865
38349
  return entityRowAsInitial !== void 0 ? { ...entityRowAsInitial, ...callerInitial } : callerInitial;
37866
38350
  }, [entity, initialData]);
37867
- const entityDerivedFields = React82__default.useMemo(() => {
38351
+ const entityDerivedFields = React83__default.useMemo(() => {
37868
38352
  if (fields && fields.length > 0) return void 0;
37869
38353
  if (!resolvedEntity) return void 0;
37870
38354
  return resolvedEntity.fields.map(
@@ -37885,16 +38369,16 @@ var init_Form = __esm({
37885
38369
  const conditionalFields = typeof conditionalFieldsRaw === "boolean" ? {} : conditionalFieldsRaw;
37886
38370
  const hiddenCalculations = typeof hiddenCalculationsRaw === "boolean" ? [] : hiddenCalculationsRaw;
37887
38371
  const violationTriggers = typeof violationTriggersRaw === "boolean" ? [] : violationTriggersRaw;
37888
- const [formData, setFormData] = React82__default.useState(
38372
+ const [formData, setFormData] = React83__default.useState(
37889
38373
  normalizedInitialData
37890
38374
  );
37891
- const [collapsedSections, setCollapsedSections] = React82__default.useState(
38375
+ const [collapsedSections, setCollapsedSections] = React83__default.useState(
37892
38376
  /* @__PURE__ */ new Set()
37893
38377
  );
37894
- const [submitError, setSubmitError] = React82__default.useState(null);
37895
- const formRef = React82__default.useRef(null);
38378
+ const [submitError, setSubmitError] = React83__default.useState(null);
38379
+ const formRef = React83__default.useRef(null);
37896
38380
  const formMode = props.mode;
37897
- const mountedRef = React82__default.useRef(false);
38381
+ const mountedRef = React83__default.useRef(false);
37898
38382
  if (!mountedRef.current) {
37899
38383
  mountedRef.current = true;
37900
38384
  debug("forms", "mount", {
@@ -37907,7 +38391,7 @@ var init_Form = __esm({
37907
38391
  });
37908
38392
  }
37909
38393
  const shouldShowCancel = showCancel ?? (fields && fields.length > 0);
37910
- const evalContext = React82__default.useMemo(
38394
+ const evalContext = React83__default.useMemo(
37911
38395
  () => ({
37912
38396
  formValues: formData,
37913
38397
  globalVariables: externalContext?.globalVariables ?? {},
@@ -37916,7 +38400,7 @@ var init_Form = __esm({
37916
38400
  }),
37917
38401
  [formData, externalContext]
37918
38402
  );
37919
- React82__default.useEffect(() => {
38403
+ React83__default.useEffect(() => {
37920
38404
  debug("forms", "initialData-sync", {
37921
38405
  mode: formMode,
37922
38406
  normalizedInitialData,
@@ -37927,7 +38411,7 @@ var init_Form = __esm({
37927
38411
  setFormData(normalizedInitialData);
37928
38412
  }
37929
38413
  }, [normalizedInitialData]);
37930
- const processCalculations = React82__default.useCallback(
38414
+ const processCalculations = React83__default.useCallback(
37931
38415
  (changedFieldId, newFormData) => {
37932
38416
  if (!hiddenCalculations.length) return;
37933
38417
  const context = {
@@ -37952,7 +38436,7 @@ var init_Form = __esm({
37952
38436
  },
37953
38437
  [hiddenCalculations, externalContext, eventBus]
37954
38438
  );
37955
- const checkViolations = React82__default.useCallback(
38439
+ const checkViolations = React83__default.useCallback(
37956
38440
  (changedFieldId, newFormData) => {
37957
38441
  if (!violationTriggers.length) return;
37958
38442
  const context = {
@@ -37990,7 +38474,7 @@ var init_Form = __esm({
37990
38474
  processCalculations(name, newFormData);
37991
38475
  checkViolations(name, newFormData);
37992
38476
  };
37993
- const isFieldVisible = React82__default.useCallback(
38477
+ const isFieldVisible = React83__default.useCallback(
37994
38478
  (fieldName) => {
37995
38479
  const condition = conditionalFields[fieldName];
37996
38480
  if (!condition) return true;
@@ -37998,7 +38482,7 @@ var init_Form = __esm({
37998
38482
  },
37999
38483
  [conditionalFields, evalContext]
38000
38484
  );
38001
- const isSectionVisible = React82__default.useCallback(
38485
+ const isSectionVisible = React83__default.useCallback(
38002
38486
  (section) => {
38003
38487
  if (!section.condition) return true;
38004
38488
  return Boolean(evaluateFormExpression(section.condition, evalContext));
@@ -38074,7 +38558,7 @@ var init_Form = __esm({
38074
38558
  eventBus.emit(`UI:${onCancel}`);
38075
38559
  }
38076
38560
  };
38077
- const renderField = React82__default.useCallback(
38561
+ const renderField = React83__default.useCallback(
38078
38562
  (field) => {
38079
38563
  const fieldName = field.name || field.field;
38080
38564
  if (!fieldName) return null;
@@ -38095,7 +38579,7 @@ var init_Form = __esm({
38095
38579
  [formData, isFieldVisible, relationsData, relationsLoading, isLoading]
38096
38580
  );
38097
38581
  const effectiveFields = entityDerivedFields ?? fields;
38098
- const normalizedFields = React82__default.useMemo(() => {
38582
+ const normalizedFields = React83__default.useMemo(() => {
38099
38583
  if (!effectiveFields || effectiveFields.length === 0) return [];
38100
38584
  return effectiveFields.map((field) => {
38101
38585
  if (typeof field === "string") {
@@ -38119,7 +38603,7 @@ var init_Form = __esm({
38119
38603
  return field;
38120
38604
  });
38121
38605
  }, [effectiveFields, resolvedEntity]);
38122
- const schemaFields = React82__default.useMemo(() => {
38606
+ const schemaFields = React83__default.useMemo(() => {
38123
38607
  if (normalizedFields.length === 0) return null;
38124
38608
  if (isDebugEnabled()) {
38125
38609
  debugGroup(`Form: ${entityName || "unknown"}`);
@@ -38129,7 +38613,7 @@ var init_Form = __esm({
38129
38613
  }
38130
38614
  return normalizedFields.map(renderField).filter(Boolean);
38131
38615
  }, [normalizedFields, renderField, entityName, conditionalFields]);
38132
- const sectionElements = React82__default.useMemo(() => {
38616
+ const sectionElements = React83__default.useMemo(() => {
38133
38617
  if (!sections || sections.length === 0) return null;
38134
38618
  return sections.map((section) => {
38135
38619
  if (!isSectionVisible(section)) {
@@ -38855,7 +39339,7 @@ var init_List = __esm({
38855
39339
  if (entity && typeof entity === "object" && "id" in entity) return [entity];
38856
39340
  return [];
38857
39341
  }, [entity]);
38858
- const getItemActions = React82__default.useCallback(
39342
+ const getItemActions = React83__default.useCallback(
38859
39343
  (item) => {
38860
39344
  if (!itemActions) return [];
38861
39345
  if (typeof itemActions === "function") {
@@ -39336,7 +39820,7 @@ var init_MediaGallery = __esm({
39336
39820
  [selectable, selectedItems, selectionEvent, eventBus]
39337
39821
  );
39338
39822
  const entityData = Array.isArray(entity) ? entity : [];
39339
- const items = React82__default.useMemo(() => {
39823
+ const items = React83__default.useMemo(() => {
39340
39824
  if (propItems && propItems.length > 0) return propItems;
39341
39825
  if (entityData.length === 0) return [];
39342
39826
  return entityData.map((record, idx) => {
@@ -39501,7 +39985,7 @@ var init_MediaGallery = __esm({
39501
39985
  }
39502
39986
  });
39503
39987
  function extractTitle2(children) {
39504
- if (!React82__default.isValidElement(children)) return void 0;
39988
+ if (!React83__default.isValidElement(children)) return void 0;
39505
39989
  const props = children.props;
39506
39990
  if (typeof props.title === "string") {
39507
39991
  return props.title;
@@ -39775,7 +40259,7 @@ var init_debugRegistry = __esm({
39775
40259
  }
39776
40260
  });
39777
40261
  function useDebugData() {
39778
- const [data, setData] = React82.useState(() => ({
40262
+ const [data, setData] = React83.useState(() => ({
39779
40263
  traits: [],
39780
40264
  ticks: [],
39781
40265
  guards: [],
@@ -39789,7 +40273,7 @@ function useDebugData() {
39789
40273
  },
39790
40274
  lastUpdate: Date.now()
39791
40275
  }));
39792
- React82.useEffect(() => {
40276
+ React83.useEffect(() => {
39793
40277
  const updateData = () => {
39794
40278
  setData({
39795
40279
  traits: getAllTraits(),
@@ -39898,12 +40382,12 @@ function layoutGraph(states, transitions, initialState, width, height) {
39898
40382
  return positions;
39899
40383
  }
39900
40384
  function WalkMinimap() {
39901
- const [walkStep, setWalkStep] = React82.useState(null);
39902
- const [traits2, setTraits] = React82.useState([]);
39903
- const [coveredEdges, setCoveredEdges] = React82.useState([]);
39904
- const [completedTraits, setCompletedTraits] = React82.useState(/* @__PURE__ */ new Set());
39905
- const prevTraitRef = React82.useRef(null);
39906
- React82.useEffect(() => {
40385
+ const [walkStep, setWalkStep] = React83.useState(null);
40386
+ const [traits2, setTraits] = React83.useState([]);
40387
+ const [coveredEdges, setCoveredEdges] = React83.useState([]);
40388
+ const [completedTraits, setCompletedTraits] = React83.useState(/* @__PURE__ */ new Set());
40389
+ const prevTraitRef = React83.useRef(null);
40390
+ React83.useEffect(() => {
39907
40391
  const interval = setInterval(() => {
39908
40392
  const w = window;
39909
40393
  const step = w.__orbitalWalkStep;
@@ -40339,15 +40823,15 @@ var init_EntitiesTab = __esm({
40339
40823
  });
40340
40824
  function EventFlowTab({ events: events2 }) {
40341
40825
  const { t } = useTranslate();
40342
- const [filter, setFilter] = React82.useState("all");
40343
- const containerRef = React82.useRef(null);
40344
- const [autoScroll, setAutoScroll] = React82.useState(true);
40345
- React82.useEffect(() => {
40826
+ const [filter, setFilter] = React83.useState("all");
40827
+ const containerRef = React83.useRef(null);
40828
+ const [autoScroll, setAutoScroll] = React83.useState(true);
40829
+ React83.useEffect(() => {
40346
40830
  if (autoScroll && containerRef.current) {
40347
40831
  containerRef.current.scrollTop = containerRef.current.scrollHeight;
40348
40832
  }
40349
40833
  }, [events2.length, autoScroll]);
40350
- const filteredEvents = React82.useMemo(() => {
40834
+ const filteredEvents = React83.useMemo(() => {
40351
40835
  if (filter === "all") return events2;
40352
40836
  return events2.filter((e) => e.type === filter);
40353
40837
  }, [events2, filter]);
@@ -40463,7 +40947,7 @@ var init_EventFlowTab = __esm({
40463
40947
  });
40464
40948
  function GuardsPanel({ guards }) {
40465
40949
  const { t } = useTranslate();
40466
- const [filter, setFilter] = React82.useState("all");
40950
+ const [filter, setFilter] = React83.useState("all");
40467
40951
  if (guards.length === 0) {
40468
40952
  return /* @__PURE__ */ jsx(
40469
40953
  EmptyState,
@@ -40476,7 +40960,7 @@ function GuardsPanel({ guards }) {
40476
40960
  }
40477
40961
  const passedCount = guards.filter((g) => g.result).length;
40478
40962
  const failedCount = guards.length - passedCount;
40479
- const filteredGuards = React82.useMemo(() => {
40963
+ const filteredGuards = React83.useMemo(() => {
40480
40964
  if (filter === "all") return guards;
40481
40965
  if (filter === "passed") return guards.filter((g) => g.result);
40482
40966
  return guards.filter((g) => !g.result);
@@ -40639,10 +41123,10 @@ function EffectBadge({ effect }) {
40639
41123
  }
40640
41124
  function TransitionTimeline({ transitions }) {
40641
41125
  const { t } = useTranslate();
40642
- const containerRef = React82.useRef(null);
40643
- const [autoScroll, setAutoScroll] = React82.useState(true);
40644
- const [expandedId, setExpandedId] = React82.useState(null);
40645
- React82.useEffect(() => {
41126
+ const containerRef = React83.useRef(null);
41127
+ const [autoScroll, setAutoScroll] = React83.useState(true);
41128
+ const [expandedId, setExpandedId] = React83.useState(null);
41129
+ React83.useEffect(() => {
40646
41130
  if (autoScroll && containerRef.current) {
40647
41131
  containerRef.current.scrollTop = containerRef.current.scrollHeight;
40648
41132
  }
@@ -40922,9 +41406,9 @@ function getAllEvents(traits2) {
40922
41406
  function EventDispatcherTab({ traits: traits2, schema }) {
40923
41407
  const eventBus = useEventBus();
40924
41408
  const { t } = useTranslate();
40925
- const [log9, setLog] = React82.useState([]);
40926
- const prevStatesRef = React82.useRef(/* @__PURE__ */ new Map());
40927
- React82.useEffect(() => {
41409
+ const [log9, setLog] = React83.useState([]);
41410
+ const prevStatesRef = React83.useRef(/* @__PURE__ */ new Map());
41411
+ React83.useEffect(() => {
40928
41412
  for (const trait of traits2) {
40929
41413
  const prev = prevStatesRef.current.get(trait.id);
40930
41414
  if (prev && prev !== trait.currentState) {
@@ -41093,10 +41577,10 @@ function VerifyModePanel({
41093
41577
  localCount
41094
41578
  }) {
41095
41579
  const { t } = useTranslate();
41096
- const [expanded, setExpanded] = React82.useState(true);
41097
- const scrollRef = React82.useRef(null);
41098
- const prevCountRef = React82.useRef(0);
41099
- React82.useEffect(() => {
41580
+ const [expanded, setExpanded] = React83.useState(true);
41581
+ const scrollRef = React83.useRef(null);
41582
+ const prevCountRef = React83.useRef(0);
41583
+ React83.useEffect(() => {
41100
41584
  if (expanded && transitions.length > prevCountRef.current && scrollRef.current) {
41101
41585
  scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
41102
41586
  }
@@ -41153,10 +41637,10 @@ function RuntimeDebugger({
41153
41637
  schema
41154
41638
  }) {
41155
41639
  const { t } = useTranslate();
41156
- const [isCollapsed, setIsCollapsed] = React82.useState(mode === "verify" ? true : defaultCollapsed);
41157
- const [isVisible, setIsVisible] = React82.useState(mode === "inline" || mode === "verify" || isDebugEnabled2());
41640
+ const [isCollapsed, setIsCollapsed] = React83.useState(mode === "verify" ? true : defaultCollapsed);
41641
+ const [isVisible, setIsVisible] = React83.useState(mode === "inline" || mode === "verify" || isDebugEnabled2());
41158
41642
  const debugData = useDebugData();
41159
- React82.useEffect(() => {
41643
+ React83.useEffect(() => {
41160
41644
  if (mode === "inline") return;
41161
41645
  return onDebugToggle((enabled) => {
41162
41646
  setIsVisible(enabled);
@@ -41165,7 +41649,7 @@ function RuntimeDebugger({
41165
41649
  }
41166
41650
  });
41167
41651
  }, [mode]);
41168
- React82.useEffect(() => {
41652
+ React83.useEffect(() => {
41169
41653
  if (mode === "inline") return;
41170
41654
  const handleKeyDown = (e) => {
41171
41655
  if (e.key === "`" && isVisible) {
@@ -41685,7 +42169,7 @@ var init_StatCard = __esm({
41685
42169
  const labelToUse = propLabel ?? propTitle;
41686
42170
  const eventBus = useEventBus();
41687
42171
  const { t } = useTranslate();
41688
- const handleActionClick = React82__default.useCallback(() => {
42172
+ const handleActionClick = React83__default.useCallback(() => {
41689
42173
  if (action?.event) {
41690
42174
  eventBus.emit(`UI:${action.event}`, {});
41691
42175
  }
@@ -41696,7 +42180,7 @@ var init_StatCard = __esm({
41696
42180
  const data = Array.isArray(entity) ? entity : entity ? [entity] : [];
41697
42181
  const isLoading = externalLoading ?? false;
41698
42182
  const error = externalError;
41699
- const computeMetricValue = React82__default.useCallback(
42183
+ const computeMetricValue = React83__default.useCallback(
41700
42184
  (metric, items) => {
41701
42185
  if (metric.value !== void 0) {
41702
42186
  return metric.value;
@@ -41735,7 +42219,7 @@ var init_StatCard = __esm({
41735
42219
  },
41736
42220
  []
41737
42221
  );
41738
- const schemaStats = React82__default.useMemo(() => {
42222
+ const schemaStats = React83__default.useMemo(() => {
41739
42223
  if (!metrics || metrics.length === 0) return null;
41740
42224
  return metrics.map((metric) => ({
41741
42225
  label: metric.label,
@@ -41743,7 +42227,7 @@ var init_StatCard = __esm({
41743
42227
  format: metric.format
41744
42228
  }));
41745
42229
  }, [metrics, data, computeMetricValue]);
41746
- const calculatedTrend = React82__default.useMemo(() => {
42230
+ const calculatedTrend = React83__default.useMemo(() => {
41747
42231
  if (manualTrend !== void 0) return manualTrend;
41748
42232
  if (previousValue === void 0 || currentValue === void 0)
41749
42233
  return void 0;
@@ -42383,8 +42867,8 @@ var init_SubagentTracePanel = __esm({
42383
42867
  ] });
42384
42868
  };
42385
42869
  InlineActivityStream = ({ activities, autoScroll = true, className }) => {
42386
- const endRef = React82__default.useRef(null);
42387
- React82__default.useEffect(() => {
42870
+ const endRef = React83__default.useRef(null);
42871
+ React83__default.useEffect(() => {
42388
42872
  if (!autoScroll) return;
42389
42873
  endRef.current?.scrollIntoView({ behavior: "smooth", block: "end" });
42390
42874
  }, [activities.length, autoScroll]);
@@ -42478,7 +42962,7 @@ var init_SubagentTracePanel = __esm({
42478
42962
  };
42479
42963
  SubagentRichCard = ({ subagent }) => {
42480
42964
  const { t } = useTranslate();
42481
- const activities = React82__default.useMemo(
42965
+ const activities = React83__default.useMemo(
42482
42966
  () => subagentMessagesToActivities(subagent.messages),
42483
42967
  [subagent.messages]
42484
42968
  );
@@ -42555,8 +43039,8 @@ var init_SubagentTracePanel = __esm({
42555
43039
  ] });
42556
43040
  };
42557
43041
  CoordinatorConversation = ({ messages, autoScroll = true, className }) => {
42558
- const endRef = React82__default.useRef(null);
42559
- React82__default.useEffect(() => {
43042
+ const endRef = React83__default.useRef(null);
43043
+ React83__default.useEffect(() => {
42560
43044
  if (!autoScroll) return;
42561
43045
  endRef.current?.scrollIntoView({ behavior: "smooth", block: "end" });
42562
43046
  }, [messages.length, autoScroll]);
@@ -42991,7 +43475,7 @@ var init_Timeline = __esm({
42991
43475
  }) => {
42992
43476
  const { t } = useTranslate();
42993
43477
  const entityData = entity ?? [];
42994
- const items = React82__default.useMemo(() => {
43478
+ const items = React83__default.useMemo(() => {
42995
43479
  if (propItems) return propItems;
42996
43480
  if (entityData.length === 0) return [];
42997
43481
  return entityData.map((record, idx) => {
@@ -43093,7 +43577,7 @@ var init_Timeline = __esm({
43093
43577
  }
43094
43578
  });
43095
43579
  function extractToastProps(children) {
43096
- if (!React82__default.isValidElement(children)) {
43580
+ if (!React83__default.isValidElement(children)) {
43097
43581
  if (typeof children === "string") {
43098
43582
  return { message: children };
43099
43583
  }
@@ -43135,7 +43619,7 @@ var init_ToastSlot = __esm({
43135
43619
  eventBus.emit(`${prefix}CLOSE`);
43136
43620
  };
43137
43621
  if (!isVisible) return null;
43138
- const isCustomContent = React82__default.isValidElement(children) && !message;
43622
+ const isCustomContent = React83__default.isValidElement(children) && !message;
43139
43623
  return /* @__PURE__ */ jsx(Box, { className: "fixed bottom-4 right-4 z-50", children: isCustomContent ? children : /* @__PURE__ */ jsx(
43140
43624
  Toast,
43141
43625
  {
@@ -43240,6 +43724,7 @@ var init_component_registry_generated = __esm({
43240
43724
  init_Drawer();
43241
43725
  init_DrawerSlot();
43242
43726
  init_EdgeDecoration();
43727
+ init_EmojiPicker();
43243
43728
  init_EmptyState();
43244
43729
  init_ErrorBoundary();
43245
43730
  init_ErrorState();
@@ -43507,6 +43992,7 @@ var init_component_registry_generated = __esm({
43507
43992
  "Drawer": Drawer,
43508
43993
  "DrawerSlot": DrawerSlot,
43509
43994
  "EdgeDecoration": EdgeDecoration,
43995
+ "EmojiPicker": EmojiPicker,
43510
43996
  "EmptyState": EmptyState,
43511
43997
  "ErrorBoundary": ErrorBoundary,
43512
43998
  "ErrorState": ErrorState,
@@ -43706,7 +44192,7 @@ function SuspenseConfigProvider({
43706
44192
  config,
43707
44193
  children
43708
44194
  }) {
43709
- return React82__default.createElement(
44195
+ return React83__default.createElement(
43710
44196
  SuspenseConfigContext.Provider,
43711
44197
  { value: config },
43712
44198
  children
@@ -43748,7 +44234,7 @@ function enrichFormFields(fields, entityDef) {
43748
44234
  }
43749
44235
  return { name: field, label: humanizeFieldName(field) };
43750
44236
  }
43751
- if (field && typeof field === "object" && !Array.isArray(field) && !React82__default.isValidElement(field) && !(field instanceof Date)) {
44237
+ if (field && typeof field === "object" && !Array.isArray(field) && !React83__default.isValidElement(field) && !(field instanceof Date)) {
43752
44238
  const obj = field;
43753
44239
  const fieldName = typeof obj.name === "string" ? obj.name : typeof obj.field === "string" ? obj.field : void 0;
43754
44240
  if (!fieldName) return field;
@@ -43934,7 +44420,19 @@ function UISlotComponent({
43934
44420
  const suspenseConfig = useContext(SuspenseConfigContext);
43935
44421
  const contained = useContext(SlotContainedContext);
43936
44422
  const schemaCtx = useEntitySchemaOptional();
43937
- const content = slots[slot];
44423
+ const rawContent = slots[slot];
44424
+ const binding = useEntityBindingSnapshot(rawContent?.sourceTrait);
44425
+ const content = useMemo(() => {
44426
+ if (!rawContent) return rawContent;
44427
+ const resolvedProps = resolveRenderBindingMarkers(
44428
+ rawContent.props,
44429
+ rawContent.sourceTrait,
44430
+ binding.entity,
44431
+ binding.config,
44432
+ binding.state
44433
+ );
44434
+ return resolvedProps === rawContent.props ? rawContent : { ...rawContent, props: resolvedProps };
44435
+ }, [rawContent, binding.entity, binding.config, binding.state]);
43938
44436
  if (children !== void 0) {
43939
44437
  if (pattern === "clear") {
43940
44438
  return null;
@@ -44208,7 +44706,7 @@ function renderPatternChildren(children, onDismiss, parentId = "root", parentPat
44208
44706
  const key = `${parentId}-${index}-trait:${traitName}`;
44209
44707
  return /* @__PURE__ */ jsx(TraitFrame, { traitName }, key);
44210
44708
  }
44211
- return /* @__PURE__ */ jsx(React82__default.Fragment, { children: child }, `${parentId}-${index}`);
44709
+ return /* @__PURE__ */ jsx(React83__default.Fragment, { children: child }, `${parentId}-${index}`);
44212
44710
  }
44213
44711
  if (!child || typeof child !== "object") return null;
44214
44712
  const childId = `${parentId}-${index}`;
@@ -44265,19 +44763,20 @@ function isPatternConfig(value) {
44265
44763
  if (value === null || value === void 0) return false;
44266
44764
  if (typeof value !== "object") return false;
44267
44765
  if (Array.isArray(value)) return false;
44268
- if (React82__default.isValidElement(value)) return false;
44766
+ if (React83__default.isValidElement(value)) return false;
44269
44767
  if (value instanceof Date) return false;
44270
44768
  if (typeof value === "function") return false;
44271
44769
  const record = value;
44272
44770
  return "type" in record && typeof record.type === "string" && getComponentForPattern$1(record.type) !== null;
44273
44771
  }
44274
44772
  function isPlainConfigObject(value) {
44275
- if (React82__default.isValidElement(value)) return false;
44773
+ if (React83__default.isValidElement(value)) return false;
44276
44774
  if (value instanceof Date) return false;
44277
44775
  const proto = Object.getPrototypeOf(value);
44278
44776
  return proto === Object.prototype || proto === null;
44279
44777
  }
44280
44778
  function substituteTraitRefsDeep(value, pathKey) {
44779
+ if (isRenderBindingMarker(value)) return value;
44281
44780
  if (typeof value === "string") {
44282
44781
  const match = TRAIT_BINDING_RE.exec(value);
44283
44782
  if (match) {
@@ -44350,7 +44849,14 @@ function SlotContentRenderer({
44350
44849
  onDismiss,
44351
44850
  patternPath
44352
44851
  }) {
44353
- const entityProp = content.props.entity;
44852
+ const ambientScope = useTraitScope();
44853
+ const bindingTrait = content.sourceTrait ?? ambientScope?.trait;
44854
+ const binding = useEntityBindingSnapshot(bindingTrait);
44855
+ const liveProps = useMemo(
44856
+ () => resolveRenderBindingMarkers(content.props, bindingTrait, binding.entity, binding.config, binding.state),
44857
+ [content.props, bindingTrait, binding.entity, binding.config, binding.state]
44858
+ );
44859
+ const entityProp = liveProps.entity;
44354
44860
  if (content.pattern === "form-section") {
44355
44861
  slotLog.debug("SlotContentRenderer:form-section-render", {
44356
44862
  contentId: content.id,
@@ -44381,7 +44887,7 @@ function SlotContentRenderer({
44381
44887
  const orbitalName = schemaCtx && content.sourceTrait !== void 0 ? schemaCtx.orbitalsByTrait.get(content.sourceTrait) : void 0;
44382
44888
  const PatternComponent = getComponentForPattern(content.pattern);
44383
44889
  if (PatternComponent) {
44384
- const childrenConfig = content.props.children;
44890
+ const childrenConfig = liveProps.children;
44385
44891
  const isSingleChild = typeof childrenConfig === "string" || typeof childrenConfig === "object" && childrenConfig !== null && !Array.isArray(childrenConfig) && "type" in childrenConfig;
44386
44892
  const hasChildren = PATTERNS_WITH_CHILDREN.has(content.pattern) || Array.isArray(childrenConfig) && childrenConfig.length > 0 || isSingleChild;
44387
44893
  const isDrawHost = isDrawHostPattern(content.pattern);
@@ -44392,15 +44898,15 @@ function SlotContentRenderer({
44392
44898
  fromState: content.fromState,
44393
44899
  entity: content.entity
44394
44900
  }) : void 0;
44395
- const incomingChildren = content.props.children;
44901
+ const incomingChildren = liveProps.children;
44396
44902
  const childrenIsRenderFn = typeof incomingChildren === "function";
44397
- const { children: _childrenConfig, ...restPropsNoChildren } = content.props;
44903
+ const { children: _childrenConfig, ...restPropsNoChildren } = liveProps;
44398
44904
  const restProps = childrenIsRenderFn ? { ...restPropsNoChildren, children: incomingChildren } : restPropsNoChildren;
44399
44905
  const nodeSlotOverrides = {};
44400
44906
  for (const slotKey of CONTENT_NODE_SLOTS) {
44401
44907
  const slotVal = restProps[slotKey];
44402
44908
  if (slotVal === void 0 || slotVal === null) continue;
44403
- if (React82__default.isValidElement(slotVal) || typeof slotVal === "string" || typeof slotVal === "number" || typeof slotVal === "boolean") continue;
44909
+ if (React83__default.isValidElement(slotVal) || typeof slotVal === "string" || typeof slotVal === "number" || typeof slotVal === "boolean") continue;
44404
44910
  const typelessChildren = !Array.isArray(slotVal) && typeof slotVal === "object" && !("type" in slotVal) && Array.isArray(slotVal.children) ? slotVal.children : void 0;
44405
44911
  if (typelessChildren !== void 0 || Array.isArray(slotVal) || typeof slotVal === "object" && "type" in slotVal) {
44406
44912
  nodeSlotOverrides[slotKey] = renderPatternChildren(
@@ -44454,7 +44960,7 @@ function SlotContentRenderer({
44454
44960
  const resolvedItems = Array.isArray(entityVal) && entityVal[0] !== "fn" ? entityVal : null;
44455
44961
  if (resolvedItems && resolvedItems.length > 0 && !finalProps.fields && !finalProps.columns) {
44456
44962
  const sample = resolvedItems[0];
44457
- if (sample && typeof sample === "object" && !Array.isArray(sample) && !React82__default.isValidElement(sample) && !(sample instanceof Date)) {
44963
+ if (sample && typeof sample === "object" && !Array.isArray(sample) && !React83__default.isValidElement(sample) && !(sample instanceof Date)) {
44458
44964
  const keys = Object.keys(sample).filter((k) => k !== "id" && k !== "_id");
44459
44965
  finalProps.fields = keys.map((k, i) => ({ name: k, variant: i === 0 ? "h4" : "body" }));
44460
44966
  }
@@ -44503,7 +45009,7 @@ function SlotContentRenderer({
44503
45009
  "data-orb-path": patternPath ?? "root",
44504
45010
  "data-orb-pattern": content.pattern,
44505
45011
  "data-orb-orbital": orbitalName,
44506
- children: content.props.children ?? /* @__PURE__ */ jsxs(Box, { className: "p-4 text-sm text-muted-foreground border border-dashed border-border rounded", children: [
45012
+ children: liveProps.children ?? /* @__PURE__ */ jsxs(Box, { className: "p-4 text-sm text-muted-foreground border border-dashed border-border rounded", children: [
44507
45013
  "Unknown pattern: ",
44508
45014
  content.pattern,
44509
45015
  content.sourceTrait && /* @__PURE__ */ jsxs(Typography, { variant: "small", className: "ml-2", children: [
@@ -44575,6 +45081,7 @@ var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SlotContainedContext,
44575
45081
  var init_UISlotRenderer = __esm({
44576
45082
  "components/core/organisms/UISlotRenderer.tsx"() {
44577
45083
  "use client";
45084
+ init_resolve_render_bindings();
44578
45085
  init_Modal();
44579
45086
  init_Drawer();
44580
45087
  init_Toast();
@@ -44821,12 +45328,15 @@ function resolveLambdaBindings(body, params, item, index) {
44821
45328
  const arr = body;
44822
45329
  const substituted = arr.map((b) => recur(b));
44823
45330
  if (isOperatorCall(substituted) && isSExpr(substituted)) {
45331
+ if (containsEntityBinding(substituted)) {
45332
+ return substituted;
45333
+ }
44824
45334
  const evaluated = evaluate(substituted, createMinimalContext());
44825
45335
  return isEventPayloadValue(evaluated) ? evaluated : String(evaluated);
44826
45336
  }
44827
45337
  return substituted;
44828
45338
  }
44829
- if (body !== null && typeof body === "object" && !React82__default.isValidElement(body) && !(body instanceof Date) && typeof body !== "function") {
45339
+ if (body !== null && typeof body === "object" && !React83__default.isValidElement(body) && !(body instanceof Date) && typeof body !== "function") {
44830
45340
  const out = {};
44831
45341
  for (const [k, v] of Object.entries(body)) {
44832
45342
  out[k] = recur(v);
@@ -44842,10 +45352,38 @@ function getSlotContentRenderer2() {
44842
45352
  _slotContentRenderer2 = mod.SlotContentRenderer;
44843
45353
  return _slotContentRenderer2;
44844
45354
  }
45355
+ function deferLambdaEntityExprs(value) {
45356
+ if (typeof value === "string") {
45357
+ if (containsEntityBinding(value)) {
45358
+ const marker = { [RENDER_BINDING_MARKER]: true, expression: value };
45359
+ return marker;
45360
+ }
45361
+ return value;
45362
+ }
45363
+ if (Array.isArray(value)) {
45364
+ if (isFnFormLambda(value)) return value;
45365
+ const arr = value;
45366
+ if (isOperatorCall(arr) && isSExpr(arr) && containsEntityBinding(arr)) {
45367
+ const marker = { [RENDER_BINDING_MARKER]: true, expression: arr };
45368
+ return marker;
45369
+ }
45370
+ return arr.map((v) => deferLambdaEntityExprs(v));
45371
+ }
45372
+ if (value !== null && typeof value === "object" && !React83__default.isValidElement(value) && !(value instanceof Date) && typeof value !== "function" && !isRenderBindingMarker(value)) {
45373
+ const out = {};
45374
+ for (const [k, v] of Object.entries(value)) {
45375
+ out[k] = deferLambdaEntityExprs(v);
45376
+ }
45377
+ return out;
45378
+ }
45379
+ return value;
45380
+ }
44845
45381
  function makeLambdaFn(params, lambdaBody, callerKey) {
44846
45382
  return (item, index) => {
44847
- const resolvedBody = resolveLambdaBindings(lambdaBody, params, item, index);
44848
- if (resolvedBody === null || typeof resolvedBody !== "object" || Array.isArray(resolvedBody) || typeof resolvedBody === "function" || React82__default.isValidElement(resolvedBody) || resolvedBody instanceof Date) {
45383
+ const resolvedBody = deferLambdaEntityExprs(
45384
+ resolveLambdaBindings(lambdaBody, params, item, index)
45385
+ );
45386
+ if (resolvedBody === null || typeof resolvedBody !== "object" || Array.isArray(resolvedBody) || typeof resolvedBody === "function" || React83__default.isValidElement(resolvedBody) || resolvedBody instanceof Date) {
44849
45387
  return null;
44850
45388
  }
44851
45389
  const record = resolvedBody;
@@ -44864,11 +45402,12 @@ function makeLambdaFn(params, lambdaBody, callerKey) {
44864
45402
  props: childProps,
44865
45403
  priority: 0
44866
45404
  };
44867
- return React82__default.createElement(SlotContentRenderer2, { content: childContent });
45405
+ return React83__default.createElement(SlotContentRenderer2, { content: childContent });
44868
45406
  };
44869
45407
  }
44870
45408
  function convertNode(node, callerKey) {
44871
45409
  if (node === null || node === void 0) return node;
45410
+ if (isRenderBindingMarker(node)) return node;
44872
45411
  if (Array.isArray(node)) {
44873
45412
  if (isFnFormLambda(node)) {
44874
45413
  const arr2 = node;
@@ -44883,7 +45422,7 @@ function convertNode(node, callerKey) {
44883
45422
  });
44884
45423
  return anyChanged ? mapped : node;
44885
45424
  }
44886
- if (typeof node === "object" && !React82__default.isValidElement(node) && !(node instanceof Date)) {
45425
+ if (typeof node === "object" && !React83__default.isValidElement(node) && !(node instanceof Date)) {
44887
45426
  return convertObjectProps(node);
44888
45427
  }
44889
45428
  return node;
@@ -44921,6 +45460,7 @@ var tickLog = createLogger("almadar:ui:tick-effects");
44921
45460
  setNamespaceLevel("almadar:ui:tick-effects", "WARN");
44922
45461
  var sharedEntityLog = createLogger("almadar:ui:shared-entity");
44923
45462
  setNamespaceLevel("almadar:ui:shared-entity", "WARN");
45463
+ var EMPTY_BINDING_SNAPSHOT = {};
44924
45464
  var SYNC_TICK_OPERATORS = /* @__PURE__ */ new Set([
44925
45465
  "set",
44926
45466
  "emit",
@@ -44941,11 +45481,6 @@ var SYNC_TICK_OPERATORS = /* @__PURE__ */ new Set([
44941
45481
  "do",
44942
45482
  "when"
44943
45483
  ]);
44944
- var REACTIVE_REPAINT_PATTERN_TYPES = /* @__PURE__ */ new Set([
44945
- "canvas",
44946
- "game-hud",
44947
- "game-shell"
44948
- ]);
44949
45484
  var LIFECYCLE_EVENTS = ["INIT", "LOAD", "$MOUNT"];
44950
45485
  function toTraitDefinition(binding) {
44951
45486
  return {
@@ -44986,6 +45521,27 @@ function classifySharedTick(tick) {
44986
45521
  if (renders) return "renderer";
44987
45522
  return "neither";
44988
45523
  }
45524
+ function buildTraitRenderConfig(binding, traitConfigsByName, payload) {
45525
+ const declaredDefaults = collectDeclaredConfigDefaults(binding.trait);
45526
+ const resolvedDefaults = traitConfigsByName?.[binding.trait.name];
45527
+ const callSiteConfig = getBindingConfig(binding);
45528
+ const callSiteOverrides = callSiteConfig ? resolveCallSitePayloadCaptures(
45529
+ Object.fromEntries(
45530
+ Object.entries(callSiteConfig).filter(
45531
+ ([, v]) => !containsConfigForward(v)
45532
+ )
45533
+ ),
45534
+ payload
45535
+ ) : void 0;
45536
+ if (declaredDefaults || resolvedDefaults || callSiteOverrides) {
45537
+ return {
45538
+ ...declaredDefaults ?? {},
45539
+ ...resolvedDefaults ?? {},
45540
+ ...callSiteOverrides ?? {}
45541
+ };
45542
+ }
45543
+ return void 0;
45544
+ }
44989
45545
  function createSharedEntityWriter(binding, tick, traitStatesRef, emit) {
44990
45546
  return (scratch) => {
44991
45547
  const traitName = binding.trait.name;
@@ -45206,8 +45762,24 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
45206
45762
  }, [traitStates]);
45207
45763
  const traitSnapshotDataRef = useRef(/* @__PURE__ */ new Map());
45208
45764
  const traitFieldStatesRef = useRef(/* @__PURE__ */ new Map());
45209
- const lastCanvasRenderUiRef = useRef(/* @__PURE__ */ new Map());
45210
- const executeTransitionEffectsRef = useRef(null);
45765
+ const bridgeEchoPendingRef = useRef(/* @__PURE__ */ new Map());
45766
+ const bindingSnapshotsRef = useRef(/* @__PURE__ */ new Map());
45767
+ const bindingListenersRef = useRef(/* @__PURE__ */ new Map());
45768
+ const publishBindingSnapshot = useCallback((traitName, row) => {
45769
+ bindingSnapshotsRef.current.set(traitName, { ...row });
45770
+ const listeners7 = bindingListenersRef.current.get(traitName);
45771
+ if (!listeners7) return;
45772
+ listeners7.forEach((callback) => {
45773
+ try {
45774
+ callback();
45775
+ } catch (error) {
45776
+ stateLog.error("binding-snapshot listener error", {
45777
+ traitName,
45778
+ error: error instanceof Error ? error.message : String(error)
45779
+ });
45780
+ }
45781
+ });
45782
+ }, []);
45211
45783
  useEffect(() => {
45212
45784
  const mgr = managerRef.current;
45213
45785
  const bindings = traitBindingsRef.current;
@@ -45335,15 +45907,6 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
45335
45907
  const existing = pendingSlots.get(slot) || [];
45336
45908
  existing.push({ pattern, props: props || {} });
45337
45909
  pendingSlots.set(slot, existing);
45338
- const patternType = pattern?.type;
45339
- if (patternType !== void 0 && REACTIVE_REPAINT_PATTERN_TYPES.has(patternType)) {
45340
- const rawForSlot = effects.filter(
45341
- (e) => Array.isArray(e) && (e[0] === "render-ui" || e[0] === "render") && e[1] === slot
45342
- );
45343
- if (rawForSlot.length > 0) {
45344
- lastCanvasRenderUiRef.current.set(traitName, rawForSlot);
45345
- }
45346
- }
45347
45910
  },
45348
45911
  clearSlot: (slot) => {
45349
45912
  pendingSlots.set(slot, []);
@@ -45415,11 +45978,13 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
45415
45978
  };
45416
45979
  }
45417
45980
  const sharedWrites = [];
45981
+ let didWrite = false;
45418
45982
  const baseSet = handlers.set;
45419
45983
  handlers = {
45420
45984
  ...handlers,
45421
45985
  set: async (targetId, field, value) => {
45422
45986
  if (baseSet) await baseSet(targetId, field, value);
45987
+ didWrite = true;
45423
45988
  if (sharedKey !== void 0) {
45424
45989
  sharedWrites.push({ field, value });
45425
45990
  }
@@ -45436,23 +46001,9 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
45436
46001
  payload: payload || {},
45437
46002
  state: previousState
45438
46003
  };
45439
- const declaredDefaults = collectDeclaredConfigDefaults(binding.trait);
45440
- const resolvedDefaults = traitConfigsByName?.[traitName];
45441
- const callSiteConfig = getBindingConfig(binding);
45442
- const callSiteOverrides = callSiteConfig ? resolveCallSitePayloadCaptures(
45443
- Object.fromEntries(
45444
- Object.entries(callSiteConfig).filter(
45445
- ([, v]) => !containsConfigForward(v)
45446
- )
45447
- ),
45448
- payload || {}
45449
- ) : void 0;
45450
- if (declaredDefaults || resolvedDefaults || callSiteOverrides) {
45451
- bindingCtx.config = {
45452
- ...declaredDefaults ?? {},
45453
- ...resolvedDefaults ?? {},
45454
- ...callSiteOverrides ?? {}
45455
- };
46004
+ const renderConfig = buildTraitRenderConfig(binding, traitConfigsByName, payload || {});
46005
+ if (renderConfig !== void 0) {
46006
+ bindingCtx.config = renderConfig;
45456
46007
  }
45457
46008
  if (traitName === "Authority" || traitName === "Hero") {
45458
46009
  sharedEntityLog.debug("executeTransitionEffects config tiles", {
@@ -45486,7 +46037,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
45486
46037
  effectHeads: effects.map((e) => Array.isArray(e) ? String(e[0]) : "??")
45487
46038
  });
45488
46039
  }
45489
- const executor = new EffectExecutor({ handlers: trackingHandlers, bindings: bindingCtx, context: effectContext });
46040
+ const executor = new EffectExecutor({ handlers: trackingHandlers, bindings: bindingCtx, context: effectContext, deferRenderBindings: true });
45490
46041
  try {
45491
46042
  await executor.executeAll(effects);
45492
46043
  if (traitName === "Authority" || traitName === "Hero") {
@@ -45527,37 +46078,8 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
45527
46078
  entity: binding.linkedEntity
45528
46079
  });
45529
46080
  }
45530
- if (pendingSlots.size === 0 && effectsCallOp(effects, SHARED_ENTITY_WRITE_OPS)) {
45531
- const stashed = lastCanvasRenderUiRef.current.get(traitName);
45532
- if (stashed !== void 0 && stashed.length > 0) {
45533
- await executor.executeAll(stashed);
45534
- for (const [slot, patterns] of pendingSlots) {
45535
- flushSlot(traitName, slot, patterns, {
45536
- event: flushEvent,
45537
- state: previousState,
45538
- entity: binding.linkedEntity
45539
- });
45540
- }
45541
- }
45542
- if (sharedKey !== void 0 && executeTransitionEffectsRef.current !== null) {
45543
- for (const sibling of traitBindingsRef.current) {
45544
- const siblingName = sibling.trait.name;
45545
- if (siblingName === traitName) continue;
45546
- if (sharedKeyByTraitNameRef.current.get(siblingName) !== sharedKey) continue;
45547
- const siblingStash = lastCanvasRenderUiRef.current.get(siblingName);
45548
- if (siblingStash === void 0 || siblingStash.length === 0) continue;
45549
- const siblingState = traitStatesRef.current.get(siblingName)?.currentState ?? "";
45550
- await executeTransitionEffectsRef.current({
45551
- binding: sibling,
45552
- effects: siblingStash,
45553
- previousState: siblingState,
45554
- newState: siblingState,
45555
- flushEvent: `${flushEvent}:repaint`,
45556
- syncOnly,
45557
- log: log9
45558
- });
45559
- }
45560
- }
46081
+ if (didWrite && sharedKey === void 0) {
46082
+ publishBindingSnapshot(traitName, liveEntity);
45561
46083
  }
45562
46084
  } catch (error) {
45563
46085
  log9.error("effects:error", {
@@ -45569,10 +46091,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
45569
46091
  });
45570
46092
  }
45571
46093
  return emittedDuringExec;
45572
- }, [eventBus, flushSlot, sharedEntityStore]);
45573
- useEffect(() => {
45574
- executeTransitionEffectsRef.current = executeTransitionEffects;
45575
- }, [executeTransitionEffects]);
46094
+ }, [eventBus, flushSlot, sharedEntityStore, publishBindingSnapshot]);
45576
46095
  const runTickEffects = useCallback((tick, binding) => {
45577
46096
  const traitName = binding.trait.name;
45578
46097
  const currentState = traitStatesRef.current.get(traitName)?.currentState ?? "";
@@ -45635,24 +46154,6 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
45635
46154
  ({ binding, tick }) => createSharedEntityWriter(binding, tick, traitStatesRef, emitFromSharedWriter)
45636
46155
  );
45637
46156
  runTickFrame(group.storeKey, writers, sharedEntityStore);
45638
- const repaint = executeTransitionEffectsRef.current;
45639
- if (repaint !== null) {
45640
- for (const renderBinding of group.renderBindings) {
45641
- const renderTraitName = renderBinding.trait.name;
45642
- const stash = lastCanvasRenderUiRef.current.get(renderTraitName);
45643
- if (stash === void 0 || stash.length === 0) continue;
45644
- const renderState = traitStatesRef.current.get(renderTraitName)?.currentState ?? "";
45645
- void repaint({
45646
- binding: renderBinding,
45647
- effects: stash,
45648
- previousState: renderState,
45649
- newState: renderState,
45650
- flushEvent: "tick:repaint",
45651
- syncOnly: true,
45652
- log: sharedEntityLog
45653
- });
45654
- }
45655
- }
45656
46157
  };
45657
46158
  if (interval === "frame") {
45658
46159
  scheduler.add(0, onDue);
@@ -45723,6 +46224,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
45723
46224
  executedTraits: results.map((r) => r.traitName).join(",")
45724
46225
  });
45725
46226
  const emittedByTrait = /* @__PURE__ */ new Map();
46227
+ bridgeEchoPendingRef.current.clear();
45726
46228
  for (const { traitName, result } of results) {
45727
46229
  const binding = bindingMap.get(traitName);
45728
46230
  const traitState = currentManager.getState(traitName);
@@ -45777,6 +46279,12 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
45777
46279
  log: stateLog
45778
46280
  });
45779
46281
  emittedByTrait.set(traitName, emittedDuringExec);
46282
+ for (const emittedKey of emittedDuringExec) {
46283
+ bridgeEchoPendingRef.current.set(
46284
+ emittedKey,
46285
+ (bridgeEchoPendingRef.current.get(emittedKey) ?? 0) + 1
46286
+ );
46287
+ }
45780
46288
  } else if (!result.executed) {
45781
46289
  if (result.guardResult === false) {
45782
46290
  stateLog.debug("guard-blocked-transition", {
@@ -45926,8 +46434,13 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
45926
46434
  crossTraitLog.debug("self:subscribe", { traitName, busKey: selfBusKey, eventKey });
45927
46435
  const unsub = eventBus.on(selfBusKey, (event) => {
45928
46436
  if (event.source && event.source.dispatched) {
45929
- crossTraitLog.debug("self:fire-skipped-bridge-echo", { traitName, busKey: selfBusKey, eventKey });
45930
- return;
46437
+ const pendingEchoes = bridgeEchoPendingRef.current.get(eventKey) ?? 0;
46438
+ if (pendingEchoes > 0) {
46439
+ bridgeEchoPendingRef.current.set(eventKey, pendingEchoes - 1);
46440
+ crossTraitLog.debug("self:fire-skipped-bridge-echo", { traitName, busKey: selfBusKey, eventKey });
46441
+ return;
46442
+ }
46443
+ crossTraitLog.debug("self:fire-server-cascade", { traitName, busKey: selfBusKey, eventKey });
45931
46444
  }
45932
46445
  crossTraitLog.debug("self:fire", { traitName, busKey: selfBusKey, eventKey });
45933
46446
  enqueueAndDrain(eventKey, event.payload, traitName);
@@ -46019,11 +46532,47 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
46019
46532
  initedTraitsRef.current = /* @__PURE__ */ new Set();
46020
46533
  };
46021
46534
  }, [traitBindings, enqueueAndDrain]);
46535
+ const entityBindingSource = useMemo(() => ({
46536
+ getEntitySnapshot: (traitName) => {
46537
+ const sharedKey = sharedKeyByTraitNameRef.current.get(traitName);
46538
+ if (sharedKey !== void 0) {
46539
+ return sharedEntityStore.getSnapshot(sharedKey);
46540
+ }
46541
+ return bindingSnapshotsRef.current.get(traitName) ?? EMPTY_BINDING_SNAPSHOT;
46542
+ },
46543
+ getConfig: (traitName) => {
46544
+ const binding = traitBindingsRef.current.find((b) => b.trait.name === traitName);
46545
+ if (binding === void 0) return void 0;
46546
+ return buildTraitRenderConfig(binding, traitConfigsByName, {});
46547
+ },
46548
+ getState: (traitName) => traitStatesRef.current.get(traitName)?.currentState ?? "",
46549
+ subscribe: (traitName, callback) => {
46550
+ const sharedKey = sharedKeyByTraitNameRef.current.get(traitName);
46551
+ if (sharedKey !== void 0) {
46552
+ return sharedEntityStore.subscribe(sharedKey, callback);
46553
+ }
46554
+ let listeners7 = bindingListenersRef.current.get(traitName);
46555
+ if (!listeners7) {
46556
+ listeners7 = /* @__PURE__ */ new Set();
46557
+ bindingListenersRef.current.set(traitName, listeners7);
46558
+ }
46559
+ listeners7.add(callback);
46560
+ return () => {
46561
+ const current = bindingListenersRef.current.get(traitName);
46562
+ if (!current) return;
46563
+ current.delete(callback);
46564
+ if (current.size === 0) {
46565
+ bindingListenersRef.current.delete(traitName);
46566
+ }
46567
+ };
46568
+ }
46569
+ }), [sharedEntityStore, traitConfigsByName]);
46022
46570
  return {
46023
46571
  traitStates,
46024
46572
  sendEvent,
46025
46573
  getTraitState,
46026
- canHandleEvent
46574
+ canHandleEvent,
46575
+ entityBindingSource
46027
46576
  };
46028
46577
  }
46029
46578
  var resolvedSchemaLog = createLogger("almadar:ui:resolved-schema");
@@ -46215,7 +46764,7 @@ function collectServerActiveTraits(ir, allTraits, mountedTraitNames) {
46215
46764
  }
46216
46765
  return active;
46217
46766
  }
46218
- function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNavigate, onLocalFallback, persistence, traitConfigsByName, orbitalsByTrait, embeddedTraits, serverActiveTraits }) {
46767
+ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNavigate, onLocalFallback, persistence, traitConfigsByName, orbitalsByTrait, embeddedTraits, serverActiveTraits, children }) {
46219
46768
  const bridge = useServerBridge();
46220
46769
  const activeTraitNames = useMemo(
46221
46770
  () => new Set(traits2.map((b) => b.trait.name).filter((n) => !!n)),
@@ -46245,7 +46794,7 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
46245
46794
  }
46246
46795
  }, [bridge.connected, bridge.sendEvent, orbitalNames, uiSlots, onNavigate, embeddedTraits, activeTraitNames, withActiveTraits]);
46247
46796
  const opts = orbitalNames ? { onEventProcessed, navigate: onNavigate, traitConfigsByName, orbitalsByTrait, embeddedTraits, initPayload: routeParams } : { navigate: onNavigate, persistence, traitConfigsByName, orbitalsByTrait, embeddedTraits, initPayload: routeParams };
46248
- const { sendEvent } = useTraitStateMachine(traits2, uiSlots, opts);
46797
+ const { sendEvent, entityBindingSource } = useTraitStateMachine(traits2, uiSlots, opts);
46249
46798
  const initSentRef = useRef(false);
46250
46799
  const prevTraitsRef = useRef(void 0);
46251
46800
  const paramsKey = JSON.stringify(routeParams ?? {});
@@ -46291,7 +46840,7 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
46291
46840
  { type: "fetch", args: [], status: "executed" },
46292
46841
  ...effects.map((eff) => ({
46293
46842
  type: eff.type,
46294
- args: eff.type === "render-ui" ? [eff.slot] : [],
46843
+ args: eff.type === "render-ui" && eff.slot !== void 0 ? [eff.slot] : [],
46295
46844
  status: "executed"
46296
46845
  }))
46297
46846
  ];
@@ -46307,7 +46856,7 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
46307
46856
  }
46308
46857
  })();
46309
46858
  }, [bridge.connected, orbitalNames, bridge.sendEvent, uiSlots, onNavigate, embeddedTraits, activeTraitNames, withActiveTraits, routeParams]);
46310
- return null;
46859
+ return /* @__PURE__ */ jsx(EntityBindingContext.Provider, { value: entityBindingSource, children });
46311
46860
  }
46312
46861
  function SchemaRunner({ schema, serverUrl, transport, mockData, pageName, routeParams, onNavigate, onLocalFallback, persistence }) {
46313
46862
  const { traits: traits2, allEntities, allTraits, ir } = useResolvedSchema(schema, pageName);
@@ -46440,30 +46989,28 @@ function SchemaRunner({ schema, serverUrl, transport, mockData, pageName, routeP
46440
46989
  }
46441
46990
  return schema.orbitals[0]?.theme;
46442
46991
  }, [schema, pageName]);
46443
- const inner = /* @__PURE__ */ jsx(VerificationProvider, { enabled: true, children: /* @__PURE__ */ jsxs(
46992
+ const inner = /* @__PURE__ */ jsx(VerificationProvider, { enabled: true, children: /* @__PURE__ */ jsx(
46444
46993
  EntitySchemaProvider,
46445
46994
  {
46446
46995
  entities: entitiesArray,
46447
46996
  traitLinkedEntities: traitLinkedEntitiesMap,
46448
46997
  orbitalsByTrait: orbitalsByTraitMap,
46449
- children: [
46450
- /* @__PURE__ */ jsx(
46451
- TraitInitializer,
46452
- {
46453
- traits: allPageTraits,
46454
- routeParams,
46455
- orbitalNames: serverUrl || transport ? pageOrbitalNames : void 0,
46456
- traitConfigsByName,
46457
- orbitalsByTrait,
46458
- embeddedTraits,
46459
- serverActiveTraits,
46460
- onNavigate,
46461
- onLocalFallback,
46462
- persistence
46463
- }
46464
- ),
46465
- /* @__PURE__ */ jsx(OrbitalThemeProvider, { theme: activeOrbitalTheme, children: /* @__PURE__ */ jsx(Box, { className: "h-full min-h-full overflow-auto p-4", children: /* @__PURE__ */ jsx(UISlotRenderer, { includeHud: true, hudMode: "inline", includeFloating: true }) }) })
46466
- ]
46998
+ children: /* @__PURE__ */ jsx(
46999
+ TraitInitializer,
47000
+ {
47001
+ traits: allPageTraits,
47002
+ routeParams,
47003
+ orbitalNames: serverUrl || transport ? pageOrbitalNames : void 0,
47004
+ traitConfigsByName,
47005
+ orbitalsByTrait,
47006
+ embeddedTraits,
47007
+ serverActiveTraits,
47008
+ onNavigate,
47009
+ onLocalFallback,
47010
+ persistence,
47011
+ children: /* @__PURE__ */ jsx(OrbitalThemeProvider, { theme: activeOrbitalTheme, children: /* @__PURE__ */ jsx(Box, { className: "h-full min-h-full overflow-auto p-4", children: /* @__PURE__ */ jsx(UISlotRenderer, { includeHud: true, hudMode: "inline", includeFloating: true }) }) })
47012
+ }
47013
+ )
46467
47014
  }
46468
47015
  ) });
46469
47016
  if (serverUrl || transport) {