@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
@@ -9971,7 +9971,7 @@ function collectDrawnItems(nodes) {
9971
9971
  for (const n of nodes) {
9972
9972
  switch (n.type) {
9973
9973
  case "draw-sprite":
9974
- if (isValidScenePos(n.position)) out.push({ pos: n.position, id: n.id, anchor: n.anchor, width: n.width, height: n.height });
9974
+ if (isValidScenePos(n.position)) out.push({ pos: n.position, id: n.id, anchor: n.anchor, width: n.width, height: n.height, rotation: n.rotation });
9975
9975
  break;
9976
9976
  case "draw-shape":
9977
9977
  case "draw-text":
@@ -9981,7 +9981,7 @@ function collectDrawnItems(nodes) {
9981
9981
  break;
9982
9982
  case "draw-sprite-layer":
9983
9983
  for (const it of n.items) {
9984
- if (isValidScenePos(it.position)) out.push({ pos: it.position, id: it.id, anchor: it.anchor, width: it.width, height: it.height });
9984
+ if (isValidScenePos(it.position)) out.push({ pos: it.position, id: it.id, anchor: it.anchor, width: it.width, height: it.height, rotation: it.rotation });
9985
9985
  }
9986
9986
  break;
9987
9987
  case "draw-shape-layer":
@@ -10001,15 +10001,39 @@ function buildHitIndex(items) {
10001
10001
  }
10002
10002
  return m;
10003
10003
  }
10004
+ function withPreviewPosition(nodes, id, pos) {
10005
+ return nodes.map((n) => {
10006
+ if (n.type === "draw-sprite-layer" || n.type === "draw-shape-layer" || n.type === "draw-text-layer") {
10007
+ if (!n.items.some((it) => it.id === id)) return n;
10008
+ return { ...n, items: n.items.map((it) => it.id === id ? { ...it, position: pos } : it) };
10009
+ }
10010
+ if (n.type === "draw-group") {
10011
+ if (!Array.isArray(n.items)) return n;
10012
+ return { ...n, items: withPreviewPosition(n.items, id, pos) };
10013
+ }
10014
+ if (n.id === id && "position" in n) {
10015
+ return { ...n, position: pos };
10016
+ }
10017
+ return n;
10018
+ });
10019
+ }
10004
10020
  function hitTestSprites(items, projector, point) {
10005
10021
  for (let i = items.length - 1; i >= 0; i--) {
10006
10022
  const it = items[i];
10007
10023
  if (it.id === void 0) continue;
10008
10024
  const r = spriteRect(projector, { position: it.pos, anchor: it.anchor, width: it.width, height: it.height });
10009
- if (point.x >= r.x && point.x <= r.x + r.w && point.y >= r.y && point.y <= r.y + r.h) return it.id;
10025
+ const test = it.rotation ? rotatePoint(point, { x: r.x + r.w / 2, y: r.y + r.h / 2 }, -it.rotation) : point;
10026
+ if (test.x >= r.x && test.x <= r.x + r.w && test.y >= r.y && test.y <= r.y + r.h) return it.id;
10010
10027
  }
10011
10028
  return void 0;
10012
10029
  }
10030
+ function rotatePoint(p, center, radians) {
10031
+ const cos = Math.cos(radians);
10032
+ const sin = Math.sin(radians);
10033
+ const dx = p.x - center.x;
10034
+ const dy = p.y - center.y;
10035
+ return { x: center.x + dx * cos - dy * sin, y: center.y + dx * sin + dy * cos };
10036
+ }
10013
10037
  var init_hitTest = __esm({
10014
10038
  "lib/drawable/hitTest.ts"() {
10015
10039
  init_contract();
@@ -10018,6 +10042,41 @@ var init_hitTest = __esm({
10018
10042
  function normalizeBackdrop(bg) {
10019
10043
  return typeof bg === "string" ? { url: bg, role: "decoration", category: "background" } : bg;
10020
10044
  }
10045
+ function selectionOverlayNodes(projector, item) {
10046
+ const r = spriteRect(projector, { position: item.pos, anchor: item.anchor, width: item.width, height: item.height });
10047
+ const tw = projector.tileWidth;
10048
+ const cellTopLeft = projector.anchorPoint(item.pos, "top-left");
10049
+ const offsetX = (r.x - cellTopLeft.x) / tw;
10050
+ const offsetY = (r.y - cellTopLeft.y) / tw;
10051
+ const width = r.w / tw;
10052
+ const height = r.h / tw;
10053
+ const handle = EDIT_HANDLE_SIZE_PX / tw;
10054
+ const ring = {
10055
+ type: "draw-shape",
10056
+ shape: "rect",
10057
+ position: item.pos,
10058
+ anchor: "top-left",
10059
+ offsetX,
10060
+ offsetY,
10061
+ width,
10062
+ height,
10063
+ stroke: EDIT_SELECTION_COLOR,
10064
+ strokeWidth: 2,
10065
+ fill: "none"
10066
+ };
10067
+ const handles = EDIT_SELECTION_CORNERS.map(([cx, cy]) => ({
10068
+ type: "draw-shape",
10069
+ shape: "rect",
10070
+ position: item.pos,
10071
+ anchor: "top-left",
10072
+ offsetX: offsetX + cx * width - handle / 2,
10073
+ offsetY: offsetY + cy * height - handle / 2,
10074
+ width: handle,
10075
+ height: handle,
10076
+ fill: EDIT_SELECTION_COLOR
10077
+ }));
10078
+ return [ring, ...handles];
10079
+ }
10021
10080
  function Canvas2D({
10022
10081
  className,
10023
10082
  isLoading = false,
@@ -10031,6 +10090,12 @@ function Canvas2D({
10031
10090
  tileLeaveEvent,
10032
10091
  keyMap,
10033
10092
  keyUpMap,
10093
+ editable = false,
10094
+ selectedId = null,
10095
+ onSelect,
10096
+ onMove,
10097
+ selectEvent,
10098
+ moveEvent,
10034
10099
  camera = "pan-zoom",
10035
10100
  scale = 0.4,
10036
10101
  tileWidth,
@@ -10288,10 +10353,22 @@ function Canvas2D({
10288
10353
  painter.scale(cam.zoom, cam.zoom);
10289
10354
  painter.translate(-viewportSize.width / 2 - cam.x, -viewportSize.height / 2 - cam.y);
10290
10355
  const dctx = { projector, time: timeMs, invalidate: bumpAtlas };
10291
- for (const node of drawables) paintDrawable(painter, node, dctx);
10356
+ let paintNodes = drawables;
10357
+ if (editable) {
10358
+ const drag = editDragRef.current;
10359
+ if (drag && drag.moved) {
10360
+ paintNodes = withPreviewPosition(paintNodes, drag.id, { x: drag.previewX, y: drag.previewY });
10361
+ }
10362
+ const selectedItem = selectedId != null ? drawnItems.find((it) => it.id === selectedId) : void 0;
10363
+ if (selectedItem) {
10364
+ const overlaySource = drag && drag.moved && drag.id === selectedId ? { ...selectedItem, pos: { x: drag.previewX, y: drag.previewY } } : selectedItem;
10365
+ paintNodes = [...paintNodes, ...selectionOverlayNodes(projector, overlaySource)];
10366
+ }
10367
+ }
10368
+ for (const node of paintNodes) paintDrawable(painter, node, dctx);
10292
10369
  painter.restore();
10293
- scheduleAnimation(drawables);
10294
- }, [viewportSize, backgroundImage, bgColor, drawables, projector, cameraRef, bumpAtlas, getImage, cameraPos, defaultGridFocus, camera, dragDistance]);
10370
+ scheduleAnimation(paintNodes);
10371
+ }, [viewportSize, backgroundImage, bgColor, drawables, projector, cameraRef, bumpAtlas, getImage, cameraPos, defaultGridFocus, camera, dragDistance, editable, selectedId, drawnItems]);
10295
10372
  useEffect(() => {
10296
10373
  drawTimeRef.current = draw;
10297
10374
  }, [draw]);
@@ -10336,23 +10413,83 @@ function Canvas2D({
10336
10413
  };
10337
10414
  }, [camera, followTarget, lerpToTarget, draw]);
10338
10415
  const singlePointerActiveRef = useRef(false);
10416
+ const editDragRef = useRef(null);
10417
+ const pointerToScene = useCallback((clientX, clientY) => {
10418
+ const canvas = canvasRef.current;
10419
+ if (!canvas) return { x: 0, y: 0 };
10420
+ const world = screenToWorld(clientX, clientY, canvas, viewportSize);
10421
+ const adjustedX = world.x - scaledTileWidth / 2;
10422
+ const adjustedY = squareGrid ? world.y - scaledTileWidth / 2 : world.y - scaledDiamondTopY - scaledFloorHeight / 2;
10423
+ return unproject(adjustedX, adjustedY);
10424
+ }, [screenToWorld, viewportSize, scaledTileWidth, squareGrid, scaledDiamondTopY, scaledFloorHeight, unproject]);
10339
10425
  const handleCanvasPointerDown = useCallback((e) => {
10340
10426
  singlePointerActiveRef.current = true;
10427
+ if (editable) {
10428
+ if (!canvasRef.current) return;
10429
+ const world = screenToWorld(e.clientX, e.clientY, canvasRef.current, viewportSize);
10430
+ const hitId = hitTestSprites(drawnItems, projector, world);
10431
+ if (hitId === void 0) return;
10432
+ const item = [...drawnItems].reverse().find((it) => it.id === hitId);
10433
+ if (!item) return;
10434
+ editDragRef.current = {
10435
+ id: hitId,
10436
+ pointerId: e.pointerId,
10437
+ startClientX: e.clientX,
10438
+ startClientY: e.clientY,
10439
+ startSceneX: item.pos.x,
10440
+ startSceneY: item.pos.y,
10441
+ moved: false,
10442
+ previewX: item.pos.x,
10443
+ previewY: item.pos.y
10444
+ };
10445
+ return;
10446
+ }
10341
10447
  if (enableCamera) handlePointerDown(e);
10342
- }, [enableCamera, handlePointerDown]);
10448
+ }, [editable, screenToWorld, viewportSize, drawnItems, projector, enableCamera, handlePointerDown]);
10343
10449
  const handleCanvasPointerMove = useCallback((e) => {
10450
+ if (editable) {
10451
+ const drag = editDragRef.current;
10452
+ if (!drag || drag.pointerId !== e.pointerId) return;
10453
+ const dxPx = e.clientX - drag.startClientX;
10454
+ const dyPx = e.clientY - drag.startClientY;
10455
+ if (!drag.moved && Math.abs(dxPx) + Math.abs(dyPx) <= 5) return;
10456
+ drag.moved = true;
10457
+ const nowScene = pointerToScene(e.clientX, e.clientY);
10458
+ const startScene = pointerToScene(drag.startClientX, drag.startClientY);
10459
+ drag.previewX = drag.startSceneX + (nowScene.x - startScene.x);
10460
+ drag.previewY = drag.startSceneY + (nowScene.y - startScene.y);
10461
+ draw();
10462
+ return;
10463
+ }
10344
10464
  if (enableCamera) handlePointerMove(e, () => draw());
10345
- }, [enableCamera, handlePointerMove, draw]);
10465
+ }, [editable, pointerToScene, draw, enableCamera, handlePointerMove]);
10346
10466
  const handleCanvasHover = useCallback((e) => {
10347
10467
  if (singlePointerActiveRef.current) return;
10348
10468
  if (!tileHoverEvent || !canvasRef.current) return;
10349
- const world = screenToWorld(e.clientX, e.clientY, canvasRef.current, viewportSize);
10350
- const adjustedX = world.x - scaledTileWidth / 2;
10351
- const adjustedY = squareGrid ? world.y - scaledTileWidth / 2 : world.y - scaledDiamondTopY - scaledFloorHeight / 2;
10352
- const isoPos = unproject(adjustedX, adjustedY);
10469
+ const isoPos = pointerToScene(e.clientX, e.clientY);
10353
10470
  eventBus.emit(`UI:${tileHoverEvent}`, { x: isoPos.x, y: isoPos.y });
10354
- }, [screenToWorld, viewportSize, scaledTileWidth, squareGrid, scaledDiamondTopY, scaledFloorHeight, unproject, tileHoverEvent, eventBus]);
10471
+ }, [pointerToScene, tileHoverEvent, eventBus]);
10355
10472
  const handleCanvasPointerUp = useCallback((e) => {
10473
+ if (editable) {
10474
+ singlePointerActiveRef.current = false;
10475
+ const drag = editDragRef.current;
10476
+ if (drag && drag.pointerId === e.pointerId) {
10477
+ editDragRef.current = null;
10478
+ if (drag.moved) {
10479
+ onMove?.(drag.id, drag.previewX, drag.previewY);
10480
+ if (moveEvent) eventBus.emit(`UI:${moveEvent}`, { id: drag.id, x: drag.previewX, y: drag.previewY });
10481
+ draw();
10482
+ return;
10483
+ }
10484
+ const next = selectedId === drag.id ? null : drag.id;
10485
+ onSelect?.(next);
10486
+ if (selectEvent) eventBus.emit(`UI:${selectEvent}`, { id: next });
10487
+ return;
10488
+ }
10489
+ onSelect?.(null);
10490
+ if (selectEvent) eventBus.emit(`UI:${selectEvent}`, { id: null });
10491
+ return;
10492
+ }
10356
10493
  singlePointerActiveRef.current = false;
10357
10494
  if (enableCamera) handlePointerUp();
10358
10495
  if (dragDistance() > 5) return;
@@ -10363,16 +10500,14 @@ function Canvas2D({
10363
10500
  eventBus.emit(`UI:${unitClickEvent}`, { unitId: spriteHit });
10364
10501
  return;
10365
10502
  }
10366
- const adjustedX = world.x - scaledTileWidth / 2;
10367
- const adjustedY = squareGrid ? world.y - scaledTileWidth / 2 : world.y - scaledDiamondTopY - scaledFloorHeight / 2;
10368
- const isoPos = unproject(adjustedX, adjustedY);
10503
+ const isoPos = pointerToScene(e.clientX, e.clientY);
10369
10504
  const hitId = hitIndex.get(`${isoPos.x},${isoPos.y}`);
10370
10505
  if (hitId !== void 0 && unitClickEvent) {
10371
10506
  eventBus.emit(`UI:${unitClickEvent}`, { unitId: hitId });
10372
10507
  } else if (tileClickEvent) {
10373
10508
  eventBus.emit(`UI:${tileClickEvent}`, { x: isoPos.x, y: isoPos.y });
10374
10509
  }
10375
- }, [enableCamera, handlePointerUp, dragDistance, screenToWorld, viewportSize, scaledTileWidth, squareGrid, scaledDiamondTopY, scaledFloorHeight, unproject, hitIndex, drawnItems, projector, tileClickEvent, unitClickEvent, eventBus]);
10510
+ }, [editable, selectedId, onMove, moveEvent, onSelect, selectEvent, eventBus, draw, enableCamera, handlePointerUp, dragDistance, screenToWorld, viewportSize, drawnItems, projector, tileClickEvent, unitClickEvent, hitIndex, pointerToScene]);
10376
10511
  const handleCanvasPointerLeave = useCallback(() => {
10377
10512
  handleMouseLeave();
10378
10513
  if (tileLeaveEvent) eventBus.emit(`UI:${tileLeaveEvent}`, {});
@@ -10391,7 +10526,7 @@ function Canvas2D({
10391
10526
  }, [enableCamera, handlePointerUp]);
10392
10527
  const gestureHandlers = useCanvasGestures({
10393
10528
  canvasRef,
10394
- enabled: enableCamera || !!tileHoverEvent || !!tileClickEvent || !!unitClickEvent,
10529
+ enabled: enableCamera || !!tileHoverEvent || !!tileClickEvent || !!unitClickEvent || editable,
10395
10530
  onPointerDown: handleCanvasPointerDown,
10396
10531
  onPointerMove: handleCanvasPointerMove,
10397
10532
  onPointerUp: handleCanvasPointerUp,
@@ -10523,7 +10658,7 @@ function Canvas2D({
10523
10658
  }
10524
10659
  ) });
10525
10660
  }
10526
- var canvas2DLog;
10661
+ var canvas2DLog, EDIT_SELECTION_COLOR, EDIT_HANDLE_SIZE_PX, EDIT_SELECTION_CORNERS;
10527
10662
  var init_Canvas2D = __esm({
10528
10663
  "components/game/molecules/Canvas2D.tsx"() {
10529
10664
  "use client";
@@ -10548,8 +10683,12 @@ var init_Canvas2D = __esm({
10548
10683
  init_DrawGroup();
10549
10684
  init_registry();
10550
10685
  init_hitTest();
10686
+ init_contract();
10551
10687
  init_isometric();
10552
10688
  canvas2DLog = createLogger("almadar:ui:game-canvas");
10689
+ EDIT_SELECTION_COLOR = "#3b82f6";
10690
+ EDIT_HANDLE_SIZE_PX = 8;
10691
+ EDIT_SELECTION_CORNERS = [[0, 0], [1, 0], [0, 1], [1, 1]];
10553
10692
  Canvas2D.displayName = "Canvas2D";
10554
10693
  }
10555
10694
  });
@@ -10591,6 +10730,12 @@ function Canvas({
10591
10730
  featureClickEvent,
10592
10731
  keyMap,
10593
10732
  keyUpMap,
10733
+ editable,
10734
+ selectedId,
10735
+ onSelect,
10736
+ onMove,
10737
+ selectEvent,
10738
+ moveEvent,
10594
10739
  children
10595
10740
  }) {
10596
10741
  canvasLog.debug("Canvas render", { mode, drawablesCount: drawables?.length, projection, camera: camera ? JSON.stringify(camera) : void 0 });
@@ -10668,6 +10813,12 @@ function Canvas({
10668
10813
  tileLeaveEvent,
10669
10814
  keyMap,
10670
10815
  keyUpMap,
10816
+ editable,
10817
+ selectedId,
10818
+ onSelect,
10819
+ onMove,
10820
+ selectEvent,
10821
+ moveEvent,
10671
10822
  ...children !== void 0 ? { children } : {}
10672
10823
  }
10673
10824
  );
@@ -10689,15 +10840,19 @@ function GameAudioToggle({
10689
10840
  size = "sm",
10690
10841
  className,
10691
10842
  onAsset,
10692
- offAsset
10843
+ offAsset,
10844
+ toggleEvent
10693
10845
  }) {
10694
10846
  const ctx = useGameAudioContextOptional();
10695
10847
  const [localMuted, setLocalMuted] = useState(false);
10696
10848
  const muted = ctx ? ctx.muted : localMuted;
10697
10849
  const setMuted = ctx ? ctx.setMuted : setLocalMuted;
10850
+ const eventBus = useEventBus();
10698
10851
  const handleToggle = useCallback(() => {
10699
- setMuted(!muted);
10700
- }, [muted, setMuted]);
10852
+ const next = !muted;
10853
+ setMuted(next);
10854
+ if (toggleEvent) eventBus.emit(`UI:${toggleEvent}`, { muted: next });
10855
+ }, [muted, setMuted, toggleEvent, eventBus]);
10701
10856
  const activeAsset = muted ? offAsset : onAsset;
10702
10857
  return /* @__PURE__ */ jsx(
10703
10858
  Button,
@@ -10716,6 +10871,7 @@ var init_GameAudioToggle = __esm({
10716
10871
  "use client";
10717
10872
  init_atoms();
10718
10873
  init_cn();
10874
+ init_useEventBus();
10719
10875
  init_GameIcon();
10720
10876
  GameAudioToggle.displayName = "GameAudioToggle";
10721
10877
  }
@@ -10987,6 +11143,47 @@ var init_useGameAudio = __esm({
10987
11143
  useGameAudio.displayName = "useGameAudio";
10988
11144
  }
10989
11145
  });
11146
+ function GameAudioCue({
11147
+ cue,
11148
+ cueSeq,
11149
+ music,
11150
+ muted,
11151
+ volume,
11152
+ manifest,
11153
+ baseUrl
11154
+ }) {
11155
+ const { play, playMusic, stopMusic, setMuted, setMasterVolume } = useGameAudio({
11156
+ manifest,
11157
+ baseUrl,
11158
+ initialMuted: muted,
11159
+ initialVolume: volume
11160
+ });
11161
+ const prevCueSeqRef = useRef(cueSeq);
11162
+ useEffect(() => {
11163
+ if (cue && cueSeq !== void 0 && cueSeq !== prevCueSeqRef.current) {
11164
+ play(cue);
11165
+ }
11166
+ prevCueSeqRef.current = cueSeq;
11167
+ }, [cue, cueSeq, play]);
11168
+ useEffect(() => {
11169
+ if (music) playMusic(music);
11170
+ else stopMusic();
11171
+ }, [music, playMusic, stopMusic]);
11172
+ useEffect(() => {
11173
+ if (muted !== void 0) setMuted(muted);
11174
+ }, [muted, setMuted]);
11175
+ useEffect(() => {
11176
+ if (volume !== void 0) setMasterVolume(volume);
11177
+ }, [volume, setMasterVolume]);
11178
+ return null;
11179
+ }
11180
+ var init_GameAudioCue = __esm({
11181
+ "components/game/atoms/GameAudioCue.tsx"() {
11182
+ "use client";
11183
+ init_useGameAudio();
11184
+ GameAudioCue.displayName = "GameAudioCue";
11185
+ }
11186
+ });
10990
11187
  function isKnownState(s) {
10991
11188
  return s in DEFAULT_STATE_STYLES;
10992
11189
  }
@@ -11685,15 +11882,18 @@ var init_StateJsonView = __esm({
11685
11882
  StateJsonView.displayName = "StateJsonView";
11686
11883
  }
11687
11884
  });
11688
- var GAME_FONTS, GameShell;
11689
- var init_GameShell = __esm({
11690
- "components/game/templates/GameShell.tsx"() {
11691
- init_cn();
11692
- init_Box();
11693
- init_Card();
11694
- init_Typography();
11695
- init_AtlasImage();
11696
- GAME_FONTS = {
11885
+
11886
+ // lib/gameFonts.ts
11887
+ function resolveGameFontFamily(input) {
11888
+ if (!input) return void 0;
11889
+ const resolved = GAME_FONT_KEYS[input];
11890
+ if (resolved) return `'${resolved}', ui-sans-serif, system-ui, sans-serif`;
11891
+ return input;
11892
+ }
11893
+ var GAME_FONT_KEYS;
11894
+ var init_gameFonts = __esm({
11895
+ "lib/gameFonts.ts"() {
11896
+ GAME_FONT_KEYS = {
11697
11897
  fredoka: "Fredoka",
11698
11898
  future: "Kenney Future",
11699
11899
  "future-narrow": "Kenney Future Narrow",
@@ -11701,6 +11901,17 @@ var init_GameShell = __esm({
11701
11901
  blocks: "Kenney Blocks",
11702
11902
  mini: "Kenney Mini"
11703
11903
  };
11904
+ }
11905
+ });
11906
+ var GameShell;
11907
+ var init_GameShell = __esm({
11908
+ "components/game/templates/GameShell.tsx"() {
11909
+ init_cn();
11910
+ init_gameFonts();
11911
+ init_Box();
11912
+ init_Card();
11913
+ init_Typography();
11914
+ init_AtlasImage();
11704
11915
  GameShell = ({
11705
11916
  appName = "Game",
11706
11917
  hud,
@@ -11714,7 +11925,7 @@ var init_GameShell = __esm({
11714
11925
  fontFamily,
11715
11926
  "data-theme": dataTheme
11716
11927
  }) => {
11717
- const font = fontFamily ? GAME_FONTS[fontFamily] ?? fontFamily : void 0;
11928
+ const displayFont = resolveGameFontFamily(fontFamily);
11718
11929
  return /* @__PURE__ */ jsxs(
11719
11930
  Box,
11720
11931
  {
@@ -11733,7 +11944,7 @@ var init_GameShell = __esm({
11733
11944
  // passed — an always-on inline stamp would shadow the orbital's
11734
11945
  // inline-theme font-family-display token (inline style beats the
11735
11946
  // theme provider's vars for the whole shell subtree).
11736
- ...font ? { "--font-family-display": `'${font}', ui-sans-serif, system-ui, sans-serif` } : {}
11947
+ ...displayFont ? { "--font-family-display": displayFont } : {}
11737
11948
  },
11738
11949
  children: [
11739
11950
  backgroundAsset && /* @__PURE__ */ jsx(
@@ -11935,14 +12146,15 @@ function drawArrowHead(ctx, x1, y1, x2, y2, size) {
11935
12146
  ctx.closePath();
11936
12147
  ctx.fill();
11937
12148
  }
11938
- function drawShape(ctx, shape, width, height, allShapes) {
12149
+ function drawShape(ctx, shape, width, height, allShapes, fontFamily) {
11939
12150
  ctx.save();
11940
12151
  const opacity = shape.opacity ?? 1;
11941
12152
  ctx.globalAlpha = opacity;
11942
12153
  const stroke = resolveColor2(shape.color, ctx, "#333333");
11943
12154
  const fill = shape.fill ? resolveColor2(shape.fill, ctx, "#cccccc") : void 0;
11944
12155
  ctx.lineWidth = shape.lineWidth ?? 2;
11945
- if (shape.dash) ctx.setLineDash([...DASH_PATTERNS[shape.dash]]);
12156
+ const dashPattern = shape.dash ? DASH_PATTERNS[shape.dash] : void 0;
12157
+ if (dashPattern) ctx.setLineDash([...dashPattern]);
11946
12158
  switch (shape.type) {
11947
12159
  case "grid": {
11948
12160
  const step = shape.step ?? 40;
@@ -12064,7 +12276,7 @@ function drawShape(ctx, shape, width, height, allShapes) {
12064
12276
  case "text": {
12065
12277
  if (shape.x == null || shape.y == null || !shape.text) break;
12066
12278
  ctx.fillStyle = stroke;
12067
- ctx.font = `${shape.fontSize ?? 14}px ${themeBodyFont(ctx.canvas)}`;
12279
+ ctx.font = `${shape.fontSize ?? 14}px ${shape.fontFamily ?? fontFamily ?? themeBodyFont(ctx.canvas)}`;
12068
12280
  ctx.textAlign = shape.align ?? "left";
12069
12281
  ctx.textBaseline = "middle";
12070
12282
  ctx.fillText(shape.text, shape.x, shape.y);
@@ -12106,7 +12318,7 @@ function drawShape(ctx, shape, width, height, allShapes) {
12106
12318
  }
12107
12319
  ctx.restore();
12108
12320
  }
12109
- function readoutShapes(readouts, width) {
12321
+ function readoutShapes(readouts, width, fontFamily) {
12110
12322
  const out = [];
12111
12323
  const chipH = 18;
12112
12324
  const gap = 6;
@@ -12130,13 +12342,14 @@ function readoutShapes(readouts, width) {
12130
12342
  text,
12131
12343
  color: "#ffffff",
12132
12344
  fontSize: 10,
12133
- align: "center"
12345
+ align: "center",
12346
+ fontFamily
12134
12347
  });
12135
12348
  rightEdge = chipX - gap;
12136
12349
  }
12137
12350
  return out;
12138
12351
  }
12139
- function traceShapes(panel, k, width, height) {
12352
+ function traceShapes(panel, k, width, height, fontFamily) {
12140
12353
  const w = panel.width ?? Math.round(width * 0.32);
12141
12354
  const h = panel.height ?? Math.round(height * 0.28);
12142
12355
  const x = panel.x ?? width - w - 8;
@@ -12190,14 +12403,14 @@ function traceShapes(panel, k, width, height) {
12190
12403
  out.push({ type: "circle", x: last.x, y: last.y, radius: 2, color, fill: color });
12191
12404
  }
12192
12405
  if (series.label) {
12193
- out.push({ type: "text", x: x + 6, y: y + 10 + 11 * j, text: series.label, color, fontSize: 9 });
12406
+ out.push({ type: "text", x: x + 6, y: y + 10 + 11 * j, text: series.label, color, fontSize: 9, fontFamily });
12194
12407
  }
12195
12408
  });
12196
12409
  if (panel.yLabel) {
12197
- out.push({ type: "text", x: x + w - 6, y: y + 10, text: panel.yLabel, color: "#6b7280", fontSize: 9, align: "right" });
12410
+ out.push({ type: "text", x: x + w - 6, y: y + 10, text: panel.yLabel, color: "#6b7280", fontSize: 9, align: "right", fontFamily });
12198
12411
  }
12199
12412
  if (panel.xLabel) {
12200
- out.push({ type: "text", x: x + w - 6, y: y + h - 6, text: panel.xLabel, color: "#6b7280", fontSize: 9, align: "right" });
12413
+ out.push({ type: "text", x: x + w - 6, y: y + h - 6, text: panel.xLabel, color: "#6b7280", fontSize: 9, align: "right", fontFamily });
12201
12414
  }
12202
12415
  return out;
12203
12416
  }
@@ -12220,13 +12433,14 @@ var init_LearningCanvas = __esm({
12220
12433
  init_useEventBus();
12221
12434
  init_webPainter2d();
12222
12435
  init_paintDispatch();
12223
- DASH_PATTERNS = { dashed: [6, 4], dotted: [2, 3] };
12436
+ DASH_PATTERNS = { solid: [], dashed: [6, 4], dotted: [2, 3] };
12224
12437
  TRACE_SERIES_COLORS = ["#2563eb", "#dc2626", "#16a34a", "#f59e0b"];
12225
12438
  LearningCanvas = ({
12226
12439
  className,
12227
12440
  width = 600,
12228
12441
  height = 400,
12229
12442
  backgroundColor,
12443
+ fontFamily,
12230
12444
  shapes = [],
12231
12445
  drawables,
12232
12446
  projector,
@@ -12262,10 +12476,10 @@ var init_LearningCanvas = __esm({
12262
12476
  }, [shapes]);
12263
12477
  const derivedShapes = useMemo(() => {
12264
12478
  if (!traces?.length && !readouts?.length) return shapes;
12265
- const traceOut = (traces ?? []).flatMap((panel, k) => traceShapes(panel, k, width, height));
12266
- const readoutOut = readouts?.length ? readoutShapes(readouts, width) : [];
12479
+ const traceOut = (traces ?? []).flatMap((panel, k) => traceShapes(panel, k, width, height, fontFamily));
12480
+ const readoutOut = readouts?.length ? readoutShapes(readouts, width, fontFamily) : [];
12267
12481
  return [...shapes, ...traceOut, ...readoutOut];
12268
- }, [shapes, traces, readouts, width, height]);
12482
+ }, [shapes, traces, readouts, width, height, fontFamily]);
12269
12483
  const draw = useCallback(() => {
12270
12484
  const _perfT = perfStart("learningcanvas:paint");
12271
12485
  const canvas = canvasRef.current;
@@ -12284,15 +12498,15 @@ var init_LearningCanvas = __esm({
12284
12498
  ctx.fillRect(0, 0, width, height);
12285
12499
  }
12286
12500
  for (const shape of derivedShapes) {
12287
- if (shape.type !== "text") drawShape(ctx, shape, width, height, derivedShapes);
12501
+ if (shape.type !== "text") drawShape(ctx, shape, width, height, derivedShapes, fontFamily);
12288
12502
  }
12289
12503
  for (const shape of derivedShapes) {
12290
- if (shape.type === "text") drawShape(ctx, shape, width, height, derivedShapes);
12504
+ if (shape.type === "text") drawShape(ctx, shape, width, height, derivedShapes, fontFamily);
12291
12505
  }
12292
12506
  if (drawables?.length && projector) {
12293
12507
  const painter = createWebPainter(ctx, invalidateRef.current);
12294
12508
  const timeMs = needsAnim && typeof performance !== "undefined" ? performance.now() : 0;
12295
- const dctx = { projector, time: timeMs, invalidate: invalidateRef.current, fontFamily: themeBodyFont(canvas) };
12509
+ const dctx = { projector, time: timeMs, invalidate: invalidateRef.current, fontFamily: fontFamily || themeBodyFont(canvas) };
12296
12510
  for (const node of drawables) {
12297
12511
  paintDrawable(painter, node, dctx);
12298
12512
  }
@@ -17274,6 +17488,250 @@ var init_EmptyState = __esm({
17274
17488
  EmptyState.displayName = "EmptyState";
17275
17489
  }
17276
17490
  });
17491
+
17492
+ // lib/editorMotions.ts
17493
+ function clamp(value, min, max) {
17494
+ return Math.max(min, Math.min(max, value));
17495
+ }
17496
+ function computeLines(text) {
17497
+ const lines = [];
17498
+ let start = 0;
17499
+ for (let i = 0; i <= text.length; i++) {
17500
+ if (i === text.length || text[i] === "\n") {
17501
+ lines.push({ start, end: i });
17502
+ start = i + 1;
17503
+ }
17504
+ }
17505
+ return lines;
17506
+ }
17507
+ function lineIndexAt(lines, pos) {
17508
+ for (let i = 0; i < lines.length; i++) {
17509
+ if (pos <= lines[i].end) return i;
17510
+ }
17511
+ return lines.length - 1;
17512
+ }
17513
+ function findWords(text) {
17514
+ const words = [];
17515
+ const re = /\w+|\S+/g;
17516
+ let m;
17517
+ while ((m = re.exec(text)) !== null) {
17518
+ words.push({ start: m.index, end: m.index + m[0].length });
17519
+ }
17520
+ return words;
17521
+ }
17522
+ function nextWordStart(text, pos) {
17523
+ for (const w of findWords(text)) {
17524
+ if (w.start > pos) return w.start;
17525
+ }
17526
+ return text.length;
17527
+ }
17528
+ function prevWordStart(text, pos) {
17529
+ let result = 0;
17530
+ for (const w of findWords(text)) {
17531
+ if (w.start < pos) result = w.start;
17532
+ else break;
17533
+ }
17534
+ return result;
17535
+ }
17536
+ function nextWordEnd(text, pos) {
17537
+ for (const w of findWords(text)) {
17538
+ const lastChar = w.end - 1;
17539
+ if (lastChar > pos) return lastChar;
17540
+ }
17541
+ return text.length > 0 ? text.length - 1 : 0;
17542
+ }
17543
+ function firstNonBlank(text, line) {
17544
+ let i = line.start;
17545
+ while (i < line.end && (text[i] === " " || text[i] === " ")) i++;
17546
+ return i;
17547
+ }
17548
+ function nextParagraphBoundary(lines, fromLineIdx, textLength) {
17549
+ for (let i = fromLineIdx + 1; i < lines.length; i++) {
17550
+ if (lines[i].start === lines[i].end) return lines[i].start;
17551
+ }
17552
+ return textLength;
17553
+ }
17554
+ function prevParagraphBoundary(lines, fromLineIdx) {
17555
+ for (let i = fromLineIdx - 1; i >= 0; i--) {
17556
+ if (lines[i].start === lines[i].end) return lines[i].start;
17557
+ }
17558
+ return 0;
17559
+ }
17560
+ function applyMotion(text, caret, motion, count) {
17561
+ const n = Math.max(1, count);
17562
+ const lines = computeLines(text);
17563
+ const lineIdx = lineIndexAt(lines, caret);
17564
+ const line = lines[lineIdx];
17565
+ switch (motion) {
17566
+ case "left":
17567
+ return clamp(caret - n, line.start, line.end);
17568
+ case "right":
17569
+ return clamp(caret + n, line.start, line.end);
17570
+ case "up": {
17571
+ const col = caret - line.start;
17572
+ const targetIdx = clamp(lineIdx - n, 0, lines.length - 1);
17573
+ const target = lines[targetIdx];
17574
+ return clamp(target.start + col, target.start, target.end);
17575
+ }
17576
+ case "down": {
17577
+ const col = caret - line.start;
17578
+ const targetIdx = clamp(lineIdx + n, 0, lines.length - 1);
17579
+ const target = lines[targetIdx];
17580
+ return clamp(target.start + col, target.start, target.end);
17581
+ }
17582
+ case "word-forward": {
17583
+ let pos = caret;
17584
+ for (let i = 0; i < n; i++) pos = nextWordStart(text, pos);
17585
+ return pos;
17586
+ }
17587
+ case "word-back": {
17588
+ let pos = caret;
17589
+ for (let i = 0; i < n; i++) pos = prevWordStart(text, pos);
17590
+ return pos;
17591
+ }
17592
+ case "word-end": {
17593
+ let pos = caret;
17594
+ for (let i = 0; i < n; i++) pos = nextWordEnd(text, pos);
17595
+ return pos;
17596
+ }
17597
+ case "line-start":
17598
+ return line.start;
17599
+ case "line-end":
17600
+ return line.end > line.start ? line.end - 1 : line.start;
17601
+ case "first-nonblank":
17602
+ return firstNonBlank(text, line);
17603
+ case "doc-start":
17604
+ return 0;
17605
+ case "doc-end":
17606
+ return text.length;
17607
+ case "paragraph-forward": {
17608
+ let pos = caret;
17609
+ for (let i = 0; i < n; i++) {
17610
+ pos = nextParagraphBoundary(lines, lineIndexAt(lines, pos), text.length);
17611
+ }
17612
+ return pos;
17613
+ }
17614
+ case "paragraph-back": {
17615
+ let pos = caret;
17616
+ for (let i = 0; i < n; i++) {
17617
+ pos = prevParagraphBoundary(lines, lineIndexAt(lines, pos));
17618
+ }
17619
+ return pos;
17620
+ }
17621
+ case "line":
17622
+ case "selection":
17623
+ return caret;
17624
+ default: {
17625
+ const _exhaustive = motion;
17626
+ return _exhaustive;
17627
+ }
17628
+ }
17629
+ }
17630
+ function motionRange(text, caret, motion, count, selection) {
17631
+ if (motion === "selection") {
17632
+ if (!selection) return [caret, caret];
17633
+ return [Math.min(selection[0], selection[1]), Math.max(selection[0], selection[1])];
17634
+ }
17635
+ const lines = computeLines(text);
17636
+ if (motion === "line") {
17637
+ const n = Math.max(1, count);
17638
+ const startIdx = lineIndexAt(lines, caret);
17639
+ const endIdx = clamp(startIdx + n - 1, 0, lines.length - 1);
17640
+ const start2 = lines[startIdx].start;
17641
+ const rawEnd = lines[endIdx].end;
17642
+ const end2 = rawEnd < text.length ? rawEnd + 1 : rawEnd;
17643
+ return [start2, end2];
17644
+ }
17645
+ const newCaret = applyMotion(text, caret, motion, count);
17646
+ let start = Math.min(caret, newCaret);
17647
+ let end = Math.max(caret, newCaret);
17648
+ if (motion === "word-end" || motion === "line-end") {
17649
+ end = Math.min(Math.max(start, newCaret) + 1, text.length);
17650
+ } else if (motion === "word-forward" && newCaret > caret) {
17651
+ const startLine = lineIndexAt(lines, caret);
17652
+ const endLine = lineIndexAt(lines, newCaret);
17653
+ if (endLine !== startLine) {
17654
+ end = lines[startLine].end;
17655
+ }
17656
+ }
17657
+ return [start, end];
17658
+ }
17659
+ function applyOperator(text, range, operator, register) {
17660
+ const start = clamp(range[0], 0, text.length);
17661
+ const end = clamp(range[1], start, text.length);
17662
+ const removed = text.slice(start, end);
17663
+ if (operator === "yank") {
17664
+ return { text, caret: start, register: removed };
17665
+ }
17666
+ return { text: text.slice(0, start) + text.slice(end), caret: start, register: removed };
17667
+ }
17668
+ var init_editorMotions = __esm({
17669
+ "lib/editorMotions.ts"() {
17670
+ }
17671
+ });
17672
+ function isMotionPayload(payload) {
17673
+ return !!payload && typeof payload.editorId === "string" && typeof payload.motion === "string" && typeof payload.count === "number";
17674
+ }
17675
+ function isOperatePayload(payload) {
17676
+ return !!payload && typeof payload.editorId === "string" && typeof payload.operator === "string" && typeof payload.motion === "string" && typeof payload.count === "number";
17677
+ }
17678
+ function isInsertTextPayload(payload) {
17679
+ return !!payload && typeof payload.editorId === "string" && typeof payload.text === "string";
17680
+ }
17681
+ function isSetModePayload(payload) {
17682
+ return !!payload && typeof payload.editorId === "string" && typeof payload.mode === "string" && typeof payload.caret === "string";
17683
+ }
17684
+ function useEditorCapabilities(args) {
17685
+ const [caretMode, setCaretMode] = useState("bar");
17686
+ const registerRef = useRef("");
17687
+ useEventListener(`UI:${args.events.onMotion}`, (evt) => {
17688
+ if (!args.editorId || !isMotionPayload(evt.payload) || evt.payload.editorId !== args.editorId) return;
17689
+ const ta = args.textareaRef.current;
17690
+ if (!ta) return;
17691
+ const { motion, count } = evt.payload;
17692
+ const newCaret = applyMotion(ta.value, ta.selectionStart, motion, count);
17693
+ if (ta.selectionStart !== ta.selectionEnd) {
17694
+ ta.setSelectionRange(ta.selectionStart, newCaret);
17695
+ } else {
17696
+ ta.setSelectionRange(newCaret, newCaret);
17697
+ }
17698
+ });
17699
+ useEventListener(`UI:${args.events.onOperate}`, (evt) => {
17700
+ if (!args.editorId || !isOperatePayload(evt.payload) || evt.payload.editorId !== args.editorId) return;
17701
+ const ta = args.textareaRef.current;
17702
+ if (!ta) return;
17703
+ const { operator, motion, count } = evt.payload;
17704
+ const selection = motion === "selection" ? [ta.selectionStart, ta.selectionEnd] : void 0;
17705
+ const range = motionRange(ta.value, ta.selectionStart, motion, count, selection);
17706
+ const result = applyOperator(ta.value, range, operator, registerRef.current);
17707
+ registerRef.current = result.register;
17708
+ if (operator === "yank") {
17709
+ ta.setSelectionRange(range[0], range[0]);
17710
+ } else {
17711
+ ta.setRangeText("", range[0], range[1], "end");
17712
+ }
17713
+ args.applyChange(ta.value);
17714
+ });
17715
+ useEventListener(`UI:${args.events.onInsertText}`, (evt) => {
17716
+ if (!args.editorId || !isInsertTextPayload(evt.payload) || evt.payload.editorId !== args.editorId) return;
17717
+ const ta = args.textareaRef.current;
17718
+ if (!ta) return;
17719
+ ta.setRangeText(evt.payload.text, ta.selectionStart, ta.selectionEnd, "end");
17720
+ args.applyChange(ta.value);
17721
+ });
17722
+ useEventListener(`UI:${args.events.onSetMode}`, (evt) => {
17723
+ if (!args.editorId || !isSetModePayload(evt.payload) || evt.payload.editorId !== args.editorId) return;
17724
+ setCaretMode(evt.payload.caret);
17725
+ });
17726
+ return { caretMode };
17727
+ }
17728
+ var init_useEditorCapabilities = __esm({
17729
+ "components/core/molecules/markdown/useEditorCapabilities.ts"() {
17730
+ "use client";
17731
+ init_useEventBus();
17732
+ init_editorMotions();
17733
+ }
17734
+ });
17277
17735
  function isLanguageRegistered(lang) {
17278
17736
  return CODE_LANGUAGE_SET.has(lang) || dynamicallyLoaded.has(lang);
17279
17737
  }
@@ -17359,7 +17817,36 @@ function useLanguageReady(language) {
17359
17817
  }, [language]);
17360
17818
  return ready;
17361
17819
  }
17362
- 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;
17820
+ function resolveHighlightStyle(lang) {
17821
+ if (lang === "orb") return orbStyle;
17822
+ if (lang === "lolo") return loloStyle;
17823
+ return dark;
17824
+ }
17825
+ function plainCodeColorOf(style) {
17826
+ return style['code[class*="language-"]']?.color ?? "#d4d4d4";
17827
+ }
17828
+ function buildLineProps(errorLines, extraClassName) {
17829
+ return (lineNumber) => {
17830
+ const base = {
17831
+ "data-line": String(lineNumber - 1),
17832
+ ...extraClassName ? { className: extraClassName } : {}
17833
+ };
17834
+ const severity = errorLines?.get(lineNumber);
17835
+ if (!severity) return base;
17836
+ return {
17837
+ ...base,
17838
+ style: {
17839
+ display: "block",
17840
+ backgroundColor: severity === "error" ? "rgba(248, 113, 113, 0.18)" : "rgba(251, 191, 36, 0.18)",
17841
+ // amber-400 @ 18%
17842
+ borderLeft: `3px solid ${severity === "error" ? "#ef4444" : "#f59e0b"}`,
17843
+ paddingLeft: "0.5rem",
17844
+ marginLeft: "-0.5rem"
17845
+ }
17846
+ };
17847
+ };
17848
+ }
17849
+ 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;
17363
17850
  var init_CodeBlock = __esm({
17364
17851
  "components/core/molecules/markdown/CodeBlock.tsx"() {
17365
17852
  init_cn();
@@ -17375,6 +17862,7 @@ var init_CodeBlock = __esm({
17375
17862
  init_Textarea();
17376
17863
  init_Icon();
17377
17864
  init_useEventBus();
17865
+ init_useEditorCapabilities();
17378
17866
  SyntaxHighlighter.registerLanguage("json", langJson);
17379
17867
  SyntaxHighlighter.registerLanguage("javascript", langJavascript);
17380
17868
  SyntaxHighlighter.registerLanguage("js", langJavascript);
@@ -17593,6 +18081,15 @@ var init_CodeBlock = __esm({
17593
18081
  LINE_PROPS_FN = (n) => ({ "data-line": String(n - 1) });
17594
18082
  HIDDEN_LINE_NUMBERS = { display: "none" };
17595
18083
  HIGHLIGHT_CAPACITY_BYTES = 512 * 1024;
18084
+ MONO_FONT_FAMILY = 'ui-monospace, SFMono-Regular, Menlo, Monaco, "Cascadia Mono", "Courier New", monospace';
18085
+ VIEWER_LINE_NUMBER_STYLE = {
18086
+ minWidth: "2.5em",
18087
+ paddingRight: "1rem",
18088
+ textAlign: "right",
18089
+ userSelect: "none",
18090
+ opacity: 0.5,
18091
+ fontVariantNumeric: "tabular-nums"
18092
+ };
17596
18093
  CodeBlock = React89__default.memo(
17597
18094
  ({
17598
18095
  code: rawCode,
@@ -17617,15 +18114,39 @@ var init_CodeBlock = __esm({
17617
18114
  actions,
17618
18115
  isLoading = false,
17619
18116
  error,
17620
- showCopy
18117
+ showCopy,
18118
+ // editor capability surface — P1 wires these
18119
+ editorId,
18120
+ onEditorFocus = "EDITOR_FOCUS",
18121
+ onEditorBlur = "EDITOR_BLUR",
18122
+ onMotion = "MOTION",
18123
+ onOperate = "OPERATE",
18124
+ onInsertText = "INSERT_TEXT",
18125
+ onSetMode = "SET_MODE",
18126
+ motions = [
18127
+ "left",
18128
+ "right",
18129
+ "up",
18130
+ "down",
18131
+ "word-forward",
18132
+ "word-back",
18133
+ "word-end",
18134
+ "line-start",
18135
+ "line-end",
18136
+ "first-nonblank",
18137
+ "doc-start",
18138
+ "doc-end",
18139
+ "paragraph-forward",
18140
+ "paragraph-back",
18141
+ "line",
18142
+ "selection"
18143
+ ],
18144
+ operators = ["delete", "yank", "change"]
17621
18145
  }) => {
17622
18146
  const code = typeof rawCode === "string" ? rawCode : String(rawCode ?? "");
17623
- const isOrb = language === "orb";
17624
- const isLolo = language === "lolo";
17625
- const activeStyle = isOrb ? orbStyle : isLolo ? loloStyle : dark;
18147
+ const activeStyle = resolveHighlightStyle(language);
17626
18148
  const overCapacity = code.length > HIGHLIGHT_CAPACITY_BYTES;
17627
- const plainCodeColor = activeStyle['code[class*="language-"]']?.color ?? "#d4d4d4";
17628
- const languageReady = useLanguageReady(language);
18149
+ const plainCodeColor = plainCodeColorOf(activeStyle);
17629
18150
  const eventBus = useEventBus();
17630
18151
  const { t } = useTranslate();
17631
18152
  const scrollRef = useRef(null);
@@ -17637,6 +18158,9 @@ var init_CodeBlock = __esm({
17637
18158
  const activeFile = files?.[activeFileIndex];
17638
18159
  const activeCode = activeFile?.code ?? code;
17639
18160
  const activeLanguage = activeFile?.language ?? language;
18161
+ const languageReady = useLanguageReady(activeLanguage);
18162
+ const viewerStyle = resolveHighlightStyle(activeLanguage);
18163
+ const viewerPlainCodeColor = plainCodeColorOf(viewerStyle);
17640
18164
  const diffLines = useMemo(() => {
17641
18165
  if (propDiff) return propDiff;
17642
18166
  if (mode === "diff" && oldValue !== void 0 && newValue !== void 0) {
@@ -17666,28 +18190,28 @@ var init_CodeBlock = __esm({
17666
18190
  ov.scrollLeft = ta.scrollLeft;
17667
18191
  }
17668
18192
  }, []);
17669
- const errorLineProps = useMemo(() => {
17670
- if (!errorLines || errorLines.size === 0) {
17671
- return LINE_PROPS_FN;
17672
- }
17673
- return (lineNumber) => {
17674
- const severity = errorLines.get(lineNumber);
17675
- if (!severity) {
17676
- return { "data-line": String(lineNumber - 1) };
17677
- }
17678
- return {
17679
- "data-line": String(lineNumber - 1),
17680
- style: {
17681
- display: "block",
17682
- backgroundColor: severity === "error" ? "rgba(248, 113, 113, 0.18)" : "rgba(251, 191, 36, 0.18)",
17683
- // amber-400 @ 18%
17684
- borderLeft: `3px solid ${severity === "error" ? "#ef4444" : "#f59e0b"}`,
17685
- paddingLeft: "0.5rem",
17686
- marginLeft: "-0.5rem"
17687
- }
17688
- };
17689
- };
17690
- }, [errorLines]);
18193
+ const handleEditableChange = useCallback((v) => {
18194
+ lastPropCodeRef.current = v;
18195
+ setEditableValue(v);
18196
+ onChange?.(v);
18197
+ }, [onChange]);
18198
+ const { caretMode } = useEditorCapabilities({
18199
+ editorId: editable ? editorId : void 0,
18200
+ textareaRef: editableTextareaRef,
18201
+ events: { onMotion, onOperate, onInsertText, onSetMode },
18202
+ applyChange: handleEditableChange
18203
+ });
18204
+ const [caretIndex, setCaretIndex] = useState(0);
18205
+ const caretRowCol = useMemo(() => {
18206
+ const before = editableValue.slice(0, Math.min(caretIndex, editableValue.length));
18207
+ const lines = before.split("\n");
18208
+ return { row: lines.length - 1, col: lines[lines.length - 1].length };
18209
+ }, [editableValue, caretIndex]);
18210
+ const errorLineProps = useMemo(() => buildLineProps(errorLines), [errorLines]);
18211
+ const viewerLineProps = useMemo(
18212
+ () => buildLineProps(errorLines, "px-4 py-0.5 hover:bg-muted/50"),
18213
+ [errorLines]
18214
+ );
17691
18215
  const isFoldable = foldableProp ?? true;
17692
18216
  const [collapsed, setCollapsed] = useState(() => /* @__PURE__ */ new Set());
17693
18217
  const foldRegions = useMemo(
@@ -17810,6 +18334,110 @@ var init_CodeBlock = __esm({
17810
18334
  ),
17811
18335
  [code, overCapacity, plainCodeColor, language, activeStyle, languageReady]
17812
18336
  );
18337
+ const viewerOverCapacity = activeCode.length > HIGHLIGHT_CAPACITY_BYTES;
18338
+ const viewerHighlightedElement = useMemo(
18339
+ () => viewerOverCapacity ? /* @__PURE__ */ jsx(
18340
+ "div",
18341
+ {
18342
+ className: "px-4 py-0.5",
18343
+ style: {
18344
+ margin: 0,
18345
+ whiteSpace: wrap ? "pre-wrap" : "pre",
18346
+ wordBreak: wrap ? "break-all" : "normal",
18347
+ color: viewerPlainCodeColor,
18348
+ fontFamily: MONO_FONT_FAMILY,
18349
+ fontSize: "12px",
18350
+ lineHeight: "1.6"
18351
+ },
18352
+ children: activeCode
18353
+ }
18354
+ ) : /* @__PURE__ */ jsx(
18355
+ SyntaxHighlighter,
18356
+ {
18357
+ PreTag: "div",
18358
+ language: activeLanguage,
18359
+ style: viewerStyle,
18360
+ wrapLines: true,
18361
+ wrapLongLines: wrap,
18362
+ showLineNumbers,
18363
+ lineNumberStyle: VIEWER_LINE_NUMBER_STYLE,
18364
+ lineProps: viewerLineProps,
18365
+ customStyle: {
18366
+ backgroundColor: "transparent",
18367
+ borderRadius: 0,
18368
+ padding: "0.25rem 0",
18369
+ margin: 0,
18370
+ whiteSpace: wrap ? "pre-wrap" : "pre",
18371
+ wordBreak: wrap ? "break-all" : "normal",
18372
+ fontFamily: MONO_FONT_FAMILY,
18373
+ fontSize: "12px",
18374
+ lineHeight: "1.6"
18375
+ },
18376
+ codeTagProps: { style: { fontFamily: MONO_FONT_FAMILY, fontSize: "12px", lineHeight: "1.6" } },
18377
+ children: activeCode
18378
+ }
18379
+ ),
18380
+ [activeCode, viewerOverCapacity, viewerPlainCodeColor, activeLanguage, viewerStyle, wrap, showLineNumbers, viewerLineProps, languageReady]
18381
+ );
18382
+ const diffOverCapacity = useMemo(
18383
+ () => !!diffLines && diffLines.reduce((n, l) => n + l.content.length + 1, 0) > HIGHLIGHT_CAPACITY_BYTES,
18384
+ [diffLines]
18385
+ );
18386
+ const diffRowElements = useMemo(() => {
18387
+ if (!diffLines) return null;
18388
+ return diffLines.map((line, idx) => {
18389
+ const style = DIFF_STYLES[line.type] ?? DIFF_STYLE_FALLBACK;
18390
+ return /* @__PURE__ */ jsxs(HStack, { gap: "none", align: "start", className: cn(style.bg, "px-4 py-0.5"), children: [
18391
+ showLineNumbers && /* @__PURE__ */ jsx(
18392
+ Typography,
18393
+ {
18394
+ variant: "caption",
18395
+ color: "secondary",
18396
+ className: "w-8 text-right mr-3 select-none tabular-nums flex-shrink-0",
18397
+ children: line.lineNumber ?? ""
18398
+ }
18399
+ ),
18400
+ /* @__PURE__ */ jsxs(
18401
+ Typography,
18402
+ {
18403
+ variant: "caption",
18404
+ className: cn("font-mono flex-1 min-w-0", style.text, wrap ? "whitespace-pre-wrap break-all" : "whitespace-pre"),
18405
+ children: [
18406
+ /* @__PURE__ */ jsx(Box, { as: "span", className: "select-none opacity-50 mr-2", children: style.prefix }),
18407
+ diffOverCapacity ? line.content || " " : /* @__PURE__ */ jsx(
18408
+ SyntaxHighlighter,
18409
+ {
18410
+ PreTag: "span",
18411
+ CodeTag: "span",
18412
+ language: activeLanguage,
18413
+ style: viewerStyle,
18414
+ customStyle: {
18415
+ display: "inline",
18416
+ background: "transparent",
18417
+ padding: 0,
18418
+ margin: 0,
18419
+ whiteSpace: wrap ? "pre-wrap" : "pre",
18420
+ wordBreak: wrap ? "break-all" : "normal",
18421
+ fontFamily: "inherit",
18422
+ fontSize: "inherit",
18423
+ lineHeight: "inherit"
18424
+ },
18425
+ codeTagProps: {
18426
+ style: {
18427
+ whiteSpace: wrap ? "pre-wrap" : "pre",
18428
+ fontFamily: "inherit",
18429
+ fontSize: "inherit"
18430
+ }
18431
+ },
18432
+ children: line.content || " "
18433
+ }
18434
+ )
18435
+ ]
18436
+ }
18437
+ )
18438
+ ] }, idx);
18439
+ });
18440
+ }, [diffLines, showLineNumbers, wrap, diffOverCapacity, activeLanguage, viewerStyle, languageReady]);
17813
18441
  useLayoutEffect(() => {
17814
18442
  const container = codeRef.current;
17815
18443
  if (!container) return;
@@ -17953,7 +18581,6 @@ var init_CodeBlock = __esm({
17953
18581
  label: file.label,
17954
18582
  content: null
17955
18583
  }));
17956
- const lines = activeCode.split("\n");
17957
18584
  return /* @__PURE__ */ jsx(Card, { className: cn("overflow-hidden", className), children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column" }, children: [
17958
18585
  tabItems && tabItems.length > 1 && /* @__PURE__ */ jsx(Box, { className: "border-b border-border", children: /* @__PURE__ */ jsx(
17959
18586
  Tabs,
@@ -18016,49 +18643,7 @@ var init_CodeBlock = __esm({
18016
18643
  ]
18017
18644
  }
18018
18645
  ),
18019
- /* @__PURE__ */ jsx(Box, { className: "overflow-auto bg-muted/20", style: { maxHeight }, children: diffLines ? /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column" }, className: "font-mono text-xs", children: diffLines.map((line, idx) => {
18020
- const style = DIFF_STYLES[line.type] ?? DIFF_STYLE_FALLBACK;
18021
- return /* @__PURE__ */ jsxs(HStack, { gap: "none", align: "start", className: cn(style.bg, "px-4 py-0.5"), children: [
18022
- showLineNumbers && /* @__PURE__ */ jsx(
18023
- Typography,
18024
- {
18025
- variant: "caption",
18026
- color: "secondary",
18027
- className: "w-8 text-right mr-3 select-none tabular-nums flex-shrink-0",
18028
- children: line.lineNumber ?? ""
18029
- }
18030
- ),
18031
- /* @__PURE__ */ jsxs(
18032
- Typography,
18033
- {
18034
- variant: "caption",
18035
- className: cn("font-mono flex-1 min-w-0", style.text, wrap ? "whitespace-pre-wrap break-all" : "whitespace-pre"),
18036
- children: [
18037
- /* @__PURE__ */ jsx(Box, { as: "span", className: "select-none opacity-50 mr-2", children: style.prefix }),
18038
- line.content
18039
- ]
18040
- }
18041
- )
18042
- ] }, idx);
18043
- }) }) : /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column" }, className: "font-mono text-xs", children: lines.map((line, idx) => /* @__PURE__ */ jsxs(HStack, { gap: "none", align: "start", className: "px-4 py-0.5 hover:bg-muted/50", children: [
18044
- showLineNumbers && /* @__PURE__ */ jsx(
18045
- Typography,
18046
- {
18047
- variant: "caption",
18048
- color: "secondary",
18049
- className: "w-8 text-right mr-4 select-none tabular-nums flex-shrink-0",
18050
- children: idx + 1
18051
- }
18052
- ),
18053
- /* @__PURE__ */ jsx(
18054
- Typography,
18055
- {
18056
- variant: "caption",
18057
- className: cn("font-mono flex-1 min-w-0", wrap ? "whitespace-pre-wrap break-all" : "whitespace-pre"),
18058
- children: line || " "
18059
- }
18060
- )
18061
- ] }, idx)) }) })
18646
+ /* @__PURE__ */ jsx(Box, { className: "overflow-auto bg-muted/20", style: { maxHeight }, children: diffLines ? /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column" }, className: "font-mono text-xs", children: diffRowElements }) : /* @__PURE__ */ jsx("div", { className: "font-mono text-xs", children: viewerHighlightedElement }) })
18062
18647
  ] }) });
18063
18648
  }
18064
18649
  const hasHeader = showLanguageBadge || effectiveCopy;
@@ -18145,13 +18730,11 @@ var init_CodeBlock = __esm({
18145
18730
  {
18146
18731
  ref: editableTextareaRef,
18147
18732
  defaultValue: code,
18148
- onChange: (e) => {
18149
- const v = e.target.value;
18150
- lastPropCodeRef.current = v;
18151
- setEditableValue(v);
18152
- onChange?.(v);
18153
- },
18733
+ onChange: (e) => handleEditableChange(e.target.value),
18154
18734
  onScroll: handleEditableScroll,
18735
+ onSelect: (e) => setCaretIndex(e.currentTarget.selectionStart),
18736
+ onFocus: editorId ? () => eventBus.emit(`UI:${onEditorFocus}`, { editorId }) : void 0,
18737
+ onBlur: editorId ? () => eventBus.emit(`UI:${onEditorBlur}`, { editorId }) : void 0,
18155
18738
  spellCheck: false,
18156
18739
  style: {
18157
18740
  position: "absolute",
@@ -18166,7 +18749,7 @@ var init_CodeBlock = __esm({
18166
18749
  resize: "none",
18167
18750
  backgroundColor: "transparent",
18168
18751
  color: "transparent",
18169
- caretColor: "#e6e6e6",
18752
+ caretColor: caretMode === "block" ? "transparent" : "#e6e6e6",
18170
18753
  WebkitTextFillColor: "transparent",
18171
18754
  fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, "Cascadia Mono", "Courier New", monospace',
18172
18755
  fontSize: "13px",
@@ -18177,6 +18760,22 @@ var init_CodeBlock = __esm({
18177
18760
  }
18178
18761
  },
18179
18762
  editableTextareaKey
18763
+ ),
18764
+ caretMode !== "bar" && /* @__PURE__ */ jsx(
18765
+ "span",
18766
+ {
18767
+ "aria-hidden": true,
18768
+ style: {
18769
+ position: "absolute",
18770
+ top: `calc(1rem + ${caretRowCol.row * 19.5}px)`,
18771
+ left: `calc(1rem + ${caretRowCol.col}ch)`,
18772
+ width: "1ch",
18773
+ height: caretMode === "block" ? "19.5px" : "2px",
18774
+ backgroundColor: caretMode === "block" ? "rgba(230, 230, 230, 0.5)" : void 0,
18775
+ borderBottom: caretMode === "underline" ? "2px solid #e6e6e6" : void 0,
18776
+ pointerEvents: "none"
18777
+ }
18778
+ }
18180
18779
  )
18181
18780
  ]
18182
18781
  }
@@ -18204,55 +18803,175 @@ var init_CodeBlock = __esm({
18204
18803
  )
18205
18804
  ] });
18206
18805
  },
18207
- (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
18806
+ (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
18208
18807
  );
18209
18808
  CodeBlock.displayName = "CodeBlock";
18210
18809
  }
18211
18810
  });
18811
+
18812
+ // components/core/molecules/markdown/mermaidSource.ts
18813
+ function isQuoted(label) {
18814
+ const trimmed = label.trim();
18815
+ return trimmed.length === 0 || trimmed.startsWith('"') && trimmed.endsWith('"') && trimmed.length > 1;
18816
+ }
18817
+ function quote(label) {
18818
+ return `"${label.replace(/"/g, "#quot;")}"`;
18819
+ }
18820
+ function isIdentifierChar(ch) {
18821
+ return /[A-Za-z0-9_\-.]/.test(ch);
18822
+ }
18823
+ function declaredType(code) {
18824
+ for (const line of code.split("\n")) {
18825
+ const trimmed = line.trim();
18826
+ if (trimmed.length === 0 || trimmed.startsWith("%%")) continue;
18827
+ return trimmed;
18828
+ }
18829
+ return "";
18830
+ }
18831
+ function isFlowchart(code) {
18832
+ return FLOWCHART_DIRECTIVE.test(declaredType(code));
18833
+ }
18834
+ function quoteNodeLabels(code) {
18835
+ let out = "";
18836
+ let i = 0;
18837
+ while (i < code.length) {
18838
+ const shape = NODE_SHAPES.find(([open2]) => code.startsWith(open2, i));
18839
+ const precededByIdentifier = i > 0 && isIdentifierChar(code[i - 1] ?? "");
18840
+ if (shape === void 0 || !precededByIdentifier) {
18841
+ out += code[i];
18842
+ i += 1;
18843
+ continue;
18844
+ }
18845
+ const [open, close] = shape;
18846
+ const contentStart = i + open.length;
18847
+ const closeAt = code.indexOf(close, contentStart);
18848
+ const newlineAt = code.indexOf("\n", contentStart);
18849
+ if (closeAt === -1 || newlineAt !== -1 && newlineAt < closeAt) {
18850
+ out += code[i];
18851
+ i += 1;
18852
+ continue;
18853
+ }
18854
+ const label = code.slice(contentStart, closeAt);
18855
+ out += open + (isQuoted(label) ? label : quote(label)) + close;
18856
+ i = closeAt + close.length;
18857
+ }
18858
+ return out;
18859
+ }
18860
+ function quoteEdgeLabels(code) {
18861
+ return code.split("\n").map((line) => {
18862
+ let out = "";
18863
+ let rest = line;
18864
+ for (; ; ) {
18865
+ const open = rest.indexOf("|");
18866
+ if (open === -1) break;
18867
+ const close = rest.indexOf("|", open + 1);
18868
+ if (close === -1) break;
18869
+ const label = rest.slice(open + 1, close);
18870
+ out += rest.slice(0, open + 1) + (isQuoted(label) ? label : quote(label)) + "|";
18871
+ rest = rest.slice(close + 1);
18872
+ }
18873
+ return out + rest;
18874
+ }).join("\n");
18875
+ }
18876
+ function quoteSubgraphTitles(code) {
18877
+ return code.split("\n").map((line) => {
18878
+ const match = /^(\s*subgraph\s+)(.+?)(\s*)$/.exec(line);
18879
+ if (match === null) return line;
18880
+ const [, prefix, title, trailing] = match;
18881
+ if (title === void 0 || prefix === void 0) return line;
18882
+ if (isQuoted(title) || title.includes("[")) return line;
18883
+ return prefix + quote(title) + (trailing ?? "");
18884
+ }).join("\n");
18885
+ }
18886
+ function mermaidRepairCandidates(code) {
18887
+ if (!isFlowchart(code)) return [];
18888
+ const nodes = quoteNodeLabels(code);
18889
+ const nodesAndEdges = quoteEdgeLabels(nodes);
18890
+ const all = quoteSubgraphTitles(nodesAndEdges);
18891
+ const ordered2 = [nodes, nodesAndEdges, all];
18892
+ const seen = /* @__PURE__ */ new Set([code]);
18893
+ const candidates = [];
18894
+ for (const candidate of ordered2) {
18895
+ if (seen.has(candidate)) continue;
18896
+ seen.add(candidate);
18897
+ candidates.push(candidate);
18898
+ }
18899
+ return candidates;
18900
+ }
18901
+ var NODE_SHAPES, FLOWCHART_DIRECTIVE;
18902
+ var init_mermaidSource = __esm({
18903
+ "components/core/molecules/markdown/mermaidSource.ts"() {
18904
+ NODE_SHAPES = [
18905
+ ["[[", "]]"],
18906
+ ["[(", ")]"],
18907
+ ["([", "])"],
18908
+ ["((", "))"],
18909
+ ["{{", "}}"],
18910
+ ["[", "]"],
18911
+ ["(", ")"],
18912
+ ["{", "}"]
18913
+ ];
18914
+ FLOWCHART_DIRECTIVE = /^(?:graph|flowchart)\b/;
18915
+ }
18916
+ });
18212
18917
  function loadMermaid() {
18213
18918
  mermaidModule ?? (mermaidModule = import('mermaid').then((m) => m.default));
18214
18919
  return mermaidModule;
18215
18920
  }
18216
- var mermaidModule, MermaidDiagram;
18921
+ var log8, mermaidModule, MermaidDiagram;
18217
18922
  var init_MermaidDiagram = __esm({
18218
18923
  "components/core/molecules/markdown/MermaidDiagram.tsx"() {
18219
18924
  init_Box();
18220
18925
  init_Typography();
18221
18926
  init_CodeBlock();
18927
+ init_mermaidSource();
18222
18928
  init_cn();
18929
+ log8 = createLogger("almadar:ui:mermaid-diagram");
18223
18930
  mermaidModule = null;
18224
18931
  MermaidDiagram = React89__default.memo(
18225
18932
  ({ code, className }) => {
18226
18933
  const { resolvedMode } = useTheme();
18934
+ const { t } = useTranslate();
18227
18935
  const containerRef = useRef(null);
18228
- const [error, setError] = useState(null);
18936
+ const [unrenderable, setUnrenderable] = useState(false);
18229
18937
  const reactId = useId();
18230
18938
  useEffect(() => {
18231
18939
  let active = true;
18232
18940
  void (async () => {
18233
- try {
18234
- const mermaid = await loadMermaid();
18235
- mermaid.initialize({
18236
- startOnLoad: false,
18237
- securityLevel: "strict",
18238
- theme: resolvedMode === "dark" ? "dark" : "default"
18239
- });
18240
- const domId = `mermaid-${reactId.replace(/[^a-zA-Z0-9]/g, "")}`;
18241
- const { svg } = await mermaid.render(domId, code);
18242
- if (!active || !containerRef.current) return;
18243
- containerRef.current.innerHTML = svg;
18244
- setError(null);
18245
- } catch (err) {
18246
- if (active) setError(err instanceof Error ? err.message : String(err));
18941
+ const mermaid = await loadMermaid();
18942
+ mermaid.initialize({
18943
+ startOnLoad: false,
18944
+ securityLevel: "strict",
18945
+ theme: resolvedMode === "dark" ? "dark" : "default"
18946
+ });
18947
+ const domId = `mermaid-${reactId.replace(/[^a-zA-Z0-9]/g, "")}`;
18948
+ let firstError = null;
18949
+ for (const [index, source] of [code, ...mermaidRepairCandidates(code)].entries()) {
18950
+ try {
18951
+ const { svg } = await mermaid.render(domId, source);
18952
+ if (!active) return;
18953
+ const container = containerRef.current;
18954
+ if (container === null) return;
18955
+ container.innerHTML = svg;
18956
+ container.dataset.mermaidRepaired = String(index > 0);
18957
+ setUnrenderable(false);
18958
+ if (index > 0) log8.debug("mermaid:repaired", { candidate: index });
18959
+ return;
18960
+ } catch (err) {
18961
+ firstError ?? (firstError = err instanceof Error ? err : new Error(String(err)));
18962
+ }
18247
18963
  }
18964
+ if (!active) return;
18965
+ log8.warn("mermaid:unrenderable", { error: firstError?.message ?? "", code });
18966
+ setUnrenderable(true);
18248
18967
  })();
18249
18968
  return () => {
18250
18969
  active = false;
18251
18970
  };
18252
18971
  }, [code, resolvedMode, reactId]);
18253
18972
  return /* @__PURE__ */ jsxs(Box, { className: cn("not-prose my-4", className), children: [
18254
- error !== null && /* @__PURE__ */ jsxs(Box, { className: "space-y-2 mb-2", children: [
18255
- /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-error whitespace-pre-wrap", children: error }),
18973
+ unrenderable && /* @__PURE__ */ jsxs(Box, { className: "space-y-2 mb-2", "data-testid": "mermaid-unrenderable", children: [
18974
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("mermaid.unrenderable") }),
18256
18975
  /* @__PURE__ */ jsx(CodeBlock, { code, language: "mermaid" })
18257
18976
  ] }),
18258
18977
  /* @__PURE__ */ jsx(
@@ -18261,7 +18980,7 @@ var init_MermaidDiagram = __esm({
18261
18980
  ref: containerRef,
18262
18981
  "data-testid": "mermaid-diagram",
18263
18982
  className: "overflow-x-auto",
18264
- style: error !== null ? { display: "none" } : void 0
18983
+ style: unrenderable ? { display: "none" } : void 0
18265
18984
  }
18266
18985
  )
18267
18986
  ] });
@@ -21666,14 +22385,14 @@ function useSafeEventBus2() {
21666
22385
  } };
21667
22386
  }
21668
22387
  }
21669
- var log8, lookStyles4, ButtonGroup;
22388
+ var log9, lookStyles4, ButtonGroup;
21670
22389
  var init_ButtonGroup = __esm({
21671
22390
  "components/core/molecules/ButtonGroup.tsx"() {
21672
22391
  "use client";
21673
22392
  init_cn();
21674
22393
  init_atoms();
21675
22394
  init_useEventBus();
21676
- log8 = createLogger("almadar:ui:button-group");
22395
+ log9 = createLogger("almadar:ui:button-group");
21677
22396
  lookStyles4 = {
21678
22397
  "right-aligned-buttons": "",
21679
22398
  "floating-bar": "fixed bottom-section left-1/2 -translate-x-1/2 shadow-elevation-toast bg-card p-card-sm rounded-container",
@@ -21754,7 +22473,7 @@ var init_ButtonGroup = __esm({
21754
22473
  {
21755
22474
  variant: "ghost",
21756
22475
  onClick: () => {
21757
- log8.debug("Filter clicked", { field: filter.field });
22476
+ log9.debug("Filter clicked", { field: filter.field });
21758
22477
  },
21759
22478
  children: filter.label
21760
22479
  },
@@ -24538,6 +25257,12 @@ function commandMatches(command, query) {
24538
25257
  if (matchesQuery(query, command.label)) return true;
24539
25258
  return (command.keywords ?? []).some((keyword) => matchesQuery(query, keyword));
24540
25259
  }
25260
+ function dispatchCommandPaletteCommand(command, deps) {
25261
+ if (command.disabled) return;
25262
+ if (command.event) deps.emit(`UI:${command.event}`, { commandId: command.id });
25263
+ if (command.action) deps.emit(`UI:${command.action}`, command.actionPayload ?? {});
25264
+ deps.onSelect?.(command);
25265
+ }
24541
25266
  var UNGROUPED, CommandPalette;
24542
25267
  var init_CommandPalette = __esm({
24543
25268
  "components/core/molecules/CommandPalette.tsx"() {
@@ -24592,9 +25317,7 @@ var init_CommandPalette = __esm({
24592
25317
  const handleSelect = useCallback(
24593
25318
  (command) => {
24594
25319
  if (command.disabled) return;
24595
- if (command.event) eventBus.emit(`UI:${command.event}`, { commandId: command.id });
24596
- if (command.action) eventBus.emit(`UI:${command.action}`, command.actionPayload ?? {});
24597
- onSelect?.(command);
25320
+ dispatchCommandPaletteCommand(command, { emit: eventBus.emit, onSelect });
24598
25321
  handleClose();
24599
25322
  },
24600
25323
  [eventBus, onSelect, handleClose]
@@ -29573,9 +30296,9 @@ function debug(...args) {
29573
30296
  const [first, ...rest] = args;
29574
30297
  const message = typeof first === "string" ? first : "<debug>";
29575
30298
  if (rest.length === 0 && typeof first === "string") {
29576
- log9.debug(message);
30299
+ log10.debug(message);
29577
30300
  } else {
29578
- log9.debug(message, { args: rest.length > 0 ? formatArgs(rest) : formatArgs([first]) });
30301
+ log10.debug(message, { args: rest.length > 0 ? formatArgs(rest) : formatArgs([first]) });
29579
30302
  }
29580
30303
  }
29581
30304
  function debugGroup(label) {
@@ -29603,11 +30326,11 @@ function toLogMetaValue(v) {
29603
30326
  }
29604
30327
  return String(v);
29605
30328
  }
29606
- var NAMESPACE, log9;
30329
+ var NAMESPACE, log10;
29607
30330
  var init_debug = __esm({
29608
30331
  "lib/debug.ts"() {
29609
30332
  NAMESPACE = "almadar:ui:debug";
29610
- log9 = createLogger(NAMESPACE);
30333
+ log10 = createLogger(NAMESPACE);
29611
30334
  createLogger("almadar:ui:debug:input");
29612
30335
  createLogger("almadar:ui:debug:collision");
29613
30336
  createLogger("almadar:ui:debug:physics");
@@ -31260,6 +31983,7 @@ var init_MathCanvas = __esm({
31260
31983
  init_perf();
31261
31984
  init_atoms();
31262
31985
  init_Stack();
31986
+ init_gameFonts();
31263
31987
  init_LearningCanvas();
31264
31988
  MathCanvas = ({
31265
31989
  className,
@@ -31279,6 +32003,7 @@ var init_MathCanvas = __esm({
31279
32003
  showTickLabels = false,
31280
32004
  tickLabelFontSize = 10,
31281
32005
  labelFontSize = 12,
32006
+ fontFamily: fontFamilyProp,
31282
32007
  showCurveLabels = false,
31283
32008
  curves = [],
31284
32009
  points = [],
@@ -31301,6 +32026,7 @@ var init_MathCanvas = __esm({
31301
32026
  error
31302
32027
  }) => {
31303
32028
  const eventBus = useEventBus();
32029
+ const fontFamily = resolveGameFontFamily(fontFamilyProp);
31304
32030
  const keyMapKey = keyMap ? JSON.stringify(keyMap) : null;
31305
32031
  const keyUpMapKey = keyUpMap ? JSON.stringify(keyUpMap) : null;
31306
32032
  const stableKeyMap = useMemo(() => keyMap, [keyMapKey]);
@@ -31350,18 +32076,18 @@ var init_MathCanvas = __esm({
31350
32076
  let kx = 0;
31351
32077
  for (let x = Math.ceil(xMin / gridStep) * gridStep; x <= xMax; x += gridStep, kx++) {
31352
32078
  if (kx % labelEveryX === 0 && x !== 0) {
31353
- out.push({ type: "text", x: mapX(x), y: xAxisY + 12, text: formatTick(x), color: "#6b7280", fontSize: tickLabelFontSize, align: "center" });
32079
+ out.push({ type: "text", fontFamily, x: mapX(x), y: xAxisY + 12, text: formatTick(x), color: "#6b7280", fontSize: tickLabelFontSize, align: "center" });
31354
32080
  }
31355
32081
  }
31356
32082
  const labelEveryY = Math.max(1, Math.ceil((yMax - yMin) / gridStep / Math.floor(plotH / 28)));
31357
32083
  let ky = 0;
31358
32084
  for (let y = Math.ceil(yMin / gridStep) * gridStep; y <= yMax; y += gridStep, ky++) {
31359
32085
  if (ky % labelEveryY === 0 && y !== 0) {
31360
- out.push({ type: "text", x: yAxisX - 6, y: mapY(y), text: formatTick(y), color: "#6b7280", fontSize: tickLabelFontSize, align: "right" });
32086
+ out.push({ type: "text", fontFamily, x: yAxisX - 6, y: mapY(y), text: formatTick(y), color: "#6b7280", fontSize: tickLabelFontSize, align: "right" });
31361
32087
  }
31362
32088
  }
31363
32089
  if (xMin <= 0 && xMax >= 0 && yMin <= 0 && yMax >= 0) {
31364
- out.push({ type: "text", x: yAxisX - 6, y: xAxisY + 12, text: "0", color: "#6b7280", fontSize: tickLabelFontSize, align: "right" });
32090
+ out.push({ type: "text", fontFamily, x: yAxisX - 6, y: xAxisY + 12, text: "0", color: "#6b7280", fontSize: tickLabelFontSize, align: "right" });
31365
32091
  }
31366
32092
  }
31367
32093
  for (const region of regions) {
@@ -31388,6 +32114,7 @@ var init_MathCanvas = __esm({
31388
32114
  const mid = Math.floor(region.samples.length / 2);
31389
32115
  out.push({
31390
32116
  type: "text",
32117
+ fontFamily,
31391
32118
  x: mapX((first.x + last.x) / 2),
31392
32119
  y: (mapY(region.samples[mid].y) + mapY(baseline)) / 2,
31393
32120
  text: region.label,
@@ -31424,14 +32151,14 @@ var init_MathCanvas = __esm({
31424
32151
  const px = mapX(guide.at);
31425
32152
  out.push({ type: "line", x1: px, y1: margin, x2: px, y2: height - margin, color, dash });
31426
32153
  if (guide.label) {
31427
- out.push({ type: "text", x: px + 4, y: margin + 10, text: guide.label, color, fontSize: 11 });
32154
+ out.push({ type: "text", fontFamily, x: px + 4, y: margin + 10, text: guide.label, color, fontSize: 11 });
31428
32155
  }
31429
32156
  } else {
31430
32157
  if (guide.at < yMin || guide.at > yMax) continue;
31431
32158
  const py = mapY(guide.at);
31432
32159
  out.push({ type: "line", x1: margin, y1: py, x2: width - margin, y2: py, color, dash });
31433
32160
  if (guide.label) {
31434
- out.push({ type: "text", x: width - margin - 4, y: py - 8, text: guide.label, color, fontSize: labelFontSize, align: "right" });
32161
+ out.push({ type: "text", fontFamily, x: width - margin - 4, y: py - 8, text: guide.label, color, fontSize: labelFontSize, align: "right" });
31435
32162
  }
31436
32163
  }
31437
32164
  }
@@ -31470,6 +32197,7 @@ var init_MathCanvas = __esm({
31470
32197
  if (showCurveLabels && curve.label && lastInRange) {
31471
32198
  out.push({
31472
32199
  type: "text",
32200
+ fontFamily,
31473
32201
  x: mapX(lastInRange.x) + 6,
31474
32202
  y: mapY(lastInRange.y) - 6,
31475
32203
  text: curve.label,
@@ -31507,6 +32235,7 @@ var init_MathCanvas = __esm({
31507
32235
  if (hop.label) {
31508
32236
  out.push({
31509
32237
  type: "text",
32238
+ fontFamily,
31510
32239
  x: (x1 + x2) / 2,
31511
32240
  y: xAxisY - peak - 8,
31512
32241
  text: hop.label,
@@ -31534,6 +32263,7 @@ var init_MathCanvas = __esm({
31534
32263
  const rad = mid * Math.PI / 180;
31535
32264
  out.push({
31536
32265
  type: "text",
32266
+ fontFamily,
31537
32267
  x: mapX(angle.x + 1.35 * radius * Math.cos(rad)),
31538
32268
  y: mapY(angle.y + 1.35 * radius * Math.sin(rad)),
31539
32269
  text: angle.label,
@@ -31555,7 +32285,7 @@ var init_MathCanvas = __esm({
31555
32285
  fill: isOpen ? "#ffffff" : p.color ?? "#dc2626"
31556
32286
  });
31557
32287
  if (p.label) {
31558
- out.push({ type: "text", x: mapX(p.x) + 8, y: mapY(p.y) - 8, text: p.label, color: p.color ?? "#111827", fontSize: labelFontSize });
32288
+ out.push({ type: "text", fontFamily, x: mapX(p.x) + 8, y: mapY(p.y) - 8, text: p.label, color: p.color ?? "#111827", fontSize: labelFontSize });
31559
32289
  }
31560
32290
  }
31561
32291
  for (const v of vectors) {
@@ -31566,7 +32296,7 @@ var init_MathCanvas = __esm({
31566
32296
  const y2 = mapY(v.y + v.vy);
31567
32297
  out.push({ type: "arrow", x1, y1, x2, y2, color: v.color ?? "#7c3aed", lineWidth: 2 });
31568
32298
  if (v.label) {
31569
- out.push({ type: "text", x: x2 + 6, y: y2 - 6, text: v.label, color: v.color ?? "#7c3aed", fontSize: labelFontSize });
32299
+ out.push({ type: "text", fontFamily, x: x2 + 6, y: y2 - 6, text: v.label, color: v.color ?? "#7c3aed", fontSize: labelFontSize });
31570
32300
  }
31571
32301
  }
31572
32302
  out.push(...shapes);
@@ -31587,6 +32317,7 @@ var init_MathCanvas = __esm({
31587
32317
  showTickLabels,
31588
32318
  tickLabelFontSize,
31589
32319
  labelFontSize,
32320
+ fontFamily,
31590
32321
  showCurveLabels,
31591
32322
  curves,
31592
32323
  points,
@@ -31642,6 +32373,7 @@ var init_MathCanvas = __esm({
31642
32373
  width,
31643
32374
  height,
31644
32375
  backgroundColor,
32376
+ fontFamily,
31645
32377
  shapes: derivedShapes,
31646
32378
  drawables,
31647
32379
  projector,
@@ -32874,13 +33606,13 @@ var init_MapView = __esm({
32874
33606
  shadowSize: [41, 41]
32875
33607
  });
32876
33608
  L.Marker.prototype.options.icon = defaultIcon;
32877
- const { useEffect: useEffect68, useRef: useRef67, useCallback: useCallback100, useState: useState102 } = React89__default;
33609
+ const { useEffect: useEffect69, useRef: useRef69, useCallback: useCallback100, useState: useState103 } = React89__default;
32878
33610
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
32879
33611
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
32880
33612
  function MapUpdater({ centerLat, centerLng, zoom }) {
32881
33613
  const map = useMap();
32882
- const prevRef = useRef67({ centerLat, centerLng, zoom });
32883
- useEffect68(() => {
33614
+ const prevRef = useRef69({ centerLat, centerLng, zoom });
33615
+ useEffect69(() => {
32884
33616
  const prev = prevRef.current;
32885
33617
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
32886
33618
  map.setView([centerLat, centerLng], zoom);
@@ -32891,7 +33623,7 @@ var init_MapView = __esm({
32891
33623
  }
32892
33624
  function MapClickHandler({ onMapClick }) {
32893
33625
  const map = useMap();
32894
- useEffect68(() => {
33626
+ useEffect69(() => {
32895
33627
  if (!onMapClick) return;
32896
33628
  const handler = (e) => {
32897
33629
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -32919,7 +33651,7 @@ var init_MapView = __esm({
32919
33651
  showAttribution = true
32920
33652
  }) {
32921
33653
  const eventBus = useEventBus2();
32922
- const [clickedPosition, setClickedPosition] = useState102(null);
33654
+ const [clickedPosition, setClickedPosition] = useState103(null);
32923
33655
  const handleMapClick = useCallback100((lat, lng) => {
32924
33656
  if (showClickedPin) {
32925
33657
  setClickedPosition({ lat, lng });
@@ -47628,7 +48360,7 @@ function getAllEvents(traits2) {
47628
48360
  function EventDispatcherTab({ traits: traits2, schema }) {
47629
48361
  const eventBus = useEventBus();
47630
48362
  const { t } = useTranslate();
47631
- const [log13, setLog] = React89.useState([]);
48363
+ const [log14, setLog] = React89.useState([]);
47632
48364
  const prevStatesRef = React89.useRef(/* @__PURE__ */ new Map());
47633
48365
  React89.useEffect(() => {
47634
48366
  for (const trait of traits2) {
@@ -47692,9 +48424,9 @@ function EventDispatcherTab({ traits: traits2, schema }) {
47692
48424
  /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "medium", className: "text-muted-foreground mb-1", children: t("debug.otherEvents") }),
47693
48425
  /* @__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)) })
47694
48426
  ] }),
47695
- log13.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
48427
+ log14.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
47696
48428
  /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "medium", className: "text-muted-foreground mb-1", children: t("debug.recentTransitions") }),
47697
- /* @__PURE__ */ jsx(Stack, { gap: "xs", children: log13.map((entry, i) => /* @__PURE__ */ jsxs(Typography, { variant: "small", className: "font-mono text-xs", children: [
48429
+ /* @__PURE__ */ jsx(Stack, { gap: "xs", children: log14.map((entry, i) => /* @__PURE__ */ jsxs(Typography, { variant: "small", className: "font-mono text-xs", children: [
47698
48430
  /* @__PURE__ */ jsx("span", { className: "text-primary", children: entry.traitName }),
47699
48431
  " ",
47700
48432
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: entry.from }),
@@ -49885,6 +50617,7 @@ var init_component_registry_generated = __esm({
49885
50617
  init_FormSection();
49886
50618
  init_FormSectionHeader();
49887
50619
  init_FxOverlay();
50620
+ init_GameAudioCue();
49888
50621
  init_GameAudioToggle();
49889
50622
  init_GameHud();
49890
50623
  init_GameIcon();
@@ -50162,6 +50895,7 @@ var init_component_registry_generated = __esm({
50162
50895
  "FormLayout": FormLayout,
50163
50896
  "FormSectionHeader": FormSectionHeader,
50164
50897
  "FxOverlay": FxOverlay,
50898
+ "GameAudioCue": GameAudioCue,
50165
50899
  "GameAudioToggle": GameAudioToggle,
50166
50900
  "GameHud": GameHud,
50167
50901
  "GameIcon": GameIcon,
@@ -51657,7 +52391,7 @@ init_UISlotRenderer();
51657
52391
  // providers/VerificationProvider.tsx
51658
52392
  init_useEventBus();
51659
52393
  init_verificationRegistry();
51660
- var log10 = createLogger("almadar:verify");
52394
+ var log11 = createLogger("almadar:verify");
51661
52395
  var DISPATCH_SUFFIX = ":DISPATCH";
51662
52396
  var SUCCESS_SUFFIX = ":SUCCESS";
51663
52397
  var ERROR_SUFFIX = ":ERROR";
@@ -51704,7 +52438,7 @@ function VerificationProvider({
51704
52438
  const verificationProviderLifecycleListener = (evt) => {
51705
52439
  const parsed = parseLifecycleEvent(evt.type);
51706
52440
  if (!parsed) return;
51707
- log10.debug("lifecycle:event", { kind: parsed.kind, traitName: parsed.traitName, event: parsed.event, type: evt.type });
52441
+ log11.debug("lifecycle:event", { kind: parsed.kind, traitName: parsed.traitName, event: parsed.event, type: evt.type });
51708
52442
  const payload = evt.payload ?? {};
51709
52443
  if (parsed.kind === "dispatch") {
51710
52444
  const key = `${parsed.traitName}:${String(payload["event"] ?? "")}`;
@@ -51760,7 +52494,7 @@ function VerificationProvider({
51760
52494
  },
51761
52495
  timestamp: Date.now()
51762
52496
  });
51763
- log10.debug("transition:success", { trait: parsed.traitName, event: parsed.event, from: pending?.from, to: newState, effectCount: effects.length });
52497
+ log11.debug("transition:success", { trait: parsed.traitName, event: parsed.event, from: pending?.from, to: newState, effectCount: effects.length });
51764
52498
  } else if (parsed.kind === "error" && parsed.event) {
51765
52499
  const key = `${parsed.traitName}:${parsed.event}`;
51766
52500
  const pending = pendingRef.current.get(key);
@@ -51790,7 +52524,7 @@ function VerificationProvider({
51790
52524
  },
51791
52525
  timestamp: Date.now()
51792
52526
  });
51793
- log10.warn("transition:error", { trait: parsed.traitName, event: parsed.event, from: fromState, error: errorMsg });
52527
+ log11.warn("transition:error", { trait: parsed.traitName, event: parsed.event, from: fromState, error: errorMsg });
51794
52528
  }
51795
52529
  };
51796
52530
  Object.defineProperty(verificationProviderLifecycleListener, "name", {
@@ -52252,7 +52986,7 @@ function useEntitySchema() {
52252
52986
  function useEntitySchemaOptional6() {
52253
52987
  return useContext(EntitySchemaContext);
52254
52988
  }
52255
- var log11 = createLogger("almadar:ui:navigation");
52989
+ var log12 = createLogger("almadar:ui:navigation");
52256
52990
  function matchPath2(pattern, path) {
52257
52991
  const normalizeSegment = (p) => {
52258
52992
  let normalized = p.trim();
@@ -52413,12 +53147,12 @@ function NavigationProvider2({
52413
53147
  const navigateTo = useCallback((path, payload) => {
52414
53148
  const result = findPageByPath2(schema, path);
52415
53149
  if (!result) {
52416
- log11.error("No page found for path", { path });
53150
+ log12.error("No page found for path", { path });
52417
53151
  return;
52418
53152
  }
52419
53153
  const { page, params } = result;
52420
53154
  const finalPayload = { ...params, ...payload };
52421
- log11.debug("Navigating to", () => ({
53155
+ log12.debug("Navigating to", () => ({
52422
53156
  path,
52423
53157
  page: page.name,
52424
53158
  params,
@@ -52435,7 +53169,7 @@ function NavigationProvider2({
52435
53169
  try {
52436
53170
  window.history.pushState(finalPayload, "", path);
52437
53171
  } catch (e) {
52438
- log11.warn("Could not update URL", { error: e instanceof Error ? e : String(e) });
53172
+ log12.warn("Could not update URL", { error: e instanceof Error ? e : String(e) });
52439
53173
  }
52440
53174
  }
52441
53175
  if (onNavigate) {
@@ -52445,12 +53179,12 @@ function NavigationProvider2({
52445
53179
  const navigateToPage = useCallback((pageName, payload) => {
52446
53180
  const result = findPageByName2(schema, pageName);
52447
53181
  if (!result) {
52448
- log11.error("No page found with name", { pageName });
53182
+ log12.error("No page found with name", { pageName });
52449
53183
  return;
52450
53184
  }
52451
53185
  const { page } = result;
52452
53186
  const path = page.path || `/${pageName.toLowerCase()}`;
52453
- log11.debug("Navigating to page", () => ({
53187
+ log12.debug("Navigating to page", () => ({
52454
53188
  pageName,
52455
53189
  path,
52456
53190
  payload: JSON.stringify(payload)
@@ -52465,7 +53199,7 @@ function NavigationProvider2({
52465
53199
  try {
52466
53200
  window.history.pushState(payload || {}, "", path);
52467
53201
  } catch (e) {
52468
- log11.warn("Could not update URL", { error: e instanceof Error ? e : String(e) });
53202
+ log12.warn("Could not update URL", { error: e instanceof Error ? e : String(e) });
52469
53203
  }
52470
53204
  }
52471
53205
  if (onNavigate) {
@@ -52487,7 +53221,7 @@ function useNavigation2() {
52487
53221
  function useNavigateTo2() {
52488
53222
  const context = useContext(NavigationContext);
52489
53223
  const noOp = useCallback((path, _payload) => {
52490
- log11.warn("navigateTo called outside NavigationProvider", { path });
53224
+ log12.warn("navigateTo called outside NavigationProvider", { path });
52491
53225
  }, []);
52492
53226
  return context?.navigateTo || noOp;
52493
53227
  }
@@ -52830,7 +53564,7 @@ function ServerBridgeProvider({
52830
53564
  }, [serverUrl, eventBus]);
52831
53565
  return /* @__PURE__ */ jsx(ServerBridgeContext.Provider, { value: { connected, sendEvent }, children });
52832
53566
  }
52833
- var log12 = createLogger("almadar:ui:trait-provider");
53567
+ var log13 = createLogger("almadar:ui:trait-provider");
52834
53568
  var TraitContext = createContext(null);
52835
53569
  function TraitProvider({
52836
53570
  traits: traitBindings,
@@ -52847,7 +53581,7 @@ function TraitProvider({
52847
53581
  currentState: stateName,
52848
53582
  availableEvents: trait.transitions.filter((t) => t.from === stateName).map((t) => t.event),
52849
53583
  dispatch: (eventKey, payload) => {
52850
- log12.debug("Dispatch", () => ({
53584
+ log13.debug("Dispatch", () => ({
52851
53585
  trait: trait.name,
52852
53586
  event: eventKey,
52853
53587
  payloadKeys: payload ? Object.keys(payload) : []