@almadar/ui 6.5.0 → 6.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{EntityBindingContext-0Evn_LcT.d.cts → EntityBindingContext-Bn3ePJQC.d.cts} +1 -1
- package/dist/{EntityBindingContext-0Evn_LcT.d.ts → EntityBindingContext-Bn3ePJQC.d.ts} +1 -1
- package/dist/{GameAudioProvider-B48iXwz3.d.ts → GameAudioProvider-Ctceau1s.d.ts} +6 -18
- package/dist/{GameAudioProvider-CQAdPreB.d.cts → GameAudioProvider-Dk_Y3LN3.d.cts} +6 -18
- package/dist/avl/index.cjs +1268 -220
- package/dist/avl/index.js +1269 -221
- package/dist/{avl-schema-parser-dvJKXn-o.d.ts → avl-schema-parser-DncJLEn9.d.ts} +18 -0
- package/dist/{avl-schema-parser-Bt4NzAam.d.cts → avl-schema-parser-FQ1474v8.d.cts} +18 -0
- package/dist/{cn-DJSBBm5W.d.cts → cn-CCjFspAo.d.cts} +25 -1
- package/dist/{cn-BbhJq_nr.d.ts → cn-sgpqpN0U.d.ts} +25 -1
- package/dist/components/index.cjs +1092 -249
- package/dist/components/index.d.cts +193 -23
- package/dist/components/index.d.ts +193 -23
- package/dist/components/index.js +1089 -250
- package/dist/context/index.cjs +10 -13
- package/dist/context/index.js +10 -13
- package/dist/hooks/index.cjs +63 -13
- package/dist/hooks/index.d.cts +2 -2
- package/dist/hooks/index.d.ts +2 -2
- package/dist/hooks/index.js +64 -15
- package/dist/lib/drawable/three/index.cjs +126 -13
- package/dist/lib/drawable/three/index.d.cts +2 -2
- package/dist/lib/drawable/three/index.d.ts +2 -2
- package/dist/lib/drawable/three/index.js +127 -14
- package/dist/lib/index.cjs +180 -0
- package/dist/lib/index.d.cts +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.js +178 -1
- package/dist/locales/index.cjs +6 -3
- package/dist/locales/index.js +6 -3
- package/dist/providers/index.cjs +974 -202
- package/dist/providers/index.d.cts +2 -2
- package/dist/providers/index.d.ts +2 -2
- package/dist/providers/index.js +974 -202
- package/dist/runtime/index.cjs +1594 -196
- package/dist/runtime/index.d.cts +79 -6
- package/dist/runtime/index.d.ts +79 -6
- package/dist/runtime/index.js +1592 -198
- package/dist/slot-host-Czc2JAxo.d.cts +47 -0
- package/dist/slot-host-Czc2JAxo.d.ts +47 -0
- package/dist/{useEventBus-CQWyAWpK.d.ts → useKeyboardRouter-D84cNWmA.d.ts} +31 -1
- package/dist/{useEventBus-Ckr4wqW3.d.cts → useKeyboardRouter-DQEE_9mq.d.cts} +31 -1
- package/locales/ar.json +2 -1
- package/locales/en.json +2 -1
- package/locales/sl.json +2 -1
- package/package.json +4 -4
- package/themes/comic.css +437 -0
- package/themes/index.css +1 -0
package/dist/avl/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import * as React96 from 'react';
|
|
3
|
-
import React96__default, { createContext, useState, useMemo, useRef,
|
|
3
|
+
import React96__default, { createContext, useState, useEffect, useMemo, useRef, useContext, useCallback, Suspense, useLayoutEffect, Profiler, useReducer, useSyncExternalStore, lazy, useId } from 'react';
|
|
4
4
|
import { getAllPages, matchPathAmong, CurrentPagePathProvider, NavStackProvider, OrbitalProvider, EventBusContext, useTraitScopeChain, useNavStack, ServerBridgeProvider, VerificationProvider, EntitySchemaProvider, OrbitalThemeProvider, useServerBridge, EntityBindingContext, useEntitySchema, RenderSlotProvider, useEntitySchemaOptional, useEntityBindingSnapshot, TraitScopeProvider, useTraitScope, useCurrentPagePath, useRenderSlot, useGameAudioContextOptional } from '@almadar/ui/providers';
|
|
5
5
|
import { createLogger, setNamespaceLevel, isLogLevelEnabled } from '@almadar/logger';
|
|
6
6
|
import ELK from 'elkjs/lib/elk.bundled.js';
|
|
@@ -13711,7 +13711,7 @@ function collectDrawnItems(nodes) {
|
|
|
13711
13711
|
for (const n of nodes) {
|
|
13712
13712
|
switch (n.type) {
|
|
13713
13713
|
case "draw-sprite":
|
|
13714
|
-
if (isValidScenePos(n.position)) out.push({ pos: n.position, id: n.id, anchor: n.anchor, width: n.width, height: n.height });
|
|
13714
|
+
if (isValidScenePos(n.position)) out.push({ pos: n.position, id: n.id, anchor: n.anchor, width: n.width, height: n.height, rotation: n.rotation });
|
|
13715
13715
|
break;
|
|
13716
13716
|
case "draw-shape":
|
|
13717
13717
|
case "draw-text":
|
|
@@ -13721,7 +13721,7 @@ function collectDrawnItems(nodes) {
|
|
|
13721
13721
|
break;
|
|
13722
13722
|
case "draw-sprite-layer":
|
|
13723
13723
|
for (const it of n.items) {
|
|
13724
|
-
if (isValidScenePos(it.position)) out.push({ pos: it.position, id: it.id, anchor: it.anchor, width: it.width, height: it.height });
|
|
13724
|
+
if (isValidScenePos(it.position)) out.push({ pos: it.position, id: it.id, anchor: it.anchor, width: it.width, height: it.height, rotation: it.rotation });
|
|
13725
13725
|
}
|
|
13726
13726
|
break;
|
|
13727
13727
|
case "draw-shape-layer":
|
|
@@ -13741,15 +13741,39 @@ function buildHitIndex(items) {
|
|
|
13741
13741
|
}
|
|
13742
13742
|
return m;
|
|
13743
13743
|
}
|
|
13744
|
+
function withPreviewPosition(nodes, id, pos) {
|
|
13745
|
+
return nodes.map((n) => {
|
|
13746
|
+
if (n.type === "draw-sprite-layer" || n.type === "draw-shape-layer" || n.type === "draw-text-layer") {
|
|
13747
|
+
if (!n.items.some((it) => it.id === id)) return n;
|
|
13748
|
+
return { ...n, items: n.items.map((it) => it.id === id ? { ...it, position: pos } : it) };
|
|
13749
|
+
}
|
|
13750
|
+
if (n.type === "draw-group") {
|
|
13751
|
+
if (!Array.isArray(n.items)) return n;
|
|
13752
|
+
return { ...n, items: withPreviewPosition(n.items, id, pos) };
|
|
13753
|
+
}
|
|
13754
|
+
if (n.id === id && "position" in n) {
|
|
13755
|
+
return { ...n, position: pos };
|
|
13756
|
+
}
|
|
13757
|
+
return n;
|
|
13758
|
+
});
|
|
13759
|
+
}
|
|
13744
13760
|
function hitTestSprites(items, projector, point) {
|
|
13745
13761
|
for (let i = items.length - 1; i >= 0; i--) {
|
|
13746
13762
|
const it = items[i];
|
|
13747
13763
|
if (it.id === void 0) continue;
|
|
13748
13764
|
const r2 = spriteRect(projector, { position: it.pos, anchor: it.anchor, width: it.width, height: it.height });
|
|
13749
|
-
|
|
13765
|
+
const test = it.rotation ? rotatePoint(point, { x: r2.x + r2.w / 2, y: r2.y + r2.h / 2 }, -it.rotation) : point;
|
|
13766
|
+
if (test.x >= r2.x && test.x <= r2.x + r2.w && test.y >= r2.y && test.y <= r2.y + r2.h) return it.id;
|
|
13750
13767
|
}
|
|
13751
13768
|
return void 0;
|
|
13752
13769
|
}
|
|
13770
|
+
function rotatePoint(p, center, radians) {
|
|
13771
|
+
const cos = Math.cos(radians);
|
|
13772
|
+
const sin = Math.sin(radians);
|
|
13773
|
+
const dx = p.x - center.x;
|
|
13774
|
+
const dy = p.y - center.y;
|
|
13775
|
+
return { x: center.x + dx * cos - dy * sin, y: center.y + dx * sin + dy * cos };
|
|
13776
|
+
}
|
|
13753
13777
|
var init_hitTest = __esm({
|
|
13754
13778
|
"lib/drawable/hitTest.ts"() {
|
|
13755
13779
|
init_contract();
|
|
@@ -13758,6 +13782,41 @@ var init_hitTest = __esm({
|
|
|
13758
13782
|
function normalizeBackdrop(bg) {
|
|
13759
13783
|
return typeof bg === "string" ? { url: bg, role: "decoration", category: "background" } : bg;
|
|
13760
13784
|
}
|
|
13785
|
+
function selectionOverlayNodes(projector, item) {
|
|
13786
|
+
const r2 = spriteRect(projector, { position: item.pos, anchor: item.anchor, width: item.width, height: item.height });
|
|
13787
|
+
const tw = projector.tileWidth;
|
|
13788
|
+
const cellTopLeft = projector.anchorPoint(item.pos, "top-left");
|
|
13789
|
+
const offsetX = (r2.x - cellTopLeft.x) / tw;
|
|
13790
|
+
const offsetY = (r2.y - cellTopLeft.y) / tw;
|
|
13791
|
+
const width = r2.w / tw;
|
|
13792
|
+
const height = r2.h / tw;
|
|
13793
|
+
const handle = EDIT_HANDLE_SIZE_PX / tw;
|
|
13794
|
+
const ring = {
|
|
13795
|
+
type: "draw-shape",
|
|
13796
|
+
shape: "rect",
|
|
13797
|
+
position: item.pos,
|
|
13798
|
+
anchor: "top-left",
|
|
13799
|
+
offsetX,
|
|
13800
|
+
offsetY,
|
|
13801
|
+
width,
|
|
13802
|
+
height,
|
|
13803
|
+
stroke: EDIT_SELECTION_COLOR,
|
|
13804
|
+
strokeWidth: 2,
|
|
13805
|
+
fill: "none"
|
|
13806
|
+
};
|
|
13807
|
+
const handles = EDIT_SELECTION_CORNERS.map(([cx, cy]) => ({
|
|
13808
|
+
type: "draw-shape",
|
|
13809
|
+
shape: "rect",
|
|
13810
|
+
position: item.pos,
|
|
13811
|
+
anchor: "top-left",
|
|
13812
|
+
offsetX: offsetX + cx * width - handle / 2,
|
|
13813
|
+
offsetY: offsetY + cy * height - handle / 2,
|
|
13814
|
+
width: handle,
|
|
13815
|
+
height: handle,
|
|
13816
|
+
fill: EDIT_SELECTION_COLOR
|
|
13817
|
+
}));
|
|
13818
|
+
return [ring, ...handles];
|
|
13819
|
+
}
|
|
13761
13820
|
function Canvas2D({
|
|
13762
13821
|
className,
|
|
13763
13822
|
isLoading = false,
|
|
@@ -13771,6 +13830,12 @@ function Canvas2D({
|
|
|
13771
13830
|
tileLeaveEvent,
|
|
13772
13831
|
keyMap,
|
|
13773
13832
|
keyUpMap,
|
|
13833
|
+
editable = false,
|
|
13834
|
+
selectedId = null,
|
|
13835
|
+
onSelect,
|
|
13836
|
+
onMove,
|
|
13837
|
+
selectEvent,
|
|
13838
|
+
moveEvent,
|
|
13774
13839
|
camera = "pan-zoom",
|
|
13775
13840
|
scale = 0.4,
|
|
13776
13841
|
tileWidth,
|
|
@@ -14028,10 +14093,22 @@ function Canvas2D({
|
|
|
14028
14093
|
painter.scale(cam.zoom, cam.zoom);
|
|
14029
14094
|
painter.translate(-viewportSize.width / 2 - cam.x, -viewportSize.height / 2 - cam.y);
|
|
14030
14095
|
const dctx = { projector, time: timeMs, invalidate: bumpAtlas };
|
|
14031
|
-
|
|
14096
|
+
let paintNodes = drawables;
|
|
14097
|
+
if (editable) {
|
|
14098
|
+
const drag = editDragRef.current;
|
|
14099
|
+
if (drag && drag.moved) {
|
|
14100
|
+
paintNodes = withPreviewPosition(paintNodes, drag.id, { x: drag.previewX, y: drag.previewY });
|
|
14101
|
+
}
|
|
14102
|
+
const selectedItem = selectedId != null ? drawnItems.find((it) => it.id === selectedId) : void 0;
|
|
14103
|
+
if (selectedItem) {
|
|
14104
|
+
const overlaySource = drag && drag.moved && drag.id === selectedId ? { ...selectedItem, pos: { x: drag.previewX, y: drag.previewY } } : selectedItem;
|
|
14105
|
+
paintNodes = [...paintNodes, ...selectionOverlayNodes(projector, overlaySource)];
|
|
14106
|
+
}
|
|
14107
|
+
}
|
|
14108
|
+
for (const node of paintNodes) paintDrawable(painter, node, dctx);
|
|
14032
14109
|
painter.restore();
|
|
14033
|
-
scheduleAnimation(
|
|
14034
|
-
}, [viewportSize, backgroundImage, bgColor, drawables, projector, cameraRef, bumpAtlas, getImage, cameraPos, defaultGridFocus, camera, dragDistance]);
|
|
14110
|
+
scheduleAnimation(paintNodes);
|
|
14111
|
+
}, [viewportSize, backgroundImage, bgColor, drawables, projector, cameraRef, bumpAtlas, getImage, cameraPos, defaultGridFocus, camera, dragDistance, editable, selectedId, drawnItems]);
|
|
14035
14112
|
useEffect(() => {
|
|
14036
14113
|
drawTimeRef.current = draw;
|
|
14037
14114
|
}, [draw]);
|
|
@@ -14076,23 +14153,83 @@ function Canvas2D({
|
|
|
14076
14153
|
};
|
|
14077
14154
|
}, [camera, followTarget, lerpToTarget, draw]);
|
|
14078
14155
|
const singlePointerActiveRef = useRef(false);
|
|
14156
|
+
const editDragRef = useRef(null);
|
|
14157
|
+
const pointerToScene = useCallback((clientX, clientY) => {
|
|
14158
|
+
const canvas = canvasRef.current;
|
|
14159
|
+
if (!canvas) return { x: 0, y: 0 };
|
|
14160
|
+
const world = screenToWorld(clientX, clientY, canvas, viewportSize);
|
|
14161
|
+
const adjustedX = world.x - scaledTileWidth / 2;
|
|
14162
|
+
const adjustedY = squareGrid ? world.y - scaledTileWidth / 2 : world.y - scaledDiamondTopY - scaledFloorHeight / 2;
|
|
14163
|
+
return unproject(adjustedX, adjustedY);
|
|
14164
|
+
}, [screenToWorld, viewportSize, scaledTileWidth, squareGrid, scaledDiamondTopY, scaledFloorHeight, unproject]);
|
|
14079
14165
|
const handleCanvasPointerDown = useCallback((e) => {
|
|
14080
14166
|
singlePointerActiveRef.current = true;
|
|
14167
|
+
if (editable) {
|
|
14168
|
+
if (!canvasRef.current) return;
|
|
14169
|
+
const world = screenToWorld(e.clientX, e.clientY, canvasRef.current, viewportSize);
|
|
14170
|
+
const hitId = hitTestSprites(drawnItems, projector, world);
|
|
14171
|
+
if (hitId === void 0) return;
|
|
14172
|
+
const item = [...drawnItems].reverse().find((it) => it.id === hitId);
|
|
14173
|
+
if (!item) return;
|
|
14174
|
+
editDragRef.current = {
|
|
14175
|
+
id: hitId,
|
|
14176
|
+
pointerId: e.pointerId,
|
|
14177
|
+
startClientX: e.clientX,
|
|
14178
|
+
startClientY: e.clientY,
|
|
14179
|
+
startSceneX: item.pos.x,
|
|
14180
|
+
startSceneY: item.pos.y,
|
|
14181
|
+
moved: false,
|
|
14182
|
+
previewX: item.pos.x,
|
|
14183
|
+
previewY: item.pos.y
|
|
14184
|
+
};
|
|
14185
|
+
return;
|
|
14186
|
+
}
|
|
14081
14187
|
if (enableCamera) handlePointerDown(e);
|
|
14082
|
-
}, [enableCamera, handlePointerDown]);
|
|
14188
|
+
}, [editable, screenToWorld, viewportSize, drawnItems, projector, enableCamera, handlePointerDown]);
|
|
14083
14189
|
const handleCanvasPointerMove = useCallback((e) => {
|
|
14190
|
+
if (editable) {
|
|
14191
|
+
const drag = editDragRef.current;
|
|
14192
|
+
if (!drag || drag.pointerId !== e.pointerId) return;
|
|
14193
|
+
const dxPx = e.clientX - drag.startClientX;
|
|
14194
|
+
const dyPx = e.clientY - drag.startClientY;
|
|
14195
|
+
if (!drag.moved && Math.abs(dxPx) + Math.abs(dyPx) <= 5) return;
|
|
14196
|
+
drag.moved = true;
|
|
14197
|
+
const nowScene = pointerToScene(e.clientX, e.clientY);
|
|
14198
|
+
const startScene = pointerToScene(drag.startClientX, drag.startClientY);
|
|
14199
|
+
drag.previewX = drag.startSceneX + (nowScene.x - startScene.x);
|
|
14200
|
+
drag.previewY = drag.startSceneY + (nowScene.y - startScene.y);
|
|
14201
|
+
draw();
|
|
14202
|
+
return;
|
|
14203
|
+
}
|
|
14084
14204
|
if (enableCamera) handlePointerMove(e, () => draw());
|
|
14085
|
-
}, [
|
|
14205
|
+
}, [editable, pointerToScene, draw, enableCamera, handlePointerMove]);
|
|
14086
14206
|
const handleCanvasHover = useCallback((e) => {
|
|
14087
14207
|
if (singlePointerActiveRef.current) return;
|
|
14088
14208
|
if (!tileHoverEvent || !canvasRef.current) return;
|
|
14089
|
-
const
|
|
14090
|
-
const adjustedX = world.x - scaledTileWidth / 2;
|
|
14091
|
-
const adjustedY = squareGrid ? world.y - scaledTileWidth / 2 : world.y - scaledDiamondTopY - scaledFloorHeight / 2;
|
|
14092
|
-
const isoPos = unproject(adjustedX, adjustedY);
|
|
14209
|
+
const isoPos = pointerToScene(e.clientX, e.clientY);
|
|
14093
14210
|
eventBus.emit(`UI:${tileHoverEvent}`, { x: isoPos.x, y: isoPos.y });
|
|
14094
|
-
}, [
|
|
14211
|
+
}, [pointerToScene, tileHoverEvent, eventBus]);
|
|
14095
14212
|
const handleCanvasPointerUp = useCallback((e) => {
|
|
14213
|
+
if (editable) {
|
|
14214
|
+
singlePointerActiveRef.current = false;
|
|
14215
|
+
const drag = editDragRef.current;
|
|
14216
|
+
if (drag && drag.pointerId === e.pointerId) {
|
|
14217
|
+
editDragRef.current = null;
|
|
14218
|
+
if (drag.moved) {
|
|
14219
|
+
onMove?.(drag.id, drag.previewX, drag.previewY);
|
|
14220
|
+
if (moveEvent) eventBus.emit(`UI:${moveEvent}`, { id: drag.id, x: drag.previewX, y: drag.previewY });
|
|
14221
|
+
draw();
|
|
14222
|
+
return;
|
|
14223
|
+
}
|
|
14224
|
+
const next = selectedId === drag.id ? null : drag.id;
|
|
14225
|
+
onSelect?.(next);
|
|
14226
|
+
if (selectEvent) eventBus.emit(`UI:${selectEvent}`, { id: next });
|
|
14227
|
+
return;
|
|
14228
|
+
}
|
|
14229
|
+
onSelect?.(null);
|
|
14230
|
+
if (selectEvent) eventBus.emit(`UI:${selectEvent}`, { id: null });
|
|
14231
|
+
return;
|
|
14232
|
+
}
|
|
14096
14233
|
singlePointerActiveRef.current = false;
|
|
14097
14234
|
if (enableCamera) handlePointerUp();
|
|
14098
14235
|
if (dragDistance() > 5) return;
|
|
@@ -14103,16 +14240,14 @@ function Canvas2D({
|
|
|
14103
14240
|
eventBus.emit(`UI:${unitClickEvent}`, { unitId: spriteHit });
|
|
14104
14241
|
return;
|
|
14105
14242
|
}
|
|
14106
|
-
const
|
|
14107
|
-
const adjustedY = squareGrid ? world.y - scaledTileWidth / 2 : world.y - scaledDiamondTopY - scaledFloorHeight / 2;
|
|
14108
|
-
const isoPos = unproject(adjustedX, adjustedY);
|
|
14243
|
+
const isoPos = pointerToScene(e.clientX, e.clientY);
|
|
14109
14244
|
const hitId = hitIndex.get(`${isoPos.x},${isoPos.y}`);
|
|
14110
14245
|
if (hitId !== void 0 && unitClickEvent) {
|
|
14111
14246
|
eventBus.emit(`UI:${unitClickEvent}`, { unitId: hitId });
|
|
14112
14247
|
} else if (tileClickEvent) {
|
|
14113
14248
|
eventBus.emit(`UI:${tileClickEvent}`, { x: isoPos.x, y: isoPos.y });
|
|
14114
14249
|
}
|
|
14115
|
-
}, [
|
|
14250
|
+
}, [editable, selectedId, onMove, moveEvent, onSelect, selectEvent, eventBus, draw, enableCamera, handlePointerUp, dragDistance, screenToWorld, viewportSize, drawnItems, projector, tileClickEvent, unitClickEvent, hitIndex, pointerToScene]);
|
|
14116
14251
|
const handleCanvasPointerLeave = useCallback(() => {
|
|
14117
14252
|
handleMouseLeave();
|
|
14118
14253
|
if (tileLeaveEvent) eventBus.emit(`UI:${tileLeaveEvent}`, {});
|
|
@@ -14131,7 +14266,7 @@ function Canvas2D({
|
|
|
14131
14266
|
}, [enableCamera, handlePointerUp]);
|
|
14132
14267
|
const gestureHandlers = useCanvasGestures({
|
|
14133
14268
|
canvasRef,
|
|
14134
|
-
enabled: enableCamera || !!tileHoverEvent || !!tileClickEvent || !!unitClickEvent,
|
|
14269
|
+
enabled: enableCamera || !!tileHoverEvent || !!tileClickEvent || !!unitClickEvent || editable,
|
|
14135
14270
|
onPointerDown: handleCanvasPointerDown,
|
|
14136
14271
|
onPointerMove: handleCanvasPointerMove,
|
|
14137
14272
|
onPointerUp: handleCanvasPointerUp,
|
|
@@ -14263,7 +14398,7 @@ function Canvas2D({
|
|
|
14263
14398
|
}
|
|
14264
14399
|
) });
|
|
14265
14400
|
}
|
|
14266
|
-
var canvas2DLog;
|
|
14401
|
+
var canvas2DLog, EDIT_SELECTION_COLOR, EDIT_HANDLE_SIZE_PX, EDIT_SELECTION_CORNERS;
|
|
14267
14402
|
var init_Canvas2D = __esm({
|
|
14268
14403
|
"components/game/molecules/Canvas2D.tsx"() {
|
|
14269
14404
|
"use client";
|
|
@@ -14288,8 +14423,12 @@ var init_Canvas2D = __esm({
|
|
|
14288
14423
|
init_DrawGroup();
|
|
14289
14424
|
init_registry();
|
|
14290
14425
|
init_hitTest();
|
|
14426
|
+
init_contract();
|
|
14291
14427
|
init_isometric();
|
|
14292
14428
|
canvas2DLog = createLogger("almadar:ui:game-canvas");
|
|
14429
|
+
EDIT_SELECTION_COLOR = "#3b82f6";
|
|
14430
|
+
EDIT_HANDLE_SIZE_PX = 8;
|
|
14431
|
+
EDIT_SELECTION_CORNERS = [[0, 0], [1, 0], [0, 1], [1, 1]];
|
|
14293
14432
|
Canvas2D.displayName = "Canvas2D";
|
|
14294
14433
|
}
|
|
14295
14434
|
});
|
|
@@ -14331,6 +14470,12 @@ function Canvas({
|
|
|
14331
14470
|
featureClickEvent,
|
|
14332
14471
|
keyMap,
|
|
14333
14472
|
keyUpMap,
|
|
14473
|
+
editable,
|
|
14474
|
+
selectedId,
|
|
14475
|
+
onSelect,
|
|
14476
|
+
onMove,
|
|
14477
|
+
selectEvent,
|
|
14478
|
+
moveEvent,
|
|
14334
14479
|
children
|
|
14335
14480
|
}) {
|
|
14336
14481
|
canvasLog.debug("Canvas render", { mode, drawablesCount: drawables?.length, projection, camera: camera ? JSON.stringify(camera) : void 0 });
|
|
@@ -14408,6 +14553,12 @@ function Canvas({
|
|
|
14408
14553
|
tileLeaveEvent,
|
|
14409
14554
|
keyMap,
|
|
14410
14555
|
keyUpMap,
|
|
14556
|
+
editable,
|
|
14557
|
+
selectedId,
|
|
14558
|
+
onSelect,
|
|
14559
|
+
onMove,
|
|
14560
|
+
selectEvent,
|
|
14561
|
+
moveEvent,
|
|
14411
14562
|
...children !== void 0 ? { children } : {}
|
|
14412
14563
|
}
|
|
14413
14564
|
);
|
|
@@ -14429,15 +14580,19 @@ function GameAudioToggle({
|
|
|
14429
14580
|
size = "sm",
|
|
14430
14581
|
className,
|
|
14431
14582
|
onAsset,
|
|
14432
|
-
offAsset
|
|
14583
|
+
offAsset,
|
|
14584
|
+
toggleEvent
|
|
14433
14585
|
}) {
|
|
14434
14586
|
const ctx = useGameAudioContextOptional();
|
|
14435
14587
|
const [localMuted, setLocalMuted] = useState(false);
|
|
14436
14588
|
const muted = ctx ? ctx.muted : localMuted;
|
|
14437
14589
|
const setMuted = ctx ? ctx.setMuted : setLocalMuted;
|
|
14590
|
+
const eventBus = useEventBus();
|
|
14438
14591
|
const handleToggle = useCallback(() => {
|
|
14439
|
-
|
|
14440
|
-
|
|
14592
|
+
const next = !muted;
|
|
14593
|
+
setMuted(next);
|
|
14594
|
+
if (toggleEvent) eventBus.emit(`UI:${toggleEvent}`, { muted: next });
|
|
14595
|
+
}, [muted, setMuted, toggleEvent, eventBus]);
|
|
14441
14596
|
const activeAsset = muted ? offAsset : onAsset;
|
|
14442
14597
|
return /* @__PURE__ */ jsx(
|
|
14443
14598
|
Button,
|
|
@@ -14456,10 +14611,319 @@ var init_GameAudioToggle = __esm({
|
|
|
14456
14611
|
"use client";
|
|
14457
14612
|
init_atoms();
|
|
14458
14613
|
init_cn();
|
|
14614
|
+
init_useEventBus();
|
|
14459
14615
|
init_GameIcon();
|
|
14460
14616
|
GameAudioToggle.displayName = "GameAudioToggle";
|
|
14461
14617
|
}
|
|
14462
14618
|
});
|
|
14619
|
+
function pickPath(entry) {
|
|
14620
|
+
if (Array.isArray(entry.path)) {
|
|
14621
|
+
return entry.path[Math.floor(Math.random() * entry.path.length)];
|
|
14622
|
+
}
|
|
14623
|
+
return entry.path;
|
|
14624
|
+
}
|
|
14625
|
+
function useGameAudio({
|
|
14626
|
+
manifest,
|
|
14627
|
+
baseUrl = "",
|
|
14628
|
+
initialMuted = false,
|
|
14629
|
+
initialVolume = 1
|
|
14630
|
+
}) {
|
|
14631
|
+
const [muted, setMutedState] = useState(initialMuted);
|
|
14632
|
+
const [masterVolume, setMasterVolumeState] = useState(initialVolume);
|
|
14633
|
+
const mutedRef = useRef(muted);
|
|
14634
|
+
const volumeRef = useRef(masterVolume);
|
|
14635
|
+
const manifestRef = useRef(manifest);
|
|
14636
|
+
mutedRef.current = muted;
|
|
14637
|
+
volumeRef.current = masterVolume;
|
|
14638
|
+
manifestRef.current = manifest;
|
|
14639
|
+
const poolsRef = useRef(/* @__PURE__ */ new Map());
|
|
14640
|
+
const getOrCreateElement = useCallback((key) => {
|
|
14641
|
+
const entry = manifestRef.current[key];
|
|
14642
|
+
if (!entry) return null;
|
|
14643
|
+
let pool = poolsRef.current.get(key);
|
|
14644
|
+
if (!pool) {
|
|
14645
|
+
pool = [];
|
|
14646
|
+
poolsRef.current.set(key, pool);
|
|
14647
|
+
}
|
|
14648
|
+
const maxSize = entry.poolSize ?? 1;
|
|
14649
|
+
for (const audio of pool) {
|
|
14650
|
+
if (audio.paused && (audio.ended || audio.currentTime === 0)) {
|
|
14651
|
+
return audio;
|
|
14652
|
+
}
|
|
14653
|
+
}
|
|
14654
|
+
if (pool.length < maxSize) {
|
|
14655
|
+
const src = baseUrl + pickPath(entry);
|
|
14656
|
+
const audio = new Audio(src);
|
|
14657
|
+
audio.loop = entry.loop ?? false;
|
|
14658
|
+
pool.push(audio);
|
|
14659
|
+
return audio;
|
|
14660
|
+
}
|
|
14661
|
+
if (!entry.loop) {
|
|
14662
|
+
let oldest = pool[0];
|
|
14663
|
+
for (const audio of pool) {
|
|
14664
|
+
if (audio.currentTime > oldest.currentTime) {
|
|
14665
|
+
oldest = audio;
|
|
14666
|
+
}
|
|
14667
|
+
}
|
|
14668
|
+
oldest.pause();
|
|
14669
|
+
oldest.currentTime = 0;
|
|
14670
|
+
return oldest;
|
|
14671
|
+
}
|
|
14672
|
+
return null;
|
|
14673
|
+
}, [baseUrl]);
|
|
14674
|
+
const play = useCallback((key) => {
|
|
14675
|
+
if (mutedRef.current) return;
|
|
14676
|
+
const entry = manifestRef.current[key];
|
|
14677
|
+
if (!entry) return;
|
|
14678
|
+
const audio = getOrCreateElement(key);
|
|
14679
|
+
if (!audio) return;
|
|
14680
|
+
audio.volume = Math.min(1, (entry.volume ?? 1) * volumeRef.current);
|
|
14681
|
+
if (!entry.loop) {
|
|
14682
|
+
audio.currentTime = 0;
|
|
14683
|
+
}
|
|
14684
|
+
const promise = audio.play();
|
|
14685
|
+
if (promise) {
|
|
14686
|
+
promise.catch(() => {
|
|
14687
|
+
});
|
|
14688
|
+
}
|
|
14689
|
+
}, [getOrCreateElement]);
|
|
14690
|
+
const stop = useCallback((key) => {
|
|
14691
|
+
const pool = poolsRef.current.get(key);
|
|
14692
|
+
if (!pool) return;
|
|
14693
|
+
for (const audio of pool) {
|
|
14694
|
+
audio.pause();
|
|
14695
|
+
audio.currentTime = 0;
|
|
14696
|
+
}
|
|
14697
|
+
}, []);
|
|
14698
|
+
const currentMusicKeyRef = useRef(null);
|
|
14699
|
+
const currentMusicElRef = useRef(null);
|
|
14700
|
+
const musicFadeRef = useRef(null);
|
|
14701
|
+
const pendingMusicKeyRef = useRef(null);
|
|
14702
|
+
const clearMusicFade = useCallback(() => {
|
|
14703
|
+
if (musicFadeRef.current) {
|
|
14704
|
+
clearInterval(musicFadeRef.current);
|
|
14705
|
+
musicFadeRef.current = null;
|
|
14706
|
+
}
|
|
14707
|
+
}, []);
|
|
14708
|
+
const playMusic = useCallback((key) => {
|
|
14709
|
+
if (key === currentMusicKeyRef.current) return;
|
|
14710
|
+
pendingMusicKeyRef.current = key;
|
|
14711
|
+
const entry = manifestRef.current[key];
|
|
14712
|
+
if (!entry) return;
|
|
14713
|
+
const fadeDurationMs = entry.crossfadeDurationMs ?? 1500;
|
|
14714
|
+
const stepMs = 50;
|
|
14715
|
+
const totalSteps = Math.max(1, fadeDurationMs / stepMs);
|
|
14716
|
+
const targetVolume = Math.min(1, (entry.volume ?? 1) * volumeRef.current);
|
|
14717
|
+
clearMusicFade();
|
|
14718
|
+
const src = baseUrl + (Array.isArray(entry.path) ? entry.path[0] : entry.path);
|
|
14719
|
+
const incoming = new Audio(src);
|
|
14720
|
+
incoming.loop = true;
|
|
14721
|
+
incoming.volume = 0;
|
|
14722
|
+
const outgoing = currentMusicElRef.current;
|
|
14723
|
+
const outgoingStartVol = outgoing?.volume ?? 0;
|
|
14724
|
+
currentMusicKeyRef.current = key;
|
|
14725
|
+
currentMusicElRef.current = incoming;
|
|
14726
|
+
if (!mutedRef.current) {
|
|
14727
|
+
incoming.play().catch(() => {
|
|
14728
|
+
currentMusicKeyRef.current = null;
|
|
14729
|
+
currentMusicElRef.current = outgoing;
|
|
14730
|
+
});
|
|
14731
|
+
}
|
|
14732
|
+
let step = 0;
|
|
14733
|
+
musicFadeRef.current = setInterval(() => {
|
|
14734
|
+
step++;
|
|
14735
|
+
const progress = Math.min(step / totalSteps, 1);
|
|
14736
|
+
incoming.volume = Math.min(1, targetVolume * progress);
|
|
14737
|
+
if (outgoing) {
|
|
14738
|
+
outgoing.volume = Math.max(0, outgoingStartVol * (1 - progress));
|
|
14739
|
+
}
|
|
14740
|
+
if (progress >= 1) {
|
|
14741
|
+
clearMusicFade();
|
|
14742
|
+
if (outgoing) {
|
|
14743
|
+
outgoing.pause();
|
|
14744
|
+
outgoing.src = "";
|
|
14745
|
+
}
|
|
14746
|
+
}
|
|
14747
|
+
}, stepMs);
|
|
14748
|
+
}, [baseUrl, clearMusicFade]);
|
|
14749
|
+
const stopMusic = useCallback((fadeDurationMs = 1e3) => {
|
|
14750
|
+
const outgoing = currentMusicElRef.current;
|
|
14751
|
+
if (!outgoing) return;
|
|
14752
|
+
currentMusicKeyRef.current = null;
|
|
14753
|
+
currentMusicElRef.current = null;
|
|
14754
|
+
pendingMusicKeyRef.current = null;
|
|
14755
|
+
clearMusicFade();
|
|
14756
|
+
const startVolume = outgoing.volume;
|
|
14757
|
+
const stepMs = 50;
|
|
14758
|
+
const totalSteps = Math.max(1, fadeDurationMs / stepMs);
|
|
14759
|
+
let step = 0;
|
|
14760
|
+
musicFadeRef.current = setInterval(() => {
|
|
14761
|
+
step++;
|
|
14762
|
+
const progress = step / totalSteps;
|
|
14763
|
+
outgoing.volume = Math.max(0, startVolume * (1 - progress));
|
|
14764
|
+
if (progress >= 1) {
|
|
14765
|
+
clearMusicFade();
|
|
14766
|
+
outgoing.pause();
|
|
14767
|
+
outgoing.src = "";
|
|
14768
|
+
}
|
|
14769
|
+
}, stepMs);
|
|
14770
|
+
}, [clearMusicFade]);
|
|
14771
|
+
const stopAll = useCallback(() => {
|
|
14772
|
+
for (const pool of poolsRef.current.values()) {
|
|
14773
|
+
for (const audio of pool) {
|
|
14774
|
+
audio.pause();
|
|
14775
|
+
audio.currentTime = 0;
|
|
14776
|
+
}
|
|
14777
|
+
}
|
|
14778
|
+
stopMusic(0);
|
|
14779
|
+
}, [stopMusic]);
|
|
14780
|
+
const setMuted = useCallback((value) => {
|
|
14781
|
+
setMutedState(value);
|
|
14782
|
+
if (value) {
|
|
14783
|
+
for (const [key, pool] of poolsRef.current.entries()) {
|
|
14784
|
+
if (manifestRef.current[key]?.loop) {
|
|
14785
|
+
for (const audio of pool) {
|
|
14786
|
+
if (!audio.paused) audio.pause();
|
|
14787
|
+
}
|
|
14788
|
+
}
|
|
14789
|
+
}
|
|
14790
|
+
currentMusicElRef.current?.pause();
|
|
14791
|
+
} else {
|
|
14792
|
+
for (const [key, pool] of poolsRef.current.entries()) {
|
|
14793
|
+
const entry = manifestRef.current[key];
|
|
14794
|
+
if (entry?.loop && entry?.autostart) {
|
|
14795
|
+
for (const audio of pool) {
|
|
14796
|
+
if (audio.paused) audio.play().catch(() => {
|
|
14797
|
+
});
|
|
14798
|
+
}
|
|
14799
|
+
}
|
|
14800
|
+
}
|
|
14801
|
+
const musicEl = currentMusicElRef.current;
|
|
14802
|
+
if (musicEl) {
|
|
14803
|
+
musicEl.play().catch(() => {
|
|
14804
|
+
});
|
|
14805
|
+
}
|
|
14806
|
+
}
|
|
14807
|
+
}, []);
|
|
14808
|
+
const setMasterVolume = useCallback((volume) => {
|
|
14809
|
+
const clamped = Math.max(0, Math.min(1, volume));
|
|
14810
|
+
setMasterVolumeState(clamped);
|
|
14811
|
+
for (const [key, pool] of poolsRef.current.entries()) {
|
|
14812
|
+
const entryVol = manifestRef.current[key]?.volume ?? 1;
|
|
14813
|
+
for (const audio of pool) {
|
|
14814
|
+
audio.volume = Math.min(1, entryVol * clamped);
|
|
14815
|
+
}
|
|
14816
|
+
}
|
|
14817
|
+
if (!musicFadeRef.current && currentMusicElRef.current) {
|
|
14818
|
+
const key = currentMusicKeyRef.current;
|
|
14819
|
+
const entryVol = key ? manifestRef.current[key]?.volume ?? 1 : 1;
|
|
14820
|
+
currentMusicElRef.current.volume = Math.min(1, entryVol * clamped);
|
|
14821
|
+
}
|
|
14822
|
+
}, []);
|
|
14823
|
+
const unlockedRef = useRef(false);
|
|
14824
|
+
useEffect(() => {
|
|
14825
|
+
const autoKeys = Object.keys(manifest).filter((k) => manifest[k].autostart);
|
|
14826
|
+
const hasPendingMusic = () => pendingMusicKeyRef.current !== null;
|
|
14827
|
+
const hasAutoStart = autoKeys.length > 0;
|
|
14828
|
+
if (!hasAutoStart && !hasPendingMusic()) return;
|
|
14829
|
+
const unlock = () => {
|
|
14830
|
+
if (unlockedRef.current) return;
|
|
14831
|
+
unlockedRef.current = true;
|
|
14832
|
+
if (!mutedRef.current) {
|
|
14833
|
+
for (const key of autoKeys) {
|
|
14834
|
+
play(key);
|
|
14835
|
+
}
|
|
14836
|
+
const pending = pendingMusicKeyRef.current;
|
|
14837
|
+
if (pending && pending !== currentMusicKeyRef.current) {
|
|
14838
|
+
playMusic(pending);
|
|
14839
|
+
}
|
|
14840
|
+
}
|
|
14841
|
+
};
|
|
14842
|
+
document.addEventListener("click", unlock, { once: true });
|
|
14843
|
+
document.addEventListener("keydown", unlock, { once: true });
|
|
14844
|
+
document.addEventListener("touchstart", unlock, { once: true });
|
|
14845
|
+
return () => {
|
|
14846
|
+
document.removeEventListener("click", unlock);
|
|
14847
|
+
document.removeEventListener("keydown", unlock);
|
|
14848
|
+
document.removeEventListener("touchstart", unlock);
|
|
14849
|
+
};
|
|
14850
|
+
}, [manifest, play, playMusic]);
|
|
14851
|
+
useEffect(() => {
|
|
14852
|
+
return () => {
|
|
14853
|
+
clearMusicFade();
|
|
14854
|
+
for (const pool of poolsRef.current.values()) {
|
|
14855
|
+
for (const audio of pool) {
|
|
14856
|
+
audio.pause();
|
|
14857
|
+
audio.src = "";
|
|
14858
|
+
}
|
|
14859
|
+
}
|
|
14860
|
+
poolsRef.current.clear();
|
|
14861
|
+
if (currentMusicElRef.current) {
|
|
14862
|
+
currentMusicElRef.current.pause();
|
|
14863
|
+
currentMusicElRef.current.src = "";
|
|
14864
|
+
currentMusicElRef.current = null;
|
|
14865
|
+
}
|
|
14866
|
+
};
|
|
14867
|
+
}, [clearMusicFade]);
|
|
14868
|
+
return {
|
|
14869
|
+
play,
|
|
14870
|
+
stop,
|
|
14871
|
+
stopAll,
|
|
14872
|
+
playMusic,
|
|
14873
|
+
stopMusic,
|
|
14874
|
+
muted,
|
|
14875
|
+
setMuted,
|
|
14876
|
+
masterVolume,
|
|
14877
|
+
setMasterVolume
|
|
14878
|
+
};
|
|
14879
|
+
}
|
|
14880
|
+
var init_useGameAudio = __esm({
|
|
14881
|
+
"hooks/useGameAudio.ts"() {
|
|
14882
|
+
"use client";
|
|
14883
|
+
useGameAudio.displayName = "useGameAudio";
|
|
14884
|
+
}
|
|
14885
|
+
});
|
|
14886
|
+
function GameAudioCue({
|
|
14887
|
+
cue,
|
|
14888
|
+
cueSeq,
|
|
14889
|
+
music,
|
|
14890
|
+
muted,
|
|
14891
|
+
volume,
|
|
14892
|
+
manifest,
|
|
14893
|
+
baseUrl
|
|
14894
|
+
}) {
|
|
14895
|
+
const { play, playMusic, stopMusic, setMuted, setMasterVolume } = useGameAudio({
|
|
14896
|
+
manifest,
|
|
14897
|
+
baseUrl,
|
|
14898
|
+
initialMuted: muted,
|
|
14899
|
+
initialVolume: volume
|
|
14900
|
+
});
|
|
14901
|
+
const prevCueSeqRef = useRef(cueSeq);
|
|
14902
|
+
useEffect(() => {
|
|
14903
|
+
if (cue && cueSeq !== void 0 && cueSeq !== prevCueSeqRef.current) {
|
|
14904
|
+
play(cue);
|
|
14905
|
+
}
|
|
14906
|
+
prevCueSeqRef.current = cueSeq;
|
|
14907
|
+
}, [cue, cueSeq, play]);
|
|
14908
|
+
useEffect(() => {
|
|
14909
|
+
if (music) playMusic(music);
|
|
14910
|
+
else stopMusic();
|
|
14911
|
+
}, [music, playMusic, stopMusic]);
|
|
14912
|
+
useEffect(() => {
|
|
14913
|
+
if (muted !== void 0) setMuted(muted);
|
|
14914
|
+
}, [muted, setMuted]);
|
|
14915
|
+
useEffect(() => {
|
|
14916
|
+
if (volume !== void 0) setMasterVolume(volume);
|
|
14917
|
+
}, [volume, setMasterVolume]);
|
|
14918
|
+
return null;
|
|
14919
|
+
}
|
|
14920
|
+
var init_GameAudioCue = __esm({
|
|
14921
|
+
"components/game/atoms/GameAudioCue.tsx"() {
|
|
14922
|
+
"use client";
|
|
14923
|
+
init_useGameAudio();
|
|
14924
|
+
GameAudioCue.displayName = "GameAudioCue";
|
|
14925
|
+
}
|
|
14926
|
+
});
|
|
14463
14927
|
function isKnownState(s) {
|
|
14464
14928
|
return s in DEFAULT_STATE_STYLES;
|
|
14465
14929
|
}
|
|
@@ -15158,15 +15622,18 @@ var init_StateJsonView = __esm({
|
|
|
15158
15622
|
StateJsonView.displayName = "StateJsonView";
|
|
15159
15623
|
}
|
|
15160
15624
|
});
|
|
15161
|
-
|
|
15162
|
-
|
|
15163
|
-
|
|
15164
|
-
|
|
15165
|
-
|
|
15166
|
-
|
|
15167
|
-
|
|
15168
|
-
|
|
15169
|
-
|
|
15625
|
+
|
|
15626
|
+
// lib/gameFonts.ts
|
|
15627
|
+
function resolveGameFontFamily(input) {
|
|
15628
|
+
if (!input) return void 0;
|
|
15629
|
+
const resolved = GAME_FONT_KEYS[input];
|
|
15630
|
+
if (resolved) return `'${resolved}', ui-sans-serif, system-ui, sans-serif`;
|
|
15631
|
+
return input;
|
|
15632
|
+
}
|
|
15633
|
+
var GAME_FONT_KEYS;
|
|
15634
|
+
var init_gameFonts = __esm({
|
|
15635
|
+
"lib/gameFonts.ts"() {
|
|
15636
|
+
GAME_FONT_KEYS = {
|
|
15170
15637
|
fredoka: "Fredoka",
|
|
15171
15638
|
future: "Kenney Future",
|
|
15172
15639
|
"future-narrow": "Kenney Future Narrow",
|
|
@@ -15174,6 +15641,17 @@ var init_GameShell = __esm({
|
|
|
15174
15641
|
blocks: "Kenney Blocks",
|
|
15175
15642
|
mini: "Kenney Mini"
|
|
15176
15643
|
};
|
|
15644
|
+
}
|
|
15645
|
+
});
|
|
15646
|
+
var GameShell;
|
|
15647
|
+
var init_GameShell = __esm({
|
|
15648
|
+
"components/game/templates/GameShell.tsx"() {
|
|
15649
|
+
init_cn();
|
|
15650
|
+
init_gameFonts();
|
|
15651
|
+
init_Box();
|
|
15652
|
+
init_Card();
|
|
15653
|
+
init_Typography();
|
|
15654
|
+
init_AtlasImage();
|
|
15177
15655
|
GameShell = ({
|
|
15178
15656
|
appName = "Game",
|
|
15179
15657
|
hud,
|
|
@@ -15187,7 +15665,7 @@ var init_GameShell = __esm({
|
|
|
15187
15665
|
fontFamily,
|
|
15188
15666
|
"data-theme": dataTheme
|
|
15189
15667
|
}) => {
|
|
15190
|
-
const
|
|
15668
|
+
const displayFont = resolveGameFontFamily(fontFamily);
|
|
15191
15669
|
return /* @__PURE__ */ jsxs(
|
|
15192
15670
|
Box,
|
|
15193
15671
|
{
|
|
@@ -15206,7 +15684,7 @@ var init_GameShell = __esm({
|
|
|
15206
15684
|
// passed — an always-on inline stamp would shadow the orbital's
|
|
15207
15685
|
// inline-theme font-family-display token (inline style beats the
|
|
15208
15686
|
// theme provider's vars for the whole shell subtree).
|
|
15209
|
-
...
|
|
15687
|
+
...displayFont ? { "--font-family-display": displayFont } : {}
|
|
15210
15688
|
},
|
|
15211
15689
|
children: [
|
|
15212
15690
|
backgroundAsset && /* @__PURE__ */ jsx(
|
|
@@ -15417,14 +15895,15 @@ function drawArrowHead(ctx, x1, y1, x2, y2, size) {
|
|
|
15417
15895
|
ctx.closePath();
|
|
15418
15896
|
ctx.fill();
|
|
15419
15897
|
}
|
|
15420
|
-
function drawShape(ctx, shape, width, height, allShapes) {
|
|
15898
|
+
function drawShape(ctx, shape, width, height, allShapes, fontFamily) {
|
|
15421
15899
|
ctx.save();
|
|
15422
15900
|
const opacity = shape.opacity ?? 1;
|
|
15423
15901
|
ctx.globalAlpha = opacity;
|
|
15424
15902
|
const stroke = resolveColor2(shape.color, ctx, "#333333");
|
|
15425
15903
|
const fill = shape.fill ? resolveColor2(shape.fill, ctx, "#cccccc") : void 0;
|
|
15426
15904
|
ctx.lineWidth = shape.lineWidth ?? 2;
|
|
15427
|
-
|
|
15905
|
+
const dashPattern = shape.dash ? DASH_PATTERNS[shape.dash] : void 0;
|
|
15906
|
+
if (dashPattern) ctx.setLineDash([...dashPattern]);
|
|
15428
15907
|
switch (shape.type) {
|
|
15429
15908
|
case "grid": {
|
|
15430
15909
|
const step = shape.step ?? 40;
|
|
@@ -15546,7 +16025,7 @@ function drawShape(ctx, shape, width, height, allShapes) {
|
|
|
15546
16025
|
case "text": {
|
|
15547
16026
|
if (shape.x == null || shape.y == null || !shape.text) break;
|
|
15548
16027
|
ctx.fillStyle = stroke;
|
|
15549
|
-
ctx.font = `${shape.fontSize ?? 14}px ${themeBodyFont(ctx.canvas)}`;
|
|
16028
|
+
ctx.font = `${shape.fontSize ?? 14}px ${shape.fontFamily ?? fontFamily ?? themeBodyFont(ctx.canvas)}`;
|
|
15550
16029
|
ctx.textAlign = shape.align ?? "left";
|
|
15551
16030
|
ctx.textBaseline = "middle";
|
|
15552
16031
|
ctx.fillText(shape.text, shape.x, shape.y);
|
|
@@ -15588,7 +16067,7 @@ function drawShape(ctx, shape, width, height, allShapes) {
|
|
|
15588
16067
|
}
|
|
15589
16068
|
ctx.restore();
|
|
15590
16069
|
}
|
|
15591
|
-
function readoutShapes(readouts, width) {
|
|
16070
|
+
function readoutShapes(readouts, width, fontFamily) {
|
|
15592
16071
|
const out = [];
|
|
15593
16072
|
const chipH = 18;
|
|
15594
16073
|
const gap = 6;
|
|
@@ -15612,13 +16091,14 @@ function readoutShapes(readouts, width) {
|
|
|
15612
16091
|
text,
|
|
15613
16092
|
color: "#ffffff",
|
|
15614
16093
|
fontSize: 10,
|
|
15615
|
-
align: "center"
|
|
16094
|
+
align: "center",
|
|
16095
|
+
fontFamily
|
|
15616
16096
|
});
|
|
15617
16097
|
rightEdge = chipX - gap;
|
|
15618
16098
|
}
|
|
15619
16099
|
return out;
|
|
15620
16100
|
}
|
|
15621
|
-
function traceShapes(panel, k, width, height) {
|
|
16101
|
+
function traceShapes(panel, k, width, height, fontFamily) {
|
|
15622
16102
|
const w = panel.width ?? Math.round(width * 0.32);
|
|
15623
16103
|
const h = panel.height ?? Math.round(height * 0.28);
|
|
15624
16104
|
const x = panel.x ?? width - w - 8;
|
|
@@ -15672,14 +16152,14 @@ function traceShapes(panel, k, width, height) {
|
|
|
15672
16152
|
out.push({ type: "circle", x: last.x, y: last.y, radius: 2, color, fill: color });
|
|
15673
16153
|
}
|
|
15674
16154
|
if (series.label) {
|
|
15675
|
-
out.push({ type: "text", x: x + 6, y: y + 10 + 11 * j, text: series.label, color, fontSize: 9 });
|
|
16155
|
+
out.push({ type: "text", x: x + 6, y: y + 10 + 11 * j, text: series.label, color, fontSize: 9, fontFamily });
|
|
15676
16156
|
}
|
|
15677
16157
|
});
|
|
15678
16158
|
if (panel.yLabel) {
|
|
15679
|
-
out.push({ type: "text", x: x + w - 6, y: y + 10, text: panel.yLabel, color: "#6b7280", fontSize: 9, align: "right" });
|
|
16159
|
+
out.push({ type: "text", x: x + w - 6, y: y + 10, text: panel.yLabel, color: "#6b7280", fontSize: 9, align: "right", fontFamily });
|
|
15680
16160
|
}
|
|
15681
16161
|
if (panel.xLabel) {
|
|
15682
|
-
out.push({ type: "text", x: x + w - 6, y: y + h - 6, text: panel.xLabel, color: "#6b7280", fontSize: 9, align: "right" });
|
|
16162
|
+
out.push({ type: "text", x: x + w - 6, y: y + h - 6, text: panel.xLabel, color: "#6b7280", fontSize: 9, align: "right", fontFamily });
|
|
15683
16163
|
}
|
|
15684
16164
|
return out;
|
|
15685
16165
|
}
|
|
@@ -15702,13 +16182,14 @@ var init_LearningCanvas = __esm({
|
|
|
15702
16182
|
init_useEventBus();
|
|
15703
16183
|
init_webPainter2d();
|
|
15704
16184
|
init_paintDispatch();
|
|
15705
|
-
DASH_PATTERNS = { dashed: [6, 4], dotted: [2, 3] };
|
|
16185
|
+
DASH_PATTERNS = { solid: [], dashed: [6, 4], dotted: [2, 3] };
|
|
15706
16186
|
TRACE_SERIES_COLORS = ["#2563eb", "#dc2626", "#16a34a", "#f59e0b"];
|
|
15707
16187
|
LearningCanvas = ({
|
|
15708
16188
|
className,
|
|
15709
16189
|
width = 600,
|
|
15710
16190
|
height = 400,
|
|
15711
16191
|
backgroundColor,
|
|
16192
|
+
fontFamily,
|
|
15712
16193
|
shapes = [],
|
|
15713
16194
|
drawables,
|
|
15714
16195
|
projector,
|
|
@@ -15744,10 +16225,10 @@ var init_LearningCanvas = __esm({
|
|
|
15744
16225
|
}, [shapes]);
|
|
15745
16226
|
const derivedShapes = useMemo(() => {
|
|
15746
16227
|
if (!traces?.length && !readouts?.length) return shapes;
|
|
15747
|
-
const traceOut = (traces ?? []).flatMap((panel, k) => traceShapes(panel, k, width, height));
|
|
15748
|
-
const readoutOut = readouts?.length ? readoutShapes(readouts, width) : [];
|
|
16228
|
+
const traceOut = (traces ?? []).flatMap((panel, k) => traceShapes(panel, k, width, height, fontFamily));
|
|
16229
|
+
const readoutOut = readouts?.length ? readoutShapes(readouts, width, fontFamily) : [];
|
|
15749
16230
|
return [...shapes, ...traceOut, ...readoutOut];
|
|
15750
|
-
}, [shapes, traces, readouts, width, height]);
|
|
16231
|
+
}, [shapes, traces, readouts, width, height, fontFamily]);
|
|
15751
16232
|
const draw = useCallback(() => {
|
|
15752
16233
|
const _perfT = perfStart("learningcanvas:paint");
|
|
15753
16234
|
const canvas = canvasRef.current;
|
|
@@ -15766,15 +16247,15 @@ var init_LearningCanvas = __esm({
|
|
|
15766
16247
|
ctx.fillRect(0, 0, width, height);
|
|
15767
16248
|
}
|
|
15768
16249
|
for (const shape of derivedShapes) {
|
|
15769
|
-
if (shape.type !== "text") drawShape(ctx, shape, width, height, derivedShapes);
|
|
16250
|
+
if (shape.type !== "text") drawShape(ctx, shape, width, height, derivedShapes, fontFamily);
|
|
15770
16251
|
}
|
|
15771
16252
|
for (const shape of derivedShapes) {
|
|
15772
|
-
if (shape.type === "text") drawShape(ctx, shape, width, height, derivedShapes);
|
|
16253
|
+
if (shape.type === "text") drawShape(ctx, shape, width, height, derivedShapes, fontFamily);
|
|
15773
16254
|
}
|
|
15774
16255
|
if (drawables?.length && projector) {
|
|
15775
16256
|
const painter = createWebPainter(ctx, invalidateRef.current);
|
|
15776
16257
|
const timeMs = needsAnim && typeof performance !== "undefined" ? performance.now() : 0;
|
|
15777
|
-
const dctx = { projector, time: timeMs, invalidate: invalidateRef.current, fontFamily: themeBodyFont(canvas) };
|
|
16258
|
+
const dctx = { projector, time: timeMs, invalidate: invalidateRef.current, fontFamily: fontFamily || themeBodyFont(canvas) };
|
|
15778
16259
|
for (const node of drawables) {
|
|
15779
16260
|
paintDrawable(painter, node, dctx);
|
|
15780
16261
|
}
|
|
@@ -19546,6 +20027,250 @@ var init_EmptyState = __esm({
|
|
|
19546
20027
|
EmptyState.displayName = "EmptyState";
|
|
19547
20028
|
}
|
|
19548
20029
|
});
|
|
20030
|
+
|
|
20031
|
+
// lib/editorMotions.ts
|
|
20032
|
+
function clamp(value, min, max) {
|
|
20033
|
+
return Math.max(min, Math.min(max, value));
|
|
20034
|
+
}
|
|
20035
|
+
function computeLines(text) {
|
|
20036
|
+
const lines = [];
|
|
20037
|
+
let start = 0;
|
|
20038
|
+
for (let i = 0; i <= text.length; i++) {
|
|
20039
|
+
if (i === text.length || text[i] === "\n") {
|
|
20040
|
+
lines.push({ start, end: i });
|
|
20041
|
+
start = i + 1;
|
|
20042
|
+
}
|
|
20043
|
+
}
|
|
20044
|
+
return lines;
|
|
20045
|
+
}
|
|
20046
|
+
function lineIndexAt(lines, pos) {
|
|
20047
|
+
for (let i = 0; i < lines.length; i++) {
|
|
20048
|
+
if (pos <= lines[i].end) return i;
|
|
20049
|
+
}
|
|
20050
|
+
return lines.length - 1;
|
|
20051
|
+
}
|
|
20052
|
+
function findWords(text) {
|
|
20053
|
+
const words = [];
|
|
20054
|
+
const re = /\w+|\S+/g;
|
|
20055
|
+
let m;
|
|
20056
|
+
while ((m = re.exec(text)) !== null) {
|
|
20057
|
+
words.push({ start: m.index, end: m.index + m[0].length });
|
|
20058
|
+
}
|
|
20059
|
+
return words;
|
|
20060
|
+
}
|
|
20061
|
+
function nextWordStart(text, pos) {
|
|
20062
|
+
for (const w of findWords(text)) {
|
|
20063
|
+
if (w.start > pos) return w.start;
|
|
20064
|
+
}
|
|
20065
|
+
return text.length;
|
|
20066
|
+
}
|
|
20067
|
+
function prevWordStart(text, pos) {
|
|
20068
|
+
let result = 0;
|
|
20069
|
+
for (const w of findWords(text)) {
|
|
20070
|
+
if (w.start < pos) result = w.start;
|
|
20071
|
+
else break;
|
|
20072
|
+
}
|
|
20073
|
+
return result;
|
|
20074
|
+
}
|
|
20075
|
+
function nextWordEnd(text, pos) {
|
|
20076
|
+
for (const w of findWords(text)) {
|
|
20077
|
+
const lastChar = w.end - 1;
|
|
20078
|
+
if (lastChar > pos) return lastChar;
|
|
20079
|
+
}
|
|
20080
|
+
return text.length > 0 ? text.length - 1 : 0;
|
|
20081
|
+
}
|
|
20082
|
+
function firstNonBlank(text, line) {
|
|
20083
|
+
let i = line.start;
|
|
20084
|
+
while (i < line.end && (text[i] === " " || text[i] === " ")) i++;
|
|
20085
|
+
return i;
|
|
20086
|
+
}
|
|
20087
|
+
function nextParagraphBoundary(lines, fromLineIdx, textLength) {
|
|
20088
|
+
for (let i = fromLineIdx + 1; i < lines.length; i++) {
|
|
20089
|
+
if (lines[i].start === lines[i].end) return lines[i].start;
|
|
20090
|
+
}
|
|
20091
|
+
return textLength;
|
|
20092
|
+
}
|
|
20093
|
+
function prevParagraphBoundary(lines, fromLineIdx) {
|
|
20094
|
+
for (let i = fromLineIdx - 1; i >= 0; i--) {
|
|
20095
|
+
if (lines[i].start === lines[i].end) return lines[i].start;
|
|
20096
|
+
}
|
|
20097
|
+
return 0;
|
|
20098
|
+
}
|
|
20099
|
+
function applyMotion(text, caret, motion, count) {
|
|
20100
|
+
const n = Math.max(1, count);
|
|
20101
|
+
const lines = computeLines(text);
|
|
20102
|
+
const lineIdx = lineIndexAt(lines, caret);
|
|
20103
|
+
const line = lines[lineIdx];
|
|
20104
|
+
switch (motion) {
|
|
20105
|
+
case "left":
|
|
20106
|
+
return clamp(caret - n, line.start, line.end);
|
|
20107
|
+
case "right":
|
|
20108
|
+
return clamp(caret + n, line.start, line.end);
|
|
20109
|
+
case "up": {
|
|
20110
|
+
const col = caret - line.start;
|
|
20111
|
+
const targetIdx = clamp(lineIdx - n, 0, lines.length - 1);
|
|
20112
|
+
const target = lines[targetIdx];
|
|
20113
|
+
return clamp(target.start + col, target.start, target.end);
|
|
20114
|
+
}
|
|
20115
|
+
case "down": {
|
|
20116
|
+
const col = caret - line.start;
|
|
20117
|
+
const targetIdx = clamp(lineIdx + n, 0, lines.length - 1);
|
|
20118
|
+
const target = lines[targetIdx];
|
|
20119
|
+
return clamp(target.start + col, target.start, target.end);
|
|
20120
|
+
}
|
|
20121
|
+
case "word-forward": {
|
|
20122
|
+
let pos = caret;
|
|
20123
|
+
for (let i = 0; i < n; i++) pos = nextWordStart(text, pos);
|
|
20124
|
+
return pos;
|
|
20125
|
+
}
|
|
20126
|
+
case "word-back": {
|
|
20127
|
+
let pos = caret;
|
|
20128
|
+
for (let i = 0; i < n; i++) pos = prevWordStart(text, pos);
|
|
20129
|
+
return pos;
|
|
20130
|
+
}
|
|
20131
|
+
case "word-end": {
|
|
20132
|
+
let pos = caret;
|
|
20133
|
+
for (let i = 0; i < n; i++) pos = nextWordEnd(text, pos);
|
|
20134
|
+
return pos;
|
|
20135
|
+
}
|
|
20136
|
+
case "line-start":
|
|
20137
|
+
return line.start;
|
|
20138
|
+
case "line-end":
|
|
20139
|
+
return line.end > line.start ? line.end - 1 : line.start;
|
|
20140
|
+
case "first-nonblank":
|
|
20141
|
+
return firstNonBlank(text, line);
|
|
20142
|
+
case "doc-start":
|
|
20143
|
+
return 0;
|
|
20144
|
+
case "doc-end":
|
|
20145
|
+
return text.length;
|
|
20146
|
+
case "paragraph-forward": {
|
|
20147
|
+
let pos = caret;
|
|
20148
|
+
for (let i = 0; i < n; i++) {
|
|
20149
|
+
pos = nextParagraphBoundary(lines, lineIndexAt(lines, pos), text.length);
|
|
20150
|
+
}
|
|
20151
|
+
return pos;
|
|
20152
|
+
}
|
|
20153
|
+
case "paragraph-back": {
|
|
20154
|
+
let pos = caret;
|
|
20155
|
+
for (let i = 0; i < n; i++) {
|
|
20156
|
+
pos = prevParagraphBoundary(lines, lineIndexAt(lines, pos));
|
|
20157
|
+
}
|
|
20158
|
+
return pos;
|
|
20159
|
+
}
|
|
20160
|
+
case "line":
|
|
20161
|
+
case "selection":
|
|
20162
|
+
return caret;
|
|
20163
|
+
default: {
|
|
20164
|
+
const _exhaustive = motion;
|
|
20165
|
+
return _exhaustive;
|
|
20166
|
+
}
|
|
20167
|
+
}
|
|
20168
|
+
}
|
|
20169
|
+
function motionRange(text, caret, motion, count, selection) {
|
|
20170
|
+
if (motion === "selection") {
|
|
20171
|
+
if (!selection) return [caret, caret];
|
|
20172
|
+
return [Math.min(selection[0], selection[1]), Math.max(selection[0], selection[1])];
|
|
20173
|
+
}
|
|
20174
|
+
const lines = computeLines(text);
|
|
20175
|
+
if (motion === "line") {
|
|
20176
|
+
const n = Math.max(1, count);
|
|
20177
|
+
const startIdx = lineIndexAt(lines, caret);
|
|
20178
|
+
const endIdx = clamp(startIdx + n - 1, 0, lines.length - 1);
|
|
20179
|
+
const start2 = lines[startIdx].start;
|
|
20180
|
+
const rawEnd = lines[endIdx].end;
|
|
20181
|
+
const end2 = rawEnd < text.length ? rawEnd + 1 : rawEnd;
|
|
20182
|
+
return [start2, end2];
|
|
20183
|
+
}
|
|
20184
|
+
const newCaret = applyMotion(text, caret, motion, count);
|
|
20185
|
+
let start = Math.min(caret, newCaret);
|
|
20186
|
+
let end = Math.max(caret, newCaret);
|
|
20187
|
+
if (motion === "word-end" || motion === "line-end") {
|
|
20188
|
+
end = Math.min(Math.max(start, newCaret) + 1, text.length);
|
|
20189
|
+
} else if (motion === "word-forward" && newCaret > caret) {
|
|
20190
|
+
const startLine = lineIndexAt(lines, caret);
|
|
20191
|
+
const endLine = lineIndexAt(lines, newCaret);
|
|
20192
|
+
if (endLine !== startLine) {
|
|
20193
|
+
end = lines[startLine].end;
|
|
20194
|
+
}
|
|
20195
|
+
}
|
|
20196
|
+
return [start, end];
|
|
20197
|
+
}
|
|
20198
|
+
function applyOperator(text, range, operator, register) {
|
|
20199
|
+
const start = clamp(range[0], 0, text.length);
|
|
20200
|
+
const end = clamp(range[1], start, text.length);
|
|
20201
|
+
const removed = text.slice(start, end);
|
|
20202
|
+
if (operator === "yank") {
|
|
20203
|
+
return { text, caret: start, register: removed };
|
|
20204
|
+
}
|
|
20205
|
+
return { text: text.slice(0, start) + text.slice(end), caret: start, register: removed };
|
|
20206
|
+
}
|
|
20207
|
+
var init_editorMotions = __esm({
|
|
20208
|
+
"lib/editorMotions.ts"() {
|
|
20209
|
+
}
|
|
20210
|
+
});
|
|
20211
|
+
function isMotionPayload(payload) {
|
|
20212
|
+
return !!payload && typeof payload.editorId === "string" && typeof payload.motion === "string" && typeof payload.count === "number";
|
|
20213
|
+
}
|
|
20214
|
+
function isOperatePayload(payload) {
|
|
20215
|
+
return !!payload && typeof payload.editorId === "string" && typeof payload.operator === "string" && typeof payload.motion === "string" && typeof payload.count === "number";
|
|
20216
|
+
}
|
|
20217
|
+
function isInsertTextPayload(payload) {
|
|
20218
|
+
return !!payload && typeof payload.editorId === "string" && typeof payload.text === "string";
|
|
20219
|
+
}
|
|
20220
|
+
function isSetModePayload(payload) {
|
|
20221
|
+
return !!payload && typeof payload.editorId === "string" && typeof payload.mode === "string" && typeof payload.caret === "string";
|
|
20222
|
+
}
|
|
20223
|
+
function useEditorCapabilities(args) {
|
|
20224
|
+
const [caretMode, setCaretMode] = useState("bar");
|
|
20225
|
+
const registerRef = useRef("");
|
|
20226
|
+
useEventListener(`UI:${args.events.onMotion}`, (evt) => {
|
|
20227
|
+
if (!args.editorId || !isMotionPayload(evt.payload) || evt.payload.editorId !== args.editorId) return;
|
|
20228
|
+
const ta = args.textareaRef.current;
|
|
20229
|
+
if (!ta) return;
|
|
20230
|
+
const { motion, count } = evt.payload;
|
|
20231
|
+
const newCaret = applyMotion(ta.value, ta.selectionStart, motion, count);
|
|
20232
|
+
if (ta.selectionStart !== ta.selectionEnd) {
|
|
20233
|
+
ta.setSelectionRange(ta.selectionStart, newCaret);
|
|
20234
|
+
} else {
|
|
20235
|
+
ta.setSelectionRange(newCaret, newCaret);
|
|
20236
|
+
}
|
|
20237
|
+
});
|
|
20238
|
+
useEventListener(`UI:${args.events.onOperate}`, (evt) => {
|
|
20239
|
+
if (!args.editorId || !isOperatePayload(evt.payload) || evt.payload.editorId !== args.editorId) return;
|
|
20240
|
+
const ta = args.textareaRef.current;
|
|
20241
|
+
if (!ta) return;
|
|
20242
|
+
const { operator, motion, count } = evt.payload;
|
|
20243
|
+
const selection = motion === "selection" ? [ta.selectionStart, ta.selectionEnd] : void 0;
|
|
20244
|
+
const range = motionRange(ta.value, ta.selectionStart, motion, count, selection);
|
|
20245
|
+
const result = applyOperator(ta.value, range, operator, registerRef.current);
|
|
20246
|
+
registerRef.current = result.register;
|
|
20247
|
+
if (operator === "yank") {
|
|
20248
|
+
ta.setSelectionRange(range[0], range[0]);
|
|
20249
|
+
} else {
|
|
20250
|
+
ta.setRangeText("", range[0], range[1], "end");
|
|
20251
|
+
}
|
|
20252
|
+
args.applyChange(ta.value);
|
|
20253
|
+
});
|
|
20254
|
+
useEventListener(`UI:${args.events.onInsertText}`, (evt) => {
|
|
20255
|
+
if (!args.editorId || !isInsertTextPayload(evt.payload) || evt.payload.editorId !== args.editorId) return;
|
|
20256
|
+
const ta = args.textareaRef.current;
|
|
20257
|
+
if (!ta) return;
|
|
20258
|
+
ta.setRangeText(evt.payload.text, ta.selectionStart, ta.selectionEnd, "end");
|
|
20259
|
+
args.applyChange(ta.value);
|
|
20260
|
+
});
|
|
20261
|
+
useEventListener(`UI:${args.events.onSetMode}`, (evt) => {
|
|
20262
|
+
if (!args.editorId || !isSetModePayload(evt.payload) || evt.payload.editorId !== args.editorId) return;
|
|
20263
|
+
setCaretMode(evt.payload.caret);
|
|
20264
|
+
});
|
|
20265
|
+
return { caretMode };
|
|
20266
|
+
}
|
|
20267
|
+
var init_useEditorCapabilities = __esm({
|
|
20268
|
+
"components/core/molecules/markdown/useEditorCapabilities.ts"() {
|
|
20269
|
+
"use client";
|
|
20270
|
+
init_useEventBus();
|
|
20271
|
+
init_editorMotions();
|
|
20272
|
+
}
|
|
20273
|
+
});
|
|
19549
20274
|
function isLanguageRegistered(lang) {
|
|
19550
20275
|
return CODE_LANGUAGE_SET.has(lang) || dynamicallyLoaded.has(lang);
|
|
19551
20276
|
}
|
|
@@ -19631,7 +20356,36 @@ function useLanguageReady(language) {
|
|
|
19631
20356
|
}, [language]);
|
|
19632
20357
|
return ready;
|
|
19633
20358
|
}
|
|
19634
|
-
|
|
20359
|
+
function resolveHighlightStyle(lang) {
|
|
20360
|
+
if (lang === "orb") return orbStyle;
|
|
20361
|
+
if (lang === "lolo") return loloStyle;
|
|
20362
|
+
return dark;
|
|
20363
|
+
}
|
|
20364
|
+
function plainCodeColorOf(style) {
|
|
20365
|
+
return style['code[class*="language-"]']?.color ?? "#d4d4d4";
|
|
20366
|
+
}
|
|
20367
|
+
function buildLineProps(errorLines, extraClassName) {
|
|
20368
|
+
return (lineNumber) => {
|
|
20369
|
+
const base = {
|
|
20370
|
+
"data-line": String(lineNumber - 1),
|
|
20371
|
+
...extraClassName ? { className: extraClassName } : {}
|
|
20372
|
+
};
|
|
20373
|
+
const severity = errorLines?.get(lineNumber);
|
|
20374
|
+
if (!severity) return base;
|
|
20375
|
+
return {
|
|
20376
|
+
...base,
|
|
20377
|
+
style: {
|
|
20378
|
+
display: "block",
|
|
20379
|
+
backgroundColor: severity === "error" ? "rgba(248, 113, 113, 0.18)" : "rgba(251, 191, 36, 0.18)",
|
|
20380
|
+
// amber-400 @ 18%
|
|
20381
|
+
borderLeft: `3px solid ${severity === "error" ? "#ef4444" : "#f59e0b"}`,
|
|
20382
|
+
paddingLeft: "0.5rem",
|
|
20383
|
+
marginLeft: "-0.5rem"
|
|
20384
|
+
}
|
|
20385
|
+
};
|
|
20386
|
+
};
|
|
20387
|
+
}
|
|
20388
|
+
var dynamicallyLoaded, codeLanguageLoader, orbStyleOverrides, orbStyle, loloStyleOverrides, loloStyle, log4, 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;
|
|
19635
20389
|
var init_CodeBlock = __esm({
|
|
19636
20390
|
"components/core/molecules/markdown/CodeBlock.tsx"() {
|
|
19637
20391
|
init_cn();
|
|
@@ -19647,6 +20401,7 @@ var init_CodeBlock = __esm({
|
|
|
19647
20401
|
init_Textarea();
|
|
19648
20402
|
init_Icon();
|
|
19649
20403
|
init_useEventBus();
|
|
20404
|
+
init_useEditorCapabilities();
|
|
19650
20405
|
SyntaxHighlighter.registerLanguage("json", langJson);
|
|
19651
20406
|
SyntaxHighlighter.registerLanguage("javascript", langJavascript);
|
|
19652
20407
|
SyntaxHighlighter.registerLanguage("js", langJavascript);
|
|
@@ -19865,6 +20620,15 @@ var init_CodeBlock = __esm({
|
|
|
19865
20620
|
LINE_PROPS_FN = (n) => ({ "data-line": String(n - 1) });
|
|
19866
20621
|
HIDDEN_LINE_NUMBERS = { display: "none" };
|
|
19867
20622
|
HIGHLIGHT_CAPACITY_BYTES = 512 * 1024;
|
|
20623
|
+
MONO_FONT_FAMILY = 'ui-monospace, SFMono-Regular, Menlo, Monaco, "Cascadia Mono", "Courier New", monospace';
|
|
20624
|
+
VIEWER_LINE_NUMBER_STYLE = {
|
|
20625
|
+
minWidth: "2.5em",
|
|
20626
|
+
paddingRight: "1rem",
|
|
20627
|
+
textAlign: "right",
|
|
20628
|
+
userSelect: "none",
|
|
20629
|
+
opacity: 0.5,
|
|
20630
|
+
fontVariantNumeric: "tabular-nums"
|
|
20631
|
+
};
|
|
19868
20632
|
CodeBlock = React96__default.memo(
|
|
19869
20633
|
({
|
|
19870
20634
|
code: rawCode,
|
|
@@ -19889,15 +20653,39 @@ var init_CodeBlock = __esm({
|
|
|
19889
20653
|
actions,
|
|
19890
20654
|
isLoading = false,
|
|
19891
20655
|
error,
|
|
19892
|
-
showCopy
|
|
20656
|
+
showCopy,
|
|
20657
|
+
// editor capability surface — P1 wires these
|
|
20658
|
+
editorId,
|
|
20659
|
+
onEditorFocus = "EDITOR_FOCUS",
|
|
20660
|
+
onEditorBlur = "EDITOR_BLUR",
|
|
20661
|
+
onMotion = "MOTION",
|
|
20662
|
+
onOperate = "OPERATE",
|
|
20663
|
+
onInsertText = "INSERT_TEXT",
|
|
20664
|
+
onSetMode = "SET_MODE",
|
|
20665
|
+
motions = [
|
|
20666
|
+
"left",
|
|
20667
|
+
"right",
|
|
20668
|
+
"up",
|
|
20669
|
+
"down",
|
|
20670
|
+
"word-forward",
|
|
20671
|
+
"word-back",
|
|
20672
|
+
"word-end",
|
|
20673
|
+
"line-start",
|
|
20674
|
+
"line-end",
|
|
20675
|
+
"first-nonblank",
|
|
20676
|
+
"doc-start",
|
|
20677
|
+
"doc-end",
|
|
20678
|
+
"paragraph-forward",
|
|
20679
|
+
"paragraph-back",
|
|
20680
|
+
"line",
|
|
20681
|
+
"selection"
|
|
20682
|
+
],
|
|
20683
|
+
operators = ["delete", "yank", "change"]
|
|
19893
20684
|
}) => {
|
|
19894
20685
|
const code = typeof rawCode === "string" ? rawCode : String(rawCode ?? "");
|
|
19895
|
-
const
|
|
19896
|
-
const isLolo = language === "lolo";
|
|
19897
|
-
const activeStyle = isOrb ? orbStyle : isLolo ? loloStyle : dark;
|
|
20686
|
+
const activeStyle = resolveHighlightStyle(language);
|
|
19898
20687
|
const overCapacity = code.length > HIGHLIGHT_CAPACITY_BYTES;
|
|
19899
|
-
const plainCodeColor = activeStyle
|
|
19900
|
-
const languageReady = useLanguageReady(language);
|
|
20688
|
+
const plainCodeColor = plainCodeColorOf(activeStyle);
|
|
19901
20689
|
const eventBus = useEventBus();
|
|
19902
20690
|
const { t } = useTranslate();
|
|
19903
20691
|
const scrollRef = useRef(null);
|
|
@@ -19909,6 +20697,9 @@ var init_CodeBlock = __esm({
|
|
|
19909
20697
|
const activeFile = files?.[activeFileIndex];
|
|
19910
20698
|
const activeCode = activeFile?.code ?? code;
|
|
19911
20699
|
const activeLanguage = activeFile?.language ?? language;
|
|
20700
|
+
const languageReady = useLanguageReady(activeLanguage);
|
|
20701
|
+
const viewerStyle = resolveHighlightStyle(activeLanguage);
|
|
20702
|
+
const viewerPlainCodeColor = plainCodeColorOf(viewerStyle);
|
|
19912
20703
|
const diffLines = useMemo(() => {
|
|
19913
20704
|
if (propDiff) return propDiff;
|
|
19914
20705
|
if (mode === "diff" && oldValue !== void 0 && newValue !== void 0) {
|
|
@@ -19938,28 +20729,28 @@ var init_CodeBlock = __esm({
|
|
|
19938
20729
|
ov.scrollLeft = ta.scrollLeft;
|
|
19939
20730
|
}
|
|
19940
20731
|
}, []);
|
|
19941
|
-
const
|
|
19942
|
-
|
|
19943
|
-
|
|
19944
|
-
|
|
19945
|
-
|
|
19946
|
-
|
|
19947
|
-
|
|
19948
|
-
|
|
19949
|
-
|
|
19950
|
-
|
|
19951
|
-
|
|
19952
|
-
|
|
19953
|
-
|
|
19954
|
-
|
|
19955
|
-
|
|
19956
|
-
|
|
19957
|
-
|
|
19958
|
-
|
|
19959
|
-
|
|
19960
|
-
|
|
19961
|
-
|
|
19962
|
-
|
|
20732
|
+
const handleEditableChange = useCallback((v) => {
|
|
20733
|
+
lastPropCodeRef.current = v;
|
|
20734
|
+
setEditableValue(v);
|
|
20735
|
+
onChange?.(v);
|
|
20736
|
+
}, [onChange]);
|
|
20737
|
+
const { caretMode } = useEditorCapabilities({
|
|
20738
|
+
editorId: editable ? editorId : void 0,
|
|
20739
|
+
textareaRef: editableTextareaRef,
|
|
20740
|
+
events: { onMotion, onOperate, onInsertText, onSetMode },
|
|
20741
|
+
applyChange: handleEditableChange
|
|
20742
|
+
});
|
|
20743
|
+
const [caretIndex, setCaretIndex] = useState(0);
|
|
20744
|
+
const caretRowCol = useMemo(() => {
|
|
20745
|
+
const before = editableValue.slice(0, Math.min(caretIndex, editableValue.length));
|
|
20746
|
+
const lines = before.split("\n");
|
|
20747
|
+
return { row: lines.length - 1, col: lines[lines.length - 1].length };
|
|
20748
|
+
}, [editableValue, caretIndex]);
|
|
20749
|
+
const errorLineProps = useMemo(() => buildLineProps(errorLines), [errorLines]);
|
|
20750
|
+
const viewerLineProps = useMemo(
|
|
20751
|
+
() => buildLineProps(errorLines, "px-4 py-0.5 hover:bg-muted/50"),
|
|
20752
|
+
[errorLines]
|
|
20753
|
+
);
|
|
19963
20754
|
const isFoldable = foldableProp ?? true;
|
|
19964
20755
|
const [collapsed, setCollapsed] = useState(() => /* @__PURE__ */ new Set());
|
|
19965
20756
|
const foldRegions = useMemo(
|
|
@@ -20082,6 +20873,110 @@ var init_CodeBlock = __esm({
|
|
|
20082
20873
|
),
|
|
20083
20874
|
[code, overCapacity, plainCodeColor, language, activeStyle, languageReady]
|
|
20084
20875
|
);
|
|
20876
|
+
const viewerOverCapacity = activeCode.length > HIGHLIGHT_CAPACITY_BYTES;
|
|
20877
|
+
const viewerHighlightedElement = useMemo(
|
|
20878
|
+
() => viewerOverCapacity ? /* @__PURE__ */ jsx(
|
|
20879
|
+
"div",
|
|
20880
|
+
{
|
|
20881
|
+
className: "px-4 py-0.5",
|
|
20882
|
+
style: {
|
|
20883
|
+
margin: 0,
|
|
20884
|
+
whiteSpace: wrap ? "pre-wrap" : "pre",
|
|
20885
|
+
wordBreak: wrap ? "break-all" : "normal",
|
|
20886
|
+
color: viewerPlainCodeColor,
|
|
20887
|
+
fontFamily: MONO_FONT_FAMILY,
|
|
20888
|
+
fontSize: "12px",
|
|
20889
|
+
lineHeight: "1.6"
|
|
20890
|
+
},
|
|
20891
|
+
children: activeCode
|
|
20892
|
+
}
|
|
20893
|
+
) : /* @__PURE__ */ jsx(
|
|
20894
|
+
SyntaxHighlighter,
|
|
20895
|
+
{
|
|
20896
|
+
PreTag: "div",
|
|
20897
|
+
language: activeLanguage,
|
|
20898
|
+
style: viewerStyle,
|
|
20899
|
+
wrapLines: true,
|
|
20900
|
+
wrapLongLines: wrap,
|
|
20901
|
+
showLineNumbers,
|
|
20902
|
+
lineNumberStyle: VIEWER_LINE_NUMBER_STYLE,
|
|
20903
|
+
lineProps: viewerLineProps,
|
|
20904
|
+
customStyle: {
|
|
20905
|
+
backgroundColor: "transparent",
|
|
20906
|
+
borderRadius: 0,
|
|
20907
|
+
padding: "0.25rem 0",
|
|
20908
|
+
margin: 0,
|
|
20909
|
+
whiteSpace: wrap ? "pre-wrap" : "pre",
|
|
20910
|
+
wordBreak: wrap ? "break-all" : "normal",
|
|
20911
|
+
fontFamily: MONO_FONT_FAMILY,
|
|
20912
|
+
fontSize: "12px",
|
|
20913
|
+
lineHeight: "1.6"
|
|
20914
|
+
},
|
|
20915
|
+
codeTagProps: { style: { fontFamily: MONO_FONT_FAMILY, fontSize: "12px", lineHeight: "1.6" } },
|
|
20916
|
+
children: activeCode
|
|
20917
|
+
}
|
|
20918
|
+
),
|
|
20919
|
+
[activeCode, viewerOverCapacity, viewerPlainCodeColor, activeLanguage, viewerStyle, wrap, showLineNumbers, viewerLineProps, languageReady]
|
|
20920
|
+
);
|
|
20921
|
+
const diffOverCapacity = useMemo(
|
|
20922
|
+
() => !!diffLines && diffLines.reduce((n, l) => n + l.content.length + 1, 0) > HIGHLIGHT_CAPACITY_BYTES,
|
|
20923
|
+
[diffLines]
|
|
20924
|
+
);
|
|
20925
|
+
const diffRowElements = useMemo(() => {
|
|
20926
|
+
if (!diffLines) return null;
|
|
20927
|
+
return diffLines.map((line, idx) => {
|
|
20928
|
+
const style = DIFF_STYLES[line.type] ?? DIFF_STYLE_FALLBACK;
|
|
20929
|
+
return /* @__PURE__ */ jsxs(HStack, { gap: "none", align: "start", className: cn(style.bg, "px-4 py-0.5"), children: [
|
|
20930
|
+
showLineNumbers && /* @__PURE__ */ jsx(
|
|
20931
|
+
Typography,
|
|
20932
|
+
{
|
|
20933
|
+
variant: "caption",
|
|
20934
|
+
color: "secondary",
|
|
20935
|
+
className: "w-8 text-right mr-3 select-none tabular-nums flex-shrink-0",
|
|
20936
|
+
children: line.lineNumber ?? ""
|
|
20937
|
+
}
|
|
20938
|
+
),
|
|
20939
|
+
/* @__PURE__ */ jsxs(
|
|
20940
|
+
Typography,
|
|
20941
|
+
{
|
|
20942
|
+
variant: "caption",
|
|
20943
|
+
className: cn("font-mono flex-1 min-w-0", style.text, wrap ? "whitespace-pre-wrap break-all" : "whitespace-pre"),
|
|
20944
|
+
children: [
|
|
20945
|
+
/* @__PURE__ */ jsx(Box, { as: "span", className: "select-none opacity-50 mr-2", children: style.prefix }),
|
|
20946
|
+
diffOverCapacity ? line.content || " " : /* @__PURE__ */ jsx(
|
|
20947
|
+
SyntaxHighlighter,
|
|
20948
|
+
{
|
|
20949
|
+
PreTag: "span",
|
|
20950
|
+
CodeTag: "span",
|
|
20951
|
+
language: activeLanguage,
|
|
20952
|
+
style: viewerStyle,
|
|
20953
|
+
customStyle: {
|
|
20954
|
+
display: "inline",
|
|
20955
|
+
background: "transparent",
|
|
20956
|
+
padding: 0,
|
|
20957
|
+
margin: 0,
|
|
20958
|
+
whiteSpace: wrap ? "pre-wrap" : "pre",
|
|
20959
|
+
wordBreak: wrap ? "break-all" : "normal",
|
|
20960
|
+
fontFamily: "inherit",
|
|
20961
|
+
fontSize: "inherit",
|
|
20962
|
+
lineHeight: "inherit"
|
|
20963
|
+
},
|
|
20964
|
+
codeTagProps: {
|
|
20965
|
+
style: {
|
|
20966
|
+
whiteSpace: wrap ? "pre-wrap" : "pre",
|
|
20967
|
+
fontFamily: "inherit",
|
|
20968
|
+
fontSize: "inherit"
|
|
20969
|
+
}
|
|
20970
|
+
},
|
|
20971
|
+
children: line.content || " "
|
|
20972
|
+
}
|
|
20973
|
+
)
|
|
20974
|
+
]
|
|
20975
|
+
}
|
|
20976
|
+
)
|
|
20977
|
+
] }, idx);
|
|
20978
|
+
});
|
|
20979
|
+
}, [diffLines, showLineNumbers, wrap, diffOverCapacity, activeLanguage, viewerStyle, languageReady]);
|
|
20085
20980
|
useLayoutEffect(() => {
|
|
20086
20981
|
const container = codeRef.current;
|
|
20087
20982
|
if (!container) return;
|
|
@@ -20225,7 +21120,6 @@ var init_CodeBlock = __esm({
|
|
|
20225
21120
|
label: file.label,
|
|
20226
21121
|
content: null
|
|
20227
21122
|
}));
|
|
20228
|
-
const lines = activeCode.split("\n");
|
|
20229
21123
|
return /* @__PURE__ */ jsx(Card, { className: cn("overflow-hidden", className), children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column" }, children: [
|
|
20230
21124
|
tabItems && tabItems.length > 1 && /* @__PURE__ */ jsx(Box, { className: "border-b border-border", children: /* @__PURE__ */ jsx(
|
|
20231
21125
|
Tabs,
|
|
@@ -20288,49 +21182,7 @@ var init_CodeBlock = __esm({
|
|
|
20288
21182
|
]
|
|
20289
21183
|
}
|
|
20290
21184
|
),
|
|
20291
|
-
/* @__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:
|
|
20292
|
-
const style = DIFF_STYLES[line.type] ?? DIFF_STYLE_FALLBACK;
|
|
20293
|
-
return /* @__PURE__ */ jsxs(HStack, { gap: "none", align: "start", className: cn(style.bg, "px-4 py-0.5"), children: [
|
|
20294
|
-
showLineNumbers && /* @__PURE__ */ jsx(
|
|
20295
|
-
Typography,
|
|
20296
|
-
{
|
|
20297
|
-
variant: "caption",
|
|
20298
|
-
color: "secondary",
|
|
20299
|
-
className: "w-8 text-right mr-3 select-none tabular-nums flex-shrink-0",
|
|
20300
|
-
children: line.lineNumber ?? ""
|
|
20301
|
-
}
|
|
20302
|
-
),
|
|
20303
|
-
/* @__PURE__ */ jsxs(
|
|
20304
|
-
Typography,
|
|
20305
|
-
{
|
|
20306
|
-
variant: "caption",
|
|
20307
|
-
className: cn("font-mono flex-1 min-w-0", style.text, wrap ? "whitespace-pre-wrap break-all" : "whitespace-pre"),
|
|
20308
|
-
children: [
|
|
20309
|
-
/* @__PURE__ */ jsx(Box, { as: "span", className: "select-none opacity-50 mr-2", children: style.prefix }),
|
|
20310
|
-
line.content
|
|
20311
|
-
]
|
|
20312
|
-
}
|
|
20313
|
-
)
|
|
20314
|
-
] }, idx);
|
|
20315
|
-
}) }) : /* @__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: [
|
|
20316
|
-
showLineNumbers && /* @__PURE__ */ jsx(
|
|
20317
|
-
Typography,
|
|
20318
|
-
{
|
|
20319
|
-
variant: "caption",
|
|
20320
|
-
color: "secondary",
|
|
20321
|
-
className: "w-8 text-right mr-4 select-none tabular-nums flex-shrink-0",
|
|
20322
|
-
children: idx + 1
|
|
20323
|
-
}
|
|
20324
|
-
),
|
|
20325
|
-
/* @__PURE__ */ jsx(
|
|
20326
|
-
Typography,
|
|
20327
|
-
{
|
|
20328
|
-
variant: "caption",
|
|
20329
|
-
className: cn("font-mono flex-1 min-w-0", wrap ? "whitespace-pre-wrap break-all" : "whitespace-pre"),
|
|
20330
|
-
children: line || " "
|
|
20331
|
-
}
|
|
20332
|
-
)
|
|
20333
|
-
] }, idx)) }) })
|
|
21185
|
+
/* @__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 }) })
|
|
20334
21186
|
] }) });
|
|
20335
21187
|
}
|
|
20336
21188
|
const hasHeader = showLanguageBadge || effectiveCopy;
|
|
@@ -20417,13 +21269,11 @@ var init_CodeBlock = __esm({
|
|
|
20417
21269
|
{
|
|
20418
21270
|
ref: editableTextareaRef,
|
|
20419
21271
|
defaultValue: code,
|
|
20420
|
-
onChange: (e) =>
|
|
20421
|
-
const v = e.target.value;
|
|
20422
|
-
lastPropCodeRef.current = v;
|
|
20423
|
-
setEditableValue(v);
|
|
20424
|
-
onChange?.(v);
|
|
20425
|
-
},
|
|
21272
|
+
onChange: (e) => handleEditableChange(e.target.value),
|
|
20426
21273
|
onScroll: handleEditableScroll,
|
|
21274
|
+
onSelect: (e) => setCaretIndex(e.currentTarget.selectionStart),
|
|
21275
|
+
onFocus: editorId ? () => eventBus.emit(`UI:${onEditorFocus}`, { editorId }) : void 0,
|
|
21276
|
+
onBlur: editorId ? () => eventBus.emit(`UI:${onEditorBlur}`, { editorId }) : void 0,
|
|
20427
21277
|
spellCheck: false,
|
|
20428
21278
|
style: {
|
|
20429
21279
|
position: "absolute",
|
|
@@ -20438,7 +21288,7 @@ var init_CodeBlock = __esm({
|
|
|
20438
21288
|
resize: "none",
|
|
20439
21289
|
backgroundColor: "transparent",
|
|
20440
21290
|
color: "transparent",
|
|
20441
|
-
caretColor: "#e6e6e6",
|
|
21291
|
+
caretColor: caretMode === "block" ? "transparent" : "#e6e6e6",
|
|
20442
21292
|
WebkitTextFillColor: "transparent",
|
|
20443
21293
|
fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, "Cascadia Mono", "Courier New", monospace',
|
|
20444
21294
|
fontSize: "13px",
|
|
@@ -20449,6 +21299,22 @@ var init_CodeBlock = __esm({
|
|
|
20449
21299
|
}
|
|
20450
21300
|
},
|
|
20451
21301
|
editableTextareaKey
|
|
21302
|
+
),
|
|
21303
|
+
caretMode !== "bar" && /* @__PURE__ */ jsx(
|
|
21304
|
+
"span",
|
|
21305
|
+
{
|
|
21306
|
+
"aria-hidden": true,
|
|
21307
|
+
style: {
|
|
21308
|
+
position: "absolute",
|
|
21309
|
+
top: `calc(1rem + ${caretRowCol.row * 19.5}px)`,
|
|
21310
|
+
left: `calc(1rem + ${caretRowCol.col}ch)`,
|
|
21311
|
+
width: "1ch",
|
|
21312
|
+
height: caretMode === "block" ? "19.5px" : "2px",
|
|
21313
|
+
backgroundColor: caretMode === "block" ? "rgba(230, 230, 230, 0.5)" : void 0,
|
|
21314
|
+
borderBottom: caretMode === "underline" ? "2px solid #e6e6e6" : void 0,
|
|
21315
|
+
pointerEvents: "none"
|
|
21316
|
+
}
|
|
21317
|
+
}
|
|
20452
21318
|
)
|
|
20453
21319
|
]
|
|
20454
21320
|
}
|
|
@@ -20476,55 +21342,175 @@ var init_CodeBlock = __esm({
|
|
|
20476
21342
|
)
|
|
20477
21343
|
] });
|
|
20478
21344
|
},
|
|
20479
|
-
(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
|
|
21345
|
+
(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
|
|
20480
21346
|
);
|
|
20481
21347
|
CodeBlock.displayName = "CodeBlock";
|
|
20482
21348
|
}
|
|
20483
21349
|
});
|
|
21350
|
+
|
|
21351
|
+
// components/core/molecules/markdown/mermaidSource.ts
|
|
21352
|
+
function isQuoted(label) {
|
|
21353
|
+
const trimmed = label.trim();
|
|
21354
|
+
return trimmed.length === 0 || trimmed.startsWith('"') && trimmed.endsWith('"') && trimmed.length > 1;
|
|
21355
|
+
}
|
|
21356
|
+
function quote(label) {
|
|
21357
|
+
return `"${label.replace(/"/g, "#quot;")}"`;
|
|
21358
|
+
}
|
|
21359
|
+
function isIdentifierChar(ch) {
|
|
21360
|
+
return /[A-Za-z0-9_\-.]/.test(ch);
|
|
21361
|
+
}
|
|
21362
|
+
function declaredType(code) {
|
|
21363
|
+
for (const line of code.split("\n")) {
|
|
21364
|
+
const trimmed = line.trim();
|
|
21365
|
+
if (trimmed.length === 0 || trimmed.startsWith("%%")) continue;
|
|
21366
|
+
return trimmed;
|
|
21367
|
+
}
|
|
21368
|
+
return "";
|
|
21369
|
+
}
|
|
21370
|
+
function isFlowchart(code) {
|
|
21371
|
+
return FLOWCHART_DIRECTIVE.test(declaredType(code));
|
|
21372
|
+
}
|
|
21373
|
+
function quoteNodeLabels(code) {
|
|
21374
|
+
let out = "";
|
|
21375
|
+
let i = 0;
|
|
21376
|
+
while (i < code.length) {
|
|
21377
|
+
const shape = NODE_SHAPES.find(([open2]) => code.startsWith(open2, i));
|
|
21378
|
+
const precededByIdentifier = i > 0 && isIdentifierChar(code[i - 1] ?? "");
|
|
21379
|
+
if (shape === void 0 || !precededByIdentifier) {
|
|
21380
|
+
out += code[i];
|
|
21381
|
+
i += 1;
|
|
21382
|
+
continue;
|
|
21383
|
+
}
|
|
21384
|
+
const [open, close] = shape;
|
|
21385
|
+
const contentStart = i + open.length;
|
|
21386
|
+
const closeAt = code.indexOf(close, contentStart);
|
|
21387
|
+
const newlineAt = code.indexOf("\n", contentStart);
|
|
21388
|
+
if (closeAt === -1 || newlineAt !== -1 && newlineAt < closeAt) {
|
|
21389
|
+
out += code[i];
|
|
21390
|
+
i += 1;
|
|
21391
|
+
continue;
|
|
21392
|
+
}
|
|
21393
|
+
const label = code.slice(contentStart, closeAt);
|
|
21394
|
+
out += open + (isQuoted(label) ? label : quote(label)) + close;
|
|
21395
|
+
i = closeAt + close.length;
|
|
21396
|
+
}
|
|
21397
|
+
return out;
|
|
21398
|
+
}
|
|
21399
|
+
function quoteEdgeLabels(code) {
|
|
21400
|
+
return code.split("\n").map((line) => {
|
|
21401
|
+
let out = "";
|
|
21402
|
+
let rest = line;
|
|
21403
|
+
for (; ; ) {
|
|
21404
|
+
const open = rest.indexOf("|");
|
|
21405
|
+
if (open === -1) break;
|
|
21406
|
+
const close = rest.indexOf("|", open + 1);
|
|
21407
|
+
if (close === -1) break;
|
|
21408
|
+
const label = rest.slice(open + 1, close);
|
|
21409
|
+
out += rest.slice(0, open + 1) + (isQuoted(label) ? label : quote(label)) + "|";
|
|
21410
|
+
rest = rest.slice(close + 1);
|
|
21411
|
+
}
|
|
21412
|
+
return out + rest;
|
|
21413
|
+
}).join("\n");
|
|
21414
|
+
}
|
|
21415
|
+
function quoteSubgraphTitles(code) {
|
|
21416
|
+
return code.split("\n").map((line) => {
|
|
21417
|
+
const match = /^(\s*subgraph\s+)(.+?)(\s*)$/.exec(line);
|
|
21418
|
+
if (match === null) return line;
|
|
21419
|
+
const [, prefix, title, trailing] = match;
|
|
21420
|
+
if (title === void 0 || prefix === void 0) return line;
|
|
21421
|
+
if (isQuoted(title) || title.includes("[")) return line;
|
|
21422
|
+
return prefix + quote(title) + (trailing ?? "");
|
|
21423
|
+
}).join("\n");
|
|
21424
|
+
}
|
|
21425
|
+
function mermaidRepairCandidates(code) {
|
|
21426
|
+
if (!isFlowchart(code)) return [];
|
|
21427
|
+
const nodes = quoteNodeLabels(code);
|
|
21428
|
+
const nodesAndEdges = quoteEdgeLabels(nodes);
|
|
21429
|
+
const all = quoteSubgraphTitles(nodesAndEdges);
|
|
21430
|
+
const ordered2 = [nodes, nodesAndEdges, all];
|
|
21431
|
+
const seen = /* @__PURE__ */ new Set([code]);
|
|
21432
|
+
const candidates = [];
|
|
21433
|
+
for (const candidate of ordered2) {
|
|
21434
|
+
if (seen.has(candidate)) continue;
|
|
21435
|
+
seen.add(candidate);
|
|
21436
|
+
candidates.push(candidate);
|
|
21437
|
+
}
|
|
21438
|
+
return candidates;
|
|
21439
|
+
}
|
|
21440
|
+
var NODE_SHAPES, FLOWCHART_DIRECTIVE;
|
|
21441
|
+
var init_mermaidSource = __esm({
|
|
21442
|
+
"components/core/molecules/markdown/mermaidSource.ts"() {
|
|
21443
|
+
NODE_SHAPES = [
|
|
21444
|
+
["[[", "]]"],
|
|
21445
|
+
["[(", ")]"],
|
|
21446
|
+
["([", "])"],
|
|
21447
|
+
["((", "))"],
|
|
21448
|
+
["{{", "}}"],
|
|
21449
|
+
["[", "]"],
|
|
21450
|
+
["(", ")"],
|
|
21451
|
+
["{", "}"]
|
|
21452
|
+
];
|
|
21453
|
+
FLOWCHART_DIRECTIVE = /^(?:graph|flowchart)\b/;
|
|
21454
|
+
}
|
|
21455
|
+
});
|
|
20484
21456
|
function loadMermaid() {
|
|
20485
21457
|
mermaidModule ?? (mermaidModule = import('mermaid').then((m) => m.default));
|
|
20486
21458
|
return mermaidModule;
|
|
20487
21459
|
}
|
|
20488
|
-
var mermaidModule, MermaidDiagram;
|
|
21460
|
+
var log5, mermaidModule, MermaidDiagram;
|
|
20489
21461
|
var init_MermaidDiagram = __esm({
|
|
20490
21462
|
"components/core/molecules/markdown/MermaidDiagram.tsx"() {
|
|
20491
21463
|
init_Box();
|
|
20492
21464
|
init_Typography();
|
|
20493
21465
|
init_CodeBlock();
|
|
21466
|
+
init_mermaidSource();
|
|
20494
21467
|
init_cn();
|
|
21468
|
+
log5 = createLogger("almadar:ui:mermaid-diagram");
|
|
20495
21469
|
mermaidModule = null;
|
|
20496
21470
|
MermaidDiagram = React96__default.memo(
|
|
20497
21471
|
({ code, className }) => {
|
|
20498
21472
|
const { resolvedMode } = useTheme();
|
|
21473
|
+
const { t } = useTranslate();
|
|
20499
21474
|
const containerRef = useRef(null);
|
|
20500
|
-
const [
|
|
21475
|
+
const [unrenderable, setUnrenderable] = useState(false);
|
|
20501
21476
|
const reactId = useId();
|
|
20502
21477
|
useEffect(() => {
|
|
20503
21478
|
let active = true;
|
|
20504
21479
|
void (async () => {
|
|
20505
|
-
|
|
20506
|
-
|
|
20507
|
-
|
|
20508
|
-
|
|
20509
|
-
|
|
20510
|
-
|
|
20511
|
-
|
|
20512
|
-
|
|
20513
|
-
|
|
20514
|
-
|
|
20515
|
-
|
|
20516
|
-
|
|
20517
|
-
|
|
20518
|
-
|
|
21480
|
+
const mermaid = await loadMermaid();
|
|
21481
|
+
mermaid.initialize({
|
|
21482
|
+
startOnLoad: false,
|
|
21483
|
+
securityLevel: "strict",
|
|
21484
|
+
theme: resolvedMode === "dark" ? "dark" : "default"
|
|
21485
|
+
});
|
|
21486
|
+
const domId = `mermaid-${reactId.replace(/[^a-zA-Z0-9]/g, "")}`;
|
|
21487
|
+
let firstError = null;
|
|
21488
|
+
for (const [index, source] of [code, ...mermaidRepairCandidates(code)].entries()) {
|
|
21489
|
+
try {
|
|
21490
|
+
const { svg } = await mermaid.render(domId, source);
|
|
21491
|
+
if (!active) return;
|
|
21492
|
+
const container = containerRef.current;
|
|
21493
|
+
if (container === null) return;
|
|
21494
|
+
container.innerHTML = svg;
|
|
21495
|
+
container.dataset.mermaidRepaired = String(index > 0);
|
|
21496
|
+
setUnrenderable(false);
|
|
21497
|
+
if (index > 0) log5.debug("mermaid:repaired", { candidate: index });
|
|
21498
|
+
return;
|
|
21499
|
+
} catch (err) {
|
|
21500
|
+
firstError ?? (firstError = err instanceof Error ? err : new Error(String(err)));
|
|
21501
|
+
}
|
|
20519
21502
|
}
|
|
21503
|
+
if (!active) return;
|
|
21504
|
+
log5.warn("mermaid:unrenderable", { error: firstError?.message ?? "", code });
|
|
21505
|
+
setUnrenderable(true);
|
|
20520
21506
|
})();
|
|
20521
21507
|
return () => {
|
|
20522
21508
|
active = false;
|
|
20523
21509
|
};
|
|
20524
21510
|
}, [code, resolvedMode, reactId]);
|
|
20525
21511
|
return /* @__PURE__ */ jsxs(Box, { className: cn("not-prose my-4", className), children: [
|
|
20526
|
-
|
|
20527
|
-
/* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-
|
|
21512
|
+
unrenderable && /* @__PURE__ */ jsxs(Box, { className: "space-y-2 mb-2", "data-testid": "mermaid-unrenderable", children: [
|
|
21513
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("mermaid.unrenderable") }),
|
|
20528
21514
|
/* @__PURE__ */ jsx(CodeBlock, { code, language: "mermaid" })
|
|
20529
21515
|
] }),
|
|
20530
21516
|
/* @__PURE__ */ jsx(
|
|
@@ -20533,7 +21519,7 @@ var init_MermaidDiagram = __esm({
|
|
|
20533
21519
|
ref: containerRef,
|
|
20534
21520
|
"data-testid": "mermaid-diagram",
|
|
20535
21521
|
className: "overflow-x-auto",
|
|
20536
|
-
style:
|
|
21522
|
+
style: unrenderable ? { display: "none" } : void 0
|
|
20537
21523
|
}
|
|
20538
21524
|
)
|
|
20539
21525
|
] });
|
|
@@ -23938,14 +24924,14 @@ function useSafeEventBus2() {
|
|
|
23938
24924
|
} };
|
|
23939
24925
|
}
|
|
23940
24926
|
}
|
|
23941
|
-
var
|
|
24927
|
+
var log6, lookStyles4, ButtonGroup;
|
|
23942
24928
|
var init_ButtonGroup = __esm({
|
|
23943
24929
|
"components/core/molecules/ButtonGroup.tsx"() {
|
|
23944
24930
|
"use client";
|
|
23945
24931
|
init_cn();
|
|
23946
24932
|
init_atoms();
|
|
23947
24933
|
init_useEventBus();
|
|
23948
|
-
|
|
24934
|
+
log6 = createLogger("almadar:ui:button-group");
|
|
23949
24935
|
lookStyles4 = {
|
|
23950
24936
|
"right-aligned-buttons": "",
|
|
23951
24937
|
"floating-bar": "fixed bottom-section left-1/2 -translate-x-1/2 shadow-elevation-toast bg-card p-card-sm rounded-container",
|
|
@@ -24026,7 +25012,7 @@ var init_ButtonGroup = __esm({
|
|
|
24026
25012
|
{
|
|
24027
25013
|
variant: "ghost",
|
|
24028
25014
|
onClick: () => {
|
|
24029
|
-
|
|
25015
|
+
log6.debug("Filter clicked", { field: filter.field });
|
|
24030
25016
|
},
|
|
24031
25017
|
children: filter.label
|
|
24032
25018
|
},
|
|
@@ -26810,6 +27796,12 @@ function commandMatches(command, query) {
|
|
|
26810
27796
|
if (matchesQuery(query, command.label)) return true;
|
|
26811
27797
|
return (command.keywords ?? []).some((keyword) => matchesQuery(query, keyword));
|
|
26812
27798
|
}
|
|
27799
|
+
function dispatchCommandPaletteCommand(command, deps) {
|
|
27800
|
+
if (command.disabled) return;
|
|
27801
|
+
if (command.event) deps.emit(`UI:${command.event}`, { commandId: command.id });
|
|
27802
|
+
if (command.action) deps.emit(`UI:${command.action}`, command.actionPayload ?? {});
|
|
27803
|
+
deps.onSelect?.(command);
|
|
27804
|
+
}
|
|
26813
27805
|
var UNGROUPED, CommandPalette;
|
|
26814
27806
|
var init_CommandPalette = __esm({
|
|
26815
27807
|
"components/core/molecules/CommandPalette.tsx"() {
|
|
@@ -26864,9 +27856,7 @@ var init_CommandPalette = __esm({
|
|
|
26864
27856
|
const handleSelect = useCallback(
|
|
26865
27857
|
(command) => {
|
|
26866
27858
|
if (command.disabled) return;
|
|
26867
|
-
|
|
26868
|
-
if (command.action) eventBus.emit(`UI:${command.action}`, command.actionPayload ?? {});
|
|
26869
|
-
onSelect?.(command);
|
|
27859
|
+
dispatchCommandPaletteCommand(command, { emit: eventBus.emit, onSelect });
|
|
26870
27860
|
handleClose();
|
|
26871
27861
|
},
|
|
26872
27862
|
[eventBus, onSelect, handleClose]
|
|
@@ -31845,9 +32835,9 @@ function debug(...args) {
|
|
|
31845
32835
|
const [first, ...rest] = args;
|
|
31846
32836
|
const message = typeof first === "string" ? first : "<debug>";
|
|
31847
32837
|
if (rest.length === 0 && typeof first === "string") {
|
|
31848
|
-
|
|
32838
|
+
log7.debug(message);
|
|
31849
32839
|
} else {
|
|
31850
|
-
|
|
32840
|
+
log7.debug(message, { args: rest.length > 0 ? formatArgs(rest) : formatArgs([first]) });
|
|
31851
32841
|
}
|
|
31852
32842
|
}
|
|
31853
32843
|
function debugGroup(label) {
|
|
@@ -31875,11 +32865,11 @@ function toLogMetaValue(v) {
|
|
|
31875
32865
|
}
|
|
31876
32866
|
return String(v);
|
|
31877
32867
|
}
|
|
31878
|
-
var NAMESPACE,
|
|
32868
|
+
var NAMESPACE, log7;
|
|
31879
32869
|
var init_debug = __esm({
|
|
31880
32870
|
"lib/debug.ts"() {
|
|
31881
32871
|
NAMESPACE = "almadar:ui:debug";
|
|
31882
|
-
|
|
32872
|
+
log7 = createLogger(NAMESPACE);
|
|
31883
32873
|
createLogger("almadar:ui:debug:input");
|
|
31884
32874
|
createLogger("almadar:ui:debug:collision");
|
|
31885
32875
|
createLogger("almadar:ui:debug:physics");
|
|
@@ -33532,6 +34522,7 @@ var init_MathCanvas = __esm({
|
|
|
33532
34522
|
init_perf();
|
|
33533
34523
|
init_atoms();
|
|
33534
34524
|
init_Stack();
|
|
34525
|
+
init_gameFonts();
|
|
33535
34526
|
init_LearningCanvas();
|
|
33536
34527
|
MathCanvas = ({
|
|
33537
34528
|
className,
|
|
@@ -33551,6 +34542,7 @@ var init_MathCanvas = __esm({
|
|
|
33551
34542
|
showTickLabels = false,
|
|
33552
34543
|
tickLabelFontSize = 10,
|
|
33553
34544
|
labelFontSize = 12,
|
|
34545
|
+
fontFamily: fontFamilyProp,
|
|
33554
34546
|
showCurveLabels = false,
|
|
33555
34547
|
curves = [],
|
|
33556
34548
|
points = [],
|
|
@@ -33573,6 +34565,7 @@ var init_MathCanvas = __esm({
|
|
|
33573
34565
|
error
|
|
33574
34566
|
}) => {
|
|
33575
34567
|
const eventBus = useEventBus();
|
|
34568
|
+
const fontFamily = resolveGameFontFamily(fontFamilyProp);
|
|
33576
34569
|
const keyMapKey = keyMap ? JSON.stringify(keyMap) : null;
|
|
33577
34570
|
const keyUpMapKey = keyUpMap ? JSON.stringify(keyUpMap) : null;
|
|
33578
34571
|
const stableKeyMap = useMemo(() => keyMap, [keyMapKey]);
|
|
@@ -33622,18 +34615,18 @@ var init_MathCanvas = __esm({
|
|
|
33622
34615
|
let kx = 0;
|
|
33623
34616
|
for (let x = Math.ceil(xMin / gridStep) * gridStep; x <= xMax; x += gridStep, kx++) {
|
|
33624
34617
|
if (kx % labelEveryX === 0 && x !== 0) {
|
|
33625
|
-
out.push({ type: "text", x: mapX(x), y: xAxisY + 12, text: formatTick(x), color: "#6b7280", fontSize: tickLabelFontSize, align: "center" });
|
|
34618
|
+
out.push({ type: "text", fontFamily, x: mapX(x), y: xAxisY + 12, text: formatTick(x), color: "#6b7280", fontSize: tickLabelFontSize, align: "center" });
|
|
33626
34619
|
}
|
|
33627
34620
|
}
|
|
33628
34621
|
const labelEveryY = Math.max(1, Math.ceil((yMax - yMin) / gridStep / Math.floor(plotH / 28)));
|
|
33629
34622
|
let ky = 0;
|
|
33630
34623
|
for (let y = Math.ceil(yMin / gridStep) * gridStep; y <= yMax; y += gridStep, ky++) {
|
|
33631
34624
|
if (ky % labelEveryY === 0 && y !== 0) {
|
|
33632
|
-
out.push({ type: "text", x: yAxisX - 6, y: mapY(y), text: formatTick(y), color: "#6b7280", fontSize: tickLabelFontSize, align: "right" });
|
|
34625
|
+
out.push({ type: "text", fontFamily, x: yAxisX - 6, y: mapY(y), text: formatTick(y), color: "#6b7280", fontSize: tickLabelFontSize, align: "right" });
|
|
33633
34626
|
}
|
|
33634
34627
|
}
|
|
33635
34628
|
if (xMin <= 0 && xMax >= 0 && yMin <= 0 && yMax >= 0) {
|
|
33636
|
-
out.push({ type: "text", x: yAxisX - 6, y: xAxisY + 12, text: "0", color: "#6b7280", fontSize: tickLabelFontSize, align: "right" });
|
|
34629
|
+
out.push({ type: "text", fontFamily, x: yAxisX - 6, y: xAxisY + 12, text: "0", color: "#6b7280", fontSize: tickLabelFontSize, align: "right" });
|
|
33637
34630
|
}
|
|
33638
34631
|
}
|
|
33639
34632
|
for (const region of regions) {
|
|
@@ -33660,6 +34653,7 @@ var init_MathCanvas = __esm({
|
|
|
33660
34653
|
const mid = Math.floor(region.samples.length / 2);
|
|
33661
34654
|
out.push({
|
|
33662
34655
|
type: "text",
|
|
34656
|
+
fontFamily,
|
|
33663
34657
|
x: mapX((first.x + last.x) / 2),
|
|
33664
34658
|
y: (mapY(region.samples[mid].y) + mapY(baseline)) / 2,
|
|
33665
34659
|
text: region.label,
|
|
@@ -33696,14 +34690,14 @@ var init_MathCanvas = __esm({
|
|
|
33696
34690
|
const px = mapX(guide.at);
|
|
33697
34691
|
out.push({ type: "line", x1: px, y1: margin, x2: px, y2: height - margin, color, dash });
|
|
33698
34692
|
if (guide.label) {
|
|
33699
|
-
out.push({ type: "text", x: px + 4, y: margin + 10, text: guide.label, color, fontSize: 11 });
|
|
34693
|
+
out.push({ type: "text", fontFamily, x: px + 4, y: margin + 10, text: guide.label, color, fontSize: 11 });
|
|
33700
34694
|
}
|
|
33701
34695
|
} else {
|
|
33702
34696
|
if (guide.at < yMin || guide.at > yMax) continue;
|
|
33703
34697
|
const py = mapY(guide.at);
|
|
33704
34698
|
out.push({ type: "line", x1: margin, y1: py, x2: width - margin, y2: py, color, dash });
|
|
33705
34699
|
if (guide.label) {
|
|
33706
|
-
out.push({ type: "text", x: width - margin - 4, y: py - 8, text: guide.label, color, fontSize: labelFontSize, align: "right" });
|
|
34700
|
+
out.push({ type: "text", fontFamily, x: width - margin - 4, y: py - 8, text: guide.label, color, fontSize: labelFontSize, align: "right" });
|
|
33707
34701
|
}
|
|
33708
34702
|
}
|
|
33709
34703
|
}
|
|
@@ -33742,6 +34736,7 @@ var init_MathCanvas = __esm({
|
|
|
33742
34736
|
if (showCurveLabels && curve.label && lastInRange) {
|
|
33743
34737
|
out.push({
|
|
33744
34738
|
type: "text",
|
|
34739
|
+
fontFamily,
|
|
33745
34740
|
x: mapX(lastInRange.x) + 6,
|
|
33746
34741
|
y: mapY(lastInRange.y) - 6,
|
|
33747
34742
|
text: curve.label,
|
|
@@ -33779,6 +34774,7 @@ var init_MathCanvas = __esm({
|
|
|
33779
34774
|
if (hop.label) {
|
|
33780
34775
|
out.push({
|
|
33781
34776
|
type: "text",
|
|
34777
|
+
fontFamily,
|
|
33782
34778
|
x: (x1 + x2) / 2,
|
|
33783
34779
|
y: xAxisY - peak - 8,
|
|
33784
34780
|
text: hop.label,
|
|
@@ -33806,6 +34802,7 @@ var init_MathCanvas = __esm({
|
|
|
33806
34802
|
const rad = mid * Math.PI / 180;
|
|
33807
34803
|
out.push({
|
|
33808
34804
|
type: "text",
|
|
34805
|
+
fontFamily,
|
|
33809
34806
|
x: mapX(angle.x + 1.35 * radius * Math.cos(rad)),
|
|
33810
34807
|
y: mapY(angle.y + 1.35 * radius * Math.sin(rad)),
|
|
33811
34808
|
text: angle.label,
|
|
@@ -33827,7 +34824,7 @@ var init_MathCanvas = __esm({
|
|
|
33827
34824
|
fill: isOpen ? "#ffffff" : p.color ?? "#dc2626"
|
|
33828
34825
|
});
|
|
33829
34826
|
if (p.label) {
|
|
33830
|
-
out.push({ type: "text", x: mapX(p.x) + 8, y: mapY(p.y) - 8, text: p.label, color: p.color ?? "#111827", fontSize: labelFontSize });
|
|
34827
|
+
out.push({ type: "text", fontFamily, x: mapX(p.x) + 8, y: mapY(p.y) - 8, text: p.label, color: p.color ?? "#111827", fontSize: labelFontSize });
|
|
33831
34828
|
}
|
|
33832
34829
|
}
|
|
33833
34830
|
for (const v of vectors) {
|
|
@@ -33838,7 +34835,7 @@ var init_MathCanvas = __esm({
|
|
|
33838
34835
|
const y2 = mapY(v.y + v.vy);
|
|
33839
34836
|
out.push({ type: "arrow", x1, y1, x2, y2, color: v.color ?? "#7c3aed", lineWidth: 2 });
|
|
33840
34837
|
if (v.label) {
|
|
33841
|
-
out.push({ type: "text", x: x2 + 6, y: y2 - 6, text: v.label, color: v.color ?? "#7c3aed", fontSize: labelFontSize });
|
|
34838
|
+
out.push({ type: "text", fontFamily, x: x2 + 6, y: y2 - 6, text: v.label, color: v.color ?? "#7c3aed", fontSize: labelFontSize });
|
|
33842
34839
|
}
|
|
33843
34840
|
}
|
|
33844
34841
|
out.push(...shapes);
|
|
@@ -33859,6 +34856,7 @@ var init_MathCanvas = __esm({
|
|
|
33859
34856
|
showTickLabels,
|
|
33860
34857
|
tickLabelFontSize,
|
|
33861
34858
|
labelFontSize,
|
|
34859
|
+
fontFamily,
|
|
33862
34860
|
showCurveLabels,
|
|
33863
34861
|
curves,
|
|
33864
34862
|
points,
|
|
@@ -33914,6 +34912,7 @@ var init_MathCanvas = __esm({
|
|
|
33914
34912
|
width,
|
|
33915
34913
|
height,
|
|
33916
34914
|
backgroundColor,
|
|
34915
|
+
fontFamily,
|
|
33917
34916
|
shapes: derivedShapes,
|
|
33918
34917
|
drawables,
|
|
33919
34918
|
projector,
|
|
@@ -35146,13 +36145,13 @@ var init_MapView = __esm({
|
|
|
35146
36145
|
shadowSize: [41, 41]
|
|
35147
36146
|
});
|
|
35148
36147
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
35149
|
-
const { useEffect:
|
|
36148
|
+
const { useEffect: useEffect70, useRef: useRef70, useCallback: useCallback100, useState: useState109 } = React96__default;
|
|
35150
36149
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
35151
36150
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
35152
36151
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
35153
36152
|
const map = useMap();
|
|
35154
|
-
const prevRef =
|
|
35155
|
-
|
|
36153
|
+
const prevRef = useRef70({ centerLat, centerLng, zoom });
|
|
36154
|
+
useEffect70(() => {
|
|
35156
36155
|
const prev = prevRef.current;
|
|
35157
36156
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
35158
36157
|
map.setView([centerLat, centerLng], zoom);
|
|
@@ -35163,7 +36162,7 @@ var init_MapView = __esm({
|
|
|
35163
36162
|
}
|
|
35164
36163
|
function MapClickHandler({ onMapClick }) {
|
|
35165
36164
|
const map = useMap();
|
|
35166
|
-
|
|
36165
|
+
useEffect70(() => {
|
|
35167
36166
|
if (!onMapClick) return;
|
|
35168
36167
|
const handler = (e) => {
|
|
35169
36168
|
onMapClick(e.latlng.lat, e.latlng.lng);
|
|
@@ -35191,8 +36190,8 @@ var init_MapView = __esm({
|
|
|
35191
36190
|
showAttribution = true
|
|
35192
36191
|
}) {
|
|
35193
36192
|
const eventBus = useEventBus2();
|
|
35194
|
-
const [clickedPosition, setClickedPosition] =
|
|
35195
|
-
const handleMapClick =
|
|
36193
|
+
const [clickedPosition, setClickedPosition] = useState109(null);
|
|
36194
|
+
const handleMapClick = useCallback100((lat, lng) => {
|
|
35196
36195
|
if (showClickedPin) {
|
|
35197
36196
|
setClickedPosition({ lat, lng });
|
|
35198
36197
|
}
|
|
@@ -35201,7 +36200,7 @@ var init_MapView = __esm({
|
|
|
35201
36200
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
35202
36201
|
}
|
|
35203
36202
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
35204
|
-
const handleMarkerClick =
|
|
36203
|
+
const handleMarkerClick = useCallback100((marker) => {
|
|
35205
36204
|
onMarkerClick?.(marker);
|
|
35206
36205
|
if (markerClickEvent) {
|
|
35207
36206
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -49510,7 +50509,7 @@ function getAllEvents(traits2) {
|
|
|
49510
50509
|
function EventDispatcherTab({ traits: traits2, schema }) {
|
|
49511
50510
|
const eventBus = useEventBus();
|
|
49512
50511
|
const { t } = useTranslate();
|
|
49513
|
-
const [
|
|
50512
|
+
const [log12, setLog] = React96.useState([]);
|
|
49514
50513
|
const prevStatesRef = React96.useRef(/* @__PURE__ */ new Map());
|
|
49515
50514
|
React96.useEffect(() => {
|
|
49516
50515
|
for (const trait of traits2) {
|
|
@@ -49574,9 +50573,9 @@ function EventDispatcherTab({ traits: traits2, schema }) {
|
|
|
49574
50573
|
/* @__PURE__ */ jsx(Typography, { variant: "small", weight: "medium", className: "text-muted-foreground mb-1", children: t("debug.otherEvents") }),
|
|
49575
50574
|
/* @__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)) })
|
|
49576
50575
|
] }),
|
|
49577
|
-
|
|
50576
|
+
log12.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
|
|
49578
50577
|
/* @__PURE__ */ jsx(Typography, { variant: "small", weight: "medium", className: "text-muted-foreground mb-1", children: t("debug.recentTransitions") }),
|
|
49579
|
-
/* @__PURE__ */ jsx(Stack, { gap: "xs", children:
|
|
50578
|
+
/* @__PURE__ */ jsx(Stack, { gap: "xs", children: log12.map((entry, i) => /* @__PURE__ */ jsxs(Typography, { variant: "small", className: "font-mono text-xs", children: [
|
|
49580
50579
|
/* @__PURE__ */ jsx("span", { className: "text-primary", children: entry.traitName }),
|
|
49581
50580
|
" ",
|
|
49582
50581
|
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: entry.from }),
|
|
@@ -51767,6 +52766,7 @@ var init_component_registry_generated = __esm({
|
|
|
51767
52766
|
init_FormSection();
|
|
51768
52767
|
init_FormSectionHeader();
|
|
51769
52768
|
init_FxOverlay();
|
|
52769
|
+
init_GameAudioCue();
|
|
51770
52770
|
init_GameAudioToggle();
|
|
51771
52771
|
init_GameHud();
|
|
51772
52772
|
init_GameIcon();
|
|
@@ -52044,6 +53044,7 @@ var init_component_registry_generated = __esm({
|
|
|
52044
53044
|
"FormLayout": FormLayout,
|
|
52045
53045
|
"FormSectionHeader": FormSectionHeader,
|
|
52046
53046
|
"FxOverlay": FxOverlay,
|
|
53047
|
+
"GameAudioCue": GameAudioCue,
|
|
52047
53048
|
"GameAudioToggle": GameAudioToggle,
|
|
52048
53049
|
"GameHud": GameHud,
|
|
52049
53050
|
"GameIcon": GameIcon,
|
|
@@ -52492,7 +53493,9 @@ function UISlotComponentInner({
|
|
|
52492
53493
|
className,
|
|
52493
53494
|
children,
|
|
52494
53495
|
pattern,
|
|
52495
|
-
sourceTrait
|
|
53496
|
+
sourceTrait,
|
|
53497
|
+
fallback,
|
|
53498
|
+
mode = "replace"
|
|
52496
53499
|
}) {
|
|
52497
53500
|
const { slots, clear } = useUISlots();
|
|
52498
53501
|
const eventBus = useEventBus();
|
|
@@ -52544,12 +53547,26 @@ function UISlotComponentInner({
|
|
|
52544
53547
|
);
|
|
52545
53548
|
}
|
|
52546
53549
|
if (!content) {
|
|
53550
|
+
if (fallback !== void 0) {
|
|
53551
|
+
return /* @__PURE__ */ jsx(
|
|
53552
|
+
Box,
|
|
53553
|
+
{
|
|
53554
|
+
id: `slot-${slot}`,
|
|
53555
|
+
className: cn("ui-slot", `ui-slot-${slot}`, className),
|
|
53556
|
+
"data-testid": `ui-slot-${slot}`,
|
|
53557
|
+
"data-slot-mode": "fallback",
|
|
53558
|
+
children: fallback
|
|
53559
|
+
}
|
|
53560
|
+
);
|
|
53561
|
+
}
|
|
52547
53562
|
if (!portal) {
|
|
52548
53563
|
return /* @__PURE__ */ jsx(
|
|
52549
53564
|
Box,
|
|
52550
53565
|
{
|
|
52551
53566
|
id: `slot-${slot}`,
|
|
52552
|
-
className: cn("ui-slot", `ui-slot-${slot}`, className)
|
|
53567
|
+
className: cn("ui-slot", `ui-slot-${slot}`, className),
|
|
53568
|
+
"data-testid": `ui-slot-${slot}`,
|
|
53569
|
+
"data-slot-mode": "empty"
|
|
52553
53570
|
}
|
|
52554
53571
|
);
|
|
52555
53572
|
}
|
|
@@ -52566,29 +53583,51 @@ function UISlotComponentInner({
|
|
|
52566
53583
|
clear(slot);
|
|
52567
53584
|
};
|
|
52568
53585
|
if (portal) {
|
|
52569
|
-
|
|
52570
|
-
|
|
52571
|
-
}
|
|
52572
|
-
return /* @__PURE__ */ jsx(
|
|
52573
|
-
SlotPortal,
|
|
53586
|
+
const inlineFallback = mode === "append" && fallback !== void 0 ? /* @__PURE__ */ jsx(
|
|
53587
|
+
Box,
|
|
52574
53588
|
{
|
|
52575
|
-
slot
|
|
52576
|
-
|
|
52577
|
-
|
|
52578
|
-
|
|
53589
|
+
id: `slot-${slot}-fallback`,
|
|
53590
|
+
className: cn("ui-slot", `ui-slot-${slot}-fallback`, className),
|
|
53591
|
+
"data-testid": `ui-slot-${slot}-fallback`,
|
|
53592
|
+
"data-slot-mode": "append",
|
|
53593
|
+
children: fallback
|
|
52579
53594
|
}
|
|
52580
|
-
);
|
|
53595
|
+
) : null;
|
|
53596
|
+
if (contained) {
|
|
53597
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
53598
|
+
inlineFallback,
|
|
53599
|
+
renderContainedPortal(t, slot, content, handleDismiss)
|
|
53600
|
+
] });
|
|
53601
|
+
}
|
|
53602
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
53603
|
+
inlineFallback,
|
|
53604
|
+
/* @__PURE__ */ jsx(
|
|
53605
|
+
SlotPortal,
|
|
53606
|
+
{
|
|
53607
|
+
slot,
|
|
53608
|
+
content,
|
|
53609
|
+
position,
|
|
53610
|
+
onDismiss: handleDismiss
|
|
53611
|
+
}
|
|
53612
|
+
)
|
|
53613
|
+
] });
|
|
52581
53614
|
}
|
|
52582
53615
|
const slotContent = /* @__PURE__ */ jsx(SlotContentRenderer, { content, onDismiss: handleDismiss });
|
|
52583
53616
|
const wrappedContent = suspenseConfig.enabled ? /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx(Suspense, { fallback: getSlotFallback(slot, suspenseConfig), children: slotContent }) }) : /* @__PURE__ */ jsx(ErrorBoundary, { children: slotContent });
|
|
52584
|
-
|
|
53617
|
+
const showFallback = mode === "append" && fallback !== void 0;
|
|
53618
|
+
return /* @__PURE__ */ jsxs(
|
|
52585
53619
|
Box,
|
|
52586
53620
|
{
|
|
52587
53621
|
id: `slot-${slot}`,
|
|
52588
53622
|
className: cn("ui-slot", `ui-slot-${slot}`, className),
|
|
52589
53623
|
"data-pattern": content.pattern,
|
|
52590
53624
|
"data-source-trait": content.sourceTrait,
|
|
52591
|
-
|
|
53625
|
+
"data-testid": `ui-slot-${slot}`,
|
|
53626
|
+
"data-slot-mode": showFallback ? "append" : "content",
|
|
53627
|
+
children: [
|
|
53628
|
+
showFallback ? fallback : null,
|
|
53629
|
+
/* @__PURE__ */ jsx(MaybeTraitScope, { sourceTrait: content.sourceTrait, children: wrappedContent })
|
|
53630
|
+
]
|
|
52592
53631
|
}
|
|
52593
53632
|
);
|
|
52594
53633
|
}
|
|
@@ -56840,7 +57879,7 @@ function convertFnFormLambdasInProps(props) {
|
|
|
56840
57879
|
|
|
56841
57880
|
// hooks/index.ts
|
|
56842
57881
|
init_useEventBus();
|
|
56843
|
-
var
|
|
57882
|
+
var log8 = createLogger("almadar:ui:shared-entity-store");
|
|
56844
57883
|
var EMPTY_ENTITY_STATE = {};
|
|
56845
57884
|
function createSharedEntityStore() {
|
|
56846
57885
|
const states = /* @__PURE__ */ new Map();
|
|
@@ -56870,7 +57909,7 @@ function createSharedEntityStore() {
|
|
|
56870
57909
|
try {
|
|
56871
57910
|
callback();
|
|
56872
57911
|
} catch (error) {
|
|
56873
|
-
|
|
57912
|
+
log8.error("Shared entity subscriber error", {
|
|
56874
57913
|
entityId,
|
|
56875
57914
|
error: error instanceof Error ? error : String(error)
|
|
56876
57915
|
});
|
|
@@ -56901,7 +57940,7 @@ function runTickFrame(entityId, orderedWriters, store) {
|
|
|
56901
57940
|
store.commit(entityId, scratch);
|
|
56902
57941
|
return scratch;
|
|
56903
57942
|
}
|
|
56904
|
-
var
|
|
57943
|
+
var log9 = createLogger("almadar:ui:effects:client-handlers");
|
|
56905
57944
|
function createClientEffectHandlers(options) {
|
|
56906
57945
|
const { eventBus, slotSetter, navigate, navigateBack, notify, callService, liveEntity } = options;
|
|
56907
57946
|
return {
|
|
@@ -56910,12 +57949,12 @@ function createClientEffectHandlers(options) {
|
|
|
56910
57949
|
eventBus.emit(prefixedEvent, payload, source);
|
|
56911
57950
|
},
|
|
56912
57951
|
persist: async () => {
|
|
56913
|
-
|
|
57952
|
+
log9.warn("persist is server-side only, ignored on client");
|
|
56914
57953
|
},
|
|
56915
57954
|
// @almadar/runtime EffectHandlers.set types value:unknown — should be FieldValue (upstream fix queued)
|
|
56916
57955
|
set: ((_entityId, field, value) => {
|
|
56917
57956
|
if (!liveEntity) {
|
|
56918
|
-
|
|
57957
|
+
log9.warn("set is server-side only, ignored on client (no live entity)");
|
|
56919
57958
|
return;
|
|
56920
57959
|
}
|
|
56921
57960
|
liveEntity[field] = value;
|
|
@@ -56951,13 +57990,13 @@ function createClientEffectHandlers(options) {
|
|
|
56951
57990
|
window.location.href = path;
|
|
56952
57991
|
return;
|
|
56953
57992
|
}
|
|
56954
|
-
|
|
57993
|
+
log9.warn("No navigate handler, ignoring", { path });
|
|
56955
57994
|
}),
|
|
56956
57995
|
navigateBack: navigateBack ?? (() => {
|
|
56957
|
-
|
|
57996
|
+
log9.warn("No navigate-back handler, ignoring");
|
|
56958
57997
|
}),
|
|
56959
57998
|
notify: notify ?? ((msg, type) => {
|
|
56960
|
-
|
|
57999
|
+
log9.debug("notify", { type, message: msg });
|
|
56961
58000
|
})
|
|
56962
58001
|
};
|
|
56963
58002
|
}
|
|
@@ -57392,7 +58431,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
57392
58431
|
};
|
|
57393
58432
|
}, [traitBindings]);
|
|
57394
58433
|
const executeTransitionEffects = useCallback(async (params) => {
|
|
57395
|
-
const { binding, previousState, newState, payload, flushEvent, syncOnly, log:
|
|
58434
|
+
const { binding, previousState, newState, payload, flushEvent, syncOnly, log: log12 } = params;
|
|
57396
58435
|
const traitName = binding.trait.name;
|
|
57397
58436
|
const linkedEntity = binding.linkedEntity || "";
|
|
57398
58437
|
const entityId = payload?.entityId;
|
|
@@ -57521,7 +58560,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
57521
58560
|
if (sharedKey !== void 0) {
|
|
57522
58561
|
sharedWrites.push({ field, value });
|
|
57523
58562
|
}
|
|
57524
|
-
|
|
58563
|
+
log12.debug("set:write", {
|
|
57525
58564
|
traitName,
|
|
57526
58565
|
field,
|
|
57527
58566
|
value: JSON.stringify(value),
|
|
@@ -57589,7 +58628,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
57589
58628
|
mergeEntityFrame(sharedEntityStore.getSnapshot(sharedKey), sharedWrites)
|
|
57590
58629
|
);
|
|
57591
58630
|
}
|
|
57592
|
-
|
|
58631
|
+
log12.debug("effects:executed", () => ({
|
|
57593
58632
|
traitName,
|
|
57594
58633
|
transition: `${previousState}->${newState}`,
|
|
57595
58634
|
event: flushEvent,
|
|
@@ -57599,7 +58638,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
57599
58638
|
slotsTouched: Array.from(pendingSlots.keys()).join(",")
|
|
57600
58639
|
}));
|
|
57601
58640
|
for (const [slot, patterns] of pendingSlots) {
|
|
57602
|
-
|
|
58641
|
+
log12.debug("flush:slot", {
|
|
57603
58642
|
traitName,
|
|
57604
58643
|
slot,
|
|
57605
58644
|
patternCount: patterns.length,
|
|
@@ -57617,7 +58656,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
|
|
|
57617
58656
|
publishBindingSnapshot(traitName, liveEntity);
|
|
57618
58657
|
}
|
|
57619
58658
|
} catch (error) {
|
|
57620
|
-
|
|
58659
|
+
log12.error("effects:error", {
|
|
57621
58660
|
traitName,
|
|
57622
58661
|
transition: `${previousState}->${newState}`,
|
|
57623
58662
|
event: flushEvent,
|
|
@@ -58696,11 +59735,20 @@ function BrowserPlayground({
|
|
|
58696
59735
|
mode = "mock",
|
|
58697
59736
|
initialPagePath,
|
|
58698
59737
|
height,
|
|
58699
|
-
className
|
|
59738
|
+
className,
|
|
59739
|
+
paused
|
|
58700
59740
|
}) {
|
|
58701
59741
|
const [runtime] = useState(
|
|
58702
59742
|
() => new OrbitalServerRuntime({ mode, debug: false })
|
|
58703
59743
|
);
|
|
59744
|
+
useEffect(() => {
|
|
59745
|
+
if (paused === void 0) return;
|
|
59746
|
+
if (paused) {
|
|
59747
|
+
runtime.pauseTicks();
|
|
59748
|
+
} else {
|
|
59749
|
+
runtime.resumeTicks();
|
|
59750
|
+
}
|
|
59751
|
+
}, [runtime, paused]);
|
|
58704
59752
|
const registrationReady = useMemo(() => {
|
|
58705
59753
|
const orbitalNames = schema.orbitals.map((o) => o.name);
|
|
58706
59754
|
playgroundLog.debug("register:start", { schema: schema.name, orbitalNames });
|
|
@@ -58761,7 +59809,7 @@ init_useEventBus();
|
|
|
58761
59809
|
// components/avl/hooks/useCanvasDnd.tsx
|
|
58762
59810
|
init_useEventBus();
|
|
58763
59811
|
init_useAlmadarDndCollision();
|
|
58764
|
-
var
|
|
59812
|
+
var log10 = createLogger("almadar:ui:canvas-dnd");
|
|
58765
59813
|
function useCanvasDraggable({
|
|
58766
59814
|
id,
|
|
58767
59815
|
payload,
|
|
@@ -58799,7 +59847,7 @@ function defaultEmit(eventBus, drop) {
|
|
|
58799
59847
|
if (payload.kind === "pattern") {
|
|
58800
59848
|
const patternType = payload.data["type"];
|
|
58801
59849
|
if (typeof patternType !== "string") {
|
|
58802
|
-
|
|
59850
|
+
log10.warn("default-emit:pattern:missing-type");
|
|
58803
59851
|
return;
|
|
58804
59852
|
}
|
|
58805
59853
|
const out = { patternType, containerNode: target.containerNode };
|
|
@@ -58808,26 +59856,26 @@ function defaultEmit(eventBus, drop) {
|
|
|
58808
59856
|
out.index = resolved.index;
|
|
58809
59857
|
}
|
|
58810
59858
|
eventBus.emit("UI:PATTERN_DROP", out);
|
|
58811
|
-
|
|
59859
|
+
log10.info("default-emit:pattern", { patternType, level: target.level });
|
|
58812
59860
|
return;
|
|
58813
59861
|
}
|
|
58814
59862
|
if (payload.kind === "behavior") {
|
|
58815
59863
|
const behaviorName = payload.data["name"];
|
|
58816
59864
|
if (typeof behaviorName !== "string") {
|
|
58817
|
-
|
|
59865
|
+
log10.warn("default-emit:behavior:missing-name");
|
|
58818
59866
|
return;
|
|
58819
59867
|
}
|
|
58820
59868
|
eventBus.emit("UI:BEHAVIOR_DROP", {
|
|
58821
59869
|
behaviorName,
|
|
58822
59870
|
containerNode: target.containerNode
|
|
58823
59871
|
});
|
|
58824
|
-
|
|
59872
|
+
log10.info("default-emit:behavior", { behaviorName, level: target.level });
|
|
58825
59873
|
return;
|
|
58826
59874
|
}
|
|
58827
59875
|
if (payload.kind === "pattern-instance") {
|
|
58828
59876
|
const fromPath = payload.data["fromPath"];
|
|
58829
59877
|
if (typeof fromPath !== "string") {
|
|
58830
|
-
|
|
59878
|
+
log10.warn("default-emit:pattern-instance:missing-fromPath");
|
|
58831
59879
|
return;
|
|
58832
59880
|
}
|
|
58833
59881
|
const out = { fromPath, loc: payload.data["loc"] };
|
|
@@ -58836,10 +59884,10 @@ function defaultEmit(eventBus, drop) {
|
|
|
58836
59884
|
out.toIndex = resolved.index;
|
|
58837
59885
|
}
|
|
58838
59886
|
eventBus.emit("UI:PATTERN_MOVE", out);
|
|
58839
|
-
|
|
59887
|
+
log10.info("default-emit:pattern-instance", { fromPath, level: target.level });
|
|
58840
59888
|
return;
|
|
58841
59889
|
}
|
|
58842
|
-
|
|
59890
|
+
log10.debug("default-emit:unhandled-kind", { kind: payload.kind });
|
|
58843
59891
|
}
|
|
58844
59892
|
function CanvasDndProvider({
|
|
58845
59893
|
children,
|
|
@@ -58862,9 +59910,9 @@ function CanvasDndProvider({
|
|
|
58862
59910
|
if (payload) {
|
|
58863
59911
|
setActivePayload(payload);
|
|
58864
59912
|
eventBus.emit("UI:DRAG_START", { kind: payload.kind, data: payload.data });
|
|
58865
|
-
|
|
59913
|
+
log10.info("dragStart", { id: e.active.id, kind: payload.kind });
|
|
58866
59914
|
} else {
|
|
58867
|
-
|
|
59915
|
+
log10.warn("dragStart:missing-payload", { id: e.active.id });
|
|
58868
59916
|
}
|
|
58869
59917
|
}, [eventBus, trackPointer]);
|
|
58870
59918
|
const handleDragEnd = React96__default.useCallback((e) => {
|
|
@@ -58875,7 +59923,7 @@ function CanvasDndProvider({
|
|
|
58875
59923
|
const overData = e.over?.data.current;
|
|
58876
59924
|
const target = overData?.target;
|
|
58877
59925
|
const accepts = overData?.accepts;
|
|
58878
|
-
|
|
59926
|
+
log10.info("dragEnd", {
|
|
58879
59927
|
activeId: e.active.id,
|
|
58880
59928
|
overId: e.over?.id,
|
|
58881
59929
|
hasPayload: !!payload,
|
|
@@ -58887,12 +59935,12 @@ function CanvasDndProvider({
|
|
|
58887
59935
|
}
|
|
58888
59936
|
if (!payload || !target) return;
|
|
58889
59937
|
if (accepts && !accepts.includes(payload.kind)) {
|
|
58890
|
-
|
|
59938
|
+
log10.debug("dragEnd:rejected:kind", { kind: payload.kind, accepts: [...accepts] });
|
|
58891
59939
|
return;
|
|
58892
59940
|
}
|
|
58893
59941
|
const cursor = lastPointerRef.current;
|
|
58894
59942
|
const resolved = target.resolvePath && cursor ? target.resolvePath(cursor) : null;
|
|
58895
|
-
|
|
59943
|
+
log10.debug("dragEnd:resolve", {
|
|
58896
59944
|
hasResolver: !!target.resolvePath,
|
|
58897
59945
|
cursorX: cursor?.x,
|
|
58898
59946
|
cursorY: cursor?.y,
|
|
@@ -58906,7 +59954,7 @@ function CanvasDndProvider({
|
|
|
58906
59954
|
const handleDragCancel = React96__default.useCallback(() => {
|
|
58907
59955
|
setActivePayload(null);
|
|
58908
59956
|
document.removeEventListener("pointermove", trackPointer);
|
|
58909
|
-
|
|
59957
|
+
log10.info("dragCancel");
|
|
58910
59958
|
}, [trackPointer]);
|
|
58911
59959
|
return /* @__PURE__ */ jsxs(
|
|
58912
59960
|
DndContext,
|
|
@@ -60966,7 +62014,7 @@ init_AvlTransitionLane();
|
|
|
60966
62014
|
init_AvlSwimLane();
|
|
60967
62015
|
init_avl_atom_types();
|
|
60968
62016
|
init_avl_elk_layout();
|
|
60969
|
-
var
|
|
62017
|
+
var log11 = createLogger("almadar:ui:avl:trait-scene");
|
|
60970
62018
|
var SWIM_GUTTER2 = 120;
|
|
60971
62019
|
var CENTER_W2 = 360;
|
|
60972
62020
|
var AvlTraitScene = ({
|
|
@@ -60979,7 +62027,7 @@ var AvlTraitScene = ({
|
|
|
60979
62027
|
const dataKey = useMemo(() => JSON.stringify(data), [data]);
|
|
60980
62028
|
useEffect(() => {
|
|
60981
62029
|
computeTraitLayout(data).then(setLayout).catch((error) => {
|
|
60982
|
-
|
|
62030
|
+
log11.error("computeTraitLayout failed", { error: error instanceof Error ? error : String(error) });
|
|
60983
62031
|
});
|
|
60984
62032
|
}, [dataKey]);
|
|
60985
62033
|
if (!layout) {
|