@almadar/ui 5.60.0 → 5.61.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.
package/dist/avl/index.js CHANGED
@@ -12160,16 +12160,6 @@ var init_Skeleton = __esm({
12160
12160
  Skeleton.displayName = "Skeleton";
12161
12161
  }
12162
12162
  });
12163
- function isKnownPattern(type) {
12164
- return type in componentMapping;
12165
- }
12166
- var componentMapping;
12167
- var init_pattern_resolver = __esm({
12168
- "renderer/pattern-resolver.ts"() {
12169
- createLogger("almadar:ui:pattern-resolver");
12170
- componentMapping = {};
12171
- }
12172
- });
12173
12163
 
12174
12164
  // renderer/slot-definitions.ts
12175
12165
  function isPortalSlot(slot) {
@@ -12278,7 +12268,6 @@ var init_navigation = __esm({
12278
12268
  // renderer/index.ts
12279
12269
  var init_renderer = __esm({
12280
12270
  "renderer/index.ts"() {
12281
- init_pattern_resolver();
12282
12271
  init_slot_definitions();
12283
12272
  }
12284
12273
  });
@@ -13982,7 +13971,7 @@ function recordTransition(trace) {
13982
13971
  ...trace,
13983
13972
  id: `t-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
13984
13973
  };
13985
- log5.debug("transition:recorded", { trait: trace.traitName, from: trace.from, to: trace.to, event: trace.event, effectCount: trace.effects.length });
13974
+ log4.debug("transition:recorded", { trait: trace.traitName, from: trace.from, to: trace.to, event: trace.event, effectCount: trace.effects.length });
13986
13975
  getState().transitions.push(entry);
13987
13976
  if (getState().transitions.length > MAX_TRANSITIONS) {
13988
13977
  getState().transitions.shift();
@@ -14081,7 +14070,7 @@ function getTraitSnapshots() {
14081
14070
  try {
14082
14071
  snapshots.push(getter());
14083
14072
  } catch (err) {
14084
- log5.error("traitSnapshot getter failed", { trait: traitName, err: String(err) });
14073
+ log4.error("traitSnapshot getter failed", { trait: traitName, err: String(err) });
14085
14074
  }
14086
14075
  }
14087
14076
  return snapshots;
@@ -14180,10 +14169,10 @@ function updateAssetStatus(url, status) {
14180
14169
  window.__orbitalVerification.assetStatus[url] = status;
14181
14170
  }
14182
14171
  }
14183
- var log5, MAX_TRANSITIONS;
14172
+ var log4, MAX_TRANSITIONS;
14184
14173
  var init_verificationRegistry = __esm({
14185
14174
  "lib/verificationRegistry.ts"() {
14186
- log5 = createLogger("almadar:bridge");
14175
+ log4 = createLogger("almadar:bridge");
14187
14176
  MAX_TRANSITIONS = 500;
14188
14177
  exposeOnWindow();
14189
14178
  }
@@ -16114,7 +16103,7 @@ function generateDiff(oldVal, newVal) {
16114
16103
  }
16115
16104
  return diff;
16116
16105
  }
16117
- var orbStyleOverrides, orbStyle, loloStyleOverrides, loloStyle, log6, CODE_LANGUAGES, CODE_LANGUAGE_SET, DIFF_STYLES, LINE_PROPS_FN, HIDDEN_LINE_NUMBERS, CodeBlock;
16106
+ var orbStyleOverrides, orbStyle, loloStyleOverrides, loloStyle, log5, CODE_LANGUAGES, CODE_LANGUAGE_SET, DIFF_STYLES, LINE_PROPS_FN, HIDDEN_LINE_NUMBERS, CodeBlock;
16118
16107
  var init_CodeBlock = __esm({
16119
16108
  "components/core/molecules/markdown/CodeBlock.tsx"() {
16120
16109
  init_cn();
@@ -16197,7 +16186,7 @@ var init_CodeBlock = __esm({
16197
16186
  "lolo-op-async": { color: ORB_COLORS.dark.async }
16198
16187
  };
16199
16188
  loloStyle = { ...dark, ...loloStyleOverrides };
16200
- log6 = createLogger("almadar:ui:markdown-code");
16189
+ log5 = createLogger("almadar:ui:markdown-code");
16201
16190
  CODE_LANGUAGES = [
16202
16191
  "text",
16203
16192
  "json",
@@ -16461,7 +16450,7 @@ var init_CodeBlock = __esm({
16461
16450
  eventBus.emit("UI:COPY_CODE", { language: activeLanguage, success: true });
16462
16451
  setTimeout(() => setCopied(false), 2e3);
16463
16452
  } catch (err) {
16464
- log6.error("Failed to copy code", { error: err instanceof Error ? err : String(err) });
16453
+ log5.error("Failed to copy code", { error: err instanceof Error ? err : String(err) });
16465
16454
  eventBus.emit("UI:COPY_CODE", { language: activeLanguage, success: false });
16466
16455
  }
16467
16456
  };
@@ -20342,14 +20331,14 @@ function useSafeEventBus2() {
20342
20331
  } };
20343
20332
  }
20344
20333
  }
20345
- var log7, lookStyles4, ButtonGroup;
20334
+ var log6, lookStyles4, ButtonGroup;
20346
20335
  var init_ButtonGroup = __esm({
20347
20336
  "components/core/molecules/ButtonGroup.tsx"() {
20348
20337
  "use client";
20349
20338
  init_cn();
20350
20339
  init_atoms2();
20351
20340
  init_useEventBus();
20352
- log7 = createLogger("almadar:ui:button-group");
20341
+ log6 = createLogger("almadar:ui:button-group");
20353
20342
  lookStyles4 = {
20354
20343
  "right-aligned-buttons": "",
20355
20344
  "floating-bar": "fixed bottom-section left-1/2 -translate-x-1/2 shadow-elevation-toast bg-card p-card-sm rounded-container",
@@ -20430,7 +20419,7 @@ var init_ButtonGroup = __esm({
20430
20419
  {
20431
20420
  variant: "ghost",
20432
20421
  onClick: () => {
20433
- log7.debug("Filter clicked", { field: filter.field });
20422
+ log6.debug("Filter clicked", { field: filter.field });
20434
20423
  },
20435
20424
  children: filter.label
20436
20425
  },
@@ -28092,9 +28081,9 @@ function debug(...args) {
28092
28081
  const [first, ...rest] = args;
28093
28082
  const message = typeof first === "string" ? first : "<debug>";
28094
28083
  if (rest.length === 0 && typeof first === "string") {
28095
- log8.debug(message);
28084
+ log7.debug(message);
28096
28085
  } else {
28097
- log8.debug(message, { args: rest.length > 0 ? formatArgs(rest) : formatArgs([first]) });
28086
+ log7.debug(message, { args: rest.length > 0 ? formatArgs(rest) : formatArgs([first]) });
28098
28087
  }
28099
28088
  }
28100
28089
  function debugGroup(label) {
@@ -28122,11 +28111,11 @@ function toLogMetaValue(v) {
28122
28111
  }
28123
28112
  return String(v);
28124
28113
  }
28125
- var NAMESPACE, log8;
28114
+ var NAMESPACE, log7;
28126
28115
  var init_debug = __esm({
28127
28116
  "lib/debug.ts"() {
28128
28117
  NAMESPACE = "almadar:ui:debug";
28129
- log8 = createLogger(NAMESPACE);
28118
+ log7 = createLogger(NAMESPACE);
28130
28119
  createLogger("almadar:ui:debug:input");
28131
28120
  createLogger("almadar:ui:debug:collision");
28132
28121
  createLogger("almadar:ui:debug:physics");
@@ -40157,6 +40146,7 @@ var init_GraphCanvas = __esm({
40157
40146
  draggable = true,
40158
40147
  actions,
40159
40148
  onNodeClick,
40149
+ onNodeDoubleClick,
40160
40150
  nodeClickEvent,
40161
40151
  selectedNodeId,
40162
40152
  repulsion = 800,
@@ -40176,6 +40166,19 @@ var init_GraphCanvas = __esm({
40176
40166
  const [hoveredNode, setHoveredNode] = useState(null);
40177
40167
  const nodesRef = useRef([]);
40178
40168
  const [, forceUpdate] = useState(0);
40169
+ const [logicalW, setLogicalW] = useState(800);
40170
+ useEffect(() => {
40171
+ const canvas = canvasRef.current;
40172
+ if (!canvas || typeof ResizeObserver === "undefined") return;
40173
+ const measure = () => {
40174
+ const width = Math.round(canvas.clientWidth);
40175
+ if (width > 0) setLogicalW(width);
40176
+ };
40177
+ measure();
40178
+ const ro = new ResizeObserver(measure);
40179
+ ro.observe(canvas);
40180
+ return () => ro.disconnect();
40181
+ }, []);
40179
40182
  const interactionRef = useRef({
40180
40183
  mode: "none",
40181
40184
  dragNodeId: null,
@@ -40188,10 +40191,8 @@ var init_GraphCanvas = __esm({
40188
40191
  const canvas = canvasRef.current;
40189
40192
  if (!canvas) return null;
40190
40193
  const rect = canvas.getBoundingClientRect();
40191
- const scaleX = rect.width > 0 ? canvas.width / rect.width : 1;
40192
- const scaleY = rect.height > 0 ? canvas.height / rect.height : 1;
40193
- const screenX = (e.clientX - rect.left) * scaleX;
40194
- const screenY = (e.clientY - rect.top) * scaleY;
40194
+ const screenX = e.clientX - rect.left;
40195
+ const screenY = e.clientY - rect.top;
40195
40196
  return {
40196
40197
  screenX,
40197
40198
  screenY,
@@ -40231,8 +40232,8 @@ var init_GraphCanvas = __esm({
40231
40232
  useEffect(() => {
40232
40233
  const canvas = canvasRef.current;
40233
40234
  if (!canvas || propNodes.length === 0) return;
40234
- const w = canvas.width;
40235
- const h = canvas.height;
40235
+ const w = logicalW;
40236
+ const h = height;
40236
40237
  const simNodes = propNodes.map((n, idx) => {
40237
40238
  let x = n.x ?? 0;
40238
40239
  let y = n.y ?? 0;
@@ -40322,29 +40323,41 @@ var init_GraphCanvas = __esm({
40322
40323
  return () => {
40323
40324
  cancelAnimationFrame(animRef.current);
40324
40325
  };
40325
- }, [propNodes, propEdges, layout, repulsion, linkDistance]);
40326
+ }, [propNodes, propEdges, layout, repulsion, linkDistance, logicalW, height]);
40326
40327
  useEffect(() => {
40327
40328
  const canvas = canvasRef.current;
40328
40329
  if (!canvas) return;
40329
40330
  const ctx = canvas.getContext("2d");
40330
40331
  if (!ctx) return;
40331
- const w = canvas.width;
40332
- const h = canvas.height;
40332
+ const w = logicalW;
40333
+ const h = height;
40333
40334
  const nodes = nodesRef.current;
40334
40335
  const accentColor = resolveColor2("var(--color-accent)", canvas);
40336
+ const dpr = typeof window !== "undefined" && window.devicePixelRatio || 1;
40337
+ ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
40335
40338
  ctx.clearRect(0, 0, w, h);
40336
40339
  ctx.save();
40337
40340
  ctx.translate(offset.x, offset.y);
40338
40341
  ctx.scale(zoom, zoom);
40342
+ const neighbors = /* @__PURE__ */ new Set();
40343
+ if (hoveredNode) {
40344
+ neighbors.add(hoveredNode);
40345
+ for (const edge of propEdges) {
40346
+ if (edge.source === hoveredNode) neighbors.add(String(edge.target));
40347
+ else if (edge.target === hoveredNode) neighbors.add(String(edge.source));
40348
+ }
40349
+ }
40339
40350
  for (const edge of propEdges) {
40340
40351
  const source = nodes.find((n) => n.id === edge.source);
40341
40352
  const target = nodes.find((n) => n.id === edge.target);
40342
40353
  if (!source || !target) continue;
40354
+ const incident = !!hoveredNode && (edge.source === hoveredNode || edge.target === hoveredNode);
40355
+ ctx.globalAlpha = hoveredNode ? incident ? 1 : 0.12 : 1;
40343
40356
  ctx.beginPath();
40344
40357
  ctx.moveTo(source.x, source.y);
40345
40358
  ctx.lineTo(target.x, target.y);
40346
- ctx.strokeStyle = edge.color || "#88888866";
40347
- ctx.lineWidth = edge.weight ? Math.max(1, edge.weight) : 1;
40359
+ ctx.strokeStyle = incident ? accentColor : edge.color || "#88888866";
40360
+ ctx.lineWidth = incident ? 2 : edge.weight ? Math.max(1, edge.weight) : 1;
40348
40361
  ctx.stroke();
40349
40362
  if (edge.label && showLabels) {
40350
40363
  const mx = (source.x + target.x) / 2;
@@ -40355,11 +40368,13 @@ var init_GraphCanvas = __esm({
40355
40368
  ctx.fillText(edge.label, mx, my - 4);
40356
40369
  }
40357
40370
  }
40371
+ ctx.globalAlpha = 1;
40358
40372
  for (const node of nodes) {
40359
40373
  const size = node.size || 8;
40360
40374
  const color = resolveColor2(node.color || getGroupColor(node.group, groups), canvas);
40361
40375
  const isHovered = hoveredNode === node.id;
40362
40376
  const isSelected = selectedNodeId !== void 0 && node.id === selectedNodeId;
40377
+ ctx.globalAlpha = hoveredNode && !neighbors.has(node.id) ? 0.2 : 1;
40363
40378
  const radius = isSelected ? size + 4 : isHovered ? size + 2 : size;
40364
40379
  ctx.beginPath();
40365
40380
  ctx.arc(node.x, node.y, radius, 0, Math.PI * 2);
@@ -40479,6 +40494,15 @@ var init_GraphCanvas = __esm({
40479
40494
  interactionRef.current.dragNodeId = null;
40480
40495
  setHoveredNode(null);
40481
40496
  }, []);
40497
+ const handleDoubleClick = useCallback(
40498
+ (e) => {
40499
+ const coords = toCoords(e);
40500
+ if (!coords) return;
40501
+ const node = nodeAt(coords.graphX, coords.graphY);
40502
+ if (node) onNodeDoubleClick?.(node);
40503
+ },
40504
+ [toCoords, nodeAt, onNodeDoubleClick]
40505
+ );
40482
40506
  if (isLoading) {
40483
40507
  return /* @__PURE__ */ jsx(LoadingState, { message: t("common.loading"), className });
40484
40508
  }
@@ -40536,15 +40560,16 @@ var init_GraphCanvas = __esm({
40536
40560
  "canvas",
40537
40561
  {
40538
40562
  ref: canvasRef,
40539
- width: 800,
40540
- height,
40563
+ width: Math.round(logicalW * (typeof window !== "undefined" && window.devicePixelRatio || 1)),
40564
+ height: Math.round(height * (typeof window !== "undefined" && window.devicePixelRatio || 1)),
40541
40565
  className: "w-full cursor-grab active:cursor-grabbing",
40542
40566
  style: { height },
40543
40567
  onWheel: handleWheel,
40544
40568
  onMouseDown: handleMouseDown,
40545
40569
  onMouseMove: handleMouseMove,
40546
40570
  onMouseUp: handleMouseUp,
40547
- onMouseLeave: handleMouseLeave
40571
+ onMouseLeave: handleMouseLeave,
40572
+ onDoubleClick: handleDoubleClick
40548
40573
  }
40549
40574
  ) }),
40550
40575
  groups.length > 1 && /* @__PURE__ */ jsx(HStack, { gap: "md", className: "px-4 py-2 border-t border-border", wrap: true, children: groups.map((group, idx) => /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
@@ -44138,11 +44163,11 @@ var init_Canvas3DErrorBoundary = __esm({
44138
44163
  "components/game/molecules/three/components/Canvas3DErrorBoundary.css"() {
44139
44164
  }
44140
44165
  });
44141
- var log9, Canvas3DErrorBoundary;
44166
+ var log8, Canvas3DErrorBoundary;
44142
44167
  var init_Canvas3DErrorBoundary2 = __esm({
44143
44168
  "components/game/molecules/three/components/Canvas3DErrorBoundary.tsx"() {
44144
44169
  init_Canvas3DErrorBoundary();
44145
- log9 = createLogger("almadar:ui:game:canvas3d:error-boundary");
44170
+ log8 = createLogger("almadar:ui:game:canvas3d:error-boundary");
44146
44171
  Canvas3DErrorBoundary = class extends Component {
44147
44172
  constructor(props) {
44148
44173
  super(props);
@@ -44170,8 +44195,8 @@ var init_Canvas3DErrorBoundary2 = __esm({
44170
44195
  componentDidCatch(error, errorInfo) {
44171
44196
  this.setState({ errorInfo });
44172
44197
  this.props.onError?.(error, errorInfo);
44173
- log9.error("Error caught", { error });
44174
- log9.error("Component stack", { componentStack: errorInfo.componentStack ?? "<none>" });
44198
+ log8.error("Error caught", { error });
44199
+ log8.error("Component stack", { componentStack: errorInfo.componentStack ?? "<none>" });
44175
44200
  }
44176
44201
  render() {
44177
44202
  if (this.state.hasError) {
@@ -44234,7 +44259,7 @@ function useGLTFModel(url, resourceBasePath) {
44234
44259
  setState({ model: null, isLoading: false, error: null });
44235
44260
  return;
44236
44261
  }
44237
- log10.debug("Loading", { url });
44262
+ log9.debug("Loading", { url });
44238
44263
  setState((prev) => ({ ...prev, isLoading: true, error: null }));
44239
44264
  const assetRoot = resourceBasePath || detectAssetRoot2(url);
44240
44265
  const loader = new GLTFLoader$1();
@@ -44242,7 +44267,7 @@ function useGLTFModel(url, resourceBasePath) {
44242
44267
  loader.load(
44243
44268
  url,
44244
44269
  (gltf) => {
44245
- log10.debug("Loaded", { url });
44270
+ log9.debug("Loaded", { url });
44246
44271
  setState({
44247
44272
  model: gltf.scene,
44248
44273
  isLoading: false,
@@ -44251,7 +44276,7 @@ function useGLTFModel(url, resourceBasePath) {
44251
44276
  },
44252
44277
  void 0,
44253
44278
  (err) => {
44254
- log10.warn("Failed", { url, error: err instanceof Error ? err : String(err) });
44279
+ log9.warn("Failed", { url, error: err instanceof Error ? err : String(err) });
44255
44280
  setState({
44256
44281
  model: null,
44257
44282
  isLoading: false,
@@ -44367,11 +44392,11 @@ function ModelLoader({
44367
44392
  }
44368
44393
  );
44369
44394
  }
44370
- var log10;
44395
+ var log9;
44371
44396
  var init_ModelLoader = __esm({
44372
44397
  "components/game/molecules/three/components/ModelLoader.tsx"() {
44373
44398
  "use client";
44374
- log10 = createLogger("almadar:ui:game:model-loader");
44399
+ log9 = createLogger("almadar:ui:game:model-loader");
44375
44400
  }
44376
44401
  });
44377
44402
 
@@ -44632,24 +44657,28 @@ var init_GameCanvas3D2 = __esm({
44632
44657
  const cameraConfig = useMemo(() => {
44633
44658
  const size = Math.max(
44634
44659
  gridBounds.maxX - gridBounds.minX,
44635
- gridBounds.maxZ - gridBounds.minZ
44660
+ gridBounds.maxZ - gridBounds.minZ,
44661
+ 4
44662
+ // minimum framing distance so a tiny board isn't zoomed in
44636
44663
  );
44637
- const distance = size * 1.5;
44664
+ const cx = (gridBounds.minX + gridBounds.maxX) / 2;
44665
+ const cz = (gridBounds.minZ + gridBounds.maxZ) / 2;
44666
+ const d = size * 1.5;
44638
44667
  switch (cameraMode) {
44639
44668
  case "isometric":
44640
44669
  return {
44641
- position: [distance, distance * 0.8, distance],
44670
+ position: [cx + d, d * 0.8, cz + d],
44642
44671
  fov: 45
44643
44672
  };
44644
44673
  case "top-down":
44645
44674
  return {
44646
- position: [0, distance * 2, 0],
44675
+ position: [cx, d * 2, cz],
44647
44676
  fov: 45
44648
44677
  };
44649
44678
  case "perspective":
44650
44679
  default:
44651
44680
  return {
44652
- position: [distance, distance, distance],
44681
+ position: [cx + d, d, cz + d],
44653
44682
  fov: 45
44654
44683
  };
44655
44684
  }
@@ -44888,7 +44917,8 @@ var init_GameCanvas3D2 = __esm({
44888
44917
  "div",
44889
44918
  {
44890
44919
  ref: containerRef,
44891
- className: cn("game-canvas-3d relative w-full h-full min-h-[85vh] overflow-hidden", className),
44920
+ className: cn("game-canvas-3d relative w-full overflow-hidden", className),
44921
+ style: { minHeight: "85vh" },
44892
44922
  "data-orientation": orientation,
44893
44923
  "data-camera-mode": cameraMode,
44894
44924
  "data-overlay": overlay,
@@ -44903,7 +44933,7 @@ var init_GameCanvas3D2 = __esm({
44903
44933
  near: 0.1,
44904
44934
  far: 1e3
44905
44935
  },
44906
- style: { background: backgroundColor },
44936
+ style: { background: backgroundColor, height: "85vh", width: "100%" },
44907
44937
  onClick: (e) => {
44908
44938
  if (e.target === e.currentTarget) {
44909
44939
  eventHandlers.handleCanvasClick(e);
@@ -48705,7 +48735,7 @@ function getAllEvents(traits2) {
48705
48735
  function EventDispatcherTab({ traits: traits2, schema }) {
48706
48736
  const eventBus = useEventBus();
48707
48737
  const { t } = useTranslate();
48708
- const [log16, setLog] = React90.useState([]);
48738
+ const [log15, setLog] = React90.useState([]);
48709
48739
  const prevStatesRef = React90.useRef(/* @__PURE__ */ new Map());
48710
48740
  React90.useEffect(() => {
48711
48741
  for (const trait of traits2) {
@@ -48769,9 +48799,9 @@ function EventDispatcherTab({ traits: traits2, schema }) {
48769
48799
  /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "medium", className: "text-gray-500 mb-1", children: t("debug.otherEvents") }),
48770
48800
  /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: unavailableEvents.map((event) => /* @__PURE__ */ jsx(Badge, { variant: "default", size: "sm", className: "opacity-50", children: event }, event)) })
48771
48801
  ] }),
48772
- log16.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
48802
+ log15.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
48773
48803
  /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "medium", className: "text-gray-500 mb-1", children: t("debug.recentTransitions") }),
48774
- /* @__PURE__ */ jsx(Stack, { gap: "xs", children: log16.map((entry, i) => /* @__PURE__ */ jsxs(Typography, { variant: "small", className: "font-mono text-xs", children: [
48804
+ /* @__PURE__ */ jsx(Stack, { gap: "xs", children: log15.map((entry, i) => /* @__PURE__ */ jsxs(Typography, { variant: "small", className: "font-mono text-xs", children: [
48775
48805
  /* @__PURE__ */ jsx("span", { className: "text-purple-400", children: entry.traitName }),
48776
48806
  " ",
48777
48807
  /* @__PURE__ */ jsx("span", { className: "text-gray-500", children: entry.from }),
@@ -53786,7 +53816,7 @@ function isPatternConfig(value) {
53786
53816
  if (value instanceof Date) return false;
53787
53817
  if (typeof value === "function") return false;
53788
53818
  const record = value;
53789
- return "type" in record && typeof record.type === "string" && isKnownPattern(record.type);
53819
+ return "type" in record && typeof record.type === "string" && getComponentForPattern$1(record.type) !== null;
53790
53820
  }
53791
53821
  function isPlainConfigObject(value) {
53792
53822
  if (React90__default.isValidElement(value)) return false;
@@ -57698,7 +57728,7 @@ function convertObjectProps(props) {
57698
57728
  function convertFnFormLambdasInProps(props) {
57699
57729
  return convertObjectProps(props);
57700
57730
  }
57701
- var log11 = createLogger("almadar:ui:effects:client-handlers");
57731
+ var log10 = createLogger("almadar:ui:effects:client-handlers");
57702
57732
  function createClientEffectHandlers(options) {
57703
57733
  const { eventBus, slotSetter, navigate, notify, callService, liveEntity } = options;
57704
57734
  return {
@@ -57707,11 +57737,11 @@ function createClientEffectHandlers(options) {
57707
57737
  eventBus.emit(prefixedEvent, payload);
57708
57738
  },
57709
57739
  persist: async () => {
57710
- log11.warn("persist is server-side only, ignored on client");
57740
+ log10.warn("persist is server-side only, ignored on client");
57711
57741
  },
57712
57742
  set: (_entityId, field, value) => {
57713
57743
  if (!liveEntity) {
57714
- log11.warn("set is server-side only, ignored on client (no live entity)");
57744
+ log10.warn("set is server-side only, ignored on client (no live entity)");
57715
57745
  return;
57716
57746
  }
57717
57747
  liveEntity[field] = value;
@@ -57743,10 +57773,10 @@ function createClientEffectHandlers(options) {
57743
57773
  slotSetter.addPattern(slot, pattern, props);
57744
57774
  },
57745
57775
  navigate: navigate ?? ((path) => {
57746
- log11.warn("No navigate handler, ignoring", { path });
57776
+ log10.warn("No navigate handler, ignoring", { path });
57747
57777
  }),
57748
57778
  notify: notify ?? ((msg, type) => {
57749
- log11.debug("notify", { type, message: msg });
57779
+ log10.debug("notify", { type, message: msg });
57750
57780
  })
57751
57781
  };
57752
57782
  }
@@ -57978,7 +58008,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
57978
58008
  };
57979
58009
  }, [traitBindings]);
57980
58010
  const executeTransitionEffects = useCallback(async (params) => {
57981
- const { binding, previousState, newState, payload, flushEvent, syncOnly, log: log16 } = params;
58011
+ const { binding, previousState, newState, payload, flushEvent, syncOnly, log: log15 } = params;
57982
58012
  const traitName = binding.trait.name;
57983
58013
  const linkedEntity = binding.linkedEntity || "";
57984
58014
  const entityId = payload?.entityId;
@@ -58066,7 +58096,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
58066
58096
  ...handlers,
58067
58097
  set: async (targetId, field, value) => {
58068
58098
  if (baseSet) await baseSet(targetId, field, value);
58069
- log16.debug("set:write", {
58099
+ log15.debug("set:write", {
58070
58100
  traitName,
58071
58101
  field,
58072
58102
  value: JSON.stringify(value),
@@ -58106,7 +58136,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
58106
58136
  const executor = new EffectExecutor({ handlers: trackingHandlers, bindings: bindingCtx, context: effectContext });
58107
58137
  try {
58108
58138
  await executor.executeAll(effects);
58109
- log16.debug("effects:executed", () => ({
58139
+ log15.debug("effects:executed", () => ({
58110
58140
  traitName,
58111
58141
  transition: `${previousState}->${newState}`,
58112
58142
  event: flushEvent,
@@ -58116,7 +58146,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
58116
58146
  slotsTouched: Array.from(pendingSlots.keys()).join(",")
58117
58147
  }));
58118
58148
  for (const [slot, patterns] of pendingSlots) {
58119
- log16.debug("flush:slot", {
58149
+ log15.debug("flush:slot", {
58120
58150
  traitName,
58121
58151
  slot,
58122
58152
  patternCount: patterns.length,
@@ -58131,7 +58161,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
58131
58161
  });
58132
58162
  }
58133
58163
  } catch (error) {
58134
- log16.error("effects:error", {
58164
+ log15.error("effects:error", {
58135
58165
  traitName,
58136
58166
  transition: `${previousState}->${newState}`,
58137
58167
  event: flushEvent,
@@ -59126,7 +59156,7 @@ OrbitalThemeProvider.displayName = "OrbitalThemeProvider";
59126
59156
  init_navigation();
59127
59157
  init_verificationRegistry();
59128
59158
  var PERF_NAMESPACE = "almadar:perf:canvas";
59129
- var log13 = createLogger(PERF_NAMESPACE);
59159
+ var log12 = createLogger(PERF_NAMESPACE);
59130
59160
  var RING_SIZE = 50;
59131
59161
  var ring = [];
59132
59162
  var writeIdx = 0;
@@ -59177,7 +59207,7 @@ function perfEnd(name, startToken, detail) {
59177
59207
  }
59178
59208
  }
59179
59209
  push({ name, durationMs, ts: endTs, detail });
59180
- log13.debug(name, () => ({ durationMs, ...detail ?? {} }));
59210
+ log12.debug(name, () => ({ durationMs, ...detail ?? {} }));
59181
59211
  }
59182
59212
  var profilerOnRender = (id, phase, actualDuration, baseDuration, _startTime, commitTime) => {
59183
59213
  if (!isEnabled()) return;
@@ -59187,7 +59217,7 @@ var profilerOnRender = (id, phase, actualDuration, baseDuration, _startTime, com
59187
59217
  ts: commitTime,
59188
59218
  detail: { baseDuration }
59189
59219
  });
59190
- log13.debug(`profiler:${id}:${phase}`, () => ({ actualDuration, baseDuration }));
59220
+ log12.debug(`profiler:${id}:${phase}`, () => ({ actualDuration, baseDuration }));
59191
59221
  };
59192
59222
 
59193
59223
  // runtime/prepareSchemaForPreview.ts
@@ -59830,7 +59860,7 @@ init_useEventBus();
59830
59860
  // components/avl/molecules/useCanvasDnd.tsx
59831
59861
  init_useEventBus();
59832
59862
  init_useAlmadarDndCollision();
59833
- var log14 = createLogger("almadar:ui:canvas-dnd");
59863
+ var log13 = createLogger("almadar:ui:canvas-dnd");
59834
59864
  function useCanvasDraggable({
59835
59865
  id,
59836
59866
  payload,
@@ -59869,7 +59899,7 @@ function defaultEmit(eventBus, drop) {
59869
59899
  if (payload.kind === "pattern") {
59870
59900
  const patternType = payload.data.type;
59871
59901
  if (typeof patternType !== "string") {
59872
- log14.warn("default-emit:pattern:missing-type");
59902
+ log13.warn("default-emit:pattern:missing-type");
59873
59903
  return;
59874
59904
  }
59875
59905
  const out = { patternType, containerNode: target.containerNode };
@@ -59878,23 +59908,23 @@ function defaultEmit(eventBus, drop) {
59878
59908
  out.index = resolved.index;
59879
59909
  }
59880
59910
  eventBus.emit("UI:PATTERN_DROP", out);
59881
- log14.info("default-emit:pattern", { patternType, level: target.level });
59911
+ log13.info("default-emit:pattern", { patternType, level: target.level });
59882
59912
  return;
59883
59913
  }
59884
59914
  if (payload.kind === "behavior") {
59885
59915
  const behaviorName = payload.data.name;
59886
59916
  if (typeof behaviorName !== "string") {
59887
- log14.warn("default-emit:behavior:missing-name");
59917
+ log13.warn("default-emit:behavior:missing-name");
59888
59918
  return;
59889
59919
  }
59890
59920
  eventBus.emit("UI:BEHAVIOR_DROP", {
59891
59921
  behaviorName,
59892
59922
  containerNode: target.containerNode
59893
59923
  });
59894
- log14.info("default-emit:behavior", { behaviorName, level: target.level });
59924
+ log13.info("default-emit:behavior", { behaviorName, level: target.level });
59895
59925
  return;
59896
59926
  }
59897
- log14.debug("default-emit:unhandled-kind", { kind: payload.kind });
59927
+ log13.debug("default-emit:unhandled-kind", { kind: payload.kind });
59898
59928
  }
59899
59929
  function CanvasDndProvider({
59900
59930
  children,
@@ -59910,9 +59940,9 @@ function CanvasDndProvider({
59910
59940
  if (payload) {
59911
59941
  setActivePayload(payload);
59912
59942
  eventBus.emit("UI:DRAG_START", { kind: payload.kind, data: payload.data });
59913
- log14.info("dragStart", { id: e.active.id, kind: payload.kind });
59943
+ log13.info("dragStart", { id: e.active.id, kind: payload.kind });
59914
59944
  } else {
59915
- log14.warn("dragStart:missing-payload", { id: e.active.id });
59945
+ log13.warn("dragStart:missing-payload", { id: e.active.id });
59916
59946
  }
59917
59947
  }, [eventBus]);
59918
59948
  const handleDragEnd = React90__default.useCallback((e) => {
@@ -59922,7 +59952,7 @@ function CanvasDndProvider({
59922
59952
  const overData = e.over?.data.current;
59923
59953
  const target = overData?.target;
59924
59954
  const accepts = overData?.accepts;
59925
- log14.info("dragEnd", {
59955
+ log13.info("dragEnd", {
59926
59956
  activeId: e.active.id,
59927
59957
  overId: e.over?.id,
59928
59958
  hasPayload: !!payload,
@@ -59934,7 +59964,7 @@ function CanvasDndProvider({
59934
59964
  }
59935
59965
  if (!payload || !target) return;
59936
59966
  if (accepts && !accepts.includes(payload.kind)) {
59937
- log14.debug("dragEnd:rejected:kind", { kind: payload.kind, accepts: [...accepts] });
59967
+ log13.debug("dragEnd:rejected:kind", { kind: payload.kind, accepts: [...accepts] });
59938
59968
  return;
59939
59969
  }
59940
59970
  const activator = e.activatorEvent;
@@ -59946,7 +59976,7 @@ function CanvasDndProvider({
59946
59976
  }, [eventBus, onDrop]);
59947
59977
  const handleDragCancel = React90__default.useCallback(() => {
59948
59978
  setActivePayload(null);
59949
- log14.info("dragCancel");
59979
+ log13.info("dragCancel");
59950
59980
  }, []);
59951
59981
  return /* @__PURE__ */ jsxs(
59952
59982
  DndContext,
@@ -61761,7 +61791,7 @@ init_AvlTransitionLane();
61761
61791
  init_AvlSwimLane();
61762
61792
  init_types();
61763
61793
  init_avl_elk_layout();
61764
- var log15 = createLogger("almadar:ui:avl:trait-scene");
61794
+ var log14 = createLogger("almadar:ui:avl:trait-scene");
61765
61795
  var SWIM_GUTTER2 = 120;
61766
61796
  var CENTER_W2 = 360;
61767
61797
  var AvlTraitScene = ({
@@ -61774,7 +61804,7 @@ var AvlTraitScene = ({
61774
61804
  const dataKey = useMemo(() => JSON.stringify(data), [data]);
61775
61805
  useEffect(() => {
61776
61806
  computeTraitLayout(data).then(setLayout).catch((error) => {
61777
- log15.error("computeTraitLayout failed", { error: error instanceof Error ? error : String(error) });
61807
+ log14.error("computeTraitLayout failed", { error: error instanceof Error ? error : String(error) });
61778
61808
  });
61779
61809
  }, [dataKey]);
61780
61810
  if (!layout) {
@@ -55,6 +55,8 @@ export interface GraphCanvasProps {
55
55
  actions?: readonly GraphAction[];
56
56
  /** On node click */
57
57
  onNodeClick?: (node: GraphNode) => void;
58
+ /** On node double-click (e.g. to drill in) */
59
+ onNodeDoubleClick?: (node: GraphNode) => void;
58
60
  /** Node click event */
59
61
  nodeClickEvent?: EventEmit<{
60
62
  id: string;