@almadar/ui 6.5.0 → 6.6.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.
Files changed (46) hide show
  1. package/dist/{EntityBindingContext-0Evn_LcT.d.cts → EntityBindingContext-Bn3ePJQC.d.cts} +1 -1
  2. package/dist/{EntityBindingContext-0Evn_LcT.d.ts → EntityBindingContext-Bn3ePJQC.d.ts} +1 -1
  3. package/dist/{GameAudioProvider-B48iXwz3.d.ts → GameAudioProvider-Ctceau1s.d.ts} +6 -18
  4. package/dist/{GameAudioProvider-CQAdPreB.d.cts → GameAudioProvider-Dk_Y3LN3.d.cts} +6 -18
  5. package/dist/avl/index.cjs +1216 -206
  6. package/dist/avl/index.js +1217 -207
  7. package/dist/{avl-schema-parser-dvJKXn-o.d.ts → avl-schema-parser-DncJLEn9.d.ts} +18 -0
  8. package/dist/{avl-schema-parser-Bt4NzAam.d.cts → avl-schema-parser-FQ1474v8.d.cts} +18 -0
  9. package/dist/{cn-DJSBBm5W.d.cts → cn-CCjFspAo.d.cts} +25 -1
  10. package/dist/{cn-BbhJq_nr.d.ts → cn-sgpqpN0U.d.ts} +25 -1
  11. package/dist/components/index.cjs +1025 -235
  12. package/dist/components/index.d.cts +176 -23
  13. package/dist/components/index.d.ts +176 -23
  14. package/dist/components/index.js +1023 -236
  15. package/dist/context/index.cjs +10 -13
  16. package/dist/context/index.js +10 -13
  17. package/dist/hooks/index.cjs +63 -13
  18. package/dist/hooks/index.d.cts +2 -2
  19. package/dist/hooks/index.d.ts +2 -2
  20. package/dist/hooks/index.js +64 -15
  21. package/dist/lib/drawable/three/index.cjs +126 -13
  22. package/dist/lib/drawable/three/index.d.cts +2 -2
  23. package/dist/lib/drawable/three/index.d.ts +2 -2
  24. package/dist/lib/drawable/three/index.js +127 -14
  25. package/dist/lib/index.cjs +180 -0
  26. package/dist/lib/index.d.cts +1 -1
  27. package/dist/lib/index.d.ts +1 -1
  28. package/dist/lib/index.js +178 -1
  29. package/dist/locales/index.cjs +6 -3
  30. package/dist/locales/index.js +6 -3
  31. package/dist/providers/index.cjs +922 -188
  32. package/dist/providers/index.d.cts +2 -2
  33. package/dist/providers/index.d.ts +2 -2
  34. package/dist/providers/index.js +922 -188
  35. package/dist/runtime/index.cjs +1505 -182
  36. package/dist/runtime/index.d.cts +78 -6
  37. package/dist/runtime/index.d.ts +78 -6
  38. package/dist/runtime/index.js +1504 -184
  39. package/dist/{useEventBus-CQWyAWpK.d.ts → useKeyboardRouter-D84cNWmA.d.ts} +31 -1
  40. package/dist/{useEventBus-Ckr4wqW3.d.cts → useKeyboardRouter-DQEE_9mq.d.cts} +31 -1
  41. package/locales/ar.json +2 -1
  42. package/locales/en.json +2 -1
  43. package/locales/sl.json +2 -1
  44. package/package.json +4 -4
  45. package/themes/comic.css +437 -0
  46. package/themes/index.css +1 -0
@@ -10045,7 +10045,7 @@ function collectDrawnItems(nodes) {
10045
10045
  for (const n of nodes) {
10046
10046
  switch (n.type) {
10047
10047
  case "draw-sprite":
10048
- if (isValidScenePos(n.position)) out.push({ pos: n.position, id: n.id, anchor: n.anchor, width: n.width, height: n.height });
10048
+ if (isValidScenePos(n.position)) out.push({ pos: n.position, id: n.id, anchor: n.anchor, width: n.width, height: n.height, rotation: n.rotation });
10049
10049
  break;
10050
10050
  case "draw-shape":
10051
10051
  case "draw-text":
@@ -10055,7 +10055,7 @@ function collectDrawnItems(nodes) {
10055
10055
  break;
10056
10056
  case "draw-sprite-layer":
10057
10057
  for (const it of n.items) {
10058
- if (isValidScenePos(it.position)) out.push({ pos: it.position, id: it.id, anchor: it.anchor, width: it.width, height: it.height });
10058
+ if (isValidScenePos(it.position)) out.push({ pos: it.position, id: it.id, anchor: it.anchor, width: it.width, height: it.height, rotation: it.rotation });
10059
10059
  }
10060
10060
  break;
10061
10061
  case "draw-shape-layer":
@@ -10075,15 +10075,39 @@ function buildHitIndex(items) {
10075
10075
  }
10076
10076
  return m;
10077
10077
  }
10078
+ function withPreviewPosition(nodes, id, pos) {
10079
+ return nodes.map((n) => {
10080
+ if (n.type === "draw-sprite-layer" || n.type === "draw-shape-layer" || n.type === "draw-text-layer") {
10081
+ if (!n.items.some((it) => it.id === id)) return n;
10082
+ return { ...n, items: n.items.map((it) => it.id === id ? { ...it, position: pos } : it) };
10083
+ }
10084
+ if (n.type === "draw-group") {
10085
+ if (!Array.isArray(n.items)) return n;
10086
+ return { ...n, items: withPreviewPosition(n.items, id, pos) };
10087
+ }
10088
+ if (n.id === id && "position" in n) {
10089
+ return { ...n, position: pos };
10090
+ }
10091
+ return n;
10092
+ });
10093
+ }
10078
10094
  function hitTestSprites(items, projector, point) {
10079
10095
  for (let i = items.length - 1; i >= 0; i--) {
10080
10096
  const it = items[i];
10081
10097
  if (it.id === void 0) continue;
10082
10098
  const r = spriteRect(projector, { position: it.pos, anchor: it.anchor, width: it.width, height: it.height });
10083
- if (point.x >= r.x && point.x <= r.x + r.w && point.y >= r.y && point.y <= r.y + r.h) return it.id;
10099
+ const test = it.rotation ? rotatePoint(point, { x: r.x + r.w / 2, y: r.y + r.h / 2 }, -it.rotation) : point;
10100
+ if (test.x >= r.x && test.x <= r.x + r.w && test.y >= r.y && test.y <= r.y + r.h) return it.id;
10084
10101
  }
10085
10102
  return void 0;
10086
10103
  }
10104
+ function rotatePoint(p, center, radians) {
10105
+ const cos = Math.cos(radians);
10106
+ const sin = Math.sin(radians);
10107
+ const dx = p.x - center.x;
10108
+ const dy = p.y - center.y;
10109
+ return { x: center.x + dx * cos - dy * sin, y: center.y + dx * sin + dy * cos };
10110
+ }
10087
10111
  var init_hitTest = __esm({
10088
10112
  "lib/drawable/hitTest.ts"() {
10089
10113
  init_contract();
@@ -10092,6 +10116,41 @@ var init_hitTest = __esm({
10092
10116
  function normalizeBackdrop(bg) {
10093
10117
  return typeof bg === "string" ? { url: bg, role: "decoration", category: "background" } : bg;
10094
10118
  }
10119
+ function selectionOverlayNodes(projector, item) {
10120
+ const r = spriteRect(projector, { position: item.pos, anchor: item.anchor, width: item.width, height: item.height });
10121
+ const tw = projector.tileWidth;
10122
+ const cellTopLeft = projector.anchorPoint(item.pos, "top-left");
10123
+ const offsetX = (r.x - cellTopLeft.x) / tw;
10124
+ const offsetY = (r.y - cellTopLeft.y) / tw;
10125
+ const width = r.w / tw;
10126
+ const height = r.h / tw;
10127
+ const handle = EDIT_HANDLE_SIZE_PX / tw;
10128
+ const ring = {
10129
+ type: "draw-shape",
10130
+ shape: "rect",
10131
+ position: item.pos,
10132
+ anchor: "top-left",
10133
+ offsetX,
10134
+ offsetY,
10135
+ width,
10136
+ height,
10137
+ stroke: EDIT_SELECTION_COLOR,
10138
+ strokeWidth: 2,
10139
+ fill: "none"
10140
+ };
10141
+ const handles = EDIT_SELECTION_CORNERS.map(([cx, cy]) => ({
10142
+ type: "draw-shape",
10143
+ shape: "rect",
10144
+ position: item.pos,
10145
+ anchor: "top-left",
10146
+ offsetX: offsetX + cx * width - handle / 2,
10147
+ offsetY: offsetY + cy * height - handle / 2,
10148
+ width: handle,
10149
+ height: handle,
10150
+ fill: EDIT_SELECTION_COLOR
10151
+ }));
10152
+ return [ring, ...handles];
10153
+ }
10095
10154
  function Canvas2D({
10096
10155
  className,
10097
10156
  isLoading = false,
@@ -10105,6 +10164,12 @@ function Canvas2D({
10105
10164
  tileLeaveEvent,
10106
10165
  keyMap,
10107
10166
  keyUpMap,
10167
+ editable = false,
10168
+ selectedId = null,
10169
+ onSelect,
10170
+ onMove,
10171
+ selectEvent,
10172
+ moveEvent,
10108
10173
  camera = "pan-zoom",
10109
10174
  scale = 0.4,
10110
10175
  tileWidth,
@@ -10362,10 +10427,22 @@ function Canvas2D({
10362
10427
  painter.scale(cam.zoom, cam.zoom);
10363
10428
  painter.translate(-viewportSize.width / 2 - cam.x, -viewportSize.height / 2 - cam.y);
10364
10429
  const dctx = { projector, time: timeMs, invalidate: bumpAtlas };
10365
- for (const node of drawables) paintDrawable(painter, node, dctx);
10430
+ let paintNodes = drawables;
10431
+ if (editable) {
10432
+ const drag = editDragRef.current;
10433
+ if (drag && drag.moved) {
10434
+ paintNodes = withPreviewPosition(paintNodes, drag.id, { x: drag.previewX, y: drag.previewY });
10435
+ }
10436
+ const selectedItem = selectedId != null ? drawnItems.find((it) => it.id === selectedId) : void 0;
10437
+ if (selectedItem) {
10438
+ const overlaySource = drag && drag.moved && drag.id === selectedId ? { ...selectedItem, pos: { x: drag.previewX, y: drag.previewY } } : selectedItem;
10439
+ paintNodes = [...paintNodes, ...selectionOverlayNodes(projector, overlaySource)];
10440
+ }
10441
+ }
10442
+ for (const node of paintNodes) paintDrawable(painter, node, dctx);
10366
10443
  painter.restore();
10367
- scheduleAnimation(drawables);
10368
- }, [viewportSize, backgroundImage, bgColor, drawables, projector, cameraRef, bumpAtlas, getImage, cameraPos, defaultGridFocus, camera, dragDistance]);
10444
+ scheduleAnimation(paintNodes);
10445
+ }, [viewportSize, backgroundImage, bgColor, drawables, projector, cameraRef, bumpAtlas, getImage, cameraPos, defaultGridFocus, camera, dragDistance, editable, selectedId, drawnItems]);
10369
10446
  React89.useEffect(() => {
10370
10447
  drawTimeRef.current = draw;
10371
10448
  }, [draw]);
@@ -10410,23 +10487,83 @@ function Canvas2D({
10410
10487
  };
10411
10488
  }, [camera, followTarget, lerpToTarget, draw]);
10412
10489
  const singlePointerActiveRef = React89.useRef(false);
10490
+ const editDragRef = React89.useRef(null);
10491
+ const pointerToScene = React89.useCallback((clientX, clientY) => {
10492
+ const canvas = canvasRef.current;
10493
+ if (!canvas) return { x: 0, y: 0 };
10494
+ const world = screenToWorld(clientX, clientY, canvas, viewportSize);
10495
+ const adjustedX = world.x - scaledTileWidth / 2;
10496
+ const adjustedY = squareGrid ? world.y - scaledTileWidth / 2 : world.y - scaledDiamondTopY - scaledFloorHeight / 2;
10497
+ return unproject(adjustedX, adjustedY);
10498
+ }, [screenToWorld, viewportSize, scaledTileWidth, squareGrid, scaledDiamondTopY, scaledFloorHeight, unproject]);
10413
10499
  const handleCanvasPointerDown = React89.useCallback((e) => {
10414
10500
  singlePointerActiveRef.current = true;
10501
+ if (editable) {
10502
+ if (!canvasRef.current) return;
10503
+ const world = screenToWorld(e.clientX, e.clientY, canvasRef.current, viewportSize);
10504
+ const hitId = hitTestSprites(drawnItems, projector, world);
10505
+ if (hitId === void 0) return;
10506
+ const item = [...drawnItems].reverse().find((it) => it.id === hitId);
10507
+ if (!item) return;
10508
+ editDragRef.current = {
10509
+ id: hitId,
10510
+ pointerId: e.pointerId,
10511
+ startClientX: e.clientX,
10512
+ startClientY: e.clientY,
10513
+ startSceneX: item.pos.x,
10514
+ startSceneY: item.pos.y,
10515
+ moved: false,
10516
+ previewX: item.pos.x,
10517
+ previewY: item.pos.y
10518
+ };
10519
+ return;
10520
+ }
10415
10521
  if (enableCamera) handlePointerDown(e);
10416
- }, [enableCamera, handlePointerDown]);
10522
+ }, [editable, screenToWorld, viewportSize, drawnItems, projector, enableCamera, handlePointerDown]);
10417
10523
  const handleCanvasPointerMove = React89.useCallback((e) => {
10524
+ if (editable) {
10525
+ const drag = editDragRef.current;
10526
+ if (!drag || drag.pointerId !== e.pointerId) return;
10527
+ const dxPx = e.clientX - drag.startClientX;
10528
+ const dyPx = e.clientY - drag.startClientY;
10529
+ if (!drag.moved && Math.abs(dxPx) + Math.abs(dyPx) <= 5) return;
10530
+ drag.moved = true;
10531
+ const nowScene = pointerToScene(e.clientX, e.clientY);
10532
+ const startScene = pointerToScene(drag.startClientX, drag.startClientY);
10533
+ drag.previewX = drag.startSceneX + (nowScene.x - startScene.x);
10534
+ drag.previewY = drag.startSceneY + (nowScene.y - startScene.y);
10535
+ draw();
10536
+ return;
10537
+ }
10418
10538
  if (enableCamera) handlePointerMove(e, () => draw());
10419
- }, [enableCamera, handlePointerMove, draw]);
10539
+ }, [editable, pointerToScene, draw, enableCamera, handlePointerMove]);
10420
10540
  const handleCanvasHover = React89.useCallback((e) => {
10421
10541
  if (singlePointerActiveRef.current) return;
10422
10542
  if (!tileHoverEvent || !canvasRef.current) return;
10423
- const world = screenToWorld(e.clientX, e.clientY, canvasRef.current, viewportSize);
10424
- const adjustedX = world.x - scaledTileWidth / 2;
10425
- const adjustedY = squareGrid ? world.y - scaledTileWidth / 2 : world.y - scaledDiamondTopY - scaledFloorHeight / 2;
10426
- const isoPos = unproject(adjustedX, adjustedY);
10543
+ const isoPos = pointerToScene(e.clientX, e.clientY);
10427
10544
  eventBus.emit(`UI:${tileHoverEvent}`, { x: isoPos.x, y: isoPos.y });
10428
- }, [screenToWorld, viewportSize, scaledTileWidth, squareGrid, scaledDiamondTopY, scaledFloorHeight, unproject, tileHoverEvent, eventBus]);
10545
+ }, [pointerToScene, tileHoverEvent, eventBus]);
10429
10546
  const handleCanvasPointerUp = React89.useCallback((e) => {
10547
+ if (editable) {
10548
+ singlePointerActiveRef.current = false;
10549
+ const drag = editDragRef.current;
10550
+ if (drag && drag.pointerId === e.pointerId) {
10551
+ editDragRef.current = null;
10552
+ if (drag.moved) {
10553
+ onMove?.(drag.id, drag.previewX, drag.previewY);
10554
+ if (moveEvent) eventBus.emit(`UI:${moveEvent}`, { id: drag.id, x: drag.previewX, y: drag.previewY });
10555
+ draw();
10556
+ return;
10557
+ }
10558
+ const next = selectedId === drag.id ? null : drag.id;
10559
+ onSelect?.(next);
10560
+ if (selectEvent) eventBus.emit(`UI:${selectEvent}`, { id: next });
10561
+ return;
10562
+ }
10563
+ onSelect?.(null);
10564
+ if (selectEvent) eventBus.emit(`UI:${selectEvent}`, { id: null });
10565
+ return;
10566
+ }
10430
10567
  singlePointerActiveRef.current = false;
10431
10568
  if (enableCamera) handlePointerUp();
10432
10569
  if (dragDistance() > 5) return;
@@ -10437,16 +10574,14 @@ function Canvas2D({
10437
10574
  eventBus.emit(`UI:${unitClickEvent}`, { unitId: spriteHit });
10438
10575
  return;
10439
10576
  }
10440
- const adjustedX = world.x - scaledTileWidth / 2;
10441
- const adjustedY = squareGrid ? world.y - scaledTileWidth / 2 : world.y - scaledDiamondTopY - scaledFloorHeight / 2;
10442
- const isoPos = unproject(adjustedX, adjustedY);
10577
+ const isoPos = pointerToScene(e.clientX, e.clientY);
10443
10578
  const hitId = hitIndex.get(`${isoPos.x},${isoPos.y}`);
10444
10579
  if (hitId !== void 0 && unitClickEvent) {
10445
10580
  eventBus.emit(`UI:${unitClickEvent}`, { unitId: hitId });
10446
10581
  } else if (tileClickEvent) {
10447
10582
  eventBus.emit(`UI:${tileClickEvent}`, { x: isoPos.x, y: isoPos.y });
10448
10583
  }
10449
- }, [enableCamera, handlePointerUp, dragDistance, screenToWorld, viewportSize, scaledTileWidth, squareGrid, scaledDiamondTopY, scaledFloorHeight, unproject, hitIndex, drawnItems, projector, tileClickEvent, unitClickEvent, eventBus]);
10584
+ }, [editable, selectedId, onMove, moveEvent, onSelect, selectEvent, eventBus, draw, enableCamera, handlePointerUp, dragDistance, screenToWorld, viewportSize, drawnItems, projector, tileClickEvent, unitClickEvent, hitIndex, pointerToScene]);
10450
10585
  const handleCanvasPointerLeave = React89.useCallback(() => {
10451
10586
  handleMouseLeave();
10452
10587
  if (tileLeaveEvent) eventBus.emit(`UI:${tileLeaveEvent}`, {});
@@ -10465,7 +10600,7 @@ function Canvas2D({
10465
10600
  }, [enableCamera, handlePointerUp]);
10466
10601
  const gestureHandlers = useCanvasGestures({
10467
10602
  canvasRef,
10468
- enabled: enableCamera || !!tileHoverEvent || !!tileClickEvent || !!unitClickEvent,
10603
+ enabled: enableCamera || !!tileHoverEvent || !!tileClickEvent || !!unitClickEvent || editable,
10469
10604
  onPointerDown: handleCanvasPointerDown,
10470
10605
  onPointerMove: handleCanvasPointerMove,
10471
10606
  onPointerUp: handleCanvasPointerUp,
@@ -10597,7 +10732,7 @@ function Canvas2D({
10597
10732
  }
10598
10733
  ) });
10599
10734
  }
10600
- var canvas2DLog;
10735
+ var canvas2DLog, EDIT_SELECTION_COLOR, EDIT_HANDLE_SIZE_PX, EDIT_SELECTION_CORNERS;
10601
10736
  var init_Canvas2D = __esm({
10602
10737
  "components/game/molecules/Canvas2D.tsx"() {
10603
10738
  "use client";
@@ -10622,8 +10757,12 @@ var init_Canvas2D = __esm({
10622
10757
  init_DrawGroup();
10623
10758
  init_registry();
10624
10759
  init_hitTest();
10760
+ init_contract();
10625
10761
  init_isometric();
10626
10762
  canvas2DLog = logger.createLogger("almadar:ui:game-canvas");
10763
+ EDIT_SELECTION_COLOR = "#3b82f6";
10764
+ EDIT_HANDLE_SIZE_PX = 8;
10765
+ EDIT_SELECTION_CORNERS = [[0, 0], [1, 0], [0, 1], [1, 1]];
10627
10766
  Canvas2D.displayName = "Canvas2D";
10628
10767
  }
10629
10768
  });
@@ -10665,6 +10804,12 @@ function Canvas({
10665
10804
  featureClickEvent,
10666
10805
  keyMap,
10667
10806
  keyUpMap,
10807
+ editable,
10808
+ selectedId,
10809
+ onSelect,
10810
+ onMove,
10811
+ selectEvent,
10812
+ moveEvent,
10668
10813
  children
10669
10814
  }) {
10670
10815
  canvasLog.debug("Canvas render", { mode, drawablesCount: drawables?.length, projection, camera: camera ? JSON.stringify(camera) : void 0 });
@@ -10742,6 +10887,12 @@ function Canvas({
10742
10887
  tileLeaveEvent,
10743
10888
  keyMap,
10744
10889
  keyUpMap,
10890
+ editable,
10891
+ selectedId,
10892
+ onSelect,
10893
+ onMove,
10894
+ selectEvent,
10895
+ moveEvent,
10745
10896
  ...children !== void 0 ? { children } : {}
10746
10897
  }
10747
10898
  );
@@ -10763,15 +10914,19 @@ function GameAudioToggle({
10763
10914
  size = "sm",
10764
10915
  className,
10765
10916
  onAsset,
10766
- offAsset
10917
+ offAsset,
10918
+ toggleEvent
10767
10919
  }) {
10768
10920
  const ctx = providers.useGameAudioContextOptional();
10769
10921
  const [localMuted, setLocalMuted] = React89.useState(false);
10770
10922
  const muted = ctx ? ctx.muted : localMuted;
10771
10923
  const setMuted = ctx ? ctx.setMuted : setLocalMuted;
10924
+ const eventBus = useEventBus();
10772
10925
  const handleToggle = React89.useCallback(() => {
10773
- setMuted(!muted);
10774
- }, [muted, setMuted]);
10926
+ const next = !muted;
10927
+ setMuted(next);
10928
+ if (toggleEvent) eventBus.emit(`UI:${toggleEvent}`, { muted: next });
10929
+ }, [muted, setMuted, toggleEvent, eventBus]);
10775
10930
  const activeAsset = muted ? offAsset : onAsset;
10776
10931
  return /* @__PURE__ */ jsxRuntime.jsx(
10777
10932
  Button,
@@ -10790,6 +10945,7 @@ var init_GameAudioToggle = __esm({
10790
10945
  "use client";
10791
10946
  init_atoms();
10792
10947
  init_cn();
10948
+ init_useEventBus();
10793
10949
  init_GameIcon();
10794
10950
  GameAudioToggle.displayName = "GameAudioToggle";
10795
10951
  }
@@ -11061,6 +11217,47 @@ var init_useGameAudio = __esm({
11061
11217
  useGameAudio.displayName = "useGameAudio";
11062
11218
  }
11063
11219
  });
11220
+ function GameAudioCue({
11221
+ cue,
11222
+ cueSeq,
11223
+ music,
11224
+ muted,
11225
+ volume,
11226
+ manifest,
11227
+ baseUrl
11228
+ }) {
11229
+ const { play, playMusic, stopMusic, setMuted, setMasterVolume } = useGameAudio({
11230
+ manifest,
11231
+ baseUrl,
11232
+ initialMuted: muted,
11233
+ initialVolume: volume
11234
+ });
11235
+ const prevCueSeqRef = React89.useRef(cueSeq);
11236
+ React89.useEffect(() => {
11237
+ if (cue && cueSeq !== void 0 && cueSeq !== prevCueSeqRef.current) {
11238
+ play(cue);
11239
+ }
11240
+ prevCueSeqRef.current = cueSeq;
11241
+ }, [cue, cueSeq, play]);
11242
+ React89.useEffect(() => {
11243
+ if (music) playMusic(music);
11244
+ else stopMusic();
11245
+ }, [music, playMusic, stopMusic]);
11246
+ React89.useEffect(() => {
11247
+ if (muted !== void 0) setMuted(muted);
11248
+ }, [muted, setMuted]);
11249
+ React89.useEffect(() => {
11250
+ if (volume !== void 0) setMasterVolume(volume);
11251
+ }, [volume, setMasterVolume]);
11252
+ return null;
11253
+ }
11254
+ var init_GameAudioCue = __esm({
11255
+ "components/game/atoms/GameAudioCue.tsx"() {
11256
+ "use client";
11257
+ init_useGameAudio();
11258
+ GameAudioCue.displayName = "GameAudioCue";
11259
+ }
11260
+ });
11064
11261
  function isKnownState(s) {
11065
11262
  return s in DEFAULT_STATE_STYLES;
11066
11263
  }
@@ -11759,15 +11956,18 @@ var init_StateJsonView = __esm({
11759
11956
  StateJsonView.displayName = "StateJsonView";
11760
11957
  }
11761
11958
  });
11762
- var GAME_FONTS, GameShell;
11763
- var init_GameShell = __esm({
11764
- "components/game/templates/GameShell.tsx"() {
11765
- init_cn();
11766
- init_Box();
11767
- init_Card();
11768
- init_Typography();
11769
- init_AtlasImage();
11770
- GAME_FONTS = {
11959
+
11960
+ // lib/gameFonts.ts
11961
+ function resolveGameFontFamily(input) {
11962
+ if (!input) return void 0;
11963
+ const resolved = GAME_FONT_KEYS[input];
11964
+ if (resolved) return `'${resolved}', ui-sans-serif, system-ui, sans-serif`;
11965
+ return input;
11966
+ }
11967
+ var GAME_FONT_KEYS;
11968
+ var init_gameFonts = __esm({
11969
+ "lib/gameFonts.ts"() {
11970
+ GAME_FONT_KEYS = {
11771
11971
  fredoka: "Fredoka",
11772
11972
  future: "Kenney Future",
11773
11973
  "future-narrow": "Kenney Future Narrow",
@@ -11775,6 +11975,17 @@ var init_GameShell = __esm({
11775
11975
  blocks: "Kenney Blocks",
11776
11976
  mini: "Kenney Mini"
11777
11977
  };
11978
+ }
11979
+ });
11980
+ var GameShell;
11981
+ var init_GameShell = __esm({
11982
+ "components/game/templates/GameShell.tsx"() {
11983
+ init_cn();
11984
+ init_gameFonts();
11985
+ init_Box();
11986
+ init_Card();
11987
+ init_Typography();
11988
+ init_AtlasImage();
11778
11989
  GameShell = ({
11779
11990
  appName = "Game",
11780
11991
  hud,
@@ -11788,7 +11999,7 @@ var init_GameShell = __esm({
11788
11999
  fontFamily,
11789
12000
  "data-theme": dataTheme
11790
12001
  }) => {
11791
- const font = fontFamily ? GAME_FONTS[fontFamily] ?? fontFamily : void 0;
12002
+ const displayFont = resolveGameFontFamily(fontFamily);
11792
12003
  return /* @__PURE__ */ jsxRuntime.jsxs(
11793
12004
  Box,
11794
12005
  {
@@ -11807,7 +12018,7 @@ var init_GameShell = __esm({
11807
12018
  // passed — an always-on inline stamp would shadow the orbital's
11808
12019
  // inline-theme font-family-display token (inline style beats the
11809
12020
  // theme provider's vars for the whole shell subtree).
11810
- ...font ? { "--font-family-display": `'${font}', ui-sans-serif, system-ui, sans-serif` } : {}
12021
+ ...displayFont ? { "--font-family-display": displayFont } : {}
11811
12022
  },
11812
12023
  children: [
11813
12024
  backgroundAsset && /* @__PURE__ */ jsxRuntime.jsx(
@@ -12009,14 +12220,15 @@ function drawArrowHead(ctx, x1, y1, x2, y2, size) {
12009
12220
  ctx.closePath();
12010
12221
  ctx.fill();
12011
12222
  }
12012
- function drawShape(ctx, shape, width, height, allShapes) {
12223
+ function drawShape(ctx, shape, width, height, allShapes, fontFamily) {
12013
12224
  ctx.save();
12014
12225
  const opacity = shape.opacity ?? 1;
12015
12226
  ctx.globalAlpha = opacity;
12016
12227
  const stroke = resolveColor2(shape.color, ctx, "#333333");
12017
12228
  const fill = shape.fill ? resolveColor2(shape.fill, ctx, "#cccccc") : void 0;
12018
12229
  ctx.lineWidth = shape.lineWidth ?? 2;
12019
- if (shape.dash) ctx.setLineDash([...DASH_PATTERNS[shape.dash]]);
12230
+ const dashPattern = shape.dash ? DASH_PATTERNS[shape.dash] : void 0;
12231
+ if (dashPattern) ctx.setLineDash([...dashPattern]);
12020
12232
  switch (shape.type) {
12021
12233
  case "grid": {
12022
12234
  const step = shape.step ?? 40;
@@ -12138,7 +12350,7 @@ function drawShape(ctx, shape, width, height, allShapes) {
12138
12350
  case "text": {
12139
12351
  if (shape.x == null || shape.y == null || !shape.text) break;
12140
12352
  ctx.fillStyle = stroke;
12141
- ctx.font = `${shape.fontSize ?? 14}px ${themeBodyFont(ctx.canvas)}`;
12353
+ ctx.font = `${shape.fontSize ?? 14}px ${shape.fontFamily ?? fontFamily ?? themeBodyFont(ctx.canvas)}`;
12142
12354
  ctx.textAlign = shape.align ?? "left";
12143
12355
  ctx.textBaseline = "middle";
12144
12356
  ctx.fillText(shape.text, shape.x, shape.y);
@@ -12180,7 +12392,7 @@ function drawShape(ctx, shape, width, height, allShapes) {
12180
12392
  }
12181
12393
  ctx.restore();
12182
12394
  }
12183
- function readoutShapes(readouts, width) {
12395
+ function readoutShapes(readouts, width, fontFamily) {
12184
12396
  const out = [];
12185
12397
  const chipH = 18;
12186
12398
  const gap = 6;
@@ -12204,13 +12416,14 @@ function readoutShapes(readouts, width) {
12204
12416
  text,
12205
12417
  color: "#ffffff",
12206
12418
  fontSize: 10,
12207
- align: "center"
12419
+ align: "center",
12420
+ fontFamily
12208
12421
  });
12209
12422
  rightEdge = chipX - gap;
12210
12423
  }
12211
12424
  return out;
12212
12425
  }
12213
- function traceShapes(panel, k, width, height) {
12426
+ function traceShapes(panel, k, width, height, fontFamily) {
12214
12427
  const w = panel.width ?? Math.round(width * 0.32);
12215
12428
  const h = panel.height ?? Math.round(height * 0.28);
12216
12429
  const x = panel.x ?? width - w - 8;
@@ -12264,14 +12477,14 @@ function traceShapes(panel, k, width, height) {
12264
12477
  out.push({ type: "circle", x: last.x, y: last.y, radius: 2, color, fill: color });
12265
12478
  }
12266
12479
  if (series.label) {
12267
- out.push({ type: "text", x: x + 6, y: y + 10 + 11 * j, text: series.label, color, fontSize: 9 });
12480
+ out.push({ type: "text", x: x + 6, y: y + 10 + 11 * j, text: series.label, color, fontSize: 9, fontFamily });
12268
12481
  }
12269
12482
  });
12270
12483
  if (panel.yLabel) {
12271
- out.push({ type: "text", x: x + w - 6, y: y + 10, text: panel.yLabel, color: "#6b7280", fontSize: 9, align: "right" });
12484
+ out.push({ type: "text", x: x + w - 6, y: y + 10, text: panel.yLabel, color: "#6b7280", fontSize: 9, align: "right", fontFamily });
12272
12485
  }
12273
12486
  if (panel.xLabel) {
12274
- out.push({ type: "text", x: x + w - 6, y: y + h - 6, text: panel.xLabel, color: "#6b7280", fontSize: 9, align: "right" });
12487
+ out.push({ type: "text", x: x + w - 6, y: y + h - 6, text: panel.xLabel, color: "#6b7280", fontSize: 9, align: "right", fontFamily });
12275
12488
  }
12276
12489
  return out;
12277
12490
  }
@@ -12294,13 +12507,14 @@ var init_LearningCanvas = __esm({
12294
12507
  init_useEventBus();
12295
12508
  init_webPainter2d();
12296
12509
  init_paintDispatch();
12297
- DASH_PATTERNS = { dashed: [6, 4], dotted: [2, 3] };
12510
+ DASH_PATTERNS = { solid: [], dashed: [6, 4], dotted: [2, 3] };
12298
12511
  TRACE_SERIES_COLORS = ["#2563eb", "#dc2626", "#16a34a", "#f59e0b"];
12299
12512
  LearningCanvas = ({
12300
12513
  className,
12301
12514
  width = 600,
12302
12515
  height = 400,
12303
12516
  backgroundColor,
12517
+ fontFamily,
12304
12518
  shapes = [],
12305
12519
  drawables,
12306
12520
  projector,
@@ -12336,10 +12550,10 @@ var init_LearningCanvas = __esm({
12336
12550
  }, [shapes]);
12337
12551
  const derivedShapes = React89.useMemo(() => {
12338
12552
  if (!traces?.length && !readouts?.length) return shapes;
12339
- const traceOut = (traces ?? []).flatMap((panel, k) => traceShapes(panel, k, width, height));
12340
- const readoutOut = readouts?.length ? readoutShapes(readouts, width) : [];
12553
+ const traceOut = (traces ?? []).flatMap((panel, k) => traceShapes(panel, k, width, height, fontFamily));
12554
+ const readoutOut = readouts?.length ? readoutShapes(readouts, width, fontFamily) : [];
12341
12555
  return [...shapes, ...traceOut, ...readoutOut];
12342
- }, [shapes, traces, readouts, width, height]);
12556
+ }, [shapes, traces, readouts, width, height, fontFamily]);
12343
12557
  const draw = React89.useCallback(() => {
12344
12558
  const _perfT = ui.perfStart("learningcanvas:paint");
12345
12559
  const canvas = canvasRef.current;
@@ -12358,15 +12572,15 @@ var init_LearningCanvas = __esm({
12358
12572
  ctx.fillRect(0, 0, width, height);
12359
12573
  }
12360
12574
  for (const shape of derivedShapes) {
12361
- if (shape.type !== "text") drawShape(ctx, shape, width, height, derivedShapes);
12575
+ if (shape.type !== "text") drawShape(ctx, shape, width, height, derivedShapes, fontFamily);
12362
12576
  }
12363
12577
  for (const shape of derivedShapes) {
12364
- if (shape.type === "text") drawShape(ctx, shape, width, height, derivedShapes);
12578
+ if (shape.type === "text") drawShape(ctx, shape, width, height, derivedShapes, fontFamily);
12365
12579
  }
12366
12580
  if (drawables?.length && projector) {
12367
12581
  const painter = createWebPainter(ctx, invalidateRef.current);
12368
12582
  const timeMs = needsAnim && typeof performance !== "undefined" ? performance.now() : 0;
12369
- const dctx = { projector, time: timeMs, invalidate: invalidateRef.current, fontFamily: themeBodyFont(canvas) };
12583
+ const dctx = { projector, time: timeMs, invalidate: invalidateRef.current, fontFamily: fontFamily || themeBodyFont(canvas) };
12370
12584
  for (const node of drawables) {
12371
12585
  paintDrawable(painter, node, dctx);
12372
12586
  }
@@ -17348,6 +17562,250 @@ var init_EmptyState = __esm({
17348
17562
  EmptyState.displayName = "EmptyState";
17349
17563
  }
17350
17564
  });
17565
+
17566
+ // lib/editorMotions.ts
17567
+ function clamp(value, min, max) {
17568
+ return Math.max(min, Math.min(max, value));
17569
+ }
17570
+ function computeLines(text) {
17571
+ const lines = [];
17572
+ let start = 0;
17573
+ for (let i = 0; i <= text.length; i++) {
17574
+ if (i === text.length || text[i] === "\n") {
17575
+ lines.push({ start, end: i });
17576
+ start = i + 1;
17577
+ }
17578
+ }
17579
+ return lines;
17580
+ }
17581
+ function lineIndexAt(lines, pos) {
17582
+ for (let i = 0; i < lines.length; i++) {
17583
+ if (pos <= lines[i].end) return i;
17584
+ }
17585
+ return lines.length - 1;
17586
+ }
17587
+ function findWords(text) {
17588
+ const words = [];
17589
+ const re = /\w+|\S+/g;
17590
+ let m;
17591
+ while ((m = re.exec(text)) !== null) {
17592
+ words.push({ start: m.index, end: m.index + m[0].length });
17593
+ }
17594
+ return words;
17595
+ }
17596
+ function nextWordStart(text, pos) {
17597
+ for (const w of findWords(text)) {
17598
+ if (w.start > pos) return w.start;
17599
+ }
17600
+ return text.length;
17601
+ }
17602
+ function prevWordStart(text, pos) {
17603
+ let result = 0;
17604
+ for (const w of findWords(text)) {
17605
+ if (w.start < pos) result = w.start;
17606
+ else break;
17607
+ }
17608
+ return result;
17609
+ }
17610
+ function nextWordEnd(text, pos) {
17611
+ for (const w of findWords(text)) {
17612
+ const lastChar = w.end - 1;
17613
+ if (lastChar > pos) return lastChar;
17614
+ }
17615
+ return text.length > 0 ? text.length - 1 : 0;
17616
+ }
17617
+ function firstNonBlank(text, line) {
17618
+ let i = line.start;
17619
+ while (i < line.end && (text[i] === " " || text[i] === " ")) i++;
17620
+ return i;
17621
+ }
17622
+ function nextParagraphBoundary(lines, fromLineIdx, textLength) {
17623
+ for (let i = fromLineIdx + 1; i < lines.length; i++) {
17624
+ if (lines[i].start === lines[i].end) return lines[i].start;
17625
+ }
17626
+ return textLength;
17627
+ }
17628
+ function prevParagraphBoundary(lines, fromLineIdx) {
17629
+ for (let i = fromLineIdx - 1; i >= 0; i--) {
17630
+ if (lines[i].start === lines[i].end) return lines[i].start;
17631
+ }
17632
+ return 0;
17633
+ }
17634
+ function applyMotion(text, caret, motion, count) {
17635
+ const n = Math.max(1, count);
17636
+ const lines = computeLines(text);
17637
+ const lineIdx = lineIndexAt(lines, caret);
17638
+ const line = lines[lineIdx];
17639
+ switch (motion) {
17640
+ case "left":
17641
+ return clamp(caret - n, line.start, line.end);
17642
+ case "right":
17643
+ return clamp(caret + n, line.start, line.end);
17644
+ case "up": {
17645
+ const col = caret - line.start;
17646
+ const targetIdx = clamp(lineIdx - n, 0, lines.length - 1);
17647
+ const target = lines[targetIdx];
17648
+ return clamp(target.start + col, target.start, target.end);
17649
+ }
17650
+ case "down": {
17651
+ const col = caret - line.start;
17652
+ const targetIdx = clamp(lineIdx + n, 0, lines.length - 1);
17653
+ const target = lines[targetIdx];
17654
+ return clamp(target.start + col, target.start, target.end);
17655
+ }
17656
+ case "word-forward": {
17657
+ let pos = caret;
17658
+ for (let i = 0; i < n; i++) pos = nextWordStart(text, pos);
17659
+ return pos;
17660
+ }
17661
+ case "word-back": {
17662
+ let pos = caret;
17663
+ for (let i = 0; i < n; i++) pos = prevWordStart(text, pos);
17664
+ return pos;
17665
+ }
17666
+ case "word-end": {
17667
+ let pos = caret;
17668
+ for (let i = 0; i < n; i++) pos = nextWordEnd(text, pos);
17669
+ return pos;
17670
+ }
17671
+ case "line-start":
17672
+ return line.start;
17673
+ case "line-end":
17674
+ return line.end > line.start ? line.end - 1 : line.start;
17675
+ case "first-nonblank":
17676
+ return firstNonBlank(text, line);
17677
+ case "doc-start":
17678
+ return 0;
17679
+ case "doc-end":
17680
+ return text.length;
17681
+ case "paragraph-forward": {
17682
+ let pos = caret;
17683
+ for (let i = 0; i < n; i++) {
17684
+ pos = nextParagraphBoundary(lines, lineIndexAt(lines, pos), text.length);
17685
+ }
17686
+ return pos;
17687
+ }
17688
+ case "paragraph-back": {
17689
+ let pos = caret;
17690
+ for (let i = 0; i < n; i++) {
17691
+ pos = prevParagraphBoundary(lines, lineIndexAt(lines, pos));
17692
+ }
17693
+ return pos;
17694
+ }
17695
+ case "line":
17696
+ case "selection":
17697
+ return caret;
17698
+ default: {
17699
+ const _exhaustive = motion;
17700
+ return _exhaustive;
17701
+ }
17702
+ }
17703
+ }
17704
+ function motionRange(text, caret, motion, count, selection) {
17705
+ if (motion === "selection") {
17706
+ if (!selection) return [caret, caret];
17707
+ return [Math.min(selection[0], selection[1]), Math.max(selection[0], selection[1])];
17708
+ }
17709
+ const lines = computeLines(text);
17710
+ if (motion === "line") {
17711
+ const n = Math.max(1, count);
17712
+ const startIdx = lineIndexAt(lines, caret);
17713
+ const endIdx = clamp(startIdx + n - 1, 0, lines.length - 1);
17714
+ const start2 = lines[startIdx].start;
17715
+ const rawEnd = lines[endIdx].end;
17716
+ const end2 = rawEnd < text.length ? rawEnd + 1 : rawEnd;
17717
+ return [start2, end2];
17718
+ }
17719
+ const newCaret = applyMotion(text, caret, motion, count);
17720
+ let start = Math.min(caret, newCaret);
17721
+ let end = Math.max(caret, newCaret);
17722
+ if (motion === "word-end" || motion === "line-end") {
17723
+ end = Math.min(Math.max(start, newCaret) + 1, text.length);
17724
+ } else if (motion === "word-forward" && newCaret > caret) {
17725
+ const startLine = lineIndexAt(lines, caret);
17726
+ const endLine = lineIndexAt(lines, newCaret);
17727
+ if (endLine !== startLine) {
17728
+ end = lines[startLine].end;
17729
+ }
17730
+ }
17731
+ return [start, end];
17732
+ }
17733
+ function applyOperator(text, range, operator, register) {
17734
+ const start = clamp(range[0], 0, text.length);
17735
+ const end = clamp(range[1], start, text.length);
17736
+ const removed = text.slice(start, end);
17737
+ if (operator === "yank") {
17738
+ return { text, caret: start, register: removed };
17739
+ }
17740
+ return { text: text.slice(0, start) + text.slice(end), caret: start, register: removed };
17741
+ }
17742
+ var init_editorMotions = __esm({
17743
+ "lib/editorMotions.ts"() {
17744
+ }
17745
+ });
17746
+ function isMotionPayload(payload) {
17747
+ return !!payload && typeof payload.editorId === "string" && typeof payload.motion === "string" && typeof payload.count === "number";
17748
+ }
17749
+ function isOperatePayload(payload) {
17750
+ return !!payload && typeof payload.editorId === "string" && typeof payload.operator === "string" && typeof payload.motion === "string" && typeof payload.count === "number";
17751
+ }
17752
+ function isInsertTextPayload(payload) {
17753
+ return !!payload && typeof payload.editorId === "string" && typeof payload.text === "string";
17754
+ }
17755
+ function isSetModePayload(payload) {
17756
+ return !!payload && typeof payload.editorId === "string" && typeof payload.mode === "string" && typeof payload.caret === "string";
17757
+ }
17758
+ function useEditorCapabilities(args) {
17759
+ const [caretMode, setCaretMode] = React89.useState("bar");
17760
+ const registerRef = React89.useRef("");
17761
+ useEventListener(`UI:${args.events.onMotion}`, (evt) => {
17762
+ if (!args.editorId || !isMotionPayload(evt.payload) || evt.payload.editorId !== args.editorId) return;
17763
+ const ta = args.textareaRef.current;
17764
+ if (!ta) return;
17765
+ const { motion, count } = evt.payload;
17766
+ const newCaret = applyMotion(ta.value, ta.selectionStart, motion, count);
17767
+ if (ta.selectionStart !== ta.selectionEnd) {
17768
+ ta.setSelectionRange(ta.selectionStart, newCaret);
17769
+ } else {
17770
+ ta.setSelectionRange(newCaret, newCaret);
17771
+ }
17772
+ });
17773
+ useEventListener(`UI:${args.events.onOperate}`, (evt) => {
17774
+ if (!args.editorId || !isOperatePayload(evt.payload) || evt.payload.editorId !== args.editorId) return;
17775
+ const ta = args.textareaRef.current;
17776
+ if (!ta) return;
17777
+ const { operator, motion, count } = evt.payload;
17778
+ const selection = motion === "selection" ? [ta.selectionStart, ta.selectionEnd] : void 0;
17779
+ const range = motionRange(ta.value, ta.selectionStart, motion, count, selection);
17780
+ const result = applyOperator(ta.value, range, operator, registerRef.current);
17781
+ registerRef.current = result.register;
17782
+ if (operator === "yank") {
17783
+ ta.setSelectionRange(range[0], range[0]);
17784
+ } else {
17785
+ ta.setRangeText("", range[0], range[1], "end");
17786
+ }
17787
+ args.applyChange(ta.value);
17788
+ });
17789
+ useEventListener(`UI:${args.events.onInsertText}`, (evt) => {
17790
+ if (!args.editorId || !isInsertTextPayload(evt.payload) || evt.payload.editorId !== args.editorId) return;
17791
+ const ta = args.textareaRef.current;
17792
+ if (!ta) return;
17793
+ ta.setRangeText(evt.payload.text, ta.selectionStart, ta.selectionEnd, "end");
17794
+ args.applyChange(ta.value);
17795
+ });
17796
+ useEventListener(`UI:${args.events.onSetMode}`, (evt) => {
17797
+ if (!args.editorId || !isSetModePayload(evt.payload) || evt.payload.editorId !== args.editorId) return;
17798
+ setCaretMode(evt.payload.caret);
17799
+ });
17800
+ return { caretMode };
17801
+ }
17802
+ var init_useEditorCapabilities = __esm({
17803
+ "components/core/molecules/markdown/useEditorCapabilities.ts"() {
17804
+ "use client";
17805
+ init_useEventBus();
17806
+ init_editorMotions();
17807
+ }
17808
+ });
17351
17809
  function isLanguageRegistered(lang) {
17352
17810
  return CODE_LANGUAGE_SET.has(lang) || dynamicallyLoaded.has(lang);
17353
17811
  }
@@ -17433,7 +17891,36 @@ function useLanguageReady(language) {
17433
17891
  }, [language]);
17434
17892
  return ready;
17435
17893
  }
17436
- var dynamicallyLoaded, codeLanguageLoader, orbStyleOverrides, orbStyle, loloStyleOverrides, loloStyle, log7, CODE_LANGUAGES, CODE_LANGUAGE_SET, DIFF_STYLES, DIFF_STYLE_FALLBACK, LINE_PROPS_FN, HIDDEN_LINE_NUMBERS, HIGHLIGHT_CAPACITY_BYTES, CodeBlock;
17894
+ function resolveHighlightStyle(lang) {
17895
+ if (lang === "orb") return orbStyle;
17896
+ if (lang === "lolo") return loloStyle;
17897
+ return dark__default.default;
17898
+ }
17899
+ function plainCodeColorOf(style) {
17900
+ return style['code[class*="language-"]']?.color ?? "#d4d4d4";
17901
+ }
17902
+ function buildLineProps(errorLines, extraClassName) {
17903
+ return (lineNumber) => {
17904
+ const base = {
17905
+ "data-line": String(lineNumber - 1),
17906
+ ...extraClassName ? { className: extraClassName } : {}
17907
+ };
17908
+ const severity = errorLines?.get(lineNumber);
17909
+ if (!severity) return base;
17910
+ return {
17911
+ ...base,
17912
+ style: {
17913
+ display: "block",
17914
+ backgroundColor: severity === "error" ? "rgba(248, 113, 113, 0.18)" : "rgba(251, 191, 36, 0.18)",
17915
+ // amber-400 @ 18%
17916
+ borderLeft: `3px solid ${severity === "error" ? "#ef4444" : "#f59e0b"}`,
17917
+ paddingLeft: "0.5rem",
17918
+ marginLeft: "-0.5rem"
17919
+ }
17920
+ };
17921
+ };
17922
+ }
17923
+ var dynamicallyLoaded, codeLanguageLoader, orbStyleOverrides, orbStyle, loloStyleOverrides, loloStyle, log7, CODE_LANGUAGES, CODE_LANGUAGE_SET, DIFF_STYLES, DIFF_STYLE_FALLBACK, LINE_PROPS_FN, HIDDEN_LINE_NUMBERS, HIGHLIGHT_CAPACITY_BYTES, MONO_FONT_FAMILY, VIEWER_LINE_NUMBER_STYLE, CodeBlock;
17437
17924
  var init_CodeBlock = __esm({
17438
17925
  "components/core/molecules/markdown/CodeBlock.tsx"() {
17439
17926
  init_cn();
@@ -17449,6 +17936,7 @@ var init_CodeBlock = __esm({
17449
17936
  init_Textarea();
17450
17937
  init_Icon();
17451
17938
  init_useEventBus();
17939
+ init_useEditorCapabilities();
17452
17940
  SyntaxHighlighter__default.default.registerLanguage("json", langJson__default.default);
17453
17941
  SyntaxHighlighter__default.default.registerLanguage("javascript", langJavascript__default.default);
17454
17942
  SyntaxHighlighter__default.default.registerLanguage("js", langJavascript__default.default);
@@ -17667,6 +18155,15 @@ var init_CodeBlock = __esm({
17667
18155
  LINE_PROPS_FN = (n) => ({ "data-line": String(n - 1) });
17668
18156
  HIDDEN_LINE_NUMBERS = { display: "none" };
17669
18157
  HIGHLIGHT_CAPACITY_BYTES = 512 * 1024;
18158
+ MONO_FONT_FAMILY = 'ui-monospace, SFMono-Regular, Menlo, Monaco, "Cascadia Mono", "Courier New", monospace';
18159
+ VIEWER_LINE_NUMBER_STYLE = {
18160
+ minWidth: "2.5em",
18161
+ paddingRight: "1rem",
18162
+ textAlign: "right",
18163
+ userSelect: "none",
18164
+ opacity: 0.5,
18165
+ fontVariantNumeric: "tabular-nums"
18166
+ };
17670
18167
  CodeBlock = React89__namespace.default.memo(
17671
18168
  ({
17672
18169
  code: rawCode,
@@ -17691,15 +18188,39 @@ var init_CodeBlock = __esm({
17691
18188
  actions,
17692
18189
  isLoading = false,
17693
18190
  error,
17694
- showCopy
18191
+ showCopy,
18192
+ // editor capability surface — P1 wires these
18193
+ editorId,
18194
+ onEditorFocus = "EDITOR_FOCUS",
18195
+ onEditorBlur = "EDITOR_BLUR",
18196
+ onMotion = "MOTION",
18197
+ onOperate = "OPERATE",
18198
+ onInsertText = "INSERT_TEXT",
18199
+ onSetMode = "SET_MODE",
18200
+ motions = [
18201
+ "left",
18202
+ "right",
18203
+ "up",
18204
+ "down",
18205
+ "word-forward",
18206
+ "word-back",
18207
+ "word-end",
18208
+ "line-start",
18209
+ "line-end",
18210
+ "first-nonblank",
18211
+ "doc-start",
18212
+ "doc-end",
18213
+ "paragraph-forward",
18214
+ "paragraph-back",
18215
+ "line",
18216
+ "selection"
18217
+ ],
18218
+ operators = ["delete", "yank", "change"]
17695
18219
  }) => {
17696
18220
  const code = typeof rawCode === "string" ? rawCode : String(rawCode ?? "");
17697
- const isOrb = language === "orb";
17698
- const isLolo = language === "lolo";
17699
- const activeStyle = isOrb ? orbStyle : isLolo ? loloStyle : dark__default.default;
18221
+ const activeStyle = resolveHighlightStyle(language);
17700
18222
  const overCapacity = code.length > HIGHLIGHT_CAPACITY_BYTES;
17701
- const plainCodeColor = activeStyle['code[class*="language-"]']?.color ?? "#d4d4d4";
17702
- const languageReady = useLanguageReady(language);
18223
+ const plainCodeColor = plainCodeColorOf(activeStyle);
17703
18224
  const eventBus = useEventBus();
17704
18225
  const { t } = hooks.useTranslate();
17705
18226
  const scrollRef = React89.useRef(null);
@@ -17711,6 +18232,9 @@ var init_CodeBlock = __esm({
17711
18232
  const activeFile = files?.[activeFileIndex];
17712
18233
  const activeCode = activeFile?.code ?? code;
17713
18234
  const activeLanguage = activeFile?.language ?? language;
18235
+ const languageReady = useLanguageReady(activeLanguage);
18236
+ const viewerStyle = resolveHighlightStyle(activeLanguage);
18237
+ const viewerPlainCodeColor = plainCodeColorOf(viewerStyle);
17714
18238
  const diffLines = React89.useMemo(() => {
17715
18239
  if (propDiff) return propDiff;
17716
18240
  if (mode === "diff" && oldValue !== void 0 && newValue !== void 0) {
@@ -17740,28 +18264,28 @@ var init_CodeBlock = __esm({
17740
18264
  ov.scrollLeft = ta.scrollLeft;
17741
18265
  }
17742
18266
  }, []);
17743
- const errorLineProps = React89.useMemo(() => {
17744
- if (!errorLines || errorLines.size === 0) {
17745
- return LINE_PROPS_FN;
17746
- }
17747
- return (lineNumber) => {
17748
- const severity = errorLines.get(lineNumber);
17749
- if (!severity) {
17750
- return { "data-line": String(lineNumber - 1) };
17751
- }
17752
- return {
17753
- "data-line": String(lineNumber - 1),
17754
- style: {
17755
- display: "block",
17756
- backgroundColor: severity === "error" ? "rgba(248, 113, 113, 0.18)" : "rgba(251, 191, 36, 0.18)",
17757
- // amber-400 @ 18%
17758
- borderLeft: `3px solid ${severity === "error" ? "#ef4444" : "#f59e0b"}`,
17759
- paddingLeft: "0.5rem",
17760
- marginLeft: "-0.5rem"
17761
- }
17762
- };
17763
- };
17764
- }, [errorLines]);
18267
+ const handleEditableChange = React89.useCallback((v) => {
18268
+ lastPropCodeRef.current = v;
18269
+ setEditableValue(v);
18270
+ onChange?.(v);
18271
+ }, [onChange]);
18272
+ const { caretMode } = useEditorCapabilities({
18273
+ editorId: editable ? editorId : void 0,
18274
+ textareaRef: editableTextareaRef,
18275
+ events: { onMotion, onOperate, onInsertText, onSetMode },
18276
+ applyChange: handleEditableChange
18277
+ });
18278
+ const [caretIndex, setCaretIndex] = React89.useState(0);
18279
+ const caretRowCol = React89.useMemo(() => {
18280
+ const before = editableValue.slice(0, Math.min(caretIndex, editableValue.length));
18281
+ const lines = before.split("\n");
18282
+ return { row: lines.length - 1, col: lines[lines.length - 1].length };
18283
+ }, [editableValue, caretIndex]);
18284
+ const errorLineProps = React89.useMemo(() => buildLineProps(errorLines), [errorLines]);
18285
+ const viewerLineProps = React89.useMemo(
18286
+ () => buildLineProps(errorLines, "px-4 py-0.5 hover:bg-muted/50"),
18287
+ [errorLines]
18288
+ );
17765
18289
  const isFoldable = foldableProp ?? true;
17766
18290
  const [collapsed, setCollapsed] = React89.useState(() => /* @__PURE__ */ new Set());
17767
18291
  const foldRegions = React89.useMemo(
@@ -17884,6 +18408,110 @@ var init_CodeBlock = __esm({
17884
18408
  ),
17885
18409
  [code, overCapacity, plainCodeColor, language, activeStyle, languageReady]
17886
18410
  );
18411
+ const viewerOverCapacity = activeCode.length > HIGHLIGHT_CAPACITY_BYTES;
18412
+ const viewerHighlightedElement = React89.useMemo(
18413
+ () => viewerOverCapacity ? /* @__PURE__ */ jsxRuntime.jsx(
18414
+ "div",
18415
+ {
18416
+ className: "px-4 py-0.5",
18417
+ style: {
18418
+ margin: 0,
18419
+ whiteSpace: wrap ? "pre-wrap" : "pre",
18420
+ wordBreak: wrap ? "break-all" : "normal",
18421
+ color: viewerPlainCodeColor,
18422
+ fontFamily: MONO_FONT_FAMILY,
18423
+ fontSize: "12px",
18424
+ lineHeight: "1.6"
18425
+ },
18426
+ children: activeCode
18427
+ }
18428
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
18429
+ SyntaxHighlighter__default.default,
18430
+ {
18431
+ PreTag: "div",
18432
+ language: activeLanguage,
18433
+ style: viewerStyle,
18434
+ wrapLines: true,
18435
+ wrapLongLines: wrap,
18436
+ showLineNumbers,
18437
+ lineNumberStyle: VIEWER_LINE_NUMBER_STYLE,
18438
+ lineProps: viewerLineProps,
18439
+ customStyle: {
18440
+ backgroundColor: "transparent",
18441
+ borderRadius: 0,
18442
+ padding: "0.25rem 0",
18443
+ margin: 0,
18444
+ whiteSpace: wrap ? "pre-wrap" : "pre",
18445
+ wordBreak: wrap ? "break-all" : "normal",
18446
+ fontFamily: MONO_FONT_FAMILY,
18447
+ fontSize: "12px",
18448
+ lineHeight: "1.6"
18449
+ },
18450
+ codeTagProps: { style: { fontFamily: MONO_FONT_FAMILY, fontSize: "12px", lineHeight: "1.6" } },
18451
+ children: activeCode
18452
+ }
18453
+ ),
18454
+ [activeCode, viewerOverCapacity, viewerPlainCodeColor, activeLanguage, viewerStyle, wrap, showLineNumbers, viewerLineProps, languageReady]
18455
+ );
18456
+ const diffOverCapacity = React89.useMemo(
18457
+ () => !!diffLines && diffLines.reduce((n, l) => n + l.content.length + 1, 0) > HIGHLIGHT_CAPACITY_BYTES,
18458
+ [diffLines]
18459
+ );
18460
+ const diffRowElements = React89.useMemo(() => {
18461
+ if (!diffLines) return null;
18462
+ return diffLines.map((line, idx) => {
18463
+ const style = DIFF_STYLES[line.type] ?? DIFF_STYLE_FALLBACK;
18464
+ return /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "none", align: "start", className: cn(style.bg, "px-4 py-0.5"), children: [
18465
+ showLineNumbers && /* @__PURE__ */ jsxRuntime.jsx(
18466
+ Typography,
18467
+ {
18468
+ variant: "caption",
18469
+ color: "secondary",
18470
+ className: "w-8 text-right mr-3 select-none tabular-nums flex-shrink-0",
18471
+ children: line.lineNumber ?? ""
18472
+ }
18473
+ ),
18474
+ /* @__PURE__ */ jsxRuntime.jsxs(
18475
+ Typography,
18476
+ {
18477
+ variant: "caption",
18478
+ className: cn("font-mono flex-1 min-w-0", style.text, wrap ? "whitespace-pre-wrap break-all" : "whitespace-pre"),
18479
+ children: [
18480
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { as: "span", className: "select-none opacity-50 mr-2", children: style.prefix }),
18481
+ diffOverCapacity ? line.content || " " : /* @__PURE__ */ jsxRuntime.jsx(
18482
+ SyntaxHighlighter__default.default,
18483
+ {
18484
+ PreTag: "span",
18485
+ CodeTag: "span",
18486
+ language: activeLanguage,
18487
+ style: viewerStyle,
18488
+ customStyle: {
18489
+ display: "inline",
18490
+ background: "transparent",
18491
+ padding: 0,
18492
+ margin: 0,
18493
+ whiteSpace: wrap ? "pre-wrap" : "pre",
18494
+ wordBreak: wrap ? "break-all" : "normal",
18495
+ fontFamily: "inherit",
18496
+ fontSize: "inherit",
18497
+ lineHeight: "inherit"
18498
+ },
18499
+ codeTagProps: {
18500
+ style: {
18501
+ whiteSpace: wrap ? "pre-wrap" : "pre",
18502
+ fontFamily: "inherit",
18503
+ fontSize: "inherit"
18504
+ }
18505
+ },
18506
+ children: line.content || " "
18507
+ }
18508
+ )
18509
+ ]
18510
+ }
18511
+ )
18512
+ ] }, idx);
18513
+ });
18514
+ }, [diffLines, showLineNumbers, wrap, diffOverCapacity, activeLanguage, viewerStyle, languageReady]);
17887
18515
  React89.useLayoutEffect(() => {
17888
18516
  const container = codeRef.current;
17889
18517
  if (!container) return;
@@ -18027,7 +18655,6 @@ var init_CodeBlock = __esm({
18027
18655
  label: file.label,
18028
18656
  content: null
18029
18657
  }));
18030
- const lines = activeCode.split("\n");
18031
18658
  return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: cn("overflow-hidden", className), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column" }, children: [
18032
18659
  tabItems && tabItems.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "border-b border-border", children: /* @__PURE__ */ jsxRuntime.jsx(
18033
18660
  Tabs,
@@ -18090,49 +18717,7 @@ var init_CodeBlock = __esm({
18090
18717
  ]
18091
18718
  }
18092
18719
  ),
18093
- /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "overflow-auto bg-muted/20", style: { maxHeight }, children: diffLines ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column" }, className: "font-mono text-xs", children: diffLines.map((line, idx) => {
18094
- const style = DIFF_STYLES[line.type] ?? DIFF_STYLE_FALLBACK;
18095
- return /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "none", align: "start", className: cn(style.bg, "px-4 py-0.5"), children: [
18096
- showLineNumbers && /* @__PURE__ */ jsxRuntime.jsx(
18097
- Typography,
18098
- {
18099
- variant: "caption",
18100
- color: "secondary",
18101
- className: "w-8 text-right mr-3 select-none tabular-nums flex-shrink-0",
18102
- children: line.lineNumber ?? ""
18103
- }
18104
- ),
18105
- /* @__PURE__ */ jsxRuntime.jsxs(
18106
- Typography,
18107
- {
18108
- variant: "caption",
18109
- className: cn("font-mono flex-1 min-w-0", style.text, wrap ? "whitespace-pre-wrap break-all" : "whitespace-pre"),
18110
- children: [
18111
- /* @__PURE__ */ jsxRuntime.jsx(Box, { as: "span", className: "select-none opacity-50 mr-2", children: style.prefix }),
18112
- line.content
18113
- ]
18114
- }
18115
- )
18116
- ] }, idx);
18117
- }) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column" }, className: "font-mono text-xs", children: lines.map((line, idx) => /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "none", align: "start", className: "px-4 py-0.5 hover:bg-muted/50", children: [
18118
- showLineNumbers && /* @__PURE__ */ jsxRuntime.jsx(
18119
- Typography,
18120
- {
18121
- variant: "caption",
18122
- color: "secondary",
18123
- className: "w-8 text-right mr-4 select-none tabular-nums flex-shrink-0",
18124
- children: idx + 1
18125
- }
18126
- ),
18127
- /* @__PURE__ */ jsxRuntime.jsx(
18128
- Typography,
18129
- {
18130
- variant: "caption",
18131
- className: cn("font-mono flex-1 min-w-0", wrap ? "whitespace-pre-wrap break-all" : "whitespace-pre"),
18132
- children: line || " "
18133
- }
18134
- )
18135
- ] }, idx)) }) })
18720
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "overflow-auto bg-muted/20", style: { maxHeight }, children: diffLines ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column" }, className: "font-mono text-xs", children: diffRowElements }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-mono text-xs", children: viewerHighlightedElement }) })
18136
18721
  ] }) });
18137
18722
  }
18138
18723
  const hasHeader = showLanguageBadge || effectiveCopy;
@@ -18219,13 +18804,11 @@ var init_CodeBlock = __esm({
18219
18804
  {
18220
18805
  ref: editableTextareaRef,
18221
18806
  defaultValue: code,
18222
- onChange: (e) => {
18223
- const v = e.target.value;
18224
- lastPropCodeRef.current = v;
18225
- setEditableValue(v);
18226
- onChange?.(v);
18227
- },
18807
+ onChange: (e) => handleEditableChange(e.target.value),
18228
18808
  onScroll: handleEditableScroll,
18809
+ onSelect: (e) => setCaretIndex(e.currentTarget.selectionStart),
18810
+ onFocus: editorId ? () => eventBus.emit(`UI:${onEditorFocus}`, { editorId }) : void 0,
18811
+ onBlur: editorId ? () => eventBus.emit(`UI:${onEditorBlur}`, { editorId }) : void 0,
18229
18812
  spellCheck: false,
18230
18813
  style: {
18231
18814
  position: "absolute",
@@ -18240,7 +18823,7 @@ var init_CodeBlock = __esm({
18240
18823
  resize: "none",
18241
18824
  backgroundColor: "transparent",
18242
18825
  color: "transparent",
18243
- caretColor: "#e6e6e6",
18826
+ caretColor: caretMode === "block" ? "transparent" : "#e6e6e6",
18244
18827
  WebkitTextFillColor: "transparent",
18245
18828
  fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, "Cascadia Mono", "Courier New", monospace',
18246
18829
  fontSize: "13px",
@@ -18251,6 +18834,22 @@ var init_CodeBlock = __esm({
18251
18834
  }
18252
18835
  },
18253
18836
  editableTextareaKey
18837
+ ),
18838
+ caretMode !== "bar" && /* @__PURE__ */ jsxRuntime.jsx(
18839
+ "span",
18840
+ {
18841
+ "aria-hidden": true,
18842
+ style: {
18843
+ position: "absolute",
18844
+ top: `calc(1rem + ${caretRowCol.row * 19.5}px)`,
18845
+ left: `calc(1rem + ${caretRowCol.col}ch)`,
18846
+ width: "1ch",
18847
+ height: caretMode === "block" ? "19.5px" : "2px",
18848
+ backgroundColor: caretMode === "block" ? "rgba(230, 230, 230, 0.5)" : void 0,
18849
+ borderBottom: caretMode === "underline" ? "2px solid #e6e6e6" : void 0,
18850
+ pointerEvents: "none"
18851
+ }
18852
+ }
18254
18853
  )
18255
18854
  ]
18256
18855
  }
@@ -18278,55 +18877,175 @@ var init_CodeBlock = __esm({
18278
18877
  )
18279
18878
  ] });
18280
18879
  },
18281
- (prev, next) => prev.language === next.language && prev.code === next.code && prev.showCopyButton === next.showCopyButton && prev.showCopy === next.showCopy && prev.maxHeight === next.maxHeight && prev.foldable === next.foldable && prev.editable === next.editable && prev.onChange === next.onChange && prev.errorLines === next.errorLines && prev.mode === next.mode && prev.title === next.title && prev.diff === next.diff && prev.files === next.files && prev.actions === next.actions && prev.isLoading === next.isLoading && prev.error === next.error
18880
+ (prev, next) => prev.language === next.language && prev.code === next.code && prev.showCopyButton === next.showCopyButton && prev.showCopy === next.showCopy && prev.maxHeight === next.maxHeight && prev.foldable === next.foldable && prev.editable === next.editable && prev.onChange === next.onChange && prev.errorLines === next.errorLines && prev.mode === next.mode && prev.title === next.title && prev.diff === next.diff && prev.files === next.files && prev.actions === next.actions && prev.isLoading === next.isLoading && prev.error === next.error && prev.editorId === next.editorId && prev.onEditorFocus === next.onEditorFocus && prev.onEditorBlur === next.onEditorBlur && prev.onMotion === next.onMotion && prev.onOperate === next.onOperate && prev.onInsertText === next.onInsertText && prev.onSetMode === next.onSetMode && prev.motions === next.motions && prev.operators === next.operators
18282
18881
  );
18283
18882
  CodeBlock.displayName = "CodeBlock";
18284
18883
  }
18285
18884
  });
18885
+
18886
+ // components/core/molecules/markdown/mermaidSource.ts
18887
+ function isQuoted(label) {
18888
+ const trimmed = label.trim();
18889
+ return trimmed.length === 0 || trimmed.startsWith('"') && trimmed.endsWith('"') && trimmed.length > 1;
18890
+ }
18891
+ function quote(label) {
18892
+ return `"${label.replace(/"/g, "#quot;")}"`;
18893
+ }
18894
+ function isIdentifierChar(ch) {
18895
+ return /[A-Za-z0-9_\-.]/.test(ch);
18896
+ }
18897
+ function declaredType(code) {
18898
+ for (const line of code.split("\n")) {
18899
+ const trimmed = line.trim();
18900
+ if (trimmed.length === 0 || trimmed.startsWith("%%")) continue;
18901
+ return trimmed;
18902
+ }
18903
+ return "";
18904
+ }
18905
+ function isFlowchart(code) {
18906
+ return FLOWCHART_DIRECTIVE.test(declaredType(code));
18907
+ }
18908
+ function quoteNodeLabels(code) {
18909
+ let out = "";
18910
+ let i = 0;
18911
+ while (i < code.length) {
18912
+ const shape = NODE_SHAPES.find(([open2]) => code.startsWith(open2, i));
18913
+ const precededByIdentifier = i > 0 && isIdentifierChar(code[i - 1] ?? "");
18914
+ if (shape === void 0 || !precededByIdentifier) {
18915
+ out += code[i];
18916
+ i += 1;
18917
+ continue;
18918
+ }
18919
+ const [open, close] = shape;
18920
+ const contentStart = i + open.length;
18921
+ const closeAt = code.indexOf(close, contentStart);
18922
+ const newlineAt = code.indexOf("\n", contentStart);
18923
+ if (closeAt === -1 || newlineAt !== -1 && newlineAt < closeAt) {
18924
+ out += code[i];
18925
+ i += 1;
18926
+ continue;
18927
+ }
18928
+ const label = code.slice(contentStart, closeAt);
18929
+ out += open + (isQuoted(label) ? label : quote(label)) + close;
18930
+ i = closeAt + close.length;
18931
+ }
18932
+ return out;
18933
+ }
18934
+ function quoteEdgeLabels(code) {
18935
+ return code.split("\n").map((line) => {
18936
+ let out = "";
18937
+ let rest = line;
18938
+ for (; ; ) {
18939
+ const open = rest.indexOf("|");
18940
+ if (open === -1) break;
18941
+ const close = rest.indexOf("|", open + 1);
18942
+ if (close === -1) break;
18943
+ const label = rest.slice(open + 1, close);
18944
+ out += rest.slice(0, open + 1) + (isQuoted(label) ? label : quote(label)) + "|";
18945
+ rest = rest.slice(close + 1);
18946
+ }
18947
+ return out + rest;
18948
+ }).join("\n");
18949
+ }
18950
+ function quoteSubgraphTitles(code) {
18951
+ return code.split("\n").map((line) => {
18952
+ const match = /^(\s*subgraph\s+)(.+?)(\s*)$/.exec(line);
18953
+ if (match === null) return line;
18954
+ const [, prefix, title, trailing] = match;
18955
+ if (title === void 0 || prefix === void 0) return line;
18956
+ if (isQuoted(title) || title.includes("[")) return line;
18957
+ return prefix + quote(title) + (trailing ?? "");
18958
+ }).join("\n");
18959
+ }
18960
+ function mermaidRepairCandidates(code) {
18961
+ if (!isFlowchart(code)) return [];
18962
+ const nodes = quoteNodeLabels(code);
18963
+ const nodesAndEdges = quoteEdgeLabels(nodes);
18964
+ const all = quoteSubgraphTitles(nodesAndEdges);
18965
+ const ordered2 = [nodes, nodesAndEdges, all];
18966
+ const seen = /* @__PURE__ */ new Set([code]);
18967
+ const candidates = [];
18968
+ for (const candidate of ordered2) {
18969
+ if (seen.has(candidate)) continue;
18970
+ seen.add(candidate);
18971
+ candidates.push(candidate);
18972
+ }
18973
+ return candidates;
18974
+ }
18975
+ var NODE_SHAPES, FLOWCHART_DIRECTIVE;
18976
+ var init_mermaidSource = __esm({
18977
+ "components/core/molecules/markdown/mermaidSource.ts"() {
18978
+ NODE_SHAPES = [
18979
+ ["[[", "]]"],
18980
+ ["[(", ")]"],
18981
+ ["([", "])"],
18982
+ ["((", "))"],
18983
+ ["{{", "}}"],
18984
+ ["[", "]"],
18985
+ ["(", ")"],
18986
+ ["{", "}"]
18987
+ ];
18988
+ FLOWCHART_DIRECTIVE = /^(?:graph|flowchart)\b/;
18989
+ }
18990
+ });
18286
18991
  function loadMermaid() {
18287
18992
  mermaidModule ?? (mermaidModule = import('mermaid').then((m) => m.default));
18288
18993
  return mermaidModule;
18289
18994
  }
18290
- var mermaidModule, MermaidDiagram;
18995
+ var log8, mermaidModule, MermaidDiagram;
18291
18996
  var init_MermaidDiagram = __esm({
18292
18997
  "components/core/molecules/markdown/MermaidDiagram.tsx"() {
18293
18998
  init_Box();
18294
18999
  init_Typography();
18295
19000
  init_CodeBlock();
19001
+ init_mermaidSource();
18296
19002
  init_cn();
19003
+ log8 = logger.createLogger("almadar:ui:mermaid-diagram");
18297
19004
  mermaidModule = null;
18298
19005
  MermaidDiagram = React89__namespace.default.memo(
18299
19006
  ({ code, className }) => {
18300
19007
  const { resolvedMode } = context.useTheme();
19008
+ const { t } = hooks.useTranslate();
18301
19009
  const containerRef = React89.useRef(null);
18302
- const [error, setError] = React89.useState(null);
19010
+ const [unrenderable, setUnrenderable] = React89.useState(false);
18303
19011
  const reactId = React89.useId();
18304
19012
  React89.useEffect(() => {
18305
19013
  let active = true;
18306
19014
  void (async () => {
18307
- try {
18308
- const mermaid = await loadMermaid();
18309
- mermaid.initialize({
18310
- startOnLoad: false,
18311
- securityLevel: "strict",
18312
- theme: resolvedMode === "dark" ? "dark" : "default"
18313
- });
18314
- const domId = `mermaid-${reactId.replace(/[^a-zA-Z0-9]/g, "")}`;
18315
- const { svg } = await mermaid.render(domId, code);
18316
- if (!active || !containerRef.current) return;
18317
- containerRef.current.innerHTML = svg;
18318
- setError(null);
18319
- } catch (err) {
18320
- if (active) setError(err instanceof Error ? err.message : String(err));
19015
+ const mermaid = await loadMermaid();
19016
+ mermaid.initialize({
19017
+ startOnLoad: false,
19018
+ securityLevel: "strict",
19019
+ theme: resolvedMode === "dark" ? "dark" : "default"
19020
+ });
19021
+ const domId = `mermaid-${reactId.replace(/[^a-zA-Z0-9]/g, "")}`;
19022
+ let firstError = null;
19023
+ for (const [index, source] of [code, ...mermaidRepairCandidates(code)].entries()) {
19024
+ try {
19025
+ const { svg } = await mermaid.render(domId, source);
19026
+ if (!active) return;
19027
+ const container = containerRef.current;
19028
+ if (container === null) return;
19029
+ container.innerHTML = svg;
19030
+ container.dataset.mermaidRepaired = String(index > 0);
19031
+ setUnrenderable(false);
19032
+ if (index > 0) log8.debug("mermaid:repaired", { candidate: index });
19033
+ return;
19034
+ } catch (err) {
19035
+ firstError ?? (firstError = err instanceof Error ? err : new Error(String(err)));
19036
+ }
18321
19037
  }
19038
+ if (!active) return;
19039
+ log8.warn("mermaid:unrenderable", { error: firstError?.message ?? "", code });
19040
+ setUnrenderable(true);
18322
19041
  })();
18323
19042
  return () => {
18324
19043
  active = false;
18325
19044
  };
18326
19045
  }, [code, resolvedMode, reactId]);
18327
19046
  return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: cn("not-prose my-4", className), children: [
18328
- error !== null && /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "space-y-2 mb-2", children: [
18329
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-error whitespace-pre-wrap", children: error }),
19047
+ unrenderable && /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "space-y-2 mb-2", "data-testid": "mermaid-unrenderable", children: [
19048
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("mermaid.unrenderable") }),
18330
19049
  /* @__PURE__ */ jsxRuntime.jsx(CodeBlock, { code, language: "mermaid" })
18331
19050
  ] }),
18332
19051
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -18335,7 +19054,7 @@ var init_MermaidDiagram = __esm({
18335
19054
  ref: containerRef,
18336
19055
  "data-testid": "mermaid-diagram",
18337
19056
  className: "overflow-x-auto",
18338
- style: error !== null ? { display: "none" } : void 0
19057
+ style: unrenderable ? { display: "none" } : void 0
18339
19058
  }
18340
19059
  )
18341
19060
  ] });
@@ -21740,14 +22459,14 @@ function useSafeEventBus2() {
21740
22459
  } };
21741
22460
  }
21742
22461
  }
21743
- var log8, lookStyles4, ButtonGroup;
22462
+ var log9, lookStyles4, ButtonGroup;
21744
22463
  var init_ButtonGroup = __esm({
21745
22464
  "components/core/molecules/ButtonGroup.tsx"() {
21746
22465
  "use client";
21747
22466
  init_cn();
21748
22467
  init_atoms();
21749
22468
  init_useEventBus();
21750
- log8 = logger.createLogger("almadar:ui:button-group");
22469
+ log9 = logger.createLogger("almadar:ui:button-group");
21751
22470
  lookStyles4 = {
21752
22471
  "right-aligned-buttons": "",
21753
22472
  "floating-bar": "fixed bottom-section left-1/2 -translate-x-1/2 shadow-elevation-toast bg-card p-card-sm rounded-container",
@@ -21828,7 +22547,7 @@ var init_ButtonGroup = __esm({
21828
22547
  {
21829
22548
  variant: "ghost",
21830
22549
  onClick: () => {
21831
- log8.debug("Filter clicked", { field: filter.field });
22550
+ log9.debug("Filter clicked", { field: filter.field });
21832
22551
  },
21833
22552
  children: filter.label
21834
22553
  },
@@ -24612,6 +25331,12 @@ function commandMatches(command, query) {
24612
25331
  if (matchesQuery(query, command.label)) return true;
24613
25332
  return (command.keywords ?? []).some((keyword) => matchesQuery(query, keyword));
24614
25333
  }
25334
+ function dispatchCommandPaletteCommand(command, deps) {
25335
+ if (command.disabled) return;
25336
+ if (command.event) deps.emit(`UI:${command.event}`, { commandId: command.id });
25337
+ if (command.action) deps.emit(`UI:${command.action}`, command.actionPayload ?? {});
25338
+ deps.onSelect?.(command);
25339
+ }
24615
25340
  var UNGROUPED, CommandPalette;
24616
25341
  var init_CommandPalette = __esm({
24617
25342
  "components/core/molecules/CommandPalette.tsx"() {
@@ -24666,9 +25391,7 @@ var init_CommandPalette = __esm({
24666
25391
  const handleSelect = React89.useCallback(
24667
25392
  (command) => {
24668
25393
  if (command.disabled) return;
24669
- if (command.event) eventBus.emit(`UI:${command.event}`, { commandId: command.id });
24670
- if (command.action) eventBus.emit(`UI:${command.action}`, command.actionPayload ?? {});
24671
- onSelect?.(command);
25394
+ dispatchCommandPaletteCommand(command, { emit: eventBus.emit, onSelect });
24672
25395
  handleClose();
24673
25396
  },
24674
25397
  [eventBus, onSelect, handleClose]
@@ -29647,9 +30370,9 @@ function debug(...args) {
29647
30370
  const [first, ...rest] = args;
29648
30371
  const message = typeof first === "string" ? first : "<debug>";
29649
30372
  if (rest.length === 0 && typeof first === "string") {
29650
- log9.debug(message);
30373
+ log10.debug(message);
29651
30374
  } else {
29652
- log9.debug(message, { args: rest.length > 0 ? formatArgs(rest) : formatArgs([first]) });
30375
+ log10.debug(message, { args: rest.length > 0 ? formatArgs(rest) : formatArgs([first]) });
29653
30376
  }
29654
30377
  }
29655
30378
  function debugGroup(label) {
@@ -29677,11 +30400,11 @@ function toLogMetaValue(v) {
29677
30400
  }
29678
30401
  return String(v);
29679
30402
  }
29680
- var NAMESPACE, log9;
30403
+ var NAMESPACE, log10;
29681
30404
  var init_debug = __esm({
29682
30405
  "lib/debug.ts"() {
29683
30406
  NAMESPACE = "almadar:ui:debug";
29684
- log9 = logger.createLogger(NAMESPACE);
30407
+ log10 = logger.createLogger(NAMESPACE);
29685
30408
  logger.createLogger("almadar:ui:debug:input");
29686
30409
  logger.createLogger("almadar:ui:debug:collision");
29687
30410
  logger.createLogger("almadar:ui:debug:physics");
@@ -31334,6 +32057,7 @@ var init_MathCanvas = __esm({
31334
32057
  init_perf();
31335
32058
  init_atoms();
31336
32059
  init_Stack();
32060
+ init_gameFonts();
31337
32061
  init_LearningCanvas();
31338
32062
  MathCanvas = ({
31339
32063
  className,
@@ -31353,6 +32077,7 @@ var init_MathCanvas = __esm({
31353
32077
  showTickLabels = false,
31354
32078
  tickLabelFontSize = 10,
31355
32079
  labelFontSize = 12,
32080
+ fontFamily: fontFamilyProp,
31356
32081
  showCurveLabels = false,
31357
32082
  curves = [],
31358
32083
  points = [],
@@ -31375,6 +32100,7 @@ var init_MathCanvas = __esm({
31375
32100
  error
31376
32101
  }) => {
31377
32102
  const eventBus = useEventBus();
32103
+ const fontFamily = resolveGameFontFamily(fontFamilyProp);
31378
32104
  const keyMapKey = keyMap ? JSON.stringify(keyMap) : null;
31379
32105
  const keyUpMapKey = keyUpMap ? JSON.stringify(keyUpMap) : null;
31380
32106
  const stableKeyMap = React89.useMemo(() => keyMap, [keyMapKey]);
@@ -31424,18 +32150,18 @@ var init_MathCanvas = __esm({
31424
32150
  let kx = 0;
31425
32151
  for (let x = Math.ceil(xMin / gridStep) * gridStep; x <= xMax; x += gridStep, kx++) {
31426
32152
  if (kx % labelEveryX === 0 && x !== 0) {
31427
- out.push({ type: "text", x: mapX(x), y: xAxisY + 12, text: formatTick(x), color: "#6b7280", fontSize: tickLabelFontSize, align: "center" });
32153
+ out.push({ type: "text", fontFamily, x: mapX(x), y: xAxisY + 12, text: formatTick(x), color: "#6b7280", fontSize: tickLabelFontSize, align: "center" });
31428
32154
  }
31429
32155
  }
31430
32156
  const labelEveryY = Math.max(1, Math.ceil((yMax - yMin) / gridStep / Math.floor(plotH / 28)));
31431
32157
  let ky = 0;
31432
32158
  for (let y = Math.ceil(yMin / gridStep) * gridStep; y <= yMax; y += gridStep, ky++) {
31433
32159
  if (ky % labelEveryY === 0 && y !== 0) {
31434
- out.push({ type: "text", x: yAxisX - 6, y: mapY(y), text: formatTick(y), color: "#6b7280", fontSize: tickLabelFontSize, align: "right" });
32160
+ out.push({ type: "text", fontFamily, x: yAxisX - 6, y: mapY(y), text: formatTick(y), color: "#6b7280", fontSize: tickLabelFontSize, align: "right" });
31435
32161
  }
31436
32162
  }
31437
32163
  if (xMin <= 0 && xMax >= 0 && yMin <= 0 && yMax >= 0) {
31438
- out.push({ type: "text", x: yAxisX - 6, y: xAxisY + 12, text: "0", color: "#6b7280", fontSize: tickLabelFontSize, align: "right" });
32164
+ out.push({ type: "text", fontFamily, x: yAxisX - 6, y: xAxisY + 12, text: "0", color: "#6b7280", fontSize: tickLabelFontSize, align: "right" });
31439
32165
  }
31440
32166
  }
31441
32167
  for (const region of regions) {
@@ -31462,6 +32188,7 @@ var init_MathCanvas = __esm({
31462
32188
  const mid = Math.floor(region.samples.length / 2);
31463
32189
  out.push({
31464
32190
  type: "text",
32191
+ fontFamily,
31465
32192
  x: mapX((first.x + last.x) / 2),
31466
32193
  y: (mapY(region.samples[mid].y) + mapY(baseline)) / 2,
31467
32194
  text: region.label,
@@ -31498,14 +32225,14 @@ var init_MathCanvas = __esm({
31498
32225
  const px = mapX(guide.at);
31499
32226
  out.push({ type: "line", x1: px, y1: margin, x2: px, y2: height - margin, color, dash });
31500
32227
  if (guide.label) {
31501
- out.push({ type: "text", x: px + 4, y: margin + 10, text: guide.label, color, fontSize: 11 });
32228
+ out.push({ type: "text", fontFamily, x: px + 4, y: margin + 10, text: guide.label, color, fontSize: 11 });
31502
32229
  }
31503
32230
  } else {
31504
32231
  if (guide.at < yMin || guide.at > yMax) continue;
31505
32232
  const py = mapY(guide.at);
31506
32233
  out.push({ type: "line", x1: margin, y1: py, x2: width - margin, y2: py, color, dash });
31507
32234
  if (guide.label) {
31508
- out.push({ type: "text", x: width - margin - 4, y: py - 8, text: guide.label, color, fontSize: labelFontSize, align: "right" });
32235
+ out.push({ type: "text", fontFamily, x: width - margin - 4, y: py - 8, text: guide.label, color, fontSize: labelFontSize, align: "right" });
31509
32236
  }
31510
32237
  }
31511
32238
  }
@@ -31544,6 +32271,7 @@ var init_MathCanvas = __esm({
31544
32271
  if (showCurveLabels && curve.label && lastInRange) {
31545
32272
  out.push({
31546
32273
  type: "text",
32274
+ fontFamily,
31547
32275
  x: mapX(lastInRange.x) + 6,
31548
32276
  y: mapY(lastInRange.y) - 6,
31549
32277
  text: curve.label,
@@ -31581,6 +32309,7 @@ var init_MathCanvas = __esm({
31581
32309
  if (hop.label) {
31582
32310
  out.push({
31583
32311
  type: "text",
32312
+ fontFamily,
31584
32313
  x: (x1 + x2) / 2,
31585
32314
  y: xAxisY - peak - 8,
31586
32315
  text: hop.label,
@@ -31608,6 +32337,7 @@ var init_MathCanvas = __esm({
31608
32337
  const rad = mid * Math.PI / 180;
31609
32338
  out.push({
31610
32339
  type: "text",
32340
+ fontFamily,
31611
32341
  x: mapX(angle.x + 1.35 * radius * Math.cos(rad)),
31612
32342
  y: mapY(angle.y + 1.35 * radius * Math.sin(rad)),
31613
32343
  text: angle.label,
@@ -31629,7 +32359,7 @@ var init_MathCanvas = __esm({
31629
32359
  fill: isOpen ? "#ffffff" : p.color ?? "#dc2626"
31630
32360
  });
31631
32361
  if (p.label) {
31632
- out.push({ type: "text", x: mapX(p.x) + 8, y: mapY(p.y) - 8, text: p.label, color: p.color ?? "#111827", fontSize: labelFontSize });
32362
+ out.push({ type: "text", fontFamily, x: mapX(p.x) + 8, y: mapY(p.y) - 8, text: p.label, color: p.color ?? "#111827", fontSize: labelFontSize });
31633
32363
  }
31634
32364
  }
31635
32365
  for (const v of vectors) {
@@ -31640,7 +32370,7 @@ var init_MathCanvas = __esm({
31640
32370
  const y2 = mapY(v.y + v.vy);
31641
32371
  out.push({ type: "arrow", x1, y1, x2, y2, color: v.color ?? "#7c3aed", lineWidth: 2 });
31642
32372
  if (v.label) {
31643
- out.push({ type: "text", x: x2 + 6, y: y2 - 6, text: v.label, color: v.color ?? "#7c3aed", fontSize: labelFontSize });
32373
+ out.push({ type: "text", fontFamily, x: x2 + 6, y: y2 - 6, text: v.label, color: v.color ?? "#7c3aed", fontSize: labelFontSize });
31644
32374
  }
31645
32375
  }
31646
32376
  out.push(...shapes);
@@ -31661,6 +32391,7 @@ var init_MathCanvas = __esm({
31661
32391
  showTickLabels,
31662
32392
  tickLabelFontSize,
31663
32393
  labelFontSize,
32394
+ fontFamily,
31664
32395
  showCurveLabels,
31665
32396
  curves,
31666
32397
  points,
@@ -31716,6 +32447,7 @@ var init_MathCanvas = __esm({
31716
32447
  width,
31717
32448
  height,
31718
32449
  backgroundColor,
32450
+ fontFamily,
31719
32451
  shapes: derivedShapes,
31720
32452
  drawables,
31721
32453
  projector,
@@ -32948,13 +33680,13 @@ var init_MapView = __esm({
32948
33680
  shadowSize: [41, 41]
32949
33681
  });
32950
33682
  L.Marker.prototype.options.icon = defaultIcon;
32951
- const { useEffect: useEffect68, useRef: useRef67, useCallback: useCallback100, useState: useState102 } = React89__namespace.default;
33683
+ const { useEffect: useEffect69, useRef: useRef69, useCallback: useCallback100, useState: useState103 } = React89__namespace.default;
32952
33684
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
32953
33685
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
32954
33686
  function MapUpdater({ centerLat, centerLng, zoom }) {
32955
33687
  const map = useMap();
32956
- const prevRef = useRef67({ centerLat, centerLng, zoom });
32957
- useEffect68(() => {
33688
+ const prevRef = useRef69({ centerLat, centerLng, zoom });
33689
+ useEffect69(() => {
32958
33690
  const prev = prevRef.current;
32959
33691
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
32960
33692
  map.setView([centerLat, centerLng], zoom);
@@ -32965,7 +33697,7 @@ var init_MapView = __esm({
32965
33697
  }
32966
33698
  function MapClickHandler({ onMapClick }) {
32967
33699
  const map = useMap();
32968
- useEffect68(() => {
33700
+ useEffect69(() => {
32969
33701
  if (!onMapClick) return;
32970
33702
  const handler = (e) => {
32971
33703
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -32993,7 +33725,7 @@ var init_MapView = __esm({
32993
33725
  showAttribution = true
32994
33726
  }) {
32995
33727
  const eventBus = useEventBus2();
32996
- const [clickedPosition, setClickedPosition] = useState102(null);
33728
+ const [clickedPosition, setClickedPosition] = useState103(null);
32997
33729
  const handleMapClick = useCallback100((lat, lng) => {
32998
33730
  if (showClickedPin) {
32999
33731
  setClickedPosition({ lat, lng });
@@ -47702,7 +48434,7 @@ function getAllEvents(traits2) {
47702
48434
  function EventDispatcherTab({ traits: traits2, schema }) {
47703
48435
  const eventBus = useEventBus();
47704
48436
  const { t } = hooks.useTranslate();
47705
- const [log13, setLog] = React89__namespace.useState([]);
48437
+ const [log14, setLog] = React89__namespace.useState([]);
47706
48438
  const prevStatesRef = React89__namespace.useRef(/* @__PURE__ */ new Map());
47707
48439
  React89__namespace.useEffect(() => {
47708
48440
  for (const trait of traits2) {
@@ -47766,9 +48498,9 @@ function EventDispatcherTab({ traits: traits2, schema }) {
47766
48498
  /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "medium", className: "text-muted-foreground mb-1", children: t("debug.otherEvents") }),
47767
48499
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1", children: unavailableEvents.map((event) => /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "default", size: "sm", className: "opacity-50", children: event }, event)) })
47768
48500
  ] }),
47769
- log13.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
48501
+ log14.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
47770
48502
  /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "medium", className: "text-muted-foreground mb-1", children: t("debug.recentTransitions") }),
47771
- /* @__PURE__ */ jsxRuntime.jsx(Stack, { gap: "xs", children: log13.map((entry, i) => /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", className: "font-mono text-xs", children: [
48503
+ /* @__PURE__ */ jsxRuntime.jsx(Stack, { gap: "xs", children: log14.map((entry, i) => /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", className: "font-mono text-xs", children: [
47772
48504
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-primary", children: entry.traitName }),
47773
48505
  " ",
47774
48506
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: entry.from }),
@@ -49959,6 +50691,7 @@ var init_component_registry_generated = __esm({
49959
50691
  init_FormSection();
49960
50692
  init_FormSectionHeader();
49961
50693
  init_FxOverlay();
50694
+ init_GameAudioCue();
49962
50695
  init_GameAudioToggle();
49963
50696
  init_GameHud();
49964
50697
  init_GameIcon();
@@ -50236,6 +50969,7 @@ var init_component_registry_generated = __esm({
50236
50969
  "FormLayout": FormLayout,
50237
50970
  "FormSectionHeader": FormSectionHeader,
50238
50971
  "FxOverlay": FxOverlay,
50972
+ "GameAudioCue": GameAudioCue,
50239
50973
  "GameAudioToggle": GameAudioToggle,
50240
50974
  "GameHud": GameHud,
50241
50975
  "GameIcon": GameIcon,
@@ -51731,7 +52465,7 @@ init_UISlotRenderer();
51731
52465
  // providers/VerificationProvider.tsx
51732
52466
  init_useEventBus();
51733
52467
  init_verificationRegistry();
51734
- var log10 = logger.createLogger("almadar:verify");
52468
+ var log11 = logger.createLogger("almadar:verify");
51735
52469
  var DISPATCH_SUFFIX = ":DISPATCH";
51736
52470
  var SUCCESS_SUFFIX = ":SUCCESS";
51737
52471
  var ERROR_SUFFIX = ":ERROR";
@@ -51778,7 +52512,7 @@ function VerificationProvider({
51778
52512
  const verificationProviderLifecycleListener = (evt) => {
51779
52513
  const parsed = parseLifecycleEvent(evt.type);
51780
52514
  if (!parsed) return;
51781
- log10.debug("lifecycle:event", { kind: parsed.kind, traitName: parsed.traitName, event: parsed.event, type: evt.type });
52515
+ log11.debug("lifecycle:event", { kind: parsed.kind, traitName: parsed.traitName, event: parsed.event, type: evt.type });
51782
52516
  const payload = evt.payload ?? {};
51783
52517
  if (parsed.kind === "dispatch") {
51784
52518
  const key = `${parsed.traitName}:${String(payload["event"] ?? "")}`;
@@ -51834,7 +52568,7 @@ function VerificationProvider({
51834
52568
  },
51835
52569
  timestamp: Date.now()
51836
52570
  });
51837
- log10.debug("transition:success", { trait: parsed.traitName, event: parsed.event, from: pending?.from, to: newState, effectCount: effects.length });
52571
+ log11.debug("transition:success", { trait: parsed.traitName, event: parsed.event, from: pending?.from, to: newState, effectCount: effects.length });
51838
52572
  } else if (parsed.kind === "error" && parsed.event) {
51839
52573
  const key = `${parsed.traitName}:${parsed.event}`;
51840
52574
  const pending = pendingRef.current.get(key);
@@ -51864,7 +52598,7 @@ function VerificationProvider({
51864
52598
  },
51865
52599
  timestamp: Date.now()
51866
52600
  });
51867
- log10.warn("transition:error", { trait: parsed.traitName, event: parsed.event, from: fromState, error: errorMsg });
52601
+ log11.warn("transition:error", { trait: parsed.traitName, event: parsed.event, from: fromState, error: errorMsg });
51868
52602
  }
51869
52603
  };
51870
52604
  Object.defineProperty(verificationProviderLifecycleListener, "name", {
@@ -52326,7 +53060,7 @@ function useEntitySchema() {
52326
53060
  function useEntitySchemaOptional6() {
52327
53061
  return React89.useContext(EntitySchemaContext);
52328
53062
  }
52329
- var log11 = logger.createLogger("almadar:ui:navigation");
53063
+ var log12 = logger.createLogger("almadar:ui:navigation");
52330
53064
  function matchPath2(pattern, path) {
52331
53065
  const normalizeSegment = (p) => {
52332
53066
  let normalized = p.trim();
@@ -52487,12 +53221,12 @@ function NavigationProvider2({
52487
53221
  const navigateTo = React89.useCallback((path, payload) => {
52488
53222
  const result = findPageByPath2(schema, path);
52489
53223
  if (!result) {
52490
- log11.error("No page found for path", { path });
53224
+ log12.error("No page found for path", { path });
52491
53225
  return;
52492
53226
  }
52493
53227
  const { page, params } = result;
52494
53228
  const finalPayload = { ...params, ...payload };
52495
- log11.debug("Navigating to", () => ({
53229
+ log12.debug("Navigating to", () => ({
52496
53230
  path,
52497
53231
  page: page.name,
52498
53232
  params,
@@ -52509,7 +53243,7 @@ function NavigationProvider2({
52509
53243
  try {
52510
53244
  window.history.pushState(finalPayload, "", path);
52511
53245
  } catch (e) {
52512
- log11.warn("Could not update URL", { error: e instanceof Error ? e : String(e) });
53246
+ log12.warn("Could not update URL", { error: e instanceof Error ? e : String(e) });
52513
53247
  }
52514
53248
  }
52515
53249
  if (onNavigate) {
@@ -52519,12 +53253,12 @@ function NavigationProvider2({
52519
53253
  const navigateToPage = React89.useCallback((pageName, payload) => {
52520
53254
  const result = findPageByName2(schema, pageName);
52521
53255
  if (!result) {
52522
- log11.error("No page found with name", { pageName });
53256
+ log12.error("No page found with name", { pageName });
52523
53257
  return;
52524
53258
  }
52525
53259
  const { page } = result;
52526
53260
  const path = page.path || `/${pageName.toLowerCase()}`;
52527
- log11.debug("Navigating to page", () => ({
53261
+ log12.debug("Navigating to page", () => ({
52528
53262
  pageName,
52529
53263
  path,
52530
53264
  payload: JSON.stringify(payload)
@@ -52539,7 +53273,7 @@ function NavigationProvider2({
52539
53273
  try {
52540
53274
  window.history.pushState(payload || {}, "", path);
52541
53275
  } catch (e) {
52542
- log11.warn("Could not update URL", { error: e instanceof Error ? e : String(e) });
53276
+ log12.warn("Could not update URL", { error: e instanceof Error ? e : String(e) });
52543
53277
  }
52544
53278
  }
52545
53279
  if (onNavigate) {
@@ -52561,7 +53295,7 @@ function useNavigation2() {
52561
53295
  function useNavigateTo2() {
52562
53296
  const context = React89.useContext(NavigationContext);
52563
53297
  const noOp = React89.useCallback((path, _payload) => {
52564
- log11.warn("navigateTo called outside NavigationProvider", { path });
53298
+ log12.warn("navigateTo called outside NavigationProvider", { path });
52565
53299
  }, []);
52566
53300
  return context?.navigateTo || noOp;
52567
53301
  }
@@ -52904,7 +53638,7 @@ function ServerBridgeProvider({
52904
53638
  }, [serverUrl, eventBus]);
52905
53639
  return /* @__PURE__ */ jsxRuntime.jsx(ServerBridgeContext.Provider, { value: { connected, sendEvent }, children });
52906
53640
  }
52907
- var log12 = logger.createLogger("almadar:ui:trait-provider");
53641
+ var log13 = logger.createLogger("almadar:ui:trait-provider");
52908
53642
  var TraitContext = React89.createContext(null);
52909
53643
  function TraitProvider({
52910
53644
  traits: traitBindings,
@@ -52921,7 +53655,7 @@ function TraitProvider({
52921
53655
  currentState: stateName,
52922
53656
  availableEvents: trait.transitions.filter((t) => t.from === stateName).map((t) => t.event),
52923
53657
  dispatch: (eventKey, payload) => {
52924
- log12.debug("Dispatch", () => ({
53658
+ log13.debug("Dispatch", () => ({
52925
53659
  trait: trait.name,
52926
53660
  event: eventKey,
52927
53661
  payloadKeys: payload ? Object.keys(payload) : []