system-canvas-standalone 0.2.2 → 0.2.4

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.
@@ -12759,12 +12759,12 @@ var SystemCanvas = (() => {
12759
12759
  render: () => render,
12760
12760
  themes: () => themes
12761
12761
  });
12762
- var import_react24 = __toESM(require_react(), 1);
12762
+ var import_react25 = __toESM(require_react(), 1);
12763
12763
  var import_client = __toESM(require_client(), 1);
12764
12764
 
12765
12765
  // ../react/dist/components/SystemCanvas.js
12766
12766
  var import_jsx_runtime28 = __toESM(require_jsx_runtime(), 1);
12767
- var import_react21 = __toESM(require_react(), 1);
12767
+ var import_react24 = __toESM(require_react(), 1);
12768
12768
 
12769
12769
  // ../core/dist/themes/dark.js
12770
12770
  var darkTheme = {
@@ -15150,8 +15150,601 @@ var SystemCanvas = (() => {
15150
15150
  return { pending, onHandlePointerDown };
15151
15151
  }
15152
15152
 
15153
- // ../react/dist/hooks/useZoomNavigation.js
15153
+ // ../react/dist/hooks/useMultiSelect.js
15154
15154
  var import_react6 = __toESM(require_react(), 1);
15155
+ function useMultiSelect(options) {
15156
+ const { svgRef, viewport, nodesRef, containerRef, enabled } = options;
15157
+ const [selectedIds, setSelectedIds] = (0, import_react6.useState)(() => /* @__PURE__ */ new Set());
15158
+ const [marqueeRect, setMarqueeRect] = (0, import_react6.useState)(null);
15159
+ const marqueeActiveRef = (0, import_react6.useRef)(false);
15160
+ const isDrawingRef = (0, import_react6.useRef)(false);
15161
+ const startScreenRef = (0, import_react6.useRef)(null);
15162
+ const pointerIdRef = (0, import_react6.useRef)(null);
15163
+ const selectedIdsRef = (0, import_react6.useRef)(selectedIds);
15164
+ selectedIdsRef.current = selectedIds;
15165
+ const selectNode = (0, import_react6.useCallback)((id2) => {
15166
+ setSelectedIds(/* @__PURE__ */ new Set([id2]));
15167
+ }, []);
15168
+ const toggleNode = (0, import_react6.useCallback)((id2) => {
15169
+ setSelectedIds((prev) => {
15170
+ const next = new Set(prev);
15171
+ if (next.has(id2)) {
15172
+ next.delete(id2);
15173
+ } else {
15174
+ next.add(id2);
15175
+ }
15176
+ return next;
15177
+ });
15178
+ }, []);
15179
+ const selectAll = (0, import_react6.useCallback)(() => {
15180
+ const nodes = nodesRef.current;
15181
+ if (!nodes)
15182
+ return;
15183
+ setSelectedIds(new Set(nodes.map((n) => n.id)));
15184
+ }, [nodesRef]);
15185
+ const clearSelection = (0, import_react6.useCallback)(() => {
15186
+ setSelectedIds(/* @__PURE__ */ new Set());
15187
+ }, []);
15188
+ (0, import_react6.useEffect)(() => {
15189
+ if (!enabled)
15190
+ return;
15191
+ const container = containerRef.current;
15192
+ if (!container)
15193
+ return;
15194
+ const onKeyDown = (e) => {
15195
+ if (e.code === "Space" && !e.repeat) {
15196
+ const active = document.activeElement;
15197
+ if (active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement || active instanceof HTMLElement && active.isContentEditable) {
15198
+ return;
15199
+ }
15200
+ e.preventDefault();
15201
+ marqueeActiveRef.current = true;
15202
+ }
15203
+ };
15204
+ const onKeyUp = (e) => {
15205
+ if (e.code === "Space") {
15206
+ marqueeActiveRef.current = false;
15207
+ if (isDrawingRef.current) {
15208
+ isDrawingRef.current = false;
15209
+ startScreenRef.current = null;
15210
+ pointerIdRef.current = null;
15211
+ setMarqueeRect(null);
15212
+ }
15213
+ }
15214
+ };
15215
+ container.addEventListener("keydown", onKeyDown);
15216
+ container.addEventListener("keyup", onKeyUp);
15217
+ return () => {
15218
+ container.removeEventListener("keydown", onKeyDown);
15219
+ container.removeEventListener("keyup", onKeyUp);
15220
+ };
15221
+ }, [enabled, containerRef]);
15222
+ (0, import_react6.useEffect)(() => {
15223
+ if (!enabled)
15224
+ return;
15225
+ const container = containerRef.current;
15226
+ if (!container)
15227
+ return;
15228
+ const onKeyDown = (e) => {
15229
+ if ((e.metaKey || e.ctrlKey) && e.key === "a") {
15230
+ const active = document.activeElement;
15231
+ if (active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement || active instanceof HTMLElement && active.isContentEditable) {
15232
+ return;
15233
+ }
15234
+ e.preventDefault();
15235
+ selectAll();
15236
+ }
15237
+ };
15238
+ container.addEventListener("keydown", onKeyDown);
15239
+ return () => {
15240
+ container.removeEventListener("keydown", onKeyDown);
15241
+ };
15242
+ }, [enabled, containerRef, selectAll]);
15243
+ (0, import_react6.useEffect)(() => {
15244
+ if (!enabled)
15245
+ return;
15246
+ const container = containerRef.current;
15247
+ if (!container)
15248
+ return;
15249
+ const onPointerDown = (e) => {
15250
+ if (!marqueeActiveRef.current)
15251
+ return;
15252
+ if (e.button !== 0)
15253
+ return;
15254
+ const target = e.target;
15255
+ if (target && typeof target.closest === "function") {
15256
+ if (target.closest(".system-canvas-node"))
15257
+ return;
15258
+ }
15259
+ const svg = svgRef.current;
15260
+ if (!svg)
15261
+ return;
15262
+ const rect = svg.getBoundingClientRect();
15263
+ const x = e.clientX - rect.left;
15264
+ const y = e.clientY - rect.top;
15265
+ startScreenRef.current = { x, y };
15266
+ isDrawingRef.current = true;
15267
+ pointerIdRef.current = e.pointerId;
15268
+ setMarqueeRect({ x1: x, y1: y, x2: x, y2: y });
15269
+ try {
15270
+ container.setPointerCapture(e.pointerId);
15271
+ } catch {
15272
+ }
15273
+ e.preventDefault();
15274
+ e.stopPropagation();
15275
+ };
15276
+ const onPointerMove = (e) => {
15277
+ if (!isDrawingRef.current)
15278
+ return;
15279
+ if (e.pointerId !== pointerIdRef.current)
15280
+ return;
15281
+ const svg = svgRef.current;
15282
+ if (!svg)
15283
+ return;
15284
+ const rect = svg.getBoundingClientRect();
15285
+ const x = e.clientX - rect.left;
15286
+ const y = e.clientY - rect.top;
15287
+ const start2 = startScreenRef.current;
15288
+ setMarqueeRect({ x1: start2.x, y1: start2.y, x2: x, y2: y });
15289
+ };
15290
+ const onPointerUp = (e) => {
15291
+ if (!isDrawingRef.current)
15292
+ return;
15293
+ if (e.pointerId !== pointerIdRef.current)
15294
+ return;
15295
+ const svg = svgRef.current;
15296
+ if (!svg)
15297
+ return;
15298
+ const rect = svg.getBoundingClientRect();
15299
+ const x = e.clientX - rect.left;
15300
+ const y = e.clientY - rect.top;
15301
+ const start2 = startScreenRef.current;
15302
+ const vp = viewport.current ?? { x: 0, y: 0, zoom: 1 };
15303
+ const topLeft = screenToCanvas(Math.min(start2.x, x), Math.min(start2.y, y), vp);
15304
+ const bottomRight = screenToCanvas(Math.max(start2.x, x), Math.max(start2.y, y), vp);
15305
+ const rectLeft = topLeft.x;
15306
+ const rectTop = topLeft.y;
15307
+ const rectRight = bottomRight.x;
15308
+ const rectBottom = bottomRight.y;
15309
+ const nodes = nodesRef.current ?? [];
15310
+ const matched = /* @__PURE__ */ new Set();
15311
+ for (const node of nodes) {
15312
+ const nRight = node.x + node.width;
15313
+ const nBottom = node.y + node.height;
15314
+ if (node.x < rectRight && nRight > rectLeft && node.y < rectBottom && nBottom > rectTop) {
15315
+ matched.add(node.id);
15316
+ }
15317
+ }
15318
+ setSelectedIds(matched);
15319
+ setMarqueeRect(null);
15320
+ isDrawingRef.current = false;
15321
+ startScreenRef.current = null;
15322
+ pointerIdRef.current = null;
15323
+ try {
15324
+ container.releasePointerCapture(e.pointerId);
15325
+ } catch {
15326
+ }
15327
+ };
15328
+ container.addEventListener("pointerdown", onPointerDown);
15329
+ container.addEventListener("pointermove", onPointerMove);
15330
+ container.addEventListener("pointerup", onPointerUp);
15331
+ return () => {
15332
+ container.removeEventListener("pointerdown", onPointerDown);
15333
+ container.removeEventListener("pointermove", onPointerMove);
15334
+ container.removeEventListener("pointerup", onPointerUp);
15335
+ };
15336
+ }, [enabled, containerRef, svgRef, viewport, nodesRef]);
15337
+ return {
15338
+ selectedIds,
15339
+ selectNode,
15340
+ toggleNode,
15341
+ selectAll,
15342
+ clearSelection,
15343
+ marqueeRect,
15344
+ marqueeActiveRef
15345
+ };
15346
+ }
15347
+
15348
+ // ../react/dist/hooks/useMultiSelectClipboard.js
15349
+ var import_react7 = __toESM(require_react(), 1);
15350
+ var clipboardSnapshot = null;
15351
+ function useMultiSelectClipboard(options) {
15352
+ const { selectedIdsRef, nodesRef, edgesRef, viewport, onNodeAdd, onEdgeAdd, canvasRef, getCursorScreenPos, onBeginBatch, onEndBatch } = options;
15353
+ const getCursorScreenPosRef = (0, import_react7.useRef)(getCursorScreenPos);
15354
+ getCursorScreenPosRef.current = getCursorScreenPos;
15355
+ const onNodeAddRef = (0, import_react7.useRef)(onNodeAdd);
15356
+ onNodeAddRef.current = onNodeAdd;
15357
+ const onEdgeAddRef = (0, import_react7.useRef)(onEdgeAdd);
15358
+ onEdgeAddRef.current = onEdgeAdd;
15359
+ const canvasRefRef = (0, import_react7.useRef)(canvasRef);
15360
+ canvasRefRef.current = canvasRef;
15361
+ const onBeginBatchRef = (0, import_react7.useRef)(onBeginBatch);
15362
+ onBeginBatchRef.current = onBeginBatch;
15363
+ const onEndBatchRef = (0, import_react7.useRef)(onEndBatch);
15364
+ onEndBatchRef.current = onEndBatch;
15365
+ (0, import_react7.useEffect)(() => {
15366
+ const handler = (e) => {
15367
+ const active = document.activeElement;
15368
+ if (active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement || active instanceof HTMLElement && active.isContentEditable) {
15369
+ return;
15370
+ }
15371
+ const isMod = e.metaKey || e.ctrlKey;
15372
+ if (isMod && e.key === "c") {
15373
+ const selectedIds = selectedIdsRef.current;
15374
+ if (!selectedIds || selectedIds.size === 0)
15375
+ return;
15376
+ const nodes = nodesRef.current ?? [];
15377
+ const edges = edgesRef.current ?? [];
15378
+ const vp = viewport.current ?? { x: 0, y: 0, zoom: 1 };
15379
+ const copiedNodes = nodes.filter((n) => selectedIds.has(n.id));
15380
+ if (copiedNodes.length === 0)
15381
+ return;
15382
+ const copiedEdges = edges.filter((edge) => selectedIds.has(edge.fromNode) && selectedIds.has(edge.toNode));
15383
+ clipboardSnapshot = {
15384
+ nodes: copiedNodes,
15385
+ edges: copiedEdges,
15386
+ viewportAtCopy: { ...vp }
15387
+ };
15388
+ e.preventDefault();
15389
+ return;
15390
+ }
15391
+ if (isMod && e.key === "v") {
15392
+ if (!clipboardSnapshot)
15393
+ return;
15394
+ const { nodes: srcNodes, edges: srcEdges } = clipboardSnapshot;
15395
+ if (srcNodes.length === 0)
15396
+ return;
15397
+ const oldToNew = /* @__PURE__ */ new Map();
15398
+ for (const n of srcNodes) {
15399
+ oldToNew.set(n.id, generateNodeId());
15400
+ }
15401
+ let minX = Infinity;
15402
+ let minY = Infinity;
15403
+ let maxX = -Infinity;
15404
+ let maxY = -Infinity;
15405
+ for (const n of srcNodes) {
15406
+ minX = Math.min(minX, n.x);
15407
+ minY = Math.min(minY, n.y);
15408
+ maxX = Math.max(maxX, n.x + (n.width ?? 0));
15409
+ maxY = Math.max(maxY, n.y + (n.height ?? 0));
15410
+ }
15411
+ const clusterCx = (minX + maxX) / 2;
15412
+ const clusterCy = (minY + maxY) / 2;
15413
+ const vp = viewport.current ?? { x: 0, y: 0, zoom: 1 };
15414
+ const cursorScreen = getCursorScreenPosRef.current?.();
15415
+ let targetCanvas;
15416
+ if (cursorScreen) {
15417
+ targetCanvas = screenToCanvas(cursorScreen.x, cursorScreen.y, vp);
15418
+ } else {
15419
+ targetCanvas = screenToCanvas(0, 0, vp);
15420
+ targetCanvas = { x: targetCanvas.x + 40, y: targetCanvas.y + 40 };
15421
+ }
15422
+ const dx = targetCanvas.x - clusterCx;
15423
+ const dy = targetCanvas.y - clusterCy;
15424
+ const clonedNodes = srcNodes.map((n) => ({
15425
+ ...structuredClone(n),
15426
+ id: oldToNew.get(n.id),
15427
+ x: n.x + dx,
15428
+ y: n.y + dy
15429
+ }));
15430
+ const clonedEdges = srcEdges.filter((edge) => oldToNew.has(edge.fromNode) && oldToNew.has(edge.toNode)).map((edge) => ({
15431
+ ...structuredClone(edge),
15432
+ id: generateEdgeId(),
15433
+ fromNode: oldToNew.get(edge.fromNode),
15434
+ toNode: oldToNew.get(edge.toNode)
15435
+ }));
15436
+ const ref = canvasRefRef.current;
15437
+ onBeginBatchRef.current?.();
15438
+ for (const node of clonedNodes) {
15439
+ onNodeAddRef.current(node, ref);
15440
+ }
15441
+ for (const edge of clonedEdges) {
15442
+ onEdgeAddRef.current(edge, ref);
15443
+ }
15444
+ onEndBatchRef.current?.();
15445
+ e.preventDefault();
15446
+ return;
15447
+ }
15448
+ };
15449
+ document.addEventListener("keydown", handler);
15450
+ return () => {
15451
+ document.removeEventListener("keydown", handler);
15452
+ };
15453
+ }, [selectedIdsRef, nodesRef, edgesRef, viewport]);
15454
+ }
15455
+
15456
+ // ../react/dist/hooks/useCommandHistory.js
15457
+ var import_react8 = __toESM(require_react(), 1);
15458
+ function getCanvasRef(cmd) {
15459
+ if (cmd.type === "batch") {
15460
+ return cmd.commands.length > 0 ? getCanvasRef(cmd.commands[0]) : void 0;
15461
+ }
15462
+ return cmd.canvasRef;
15463
+ }
15464
+ function useCommandHistory(options) {
15465
+ const { nodesRef, edgesRef, onNodeAdd, onNodeUpdate, onNodesUpdate, onNodeDelete, onNodesDelete, onEdgeAdd, onEdgeUpdate, onEdgeDelete, maxDepth = 50, enabled = true, onUndo, onRedo } = options;
15466
+ const onNodeAddRef = (0, import_react8.useRef)(onNodeAdd);
15467
+ onNodeAddRef.current = onNodeAdd;
15468
+ const onNodeUpdateRef = (0, import_react8.useRef)(onNodeUpdate);
15469
+ onNodeUpdateRef.current = onNodeUpdate;
15470
+ const onNodesUpdateRef = (0, import_react8.useRef)(onNodesUpdate);
15471
+ onNodesUpdateRef.current = onNodesUpdate;
15472
+ const onNodeDeleteRef = (0, import_react8.useRef)(onNodeDelete);
15473
+ onNodeDeleteRef.current = onNodeDelete;
15474
+ const onNodesDeleteRef = (0, import_react8.useRef)(onNodesDelete);
15475
+ onNodesDeleteRef.current = onNodesDelete;
15476
+ const onEdgeAddRef = (0, import_react8.useRef)(onEdgeAdd);
15477
+ onEdgeAddRef.current = onEdgeAdd;
15478
+ const onEdgeUpdateRef = (0, import_react8.useRef)(onEdgeUpdate);
15479
+ onEdgeUpdateRef.current = onEdgeUpdate;
15480
+ const onEdgeDeleteRef = (0, import_react8.useRef)(onEdgeDelete);
15481
+ onEdgeDeleteRef.current = onEdgeDelete;
15482
+ const undoStack = (0, import_react8.useRef)([]);
15483
+ const redoStack = (0, import_react8.useRef)([]);
15484
+ const isUndoingRef = (0, import_react8.useRef)(false);
15485
+ const pendingBatchRef = (0, import_react8.useRef)(null);
15486
+ const [canUndo, setCanUndo] = (0, import_react8.useState)(false);
15487
+ const [canRedo, setCanRedo] = (0, import_react8.useState)(false);
15488
+ function syncBooleans() {
15489
+ setCanUndo(undoStack.current.length > 0);
15490
+ setCanRedo(redoStack.current.length > 0);
15491
+ }
15492
+ function pushCommand(cmd) {
15493
+ if (pendingBatchRef.current) {
15494
+ pendingBatchRef.current.push(cmd);
15495
+ return;
15496
+ }
15497
+ undoStack.current.push(cmd);
15498
+ if (undoStack.current.length > maxDepth)
15499
+ undoStack.current.shift();
15500
+ redoStack.current = [];
15501
+ syncBooleans();
15502
+ }
15503
+ function applyInverse(cmd) {
15504
+ switch (cmd.type) {
15505
+ case "node:add":
15506
+ onNodeDeleteRef.current?.(cmd.node.id, cmd.canvasRef);
15507
+ break;
15508
+ case "node:delete":
15509
+ onNodeAddRef.current?.(cmd.node, cmd.canvasRef);
15510
+ break;
15511
+ case "node:update":
15512
+ onNodeUpdateRef.current?.(cmd.id, cmd.prev, cmd.canvasRef);
15513
+ break;
15514
+ case "nodes:update":
15515
+ onNodesUpdateRef.current?.(cmd.updates.map((u) => ({ id: u.id, patch: u.prev })), cmd.canvasRef);
15516
+ break;
15517
+ case "nodes:delete":
15518
+ for (const node of cmd.nodes) {
15519
+ onNodeAddRef.current?.(node, cmd.canvasRef);
15520
+ }
15521
+ break;
15522
+ case "edge:add":
15523
+ onEdgeDeleteRef.current?.(cmd.edge.id, cmd.canvasRef);
15524
+ break;
15525
+ case "edge:delete":
15526
+ onEdgeAddRef.current?.(cmd.edge, cmd.canvasRef);
15527
+ break;
15528
+ case "edge:update":
15529
+ onEdgeUpdateRef.current?.(cmd.id, cmd.prev, cmd.canvasRef);
15530
+ break;
15531
+ case "batch":
15532
+ for (let i = cmd.commands.length - 1; i >= 0; i--) {
15533
+ applyInverse(cmd.commands[i]);
15534
+ }
15535
+ break;
15536
+ }
15537
+ }
15538
+ function applyForward(cmd) {
15539
+ switch (cmd.type) {
15540
+ case "node:add":
15541
+ onNodeAddRef.current?.(cmd.node, cmd.canvasRef);
15542
+ break;
15543
+ case "node:delete":
15544
+ onNodeDeleteRef.current?.(cmd.node.id, cmd.canvasRef);
15545
+ break;
15546
+ case "node:update":
15547
+ onNodeUpdateRef.current?.(cmd.id, cmd.patch, cmd.canvasRef);
15548
+ break;
15549
+ case "nodes:update":
15550
+ onNodesUpdateRef.current?.(cmd.updates.map((u) => ({ id: u.id, patch: u.patch })), cmd.canvasRef);
15551
+ break;
15552
+ case "nodes:delete":
15553
+ onNodesDeleteRef.current?.(cmd.nodes.map((n) => n.id), cmd.canvasRef);
15554
+ break;
15555
+ case "edge:add":
15556
+ onEdgeAddRef.current?.(cmd.edge, cmd.canvasRef);
15557
+ break;
15558
+ case "edge:delete":
15559
+ onEdgeDeleteRef.current?.(cmd.edge.id, cmd.canvasRef);
15560
+ break;
15561
+ case "edge:update":
15562
+ onEdgeUpdateRef.current?.(cmd.id, cmd.patch, cmd.canvasRef);
15563
+ break;
15564
+ case "batch":
15565
+ for (const c of cmd.commands) {
15566
+ applyForward(c);
15567
+ }
15568
+ break;
15569
+ }
15570
+ }
15571
+ const undo = (0, import_react8.useCallback)(() => {
15572
+ if (!enabled)
15573
+ return;
15574
+ const cmd = undoStack.current.pop();
15575
+ if (!cmd)
15576
+ return;
15577
+ isUndoingRef.current = true;
15578
+ applyInverse(cmd);
15579
+ isUndoingRef.current = false;
15580
+ redoStack.current.push(cmd);
15581
+ syncBooleans();
15582
+ onUndo?.(getCanvasRef(cmd));
15583
+ }, [enabled, onUndo]);
15584
+ const redo = (0, import_react8.useCallback)(() => {
15585
+ if (!enabled)
15586
+ return;
15587
+ const cmd = redoStack.current.pop();
15588
+ if (!cmd)
15589
+ return;
15590
+ isUndoingRef.current = true;
15591
+ applyForward(cmd);
15592
+ isUndoingRef.current = false;
15593
+ undoStack.current.push(cmd);
15594
+ if (undoStack.current.length > maxDepth)
15595
+ undoStack.current.shift();
15596
+ syncBooleans();
15597
+ onRedo?.(getCanvasRef(cmd));
15598
+ }, [enabled, onRedo, maxDepth]);
15599
+ const beginBatch = (0, import_react8.useCallback)(() => {
15600
+ if (!enabled)
15601
+ return;
15602
+ pendingBatchRef.current = [];
15603
+ }, [enabled]);
15604
+ const endBatch = (0, import_react8.useCallback)(() => {
15605
+ if (!enabled)
15606
+ return;
15607
+ const cmds = pendingBatchRef.current;
15608
+ pendingBatchRef.current = null;
15609
+ if (!cmds || cmds.length === 0)
15610
+ return;
15611
+ if (cmds.length === 1) {
15612
+ pushCommand(cmds[0]);
15613
+ return;
15614
+ }
15615
+ undoStack.current.push({ type: "batch", commands: cmds });
15616
+ if (undoStack.current.length > maxDepth)
15617
+ undoStack.current.shift();
15618
+ redoStack.current = [];
15619
+ syncBooleans();
15620
+ }, [enabled, maxDepth]);
15621
+ const wrappedOnNodeAdd = (0, import_react8.useCallback)(
15622
+ (node, canvasRef) => {
15623
+ if (enabled && !isUndoingRef.current) {
15624
+ pushCommand({ type: "node:add", node, canvasRef });
15625
+ }
15626
+ onNodeAddRef.current?.(node, canvasRef);
15627
+ },
15628
+ // eslint-disable-next-line react-hooks/exhaustive-deps
15629
+ [enabled]
15630
+ );
15631
+ const wrappedOnNodeUpdate = (0, import_react8.useCallback)(
15632
+ (id2, patch, canvasRef) => {
15633
+ if (enabled && !isUndoingRef.current) {
15634
+ const node = nodesRef.current?.find((n) => n.id === id2);
15635
+ if (node) {
15636
+ const prev = Object.fromEntries(Object.keys(patch).map((k) => [k, node[k]]));
15637
+ pushCommand({ type: "node:update", id: id2, prev, patch, canvasRef });
15638
+ }
15639
+ }
15640
+ onNodeUpdateRef.current?.(id2, patch, canvasRef);
15641
+ },
15642
+ // eslint-disable-next-line react-hooks/exhaustive-deps
15643
+ [enabled, nodesRef]
15644
+ );
15645
+ const wrappedOnNodesUpdate = (0, import_react8.useCallback)(
15646
+ (updates, canvasRef) => {
15647
+ if (enabled && !isUndoingRef.current) {
15648
+ const enriched = [];
15649
+ for (const u of updates) {
15650
+ const node = nodesRef.current?.find((n) => n.id === u.id);
15651
+ if (node) {
15652
+ const prev = Object.fromEntries(Object.keys(u.patch).map((k) => [k, node[k]]));
15653
+ enriched.push({ id: u.id, prev, patch: u.patch });
15654
+ }
15655
+ }
15656
+ if (enriched.length > 0) {
15657
+ pushCommand({ type: "nodes:update", updates: enriched, canvasRef });
15658
+ }
15659
+ }
15660
+ onNodesUpdateRef.current?.(updates, canvasRef);
15661
+ },
15662
+ // eslint-disable-next-line react-hooks/exhaustive-deps
15663
+ [enabled, nodesRef]
15664
+ );
15665
+ const wrappedOnNodeDelete = (0, import_react8.useCallback)(
15666
+ (nodeId, canvasRef) => {
15667
+ if (enabled && !isUndoingRef.current) {
15668
+ const node = nodesRef.current?.find((n) => n.id === nodeId);
15669
+ if (node) {
15670
+ pushCommand({ type: "node:delete", node, canvasRef });
15671
+ }
15672
+ }
15673
+ onNodeDeleteRef.current?.(nodeId, canvasRef);
15674
+ },
15675
+ // eslint-disable-next-line react-hooks/exhaustive-deps
15676
+ [enabled, nodesRef]
15677
+ );
15678
+ const wrappedOnNodesDelete = (0, import_react8.useCallback)(
15679
+ (nodeIds, canvasRef) => {
15680
+ if (enabled && !isUndoingRef.current) {
15681
+ const nodes = nodesRef.current?.filter((n) => nodeIds.includes(n.id)) ?? [];
15682
+ if (nodes.length > 0) {
15683
+ pushCommand({ type: "nodes:delete", nodes, canvasRef });
15684
+ }
15685
+ }
15686
+ onNodesDeleteRef.current?.(nodeIds, canvasRef);
15687
+ },
15688
+ // eslint-disable-next-line react-hooks/exhaustive-deps
15689
+ [enabled, nodesRef]
15690
+ );
15691
+ const wrappedOnEdgeAdd = (0, import_react8.useCallback)(
15692
+ (edge, canvasRef) => {
15693
+ if (enabled && !isUndoingRef.current) {
15694
+ pushCommand({ type: "edge:add", edge, canvasRef });
15695
+ }
15696
+ onEdgeAddRef.current?.(edge, canvasRef);
15697
+ },
15698
+ // eslint-disable-next-line react-hooks/exhaustive-deps
15699
+ [enabled]
15700
+ );
15701
+ const wrappedOnEdgeUpdate = (0, import_react8.useCallback)(
15702
+ (id2, patch, canvasRef) => {
15703
+ if (enabled && !isUndoingRef.current) {
15704
+ const edge = edgesRef.current?.find((e) => e.id === id2);
15705
+ if (edge) {
15706
+ const prev = Object.fromEntries(Object.keys(patch).map((k) => [k, edge[k]]));
15707
+ pushCommand({ type: "edge:update", id: id2, prev, patch, canvasRef });
15708
+ }
15709
+ }
15710
+ onEdgeUpdateRef.current?.(id2, patch, canvasRef);
15711
+ },
15712
+ // eslint-disable-next-line react-hooks/exhaustive-deps
15713
+ [enabled, edgesRef]
15714
+ );
15715
+ const wrappedOnEdgeDelete = (0, import_react8.useCallback)(
15716
+ (edgeId, canvasRef) => {
15717
+ if (enabled && !isUndoingRef.current) {
15718
+ const edge = edgesRef.current?.find((e) => e.id === edgeId);
15719
+ if (edge) {
15720
+ pushCommand({ type: "edge:delete", edge, canvasRef });
15721
+ }
15722
+ }
15723
+ onEdgeDeleteRef.current?.(edgeId, canvasRef);
15724
+ },
15725
+ // eslint-disable-next-line react-hooks/exhaustive-deps
15726
+ [enabled, edgesRef]
15727
+ );
15728
+ return {
15729
+ wrappedOnNodeAdd,
15730
+ wrappedOnNodeUpdate,
15731
+ wrappedOnNodesUpdate,
15732
+ wrappedOnNodeDelete,
15733
+ wrappedOnNodesDelete,
15734
+ wrappedOnEdgeAdd,
15735
+ wrappedOnEdgeUpdate,
15736
+ wrappedOnEdgeDelete,
15737
+ beginBatch,
15738
+ endBatch,
15739
+ undo,
15740
+ redo,
15741
+ canUndo,
15742
+ canRedo
15743
+ };
15744
+ }
15745
+
15746
+ // ../react/dist/hooks/useZoomNavigation.js
15747
+ var import_react9 = __toESM(require_react(), 1);
15155
15748
  function expandRect(rect, factor) {
15156
15749
  if (factor === 1)
15157
15750
  return rect;
@@ -15189,16 +15782,16 @@ var SystemCanvas = (() => {
15189
15782
  }
15190
15783
  function useZoomNavigation(options) {
15191
15784
  const { enabled, config, nodes, currentCanvas, parentFrame, canvases, onResolveCanvas, onSeedCanvas, theme, getViewportSize, getCursorScreenPos, onEnter, onExit } = options;
15192
- const committingRef = (0, import_react6.useRef)(false);
15193
- (0, import_react6.useEffect)(() => {
15785
+ const committingRef = (0, import_react9.useRef)(false);
15786
+ (0, import_react9.useEffect)(() => {
15194
15787
  committingRef.current = false;
15195
15788
  }, [currentCanvas]);
15196
- const exitArmedRef = (0, import_react6.useRef)(false);
15197
- (0, import_react6.useEffect)(() => {
15789
+ const exitArmedRef = (0, import_react9.useRef)(false);
15790
+ (0, import_react9.useEffect)(() => {
15198
15791
  exitArmedRef.current = false;
15199
15792
  }, [currentCanvas, parentFrame]);
15200
- const prefetchRef = (0, import_react6.useRef)(/* @__PURE__ */ new Map());
15201
- const prefetch = (0, import_react6.useCallback)((ref) => {
15793
+ const prefetchRef = (0, import_react9.useRef)(/* @__PURE__ */ new Map());
15794
+ const prefetch = (0, import_react9.useCallback)((ref) => {
15202
15795
  if (!onResolveCanvas)
15203
15796
  return;
15204
15797
  if (canvases?.[ref])
@@ -15216,7 +15809,7 @@ var SystemCanvas = (() => {
15216
15809
  state.loading = false;
15217
15810
  });
15218
15811
  }, [canvases, onResolveCanvas, onSeedCanvas]);
15219
- const handleViewportChange = (0, import_react6.useCallback)((vp) => {
15812
+ const handleViewportChange = (0, import_react9.useCallback)((vp) => {
15220
15813
  if (!enabled)
15221
15814
  return;
15222
15815
  if (committingRef.current)
@@ -15355,7 +15948,7 @@ var SystemCanvas = (() => {
15355
15948
  onEnter,
15356
15949
  onExit
15357
15950
  ]);
15358
- const clearCommitting = (0, import_react6.useCallback)(() => {
15951
+ const clearCommitting = (0, import_react9.useCallback)(() => {
15359
15952
  committingRef.current = false;
15360
15953
  }, []);
15361
15954
  return { handleViewportChange, clearCommitting };
@@ -15363,10 +15956,10 @@ var SystemCanvas = (() => {
15363
15956
 
15364
15957
  // ../react/dist/components/Viewport.js
15365
15958
  var import_jsx_runtime22 = __toESM(require_jsx_runtime(), 1);
15366
- var import_react15 = __toESM(require_react(), 1);
15959
+ var import_react18 = __toESM(require_react(), 1);
15367
15960
 
15368
15961
  // ../react/dist/hooks/useViewport.js
15369
- var import_react7 = __toESM(require_react(), 1);
15962
+ var import_react10 = __toESM(require_react(), 1);
15370
15963
 
15371
15964
  // ../../node_modules/d3-dispatch/src/dispatch.js
15372
15965
  var noop = { value: () => {
@@ -18109,13 +18702,13 @@ var SystemCanvas = (() => {
18109
18702
  // ../react/dist/hooks/useViewport.js
18110
18703
  function useViewport(options) {
18111
18704
  const { minZoom, maxZoom, defaultViewport, onViewportChange, marqueeActiveRef } = options;
18112
- const svgRef = (0, import_react7.useRef)(null);
18113
- const groupRef = (0, import_react7.useRef)(null);
18114
- const viewport = (0, import_react7.useRef)(defaultViewport ?? { x: 0, y: 0, zoom: 1 });
18115
- const zoomBehaviorRef = (0, import_react7.useRef)(null);
18116
- const onViewportChangeRef = (0, import_react7.useRef)(onViewportChange);
18705
+ const svgRef = (0, import_react10.useRef)(null);
18706
+ const groupRef = (0, import_react10.useRef)(null);
18707
+ const viewport = (0, import_react10.useRef)(defaultViewport ?? { x: 0, y: 0, zoom: 1 });
18708
+ const zoomBehaviorRef = (0, import_react10.useRef)(null);
18709
+ const onViewportChangeRef = (0, import_react10.useRef)(onViewportChange);
18117
18710
  onViewportChangeRef.current = onViewportChange;
18118
- (0, import_react7.useEffect)(() => {
18711
+ (0, import_react10.useEffect)(() => {
18119
18712
  const svg = svgRef.current;
18120
18713
  const group = groupRef.current;
18121
18714
  if (!svg || !group)
@@ -18155,7 +18748,7 @@ var SystemCanvas = (() => {
18155
18748
  selection2.on(".zoom", null);
18156
18749
  };
18157
18750
  }, [minZoom, maxZoom]);
18158
- const fitToContent = (0, import_react7.useCallback)((nodes, animate = true) => {
18751
+ const fitToContent = (0, import_react10.useCallback)((nodes, animate = true) => {
18159
18752
  const svg = svgRef.current;
18160
18753
  if (!svg || !zoomBehaviorRef.current || nodes.length === 0)
18161
18754
  return;
@@ -18168,13 +18761,13 @@ var SystemCanvas = (() => {
18168
18761
  select_default2(svg).call(zoomBehaviorRef.current.transform, t);
18169
18762
  }
18170
18763
  }, []);
18171
- const resetZoom = (0, import_react7.useCallback)(() => {
18764
+ const resetZoom = (0, import_react10.useCallback)(() => {
18172
18765
  const svg = svgRef.current;
18173
18766
  if (!svg || !zoomBehaviorRef.current)
18174
18767
  return;
18175
18768
  select_default2(svg).transition().duration(400).call(zoomBehaviorRef.current.transform, identity2);
18176
18769
  }, []);
18177
- const setTransform = (0, import_react7.useCallback)((transform2, options2) => {
18770
+ const setTransform = (0, import_react10.useCallback)((transform2, options2) => {
18178
18771
  const svg = svgRef.current;
18179
18772
  if (!svg || !zoomBehaviorRef.current)
18180
18773
  return;
@@ -18186,7 +18779,7 @@ var SystemCanvas = (() => {
18186
18779
  sel.call(zoomBehaviorRef.current.transform, t);
18187
18780
  }
18188
18781
  }, []);
18189
- const zoomToNode = (0, import_react7.useCallback)((node, onComplete, options2) => {
18782
+ const zoomToNode = (0, import_react10.useCallback)((node, onComplete, options2) => {
18190
18783
  const svg = svgRef.current;
18191
18784
  if (!svg || !zoomBehaviorRef.current) {
18192
18785
  onComplete?.();
@@ -18380,9 +18973,9 @@ var SystemCanvas = (() => {
18380
18973
 
18381
18974
  // ../react/dist/components/RefIndicator.js
18382
18975
  var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);
18383
- var import_react8 = __toESM(require_react(), 1);
18976
+ var import_react11 = __toESM(require_react(), 1);
18384
18977
  function RefIndicator({ node, theme, nodeX, nodeY, nodeWidth, nodeHeight, strokeColor, strokeWidth, corner = "bottom-right", size: sizeProp, onNavigate }) {
18385
- const [hover, setHover] = (0, import_react8.useState)(false);
18978
+ const [hover, setHover] = (0, import_react11.useState)(false);
18386
18979
  const iconKind = theme.node.refIndicator.icon;
18387
18980
  if (iconKind === "none")
18388
18981
  return null;
@@ -18453,7 +19046,7 @@ var SystemCanvas = (() => {
18453
19046
 
18454
19047
  // ../react/dist/components/CategorySlotsLayer.js
18455
19048
  var import_jsx_runtime9 = __toESM(require_jsx_runtime(), 1);
18456
- var import_react10 = __toESM(require_react(), 1);
19049
+ var import_react13 = __toESM(require_react(), 1);
18457
19050
 
18458
19051
  // ../react/dist/primitives/NodeColorFill.js
18459
19052
  var import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1);
@@ -18573,9 +19166,9 @@ var SystemCanvas = (() => {
18573
19166
 
18574
19167
  // ../react/dist/primitives/NodeText.js
18575
19168
  var import_jsx_runtime7 = __toESM(require_jsx_runtime(), 1);
18576
- var import_react9 = __toESM(require_react(), 1);
19169
+ var import_react12 = __toESM(require_react(), 1);
18577
19170
  function NodeText({ region, value, theme, color: color2, fill, align = "start", fontWeight = 500, uppercase = false, useLabelFont = false, fontFamily, fontSize: fontSizeProp, wrap = false, maxLines, lineHeight: lineHeightProp, verticalAlign = "top" }) {
18578
- const reactId = (0, import_react9.useId)();
19171
+ const reactId = (0, import_react12.useId)();
18579
19172
  const safeId = reactId.replace(/:/g, "");
18580
19173
  if (!value)
18581
19174
  return null;
@@ -18649,8 +19242,8 @@ var SystemCanvas = (() => {
18649
19242
  // ../react/dist/components/CategorySlotsLayer.js
18650
19243
  function CategorySlotsLayer({ node, theme, canvases, slots: slotsProp }) {
18651
19244
  const slots = slotsProp ?? getCategorySlots(node, theme);
18652
- const regions = (0, import_react10.useMemo)(() => computeCategorySlotRegions(node, theme, slots), [node, theme, slots]);
18653
- const reactId = (0, import_react10.useId)();
19245
+ const regions = (0, import_react13.useMemo)(() => computeCategorySlotRegions(node, theme, slots), [node, theme, slots]);
19246
+ const reactId = (0, import_react13.useId)();
18654
19247
  const clipId = `sc-edge-clip-${reactId.replace(/:/g, "")}`;
18655
19248
  if (!slots)
18656
19249
  return null;
@@ -18883,7 +19476,7 @@ var SystemCanvas = (() => {
18883
19476
 
18884
19477
  // ../react/dist/components/ResizeHandles.js
18885
19478
  var import_jsx_runtime14 = __toESM(require_jsx_runtime(), 1);
18886
- var import_react11 = __toESM(require_react(), 1);
19479
+ var import_react14 = __toESM(require_react(), 1);
18887
19480
  var HANDLE_SIZE = 7;
18888
19481
  var CORNERS = [
18889
19482
  { corner: "nw", cursor: "nwse-resize", anchor: "nw" },
@@ -18894,7 +19487,7 @@ var SystemCanvas = (() => {
18894
19487
  var cornerInset = (cornerRadius) => Math.min(cornerRadius * 0.25, 3);
18895
19488
  function ResizeHandles({ node, theme, onHandlePointerDown }) {
18896
19489
  const { x, y, width, height } = node;
18897
- const [hoveredCorner, setHoveredCorner] = (0, import_react11.useState)(null);
19490
+ const [hoveredCorner, setHoveredCorner] = (0, import_react14.useState)(null);
18898
19491
  const handleColor = node.resolvedStroke ?? theme.node.labelColor;
18899
19492
  const i = cornerInset(node.resolvedCornerRadius);
18900
19493
  const anchorPos = (anchor) => {
@@ -18919,7 +19512,7 @@ var SystemCanvas = (() => {
18919
19512
  }
18920
19513
 
18921
19514
  // ../react/dist/components/NodeRenderer.js
18922
- function NodeRenderer({ nodes, theme, onClick, onDoubleClick, onContextMenu, onNavigate, onPointerDown, selectedId, editingId, onResizeHandlePointerDown, canvases, only }) {
19515
+ function NodeRenderer({ nodes, theme, onClick, onDoubleClick, onContextMenu, onNavigate, onPointerDown, selectedIds, editingId, onResizeHandlePointerDown, canvases, only }) {
18923
19516
  const groups = nodes.filter((n) => n.type === "group");
18924
19517
  const others = nodes.filter((n) => n.type !== "group");
18925
19518
  const common = (node) => {
@@ -18935,7 +19528,7 @@ var SystemCanvas = (() => {
18935
19528
  onContextMenu,
18936
19529
  onNavigate,
18937
19530
  onPointerDown,
18938
- isSelected: selectedId === node.id,
19531
+ isSelected: selectedIds?.has(node.id) ?? false,
18939
19532
  isEditing: editingId === node.id,
18940
19533
  slots,
18941
19534
  canvases,
@@ -18946,7 +19539,8 @@ var SystemCanvas = (() => {
18946
19539
  refCorner
18947
19540
  };
18948
19541
  };
18949
- const selectedNode = selectedId && editingId !== selectedId ? nodes.find((n) => n.id === selectedId) : void 0;
19542
+ const singleSelectedId = selectedIds?.size === 1 ? Array.from(selectedIds)[0] : null;
19543
+ const selectedNode = singleSelectedId && editingId !== singleSelectedId ? nodes.find((n) => n.id === singleSelectedId) : void 0;
18950
19544
  const renderResizeHandles = only !== "groups" && selectedNode && onResizeHandlePointerDown;
18951
19545
  return (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [only !== "non-groups" && groups.map((node) => (0, import_jsx_runtime15.jsx)(GroupNode, { ...common(node) }, node.id)), only !== "groups" && others.map((node) => {
18952
19546
  const Component = getNodeComponent(node.type);
@@ -19004,7 +19598,7 @@ var SystemCanvas = (() => {
19004
19598
 
19005
19599
  // ../react/dist/components/NodeEditor.js
19006
19600
  var import_jsx_runtime17 = __toESM(require_jsx_runtime(), 1);
19007
- var import_react12 = __toESM(require_react(), 1);
19601
+ var import_react15 = __toESM(require_react(), 1);
19008
19602
  function NodeEditor({ node, theme, onCommit, onCancel }) {
19009
19603
  const editableFields = useCategoryFields(node, theme);
19010
19604
  if (editableFields) {
@@ -19023,11 +19617,11 @@ var SystemCanvas = (() => {
19023
19617
  }
19024
19618
  function SingleFieldEditor({ node, theme, onCommit, onCancel }) {
19025
19619
  const initial = getInitialValue(node);
19026
- const [value, setValue] = (0, import_react12.useState)(initial);
19027
- const textareaRef = (0, import_react12.useRef)(null);
19028
- const inputRef = (0, import_react12.useRef)(null);
19029
- const committedRef = (0, import_react12.useRef)(false);
19030
- (0, import_react12.useEffect)(() => {
19620
+ const [value, setValue] = (0, import_react15.useState)(initial);
19621
+ const textareaRef = (0, import_react15.useRef)(null);
19622
+ const inputRef = (0, import_react15.useRef)(null);
19623
+ const committedRef = (0, import_react15.useRef)(false);
19624
+ (0, import_react15.useEffect)(() => {
19031
19625
  const el = textareaRef.current ?? inputRef.current;
19032
19626
  if (el) {
19033
19627
  el.focus();
@@ -19123,10 +19717,10 @@ var SystemCanvas = (() => {
19123
19717
  }
19124
19718
  }
19125
19719
  function FormEditor({ node, theme, fields, onCommit, onCancel }) {
19126
- const initial = (0, import_react12.useMemo)(() => readInitialValues(node, fields), [node, fields]);
19127
- const [values, setValues] = (0, import_react12.useState)(initial);
19128
- const committedRef = (0, import_react12.useRef)(false);
19129
- const panelRef = (0, import_react12.useRef)(null);
19720
+ const initial = (0, import_react15.useMemo)(() => readInitialValues(node, fields), [node, fields]);
19721
+ const [values, setValues] = (0, import_react15.useState)(initial);
19722
+ const committedRef = (0, import_react15.useRef)(false);
19723
+ const panelRef = (0, import_react15.useRef)(null);
19130
19724
  const width = Math.max(node.width, 240);
19131
19725
  const height = Math.max(node.height, 36 + fields.length * 44);
19132
19726
  const commit = () => {
@@ -19155,7 +19749,7 @@ var SystemCanvas = (() => {
19155
19749
  const stopPointer = (e) => {
19156
19750
  e.stopPropagation();
19157
19751
  };
19158
- (0, import_react12.useEffect)(() => {
19752
+ (0, import_react15.useEffect)(() => {
19159
19753
  const el = panelRef.current;
19160
19754
  if (!el)
19161
19755
  return;
@@ -19285,13 +19879,13 @@ var SystemCanvas = (() => {
19285
19879
 
19286
19880
  // ../react/dist/components/EdgeLabelEditor.js
19287
19881
  var import_jsx_runtime18 = __toESM(require_jsx_runtime(), 1);
19288
- var import_react13 = __toESM(require_react(), 1);
19882
+ var import_react16 = __toESM(require_react(), 1);
19289
19883
  var EDITOR_WIDTH = 110;
19290
19884
  function EdgeLabelEditor({ initialLabel, midpoint, theme, onCommit, onCancel }) {
19291
- const [value, setValue] = (0, import_react13.useState)(initialLabel);
19292
- const inputRef = (0, import_react13.useRef)(null);
19293
- const committedRef = (0, import_react13.useRef)(false);
19294
- (0, import_react13.useEffect)(() => {
19885
+ const [value, setValue] = (0, import_react16.useState)(initialLabel);
19886
+ const inputRef = (0, import_react16.useRef)(null);
19887
+ const committedRef = (0, import_react16.useRef)(false);
19888
+ (0, import_react16.useEffect)(() => {
19295
19889
  const el = inputRef.current;
19296
19890
  if (el) {
19297
19891
  el.focus();
@@ -19346,7 +19940,7 @@ var SystemCanvas = (() => {
19346
19940
 
19347
19941
  // ../react/dist/components/ConnectionHandles.js
19348
19942
  var import_jsx_runtime19 = __toESM(require_jsx_runtime(), 1);
19349
- var import_react14 = __toESM(require_react(), 1);
19943
+ var import_react17 = __toESM(require_react(), 1);
19350
19944
  var SIDES = ["top", "right", "bottom", "left"];
19351
19945
  var HANDLE_RADIUS = 4;
19352
19946
  var HANDLE_HIT_RADIUS = 10;
@@ -19355,9 +19949,9 @@ var SystemCanvas = (() => {
19355
19949
  var HOVER_SCALE = 1.42;
19356
19950
  var HOVER_TRANSITION_MS = 120;
19357
19951
  function ConnectionHandles({ node, theme, onHandlePointerDown, immediate, activeSide }) {
19358
- const [visible, setVisible] = (0, import_react14.useState)(!!immediate);
19359
- const [hoveredSide, setHoveredSide] = (0, import_react14.useState)(null);
19360
- (0, import_react14.useEffect)(() => {
19952
+ const [visible, setVisible] = (0, import_react17.useState)(!!immediate);
19953
+ const [hoveredSide, setHoveredSide] = (0, import_react17.useState)(null);
19954
+ (0, import_react17.useEffect)(() => {
19361
19955
  if (immediate) {
19362
19956
  setVisible(true);
19363
19957
  return;
@@ -19444,17 +20038,18 @@ var SystemCanvas = (() => {
19444
20038
  // ../react/dist/components/Viewport.js
19445
20039
  var HOVER_PADDING = 10;
19446
20040
  var EDGE_PROXIMITY = 16;
19447
- var Viewport = (0, import_react15.forwardRef)(function Viewport2({ nodes, edges, nodeMap, theme, edgeStyle, columns, rows, canvases, minZoom, maxZoom, defaultViewport, onViewportChange, onNodeClick, onNodeDoubleClick, onNodeNavigate, onEdgeClick, onEdgeDoubleClick, onCanvasClick, onCanvasContextMenu, onNodeContextMenu, onEdgeContextMenu, onNodePointerDown, selectedId, editingId, selectedEdgeId, editingEdgeId, dragOverrides, dropTargetId, resizeOverrides, onResizeHandlePointerDown, onEditorCommit, onEditorCancel, onEdgeEditorCommit, onEdgeEditorCancel, pendingEdge, onConnectionHandlePointerDown, edgeCreateEnabled, autoFit = "canvas-change", canvasRef, handoffTransform, onHandoffApplied, handoffFadeMs = 0 }, ref) {
20041
+ var Viewport = (0, import_react18.forwardRef)(function Viewport2({ nodes, edges, nodeMap, theme, edgeStyle, columns, rows, canvases, minZoom, maxZoom, defaultViewport, onViewportChange, onNodeClick, onNodeDoubleClick, onNodeNavigate, onEdgeClick, onEdgeDoubleClick, onCanvasClick, onCanvasContextMenu, onNodeContextMenu, onEdgeContextMenu, onNodePointerDown, selectedIds, editingId, selectedEdgeId, editingEdgeId, dragOverrides, dropTargetId, marqueeRect, marqueeActiveRef, resizeOverrides, onResizeHandlePointerDown, onEditorCommit, onEditorCancel, onEdgeEditorCommit, onEdgeEditorCancel, pendingEdge, onConnectionHandlePointerDown, edgeCreateEnabled, autoFit = "canvas-change", canvasRef, handoffTransform, onHandoffApplied, handoffFadeMs = 0 }, ref) {
19448
20042
  const { svgRef, groupRef, viewport, fitToContent, zoomToNode, setTransform } = useViewport({
19449
20043
  minZoom,
19450
20044
  maxZoom,
19451
20045
  defaultViewport,
19452
- onViewportChange
20046
+ onViewportChange,
20047
+ marqueeActiveRef
19453
20048
  });
19454
- const navigatingRef = (0, import_react15.useRef)(false);
19455
- const fadeRafRef = (0, import_react15.useRef)(null);
19456
- const fadeTimeoutRef = (0, import_react15.useRef)(null);
19457
- const triggerFade = (0, import_react15.useCallback)((durationMs) => {
20049
+ const navigatingRef = (0, import_react18.useRef)(false);
20050
+ const fadeRafRef = (0, import_react18.useRef)(null);
20051
+ const fadeTimeoutRef = (0, import_react18.useRef)(null);
20052
+ const triggerFade = (0, import_react18.useCallback)((durationMs) => {
19458
20053
  if (durationMs <= 0)
19459
20054
  return;
19460
20055
  const g = groupRef.current;
@@ -19477,7 +20072,7 @@ var SystemCanvas = (() => {
19477
20072
  }, durationMs + 16);
19478
20073
  });
19479
20074
  }, []);
19480
- (0, import_react15.useEffect)(() => {
20075
+ (0, import_react18.useEffect)(() => {
19481
20076
  return () => {
19482
20077
  if (fadeRafRef.current !== null)
19483
20078
  cancelAnimationFrame(fadeRafRef.current);
@@ -19485,10 +20080,10 @@ var SystemCanvas = (() => {
19485
20080
  clearTimeout(fadeTimeoutRef.current);
19486
20081
  };
19487
20082
  }, []);
19488
- const [hoveredNodeId, setHoveredNodeId] = (0, import_react15.useState)(null);
19489
- const [hoveredSide, setHoveredSide] = (0, import_react15.useState)(null);
19490
- const cursorPosRef = (0, import_react15.useRef)(null);
19491
- (0, import_react15.useImperativeHandle)(ref, () => ({
20083
+ const [hoveredNodeId, setHoveredNodeId] = (0, import_react18.useState)(null);
20084
+ const [hoveredSide, setHoveredSide] = (0, import_react18.useState)(null);
20085
+ const cursorPosRef = (0, import_react18.useRef)(null);
20086
+ (0, import_react18.useImperativeHandle)(ref, () => ({
19492
20087
  zoomToNode: (node, onComplete, options) => {
19493
20088
  navigatingRef.current = true;
19494
20089
  zoomToNode(node, onComplete, options);
@@ -19499,7 +20094,7 @@ var SystemCanvas = (() => {
19499
20094
  getViewport: () => viewport.current ?? { x: 0, y: 0, zoom: 1 },
19500
20095
  getCursorScreenPos: () => cursorPosRef.current
19501
20096
  }));
19502
- const renderNodes = (0, import_react15.useMemo)(() => {
20097
+ const renderNodes = (0, import_react18.useMemo)(() => {
19503
20098
  const hasDrag = dragOverrides && dragOverrides.size > 0;
19504
20099
  const hasResize = resizeOverrides && resizeOverrides.size > 0;
19505
20100
  if (!hasDrag && !hasResize)
@@ -19512,7 +20107,7 @@ var SystemCanvas = (() => {
19512
20107
  return d ? { ...n, x: d.x, y: d.y } : n;
19513
20108
  });
19514
20109
  }, [nodes, dragOverrides, resizeOverrides]);
19515
- const renderNodeMap = (0, import_react15.useMemo)(() => {
20110
+ const renderNodeMap = (0, import_react18.useMemo)(() => {
19516
20111
  const hasDrag = dragOverrides && dragOverrides.size > 0;
19517
20112
  const hasResize = resizeOverrides && resizeOverrides.size > 0;
19518
20113
  if (!hasDrag && !hasResize)
@@ -19523,11 +20118,11 @@ var SystemCanvas = (() => {
19523
20118
  }
19524
20119
  return m;
19525
20120
  }, [renderNodes, nodeMap, dragOverrides, resizeOverrides]);
19526
- const latestNodesRef = (0, import_react15.useRef)(nodes);
19527
- (0, import_react15.useEffect)(() => {
20121
+ const latestNodesRef = (0, import_react18.useRef)(nodes);
20122
+ (0, import_react18.useEffect)(() => {
19528
20123
  latestNodesRef.current = nodes;
19529
20124
  }, [nodes]);
19530
- const fitNow = (0, import_react15.useCallback)(() => {
20125
+ const fitNow = (0, import_react18.useCallback)(() => {
19531
20126
  const current = latestNodesRef.current;
19532
20127
  if (current.length === 0)
19533
20128
  return;
@@ -19537,7 +20132,7 @@ var SystemCanvas = (() => {
19537
20132
  fitToContent(current, animate);
19538
20133
  });
19539
20134
  }, [fitToContent]);
19540
- (0, import_react15.useEffect)(() => {
20135
+ (0, import_react18.useEffect)(() => {
19541
20136
  if (defaultViewport)
19542
20137
  return;
19543
20138
  if (autoFit !== "always")
@@ -19546,8 +20141,8 @@ var SystemCanvas = (() => {
19546
20141
  return;
19547
20142
  fitNow();
19548
20143
  }, [nodes, autoFit, defaultViewport, fitNow]);
19549
- const fittedForRef = (0, import_react15.useRef)(null);
19550
- (0, import_react15.useEffect)(() => {
20144
+ const fittedForRef = (0, import_react18.useRef)(null);
20145
+ (0, import_react18.useEffect)(() => {
19551
20146
  if (defaultViewport)
19552
20147
  return;
19553
20148
  if (autoFit !== "canvas-change" && autoFit !== "initial")
@@ -19579,7 +20174,7 @@ var SystemCanvas = (() => {
19579
20174
  triggerFade
19580
20175
  ]);
19581
20176
  const editingNode = editingId ? renderNodes.find((n) => n.id === editingId) ?? null : null;
19582
- const handleSvgPointerMove = (0, import_react15.useCallback)((event) => {
20177
+ const handleSvgPointerMove = (0, import_react18.useCallback)((event) => {
19583
20178
  const svg = svgRef.current;
19584
20179
  if (!svg)
19585
20180
  return;
@@ -19631,7 +20226,7 @@ var SystemCanvas = (() => {
19631
20226
  setHoveredSide((prev) => prev === null ? prev : null);
19632
20227
  }
19633
20228
  }, [edgeCreateEnabled, renderNodes, svgRef, viewport]);
19634
- const handleSvgPointerLeave = (0, import_react15.useCallback)(() => {
20229
+ const handleSvgPointerLeave = (0, import_react18.useCallback)(() => {
19635
20230
  setHoveredNodeId(null);
19636
20231
  setHoveredSide(null);
19637
20232
  cursorPosRef.current = null;
@@ -19660,12 +20255,17 @@ var SystemCanvas = (() => {
19660
20255
  WebkitUserSelect: "none",
19661
20256
  MozUserSelect: "none",
19662
20257
  msUserSelect: "none"
19663
- }, onClick: onCanvasClick, onContextMenu: onCanvasContextMenu, onPointerMove: handleSvgPointerMove, onPointerLeave: handleSvgPointerLeave, children: [(0, import_jsx_runtime22.jsx)("defs", { children: (0, import_jsx_runtime22.jsx)("pattern", { id: "system-canvas-grid", width: theme.grid.size, height: theme.grid.size, patternUnits: "userSpaceOnUse", children: (0, import_jsx_runtime22.jsx)("path", { d: `M ${theme.grid.size} 0 L 0 0 0 ${theme.grid.size}`, fill: "none", stroke: theme.grid.color, strokeWidth: theme.grid.strokeWidth }) }) }), (0, import_jsx_runtime22.jsx)("rect", { x: "-50000", y: "-50000", width: "100000", height: "100000", fill: "url(#system-canvas-grid)" }), (0, import_jsx_runtime22.jsxs)("g", { ref: groupRef, children: [(0, import_jsx_runtime22.jsx)(LanesBackground, { columns, rows, theme }), (0, import_jsx_runtime22.jsx)(NodeRenderer, { nodes: renderNodes, theme, onClick: onNodeClick, onDoubleClick: onNodeDoubleClick, onContextMenu: onNodeContextMenu, onNavigate: onNodeNavigate, onPointerDown: onNodePointerDown, selectedId, editingId, canvases, only: "groups" }), (0, import_jsx_runtime22.jsx)(EdgeRenderer, { edges, nodeMap: renderNodeMap, theme, defaultEdgeStyle: edgeStyle, onClick: onEdgeClick, onDoubleClick: onEdgeDoubleClick, onContextMenu: onEdgeContextMenu, selectedId: selectedEdgeId, editingId: editingEdgeId }), (0, import_jsx_runtime22.jsx)(NodeRenderer, { nodes: renderNodes, theme, onClick: onNodeClick, onDoubleClick: onNodeDoubleClick, onContextMenu: onNodeContextMenu, onNavigate: onNodeNavigate, onPointerDown: onNodePointerDown, selectedId, editingId, onResizeHandlePointerDown, canvases, only: "non-groups" }), pendingTargetNode && (0, import_jsx_runtime22.jsx)("rect", { className: "system-canvas-drop-target", x: pendingTargetNode.x - 4, y: pendingTargetNode.y - 4, width: pendingTargetNode.width + 8, height: pendingTargetNode.height + 8, rx: pendingTargetNode.resolvedCornerRadius + 4, fill: "none", stroke: theme.node.labelColor, strokeWidth: 2, opacity: 0.85, pointerEvents: "none" }), dropTargetNode && (0, import_jsx_runtime22.jsx)("rect", { className: "system-canvas-drop-target system-canvas-node-drop-target", x: dropTargetNode.x - 4, y: dropTargetNode.y - 4, width: dropTargetNode.width + 8, height: dropTargetNode.height + 8, rx: dropTargetNode.resolvedCornerRadius + 4, fill: "none", stroke: theme.node.labelColor, strokeWidth: 2, strokeDasharray: "6 4", opacity: 0.9, pointerEvents: "none" }), pendingEdge && pendingSourceNode && (0, import_jsx_runtime22.jsx)(PendingEdgeRenderer, { sourceNode: pendingSourceNode, sourceSide: pendingEdge.sourceSide, cursor: pendingEdge.cursor, targetNode: pendingTargetNode, theme, defaultEdgeStyle: edgeStyle }), handlesNode && onConnectionHandlePointerDown && (0, import_jsx_runtime22.jsx)(ConnectionHandles, { node: handlesNode, theme, onHandlePointerDown: onConnectionHandlePointerDown, immediate: !!pendingEdge, activeSide: hoveredSide }), editingNode && onEditorCommit && onEditorCancel && (0, import_jsx_runtime22.jsx)(NodeEditor, { node: editingNode, theme, onCommit: onEditorCommit, onCancel: onEditorCancel }), editingEdge && editingEdgeMidpoint && onEdgeEditorCommit && onEdgeEditorCancel && (0, import_jsx_runtime22.jsx)(EdgeLabelEditor, { initialLabel: editingEdge.label ?? "", midpoint: editingEdgeMidpoint, theme, onCommit: onEdgeEditorCommit, onCancel: onEdgeEditorCancel })] })] });
20258
+ }, onClick: onCanvasClick, onContextMenu: onCanvasContextMenu, onPointerMove: handleSvgPointerMove, onPointerLeave: handleSvgPointerLeave, children: [(0, import_jsx_runtime22.jsx)("defs", { children: (0, import_jsx_runtime22.jsx)("pattern", { id: "system-canvas-grid", width: theme.grid.size, height: theme.grid.size, patternUnits: "userSpaceOnUse", children: (0, import_jsx_runtime22.jsx)("path", { d: `M ${theme.grid.size} 0 L 0 0 0 ${theme.grid.size}`, fill: "none", stroke: theme.grid.color, strokeWidth: theme.grid.strokeWidth }) }) }), (0, import_jsx_runtime22.jsx)("rect", { x: "-50000", y: "-50000", width: "100000", height: "100000", fill: "url(#system-canvas-grid)" }), (0, import_jsx_runtime22.jsxs)("g", { ref: groupRef, children: [(0, import_jsx_runtime22.jsx)(LanesBackground, { columns, rows, theme }), (0, import_jsx_runtime22.jsx)(NodeRenderer, { nodes: renderNodes, theme, onClick: onNodeClick, onDoubleClick: onNodeDoubleClick, onContextMenu: onNodeContextMenu, onNavigate: onNodeNavigate, onPointerDown: onNodePointerDown, selectedIds, editingId, canvases, only: "groups" }), (0, import_jsx_runtime22.jsx)(EdgeRenderer, { edges, nodeMap: renderNodeMap, theme, defaultEdgeStyle: edgeStyle, onClick: onEdgeClick, onDoubleClick: onEdgeDoubleClick, onContextMenu: onEdgeContextMenu, selectedId: selectedEdgeId, editingId: editingEdgeId }), (0, import_jsx_runtime22.jsx)(NodeRenderer, { nodes: renderNodes, theme, onClick: onNodeClick, onDoubleClick: onNodeDoubleClick, onContextMenu: onNodeContextMenu, onNavigate: onNodeNavigate, onPointerDown: onNodePointerDown, selectedIds, editingId, onResizeHandlePointerDown, canvases, only: "non-groups" }), pendingTargetNode && (0, import_jsx_runtime22.jsx)("rect", { className: "system-canvas-drop-target", x: pendingTargetNode.x - 4, y: pendingTargetNode.y - 4, width: pendingTargetNode.width + 8, height: pendingTargetNode.height + 8, rx: pendingTargetNode.resolvedCornerRadius + 4, fill: "none", stroke: theme.node.labelColor, strokeWidth: 2, opacity: 0.85, pointerEvents: "none" }), dropTargetNode && (0, import_jsx_runtime22.jsx)("rect", { className: "system-canvas-drop-target system-canvas-node-drop-target", x: dropTargetNode.x - 4, y: dropTargetNode.y - 4, width: dropTargetNode.width + 8, height: dropTargetNode.height + 8, rx: dropTargetNode.resolvedCornerRadius + 4, fill: "none", stroke: theme.node.labelColor, strokeWidth: 2, strokeDasharray: "6 4", opacity: 0.9, pointerEvents: "none" }), selectedIds && selectedIds.size > 0 && Array.from(selectedIds).map((id2) => {
20259
+ const node = renderNodeMap.get(id2);
20260
+ if (!node)
20261
+ return null;
20262
+ return (0, import_jsx_runtime22.jsx)("rect", { x: node.x - 3, y: node.y - 3, width: node.width + 6, height: node.height + 6, rx: (node.resolvedCornerRadius ?? 0) + 3, fill: "none", stroke: theme.node.labelColor, strokeWidth: 1.5, opacity: 0.7, pointerEvents: "none" }, `halo-${id2}`);
20263
+ }), pendingEdge && pendingSourceNode && (0, import_jsx_runtime22.jsx)(PendingEdgeRenderer, { sourceNode: pendingSourceNode, sourceSide: pendingEdge.sourceSide, cursor: pendingEdge.cursor, targetNode: pendingTargetNode, theme, defaultEdgeStyle: edgeStyle }), handlesNode && onConnectionHandlePointerDown && (0, import_jsx_runtime22.jsx)(ConnectionHandles, { node: handlesNode, theme, onHandlePointerDown: onConnectionHandlePointerDown, immediate: !!pendingEdge, activeSide: hoveredSide }), editingNode && onEditorCommit && onEditorCancel && (0, import_jsx_runtime22.jsx)(NodeEditor, { node: editingNode, theme, onCommit: onEditorCommit, onCancel: onEditorCancel }), editingEdge && editingEdgeMidpoint && onEdgeEditorCommit && onEdgeEditorCancel && (0, import_jsx_runtime22.jsx)(EdgeLabelEditor, { initialLabel: editingEdge.label ?? "", midpoint: editingEdgeMidpoint, theme, onCommit: onEdgeEditorCommit, onCancel: onEdgeEditorCancel })] }), marqueeRect && (0, import_jsx_runtime22.jsx)("rect", { x: Math.min(marqueeRect.x1, marqueeRect.x2), y: Math.min(marqueeRect.y1, marqueeRect.y2), width: Math.abs(marqueeRect.x2 - marqueeRect.x1), height: Math.abs(marqueeRect.y2 - marqueeRect.y1), fill: theme.node.labelColor + "18", stroke: theme.node.labelColor, strokeWidth: 1, opacity: 0.9, pointerEvents: "none" })] });
19664
20264
  });
19665
20265
 
19666
20266
  // ../react/dist/components/Breadcrumbs.js
19667
20267
  var import_jsx_runtime23 = __toESM(require_jsx_runtime(), 1);
19668
- var import_react16 = __toESM(require_react(), 1);
20268
+ var import_react19 = __toESM(require_react(), 1);
19669
20269
  function Breadcrumbs({ breadcrumbs, theme, onNavigate }) {
19670
20270
  if (breadcrumbs.length <= 1)
19671
20271
  return null;
@@ -19686,7 +20286,7 @@ var SystemCanvas = (() => {
19686
20286
  backdropFilter: "blur(8px)"
19687
20287
  }, children: breadcrumbs.map((crumb, index) => {
19688
20288
  const isLast = index === breadcrumbs.length - 1;
19689
- return (0, import_jsx_runtime23.jsxs)(import_react16.default.Fragment, { children: [index > 0 && (0, import_jsx_runtime23.jsx)("span", { style: {
20289
+ return (0, import_jsx_runtime23.jsxs)(import_react19.default.Fragment, { children: [index > 0 && (0, import_jsx_runtime23.jsx)("span", { style: {
19690
20290
  color: theme.separatorColor,
19691
20291
  margin: "0 2px"
19692
20292
  }, children: "/" }), (0, import_jsx_runtime23.jsx)("span", { onClick: isLast ? void 0 : () => onNavigate(index), style: {
@@ -19710,11 +20310,11 @@ var SystemCanvas = (() => {
19710
20310
 
19711
20311
  // ../react/dist/components/AddNodeButton.js
19712
20312
  var import_jsx_runtime24 = __toESM(require_jsx_runtime(), 1);
19713
- var import_react17 = __toESM(require_react(), 1);
20313
+ var import_react20 = __toESM(require_react(), 1);
19714
20314
  function AddNodeButton({ options, addNode: addNode2, theme }) {
19715
- const [open, setOpen] = (0, import_react17.useState)(false);
19716
- const rootRef = (0, import_react17.useRef)(null);
19717
- (0, import_react17.useEffect)(() => {
20315
+ const [open, setOpen] = (0, import_react20.useState)(false);
20316
+ const rootRef = (0, import_react20.useRef)(null);
20317
+ (0, import_react20.useEffect)(() => {
19718
20318
  if (!open)
19719
20319
  return;
19720
20320
  function onDocClick(e) {
@@ -19803,7 +20403,7 @@ var SystemCanvas = (() => {
19803
20403
  } });
19804
20404
  }
19805
20405
  function MenuRow({ theme, option, onClick }) {
19806
- const [hover, setHover] = (0, import_react17.useState)(false);
20406
+ const [hover, setHover] = (0, import_react20.useState)(false);
19807
20407
  const swatchSize = 18;
19808
20408
  return (0, import_jsx_runtime24.jsxs)("div", { role: "button", onClick, onMouseEnter: () => setHover(true), onMouseLeave: () => setHover(false), style: {
19809
20409
  display: "flex",
@@ -19839,12 +20439,12 @@ var SystemCanvas = (() => {
19839
20439
 
19840
20440
  // ../react/dist/components/LaneHeaders.js
19841
20441
  var import_jsx_runtime25 = __toESM(require_jsx_runtime(), 1);
19842
- var import_react18 = __toESM(require_react(), 1);
20442
+ var import_react21 = __toESM(require_react(), 1);
19843
20443
  function LaneHeaders({ columns, rows, theme, getViewport, width, height, pinned = true }) {
19844
20444
  const hasColumns = columns && columns.length > 0;
19845
20445
  const hasRows = rows && rows.length > 0;
19846
- const [viewport, setViewport] = (0, import_react18.useState)(() => getViewport());
19847
- (0, import_react18.useEffect)(() => {
20446
+ const [viewport, setViewport] = (0, import_react21.useState)(() => getViewport());
20447
+ (0, import_react21.useEffect)(() => {
19848
20448
  if (!hasColumns && !hasRows)
19849
20449
  return;
19850
20450
  let raf = 0;
@@ -19918,7 +20518,7 @@ var SystemCanvas = (() => {
19918
20518
 
19919
20519
  // ../react/dist/components/NodeToolbar.js
19920
20520
  var import_jsx_runtime26 = __toESM(require_jsx_runtime(), 1);
19921
- var import_react19 = __toESM(require_react(), 1);
20521
+ var import_react22 = __toESM(require_react(), 1);
19922
20522
  var NODE_GAP = 10;
19923
20523
  var FLIP_MARGIN = 8;
19924
20524
  var PADDING = 6;
@@ -19926,9 +20526,9 @@ var SystemCanvas = (() => {
19926
20526
  var SWATCH_SIZE = 16;
19927
20527
  var BUTTON_SIZE = 28;
19928
20528
  var DELETE_SIZE = 14;
19929
- function NodeToolbar({ node, theme, onPatch, onDelete, getViewport, containerWidth, containerHeight, render: render2 }) {
19930
- const [viewport, setViewport] = (0, import_react19.useState)(() => getViewport());
19931
- (0, import_react19.useEffect)(() => {
20529
+ function NodeToolbar({ node, theme, onPatch, onDelete, getViewport, containerWidth, containerHeight, render: render2, selectedNodes, onMultiPatch }) {
20530
+ const [viewport, setViewport] = (0, import_react22.useState)(() => getViewport());
20531
+ (0, import_react22.useEffect)(() => {
19932
20532
  let raf = 0;
19933
20533
  let lastX = -Infinity;
19934
20534
  let lastY = -Infinity;
@@ -19946,13 +20546,28 @@ var SystemCanvas = (() => {
19946
20546
  raf = requestAnimationFrame(tick);
19947
20547
  return () => cancelAnimationFrame(raf);
19948
20548
  }, [getViewport]);
20549
+ const isMulti = selectedNodes != null && selectedNodes.length > 1;
19949
20550
  const align = theme.toolbarAlign ?? "center";
19950
- const anchorCanvasX = align === "left" ? node.x : align === "right" ? node.x + node.width : node.x + node.width / 2;
19951
- const topAnchor = canvasToScreen(anchorCanvasX, node.y, viewport);
19952
- const bottomAnchor = canvasToScreen(anchorCanvasX, node.y + node.height, viewport);
19953
- const toolbarRef = (0, import_react19.useRef)(null);
19954
- const [size, setSize] = (0, import_react19.useState)({ width: 0, height: 0 });
19955
- (0, import_react19.useEffect)(() => {
20551
+ const { anchorTopY, anchorBottomY, anchorX } = (0, import_react22.useMemo)(() => {
20552
+ if (isMulti && selectedNodes) {
20553
+ const minX = Math.min(...selectedNodes.map((n) => n.x));
20554
+ const maxX = Math.max(...selectedNodes.map((n) => n.x + n.width));
20555
+ const minY = Math.min(...selectedNodes.map((n) => n.y));
20556
+ const maxY = Math.max(...selectedNodes.map((n) => n.y + n.height));
20557
+ return {
20558
+ anchorX: (minX + maxX) / 2,
20559
+ anchorTopY: minY,
20560
+ anchorBottomY: maxY
20561
+ };
20562
+ }
20563
+ const x = align === "left" ? node.x : align === "right" ? node.x + node.width : node.x + node.width / 2;
20564
+ return { anchorX: x, anchorTopY: node.y, anchorBottomY: node.y + node.height };
20565
+ }, [isMulti, selectedNodes, align, node]);
20566
+ const topAnchor = canvasToScreen(anchorX, anchorTopY, viewport);
20567
+ const bottomAnchor = canvasToScreen(anchorX, anchorBottomY, viewport);
20568
+ const toolbarRef = (0, import_react22.useRef)(null);
20569
+ const [size, setSize] = (0, import_react22.useState)({ width: 0, height: 0 });
20570
+ (0, import_react22.useEffect)(() => {
19956
20571
  const el = toolbarRef.current;
19957
20572
  if (!el)
19958
20573
  return;
@@ -19965,7 +20580,12 @@ var SystemCanvas = (() => {
19965
20580
  ro.observe(el);
19966
20581
  return () => ro.disconnect();
19967
20582
  }, []);
19968
- let left = align === "left" ? topAnchor.x : align === "right" ? topAnchor.x - size.width : topAnchor.x - size.width / 2;
20583
+ let left;
20584
+ if (isMulti) {
20585
+ left = topAnchor.x - size.width / 2;
20586
+ } else {
20587
+ left = align === "left" ? topAnchor.x : align === "right" ? topAnchor.x - size.width : topAnchor.x - size.width / 2;
20588
+ }
19969
20589
  let top = topAnchor.y - size.height - NODE_GAP;
19970
20590
  if (top < FLIP_MARGIN) {
19971
20591
  top = bottomAnchor.y + NODE_GAP;
@@ -20002,13 +20622,51 @@ var SystemCanvas = (() => {
20002
20622
  userSelect: "none",
20003
20623
  whiteSpace: "nowrap"
20004
20624
  },
20005
- children: render2 ? render2({ node, theme, patch, deleteNode }) : (0, import_jsx_runtime26.jsx)(DefaultToolbarContent, { node, theme, onPatch: patch, onDelete: deleteNode })
20625
+ children: isMulti && selectedNodes && onMultiPatch ? (0, import_jsx_runtime26.jsx)(MultiToolbarContent, { selectedNodes, theme, onMultiPatch, onDelete: deleteNode }) : render2 ? render2({ node, theme, patch, deleteNode }) : (0, import_jsx_runtime26.jsx)(DefaultToolbarContent, { node, theme, onPatch: patch, onDelete: deleteNode })
20006
20626
  });
20007
20627
  }
20628
+ function MultiToolbarContent({ selectedNodes, theme, onMultiPatch, onDelete }) {
20629
+ const representativeNode = selectedNodes[0];
20630
+ const groups = (0, import_react22.useMemo)(() => getNodeActionsForNode(representativeNode, theme), [representativeNode, theme]);
20631
+ const showDelete = theme.showToolbarDelete === true;
20632
+ const swatchGroups = groups.filter((g) => g.kind === "swatches" || g.kind == null);
20633
+ const otherGroups = groups.filter((g) => g.kind !== "swatches" && g.kind != null && g.kind !== "menu");
20634
+ return (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [(0, import_jsx_runtime26.jsxs)("span", { style: {
20635
+ fontSize: 11,
20636
+ color: theme.breadcrumbs.textColor,
20637
+ opacity: 0.75,
20638
+ paddingRight: BUTTON_GAP,
20639
+ whiteSpace: "nowrap"
20640
+ }, children: [selectedNodes.length, " nodes"] }), swatchGroups.map((group, i) => {
20641
+ const actions = filterActionsForNode(group, representativeNode);
20642
+ if (actions.length === 0)
20643
+ return null;
20644
+ return (0, import_jsx_runtime26.jsxs)(import_react22.default.Fragment, { children: [i > 0 && (0, import_jsx_runtime26.jsx)(Divider2, { theme }), (0, import_jsx_runtime26.jsx)("div", { style: { display: "flex", alignItems: "center", gap: BUTTON_GAP }, children: actions.map((action) => {
20645
+ const active = action.isActive?.(representativeNode) ?? false;
20646
+ const handleClick = () => {
20647
+ const patch = resolveActionPatch(action, representativeNode);
20648
+ onMultiPatch(patch);
20649
+ };
20650
+ return (0, import_jsx_runtime26.jsx)(SwatchButton, { action, active, theme, onClick: handleClick }, action.id);
20651
+ }) })] }, group.id);
20652
+ }), otherGroups.map((group) => {
20653
+ const actions = filterActionsForNode(group, representativeNode);
20654
+ if (actions.length === 0)
20655
+ return null;
20656
+ return (0, import_jsx_runtime26.jsxs)(import_react22.default.Fragment, { children: [(0, import_jsx_runtime26.jsx)(Divider2, { theme }), (0, import_jsx_runtime26.jsx)("div", { style: { display: "flex", alignItems: "center", gap: BUTTON_GAP }, children: actions.map((action) => {
20657
+ const active = action.isActive?.(representativeNode) ?? false;
20658
+ const handleClick = () => {
20659
+ const patch = resolveActionPatch(action, representativeNode);
20660
+ onMultiPatch(patch);
20661
+ };
20662
+ return (0, import_jsx_runtime26.jsx)(IconButton, { action, active, theme, onClick: handleClick }, action.id);
20663
+ }) })] }, group.id);
20664
+ }), showDelete && (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [(0, import_jsx_runtime26.jsx)(Divider2, { theme }), (0, import_jsx_runtime26.jsx)(DeleteButton, { theme, onDelete })] })] });
20665
+ }
20008
20666
  function DefaultToolbarContent({ node, theme, onPatch, onDelete }) {
20009
- const groups = (0, import_react19.useMemo)(() => getNodeActionsForNode(node, theme), [node, theme]);
20667
+ const groups = (0, import_react22.useMemo)(() => getNodeActionsForNode(node, theme), [node, theme]);
20010
20668
  const showDelete = theme.showToolbarDelete === true;
20011
- return (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [groups.map((group, i) => (0, import_jsx_runtime26.jsxs)(import_react19.default.Fragment, { children: [i > 0 && (0, import_jsx_runtime26.jsx)(Divider2, { theme }), (0, import_jsx_runtime26.jsx)(ActionGroupView, { group, node, theme, onPatch })] }, group.id)), showDelete && (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [(0, import_jsx_runtime26.jsx)(Divider2, { theme }), (0, import_jsx_runtime26.jsx)(DeleteButton, { theme, onDelete })] })] });
20669
+ return (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [groups.map((group, i) => (0, import_jsx_runtime26.jsxs)(import_react22.default.Fragment, { children: [i > 0 && (0, import_jsx_runtime26.jsx)(Divider2, { theme }), (0, import_jsx_runtime26.jsx)(ActionGroupView, { group, node, theme, onPatch })] }, group.id)), showDelete && (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [(0, import_jsx_runtime26.jsx)(Divider2, { theme }), (0, import_jsx_runtime26.jsx)(DeleteButton, { theme, onDelete })] })] });
20012
20670
  }
20013
20671
  function Divider2({ theme }) {
20014
20672
  return (0, import_jsx_runtime26.jsx)("div", { style: {
@@ -20075,9 +20733,9 @@ var SystemCanvas = (() => {
20075
20733
  } }) : (0, import_jsx_runtime26.jsx)("span", { style: { fontSize: 10 }, children: action.label.slice(0, 2) }) });
20076
20734
  }
20077
20735
  function MenuGroup({ group, actions, node, theme, onPatch }) {
20078
- const [open, setOpen] = (0, import_react19.useState)(false);
20079
- const wrapRef = (0, import_react19.useRef)(null);
20080
- (0, import_react19.useEffect)(() => {
20736
+ const [open, setOpen] = (0, import_react22.useState)(false);
20737
+ const wrapRef = (0, import_react22.useRef)(null);
20738
+ (0, import_react22.useEffect)(() => {
20081
20739
  if (!open)
20082
20740
  return;
20083
20741
  const onDown = (e) => {
@@ -20164,18 +20822,18 @@ var SystemCanvas = (() => {
20164
20822
 
20165
20823
  // ../react/dist/components/NodeContextMenuOverlay.js
20166
20824
  var import_jsx_runtime27 = __toESM(require_jsx_runtime(), 1);
20167
- var import_react20 = __toESM(require_react(), 1);
20825
+ var import_react23 = __toESM(require_react(), 1);
20168
20826
  var ESTIMATED_MENU_WIDTH = 200;
20169
20827
  var MIN_MENU_WIDTH = 160;
20170
20828
  var VIEWPORT_MARGIN = 8;
20171
20829
  function NodeContextMenuOverlay({ state, config, theme, onClose }) {
20172
- const rootRef = (0, import_react20.useRef)(null);
20173
- const [hoveredId, setHoveredId] = (0, import_react20.useState)(null);
20174
- (0, import_react20.useEffect)(() => {
20830
+ const rootRef = (0, import_react23.useRef)(null);
20831
+ const [hoveredId, setHoveredId] = (0, import_react23.useState)(null);
20832
+ (0, import_react23.useEffect)(() => {
20175
20833
  if (state)
20176
20834
  setHoveredId(null);
20177
20835
  }, [state]);
20178
- (0, import_react20.useEffect)(() => {
20836
+ (0, import_react23.useEffect)(() => {
20179
20837
  if (!state)
20180
20838
  return;
20181
20839
  function onDown(e) {
@@ -20283,8 +20941,8 @@ var SystemCanvas = (() => {
20283
20941
  // ../react/dist/components/SystemCanvas.js
20284
20942
  var CASCADE_WINDOW_MS = 1500;
20285
20943
  var CASCADE_OFFSET = 20;
20286
- var SystemCanvas = (0, import_react21.forwardRef)(function SystemCanvas2({ canvas, onResolveCanvas, canvases, rootLabel = "Home", onNavigate, onBreadcrumbClick, onBreadcrumbsChange, onNodeClick, onNodeDoubleClick, onEdgeClick, onEdgeDoubleClick, onContextMenu, onSelectionChange, nodeContextMenu, editable = false, onNodeAdd, onNodeUpdate, onNodesUpdate, onNodeDelete, onEdgeUpdate, onEdgeDelete, onEdgeAdd, canDropNodeOn, onNodeDrop, renderAddNodeButton, showNodeToolbar = true, renderNodeToolbar, theme: themeProp, themes: customThemes, edgeStyle = "bezier", defaultViewport, minZoom: minZoomProp, maxZoom, onViewportChange, autoFit = "canvas-change", laneHeaders = "pinned", snapToLanes = false, zoomNavigation = false, className, style }, forwardedRef) {
20287
- const zoomNavConfig = (0, import_react21.useMemo)(() => {
20944
+ var SystemCanvas = (0, import_react24.forwardRef)(function SystemCanvas2({ canvas, onResolveCanvas, canvases, rootLabel = "Home", onNavigate, onBreadcrumbClick, onBreadcrumbsChange, onNodeClick, onNodeDoubleClick, onEdgeClick, onEdgeDoubleClick, onContextMenu, onSelectionChange, nodeContextMenu, editable = false, onNodeAdd, onNodeUpdate, onNodesUpdate, onNodeDelete, onNodesDelete, onEdgeUpdate, onEdgeDelete, onEdgeAdd, canDropNodeOn, onNodeDrop, renderAddNodeButton, showNodeToolbar = true, renderNodeToolbar, theme: themeProp, themes: customThemes, edgeStyle = "bezier", defaultViewport, minZoom: minZoomProp, maxZoom, onViewportChange, autoFit = "canvas-change", laneHeaders = "pinned", snapToLanes = false, zoomNavigation = false, historyDepth, onUndo, onRedo, className, style }, forwardedRef) {
20945
+ const zoomNavConfig = (0, import_react24.useMemo)(() => {
20288
20946
  const defaults = {
20289
20947
  enterThreshold: 0.66,
20290
20948
  exitThreshold: 0.33,
@@ -20309,16 +20967,16 @@ var SystemCanvas = (() => {
20309
20967
  }, [zoomNavigation]);
20310
20968
  const effectiveMaxZoom = maxZoom ?? (zoomNavConfig.enabled ? 16 : 4);
20311
20969
  const effectiveMinZoom = minZoomProp ?? (zoomNavConfig.enabled ? 0.01 : 0.1);
20312
- (0, import_react21.useEffect)(() => {
20970
+ (0, import_react24.useEffect)(() => {
20313
20971
  const env = globalThis.process?.env?.NODE_ENV;
20314
20972
  if (editable && !canvases && env !== "production") {
20315
20973
  console.warn("[system-canvas] `editable` is enabled but `canvases` prop is missing. Edits to sub-canvases will not be reflected without a synchronous ref \u2192 CanvasData map.");
20316
20974
  }
20317
20975
  }, [editable, canvases]);
20318
- const [parentFrames, setParentFrames] = (0, import_react21.useState)([]);
20319
- const [pendingHandoff, setPendingHandoff] = (0, import_react21.useState)(null);
20320
- const suppressNextHandoffClearRef = (0, import_react21.useRef)(false);
20321
- const handleBreadcrumbClick = (0, import_react21.useCallback)((index) => {
20976
+ const [parentFrames, setParentFrames] = (0, import_react24.useState)([]);
20977
+ const [pendingHandoff, setPendingHandoff] = (0, import_react24.useState)(null);
20978
+ const suppressNextHandoffClearRef = (0, import_react24.useRef)(false);
20979
+ const handleBreadcrumbClick = (0, import_react24.useCallback)((index) => {
20322
20980
  setParentFrames((prev) => prev.slice(0, index));
20323
20981
  if (suppressNextHandoffClearRef.current) {
20324
20982
  suppressNextHandoffClearRef.current = false;
@@ -20335,10 +20993,10 @@ var SystemCanvas = (() => {
20335
20993
  onNavigate,
20336
20994
  onBreadcrumbClick: handleBreadcrumbClick
20337
20995
  });
20338
- (0, import_react21.useEffect)(() => {
20996
+ (0, import_react24.useEffect)(() => {
20339
20997
  onBreadcrumbsChange?.(breadcrumbs);
20340
20998
  }, [breadcrumbs, onBreadcrumbsChange]);
20341
- const theme = (0, import_react21.useMemo)(() => {
20999
+ const theme = (0, import_react24.useMemo)(() => {
20342
21000
  const registry = { ...themes, ...customThemes };
20343
21001
  const resolveByName = (name) => name && registry[name] ? registry[name] : null;
20344
21002
  if (themeProp) {
@@ -20349,22 +21007,22 @@ var SystemCanvas = (() => {
20349
21007
  }
20350
21008
  return resolveByName(currentCanvas.theme?.base) ?? resolveByName(canvas.theme?.base) ?? darkTheme;
20351
21009
  }, [themeProp, customThemes, currentCanvas.theme?.base, canvas.theme?.base]);
20352
- const { nodes, edges, nodeMap } = (0, import_react21.useMemo)(() => {
21010
+ const { nodes, edges, nodeMap } = (0, import_react24.useMemo)(() => {
20353
21011
  const resolved = resolveCanvas(currentCanvas, theme);
20354
21012
  const map = buildNodeMap(resolved.nodes);
20355
21013
  return { nodes: resolved.nodes, edges: resolved.edges, nodeMap: map };
20356
21014
  }, [currentCanvas, theme]);
20357
- const nodesRef = (0, import_react21.useRef)(nodes);
21015
+ const nodesRef = (0, import_react24.useRef)(nodes);
20358
21016
  nodesRef.current = nodes;
20359
- const viewportStateRef = (0, import_react21.useRef)(defaultViewport ?? { x: 0, y: 0, zoom: 1 });
20360
- const viewportHandleRef = (0, import_react21.useRef)(null);
20361
- const navigateToRefRef = (0, import_react21.useRef)(navigateToRef);
21017
+ const viewportStateRef = (0, import_react24.useRef)(defaultViewport ?? { x: 0, y: 0, zoom: 1 });
21018
+ const viewportHandleRef = (0, import_react24.useRef)(null);
21019
+ const navigateToRefRef = (0, import_react24.useRef)(navigateToRef);
20362
21020
  navigateToRefRef.current = navigateToRef;
20363
- const navigateToBreadcrumbRef = (0, import_react21.useRef)(navigateToBreadcrumb);
21021
+ const navigateToBreadcrumbRef = (0, import_react24.useRef)(navigateToBreadcrumb);
20364
21022
  navigateToBreadcrumbRef.current = navigateToBreadcrumb;
20365
- const breadcrumbsRef = (0, import_react21.useRef)(breadcrumbs);
21023
+ const breadcrumbsRef = (0, import_react24.useRef)(breadcrumbs);
20366
21024
  breadcrumbsRef.current = breadcrumbs;
20367
- (0, import_react21.useImperativeHandle)(forwardedRef, () => ({
21025
+ (0, import_react24.useImperativeHandle)(forwardedRef, () => ({
20368
21026
  zoomIntoNode: (nodeId, options) => {
20369
21027
  return new Promise((resolve) => {
20370
21028
  const node = nodesRef.current.find((n) => n.id === nodeId);
@@ -20396,26 +21054,82 @@ var SystemCanvas = (() => {
20396
21054
  navigateToBreadcrumbRef.current(0);
20397
21055
  }
20398
21056
  }), [forwardedRef]);
20399
- const [selectedId, setSelectedId] = (0, import_react21.useState)(null);
20400
- const [editingId, setEditingId] = (0, import_react21.useState)(null);
20401
- const [selectedEdgeId, setSelectedEdgeId] = (0, import_react21.useState)(null);
20402
- const [editingEdgeId, setEditingEdgeId] = (0, import_react21.useState)(null);
20403
- (0, import_react21.useEffect)(() => {
20404
- setSelectedId(null);
21057
+ const [editingId, setEditingId] = (0, import_react24.useState)(null);
21058
+ const [selectedEdgeId, setSelectedEdgeId] = (0, import_react24.useState)(null);
21059
+ const [editingEdgeId, setEditingEdgeId] = (0, import_react24.useState)(null);
21060
+ const svgProxyRef = (0, import_react24.useRef)(null);
21061
+ const containerRef = (0, import_react24.useRef)(null);
21062
+ const { selectedIds, selectNode, toggleNode, selectAll, clearSelection, marqueeRect, marqueeActiveRef } = useMultiSelect({
21063
+ svgRef: svgProxyRef,
21064
+ viewport: viewportStateRef,
21065
+ nodesRef,
21066
+ containerRef,
21067
+ enabled: editable
21068
+ });
21069
+ const selectedIdsRef = (0, import_react24.useRef)(selectedIds);
21070
+ (0, import_react24.useEffect)(() => {
21071
+ selectedIdsRef.current = selectedIds;
21072
+ }, [selectedIds]);
21073
+ const edgesRef = (0, import_react24.useRef)(edges);
21074
+ (0, import_react24.useEffect)(() => {
21075
+ edgesRef.current = edges;
21076
+ }, [edges]);
21077
+ const { wrappedOnNodeAdd, wrappedOnNodeUpdate, wrappedOnNodesUpdate, wrappedOnNodeDelete, wrappedOnNodesDelete, wrappedOnEdgeAdd, wrappedOnEdgeUpdate, wrappedOnEdgeDelete, beginBatch, endBatch, undo, redo } = useCommandHistory({
21078
+ nodesRef,
21079
+ edgesRef,
21080
+ onNodeAdd,
21081
+ onNodeUpdate,
21082
+ onNodesUpdate,
21083
+ onNodeDelete,
21084
+ onNodesDelete,
21085
+ onEdgeAdd,
21086
+ onEdgeUpdate,
21087
+ onEdgeDelete,
21088
+ maxDepth: historyDepth ?? 50,
21089
+ enabled: editable,
21090
+ onUndo,
21091
+ onRedo
21092
+ });
21093
+ useMultiSelectClipboard({
21094
+ selectedIdsRef,
21095
+ nodesRef,
21096
+ edgesRef,
21097
+ viewport: viewportStateRef,
21098
+ canvasContainerRef: containerRef,
21099
+ onNodeAdd: (node) => wrappedOnNodeAdd(node, currentCanvasRef),
21100
+ onEdgeAdd: (edge) => wrappedOnEdgeAdd(edge, currentCanvasRef),
21101
+ canvasRef: currentCanvasRef,
21102
+ getCursorScreenPos: () => viewportHandleRef.current?.getCursorScreenPos() ?? null,
21103
+ onBeginBatch: beginBatch,
21104
+ onEndBatch: endBatch
21105
+ });
21106
+ (0, import_react24.useEffect)(() => {
21107
+ clearSelection();
20405
21108
  setEditingId(null);
20406
21109
  setSelectedEdgeId(null);
20407
21110
  setEditingEdgeId(null);
20408
21111
  }, [currentCanvasRef]);
20409
- const onSelectionChangeRef = (0, import_react21.useRef)(onSelectionChange);
20410
- (0, import_react21.useEffect)(() => {
21112
+ const onSelectionChangeRef = (0, import_react24.useRef)(onSelectionChange);
21113
+ (0, import_react24.useEffect)(() => {
20411
21114
  onSelectionChangeRef.current = onSelectionChange;
20412
21115
  }, [onSelectionChange]);
20413
- const lastEmittedSelectionRef = (0, import_react21.useRef)({ kind: null, id: null, canvasRef: void 0 });
20414
- (0, import_react21.useEffect)(() => {
21116
+ const lastEmittedSelectionRef = (0, import_react24.useRef)({ kind: null, id: null, multiIds: null, canvasRef: void 0 });
21117
+ (0, import_react24.useEffect)(() => {
20415
21118
  const cb = onSelectionChangeRef.current;
20416
21119
  let next = null;
20417
- if (selectedId) {
20418
- const node = nodeMap.get(selectedId);
21120
+ if (selectedIds.size > 1) {
21121
+ const resolvedNodes = [];
21122
+ for (const id2 of selectedIds) {
21123
+ const n = nodeMap.get(id2);
21124
+ if (n)
21125
+ resolvedNodes.push(n);
21126
+ }
21127
+ if (resolvedNodes.length > 0) {
21128
+ next = { kind: "multi", nodes: resolvedNodes, canvasRef: currentCanvasRef };
21129
+ }
21130
+ } else if (selectedIds.size === 1) {
21131
+ const id2 = Array.from(selectedIds)[0];
21132
+ const node = nodeMap.get(id2);
20419
21133
  if (node)
20420
21134
  next = { kind: "node", node, canvasRef: currentCanvasRef };
20421
21135
  }
@@ -20426,21 +21140,24 @@ var SystemCanvas = (() => {
20426
21140
  }
20427
21141
  const last = lastEmittedSelectionRef.current;
20428
21142
  const nextKind = next?.kind ?? null;
20429
- const nextId = next ? next.kind === "node" ? next.node.id : next.edge.id : null;
20430
21143
  const nextRef = next?.canvasRef;
20431
- if (last.kind === nextKind && last.id === nextId && last.canvasRef === nextRef) {
20432
- return;
21144
+ if (nextKind === "multi" && next?.kind === "multi") {
21145
+ const sortedIds = next.nodes.map((n) => n.id).sort().join(",");
21146
+ if (last.kind === "multi" && last.multiIds === sortedIds && last.canvasRef === nextRef) {
21147
+ return;
21148
+ }
21149
+ lastEmittedSelectionRef.current = { kind: "multi", id: null, multiIds: sortedIds, canvasRef: nextRef };
21150
+ } else {
21151
+ const nextId = next ? next.kind === "node" ? next.node.id : next.kind === "edge" ? next.edge.id : null : null;
21152
+ if (last.kind === nextKind && last.id === nextId && last.canvasRef === nextRef) {
21153
+ return;
21154
+ }
21155
+ lastEmittedSelectionRef.current = { kind: nextKind, id: nextId, multiIds: null, canvasRef: nextRef };
20433
21156
  }
20434
- lastEmittedSelectionRef.current = {
20435
- kind: nextKind,
20436
- id: nextId,
20437
- canvasRef: nextRef
20438
- };
20439
21157
  cb?.(next);
20440
- }, [selectedId, selectedEdgeId, currentCanvasRef, nodeMap, edges]);
20441
- const containerRef = (0, import_react21.useRef)(null);
20442
- const [containerSize, setContainerSize] = (0, import_react21.useState)({ width: 0, height: 0 });
20443
- (0, import_react21.useEffect)(() => {
21158
+ }, [selectedIds, selectedEdgeId, currentCanvasRef, nodeMap, edges]);
21159
+ const [containerSize, setContainerSize] = (0, import_react24.useState)({ width: 0, height: 0 });
21160
+ (0, import_react24.useEffect)(() => {
20444
21161
  const el = containerRef.current;
20445
21162
  if (!el)
20446
21163
  return;
@@ -20455,8 +21172,8 @@ var SystemCanvas = (() => {
20455
21172
  }, []);
20456
21173
  const hasLanes = currentCanvas.columns && currentCanvas.columns.length > 0 || currentCanvas.rows && currentCanvas.rows.length > 0;
20457
21174
  const showLaneHeaders = hasLanes && laneHeaders !== "none";
20458
- const getViewportState = (0, import_react21.useCallback)(() => viewportStateRef.current ?? { x: 0, y: 0, zoom: 1 }, []);
20459
- const applyLaneSnap = (0, import_react21.useCallback)((id2, patch) => {
21175
+ const getViewportState = (0, import_react24.useCallback)(() => viewportStateRef.current ?? { x: 0, y: 0, zoom: 1 }, []);
21176
+ const applyLaneSnap = (0, import_react24.useCallback)((id2, patch) => {
20460
21177
  if (!snapToLanes)
20461
21178
  return patch;
20462
21179
  const cols = currentCanvas.columns;
@@ -20481,26 +21198,25 @@ var SystemCanvas = (() => {
20481
21198
  }
20482
21199
  return final;
20483
21200
  }, [snapToLanes, currentCanvas.columns, currentCanvas.rows]);
20484
- const commitResize = (0, import_react21.useCallback)((id2, patch) => {
20485
- onNodeUpdate?.(id2, applyLaneSnap(id2, patch), currentCanvasRef);
20486
- }, [onNodeUpdate, currentCanvasRef, applyLaneSnap]);
20487
- const commitDragBatch = (0, import_react21.useCallback)((updates) => {
21201
+ const commitResize = (0, import_react24.useCallback)((id2, patch) => {
21202
+ wrappedOnNodeUpdate(id2, applyLaneSnap(id2, patch), currentCanvasRef);
21203
+ }, [wrappedOnNodeUpdate, currentCanvasRef, applyLaneSnap]);
21204
+ const commitDragBatch = (0, import_react24.useCallback)((updates) => {
20488
21205
  const final = updates.map((u) => ({
20489
21206
  id: u.id,
20490
21207
  patch: applyLaneSnap(u.id, u.patch)
20491
21208
  }));
20492
21209
  if (onNodesUpdate) {
20493
- onNodesUpdate(final, currentCanvasRef);
21210
+ wrappedOnNodesUpdate(final, currentCanvasRef);
20494
21211
  return;
20495
21212
  }
20496
21213
  if (!onNodeUpdate)
20497
21214
  return;
20498
21215
  for (const { id: id2, patch } of final) {
20499
- onNodeUpdate(id2, patch, currentCanvasRef);
21216
+ wrappedOnNodeUpdate(id2, patch, currentCanvasRef);
20500
21217
  }
20501
- }, [onNodeUpdate, onNodesUpdate, currentCanvasRef, applyLaneSnap]);
20502
- const svgProxyRef = (0, import_react21.useRef)(null);
20503
- const handleNodeDrop = (0, import_react21.useCallback)((sources, target) => {
21218
+ }, [wrappedOnNodeUpdate, wrappedOnNodesUpdate, onNodeUpdate, onNodesUpdate, currentCanvasRef, applyLaneSnap]);
21219
+ const handleNodeDrop = (0, import_react24.useCallback)((sources, target) => {
20504
21220
  onNodeDrop?.(sources, target, { canvasRef: currentCanvasRef });
20505
21221
  }, [onNodeDrop, currentCanvasRef]);
20506
21222
  const { dragOverrides, dropTargetId, onPointerDown: onNodePointerDown } = useNodeDrag({
@@ -20509,39 +21225,41 @@ var SystemCanvas = (() => {
20509
21225
  onCommit: commitDragBatch,
20510
21226
  svgRef: svgProxyRef,
20511
21227
  canDropNodeOn,
20512
- onNodeDrop: handleNodeDrop
21228
+ onNodeDrop: handleNodeDrop,
21229
+ selectedIdsRef
20513
21230
  });
20514
21231
  const { resizeOverrides, onHandlePointerDown: onResizeHandlePointerDown } = useNodeResize({
20515
21232
  viewport: viewportStateRef,
20516
21233
  onCommit: commitResize
20517
21234
  });
20518
- const selectedResolvedNode = (0, import_react21.useMemo)(() => {
20519
- if (!selectedId)
21235
+ const singleSelectedId = selectedIds.size === 1 ? Array.from(selectedIds)[0] : null;
21236
+ const selectedResolvedNode = (0, import_react24.useMemo)(() => {
21237
+ if (!singleSelectedId)
20520
21238
  return null;
20521
- const base = nodeMap.get(selectedId);
21239
+ const base = nodeMap.get(singleSelectedId);
20522
21240
  if (!base)
20523
21241
  return null;
20524
- const resize = resizeOverrides.get(selectedId);
21242
+ const resize = resizeOverrides.get(singleSelectedId);
20525
21243
  if (resize) {
20526
21244
  return { ...base, x: resize.x, y: resize.y, width: resize.width, height: resize.height };
20527
21245
  }
20528
- const drag = dragOverrides.get(selectedId);
21246
+ const drag = dragOverrides.get(singleSelectedId);
20529
21247
  if (drag) {
20530
21248
  return { ...base, x: drag.x, y: drag.y };
20531
21249
  }
20532
21250
  return base;
20533
- }, [selectedId, nodeMap, dragOverrides, resizeOverrides]);
21251
+ }, [singleSelectedId, nodeMap, dragOverrides, resizeOverrides]);
20534
21252
  svgProxyRef.current = viewportHandleRef.current?.getSvgElement() ?? null;
20535
- const handleEdgeCreated = (0, import_react21.useCallback)((edge) => {
20536
- onEdgeAdd?.(edge, currentCanvasRef);
20537
- }, [onEdgeAdd, currentCanvasRef]);
21253
+ const handleEdgeCreated = (0, import_react24.useCallback)((edge) => {
21254
+ wrappedOnEdgeAdd(edge, currentCanvasRef);
21255
+ }, [wrappedOnEdgeAdd, currentCanvasRef]);
20538
21256
  const { pending: pendingEdge, onHandlePointerDown: onConnectionHandlePointerDown } = useEdgeCreate({
20539
21257
  svgRef: svgProxyRef,
20540
21258
  viewport: viewportStateRef,
20541
21259
  nodesRef,
20542
21260
  onCreate: handleEdgeCreated
20543
21261
  });
20544
- const handleNavigableNodeClick = (0, import_react21.useCallback)((node) => {
21262
+ const handleNavigableNodeClick = (0, import_react24.useCallback)((node) => {
20545
21263
  const frame2 = {
20546
21264
  parentCanvasRef: currentCanvasRef,
20547
21265
  parentNodeRect: {
@@ -20568,7 +21286,7 @@ var SystemCanvas = (() => {
20568
21286
  navigateToRef(node);
20569
21287
  }
20570
21288
  }, [navigateToRef, currentCanvasRef, zoomNavConfig.enabled]);
20571
- const handleZoomEnter = (0, import_react21.useCallback)((node, targetTransform) => {
21289
+ const handleZoomEnter = (0, import_react24.useCallback)((node, targetTransform) => {
20572
21290
  const frame2 = {
20573
21291
  parentCanvasRef: currentCanvasRef,
20574
21292
  parentNodeRect: {
@@ -20582,7 +21300,7 @@ var SystemCanvas = (() => {
20582
21300
  setPendingHandoff(targetTransform);
20583
21301
  navigateToRef(node);
20584
21302
  }, [currentCanvasRef, navigateToRef]);
20585
- const handleZoomExit = (0, import_react21.useCallback)((targetTransform) => {
21303
+ const handleZoomExit = (0, import_react24.useCallback)((targetTransform) => {
20586
21304
  setPendingHandoff(targetTransform);
20587
21305
  suppressNextHandoffClearRef.current = true;
20588
21306
  navigateToBreadcrumb(breadcrumbs.length - 2);
@@ -20609,26 +21327,26 @@ var SystemCanvas = (() => {
20609
21327
  onEnter: handleZoomEnter,
20610
21328
  onExit: handleZoomExit
20611
21329
  });
20612
- const handleViewportChange = (0, import_react21.useCallback)((vp) => {
21330
+ const handleViewportChange = (0, import_react24.useCallback)((vp) => {
20613
21331
  viewportStateRef.current = vp;
20614
21332
  handleZoomNavViewportChange(vp);
20615
21333
  onViewportChange?.(vp);
20616
21334
  }, [handleZoomNavViewportChange, onViewportChange]);
20617
- const handleHandoffApplied = (0, import_react21.useCallback)(() => {
21335
+ const handleHandoffApplied = (0, import_react24.useCallback)(() => {
20618
21336
  setPendingHandoff(null);
20619
21337
  clearZoomNavCommitting();
20620
21338
  }, [clearZoomNavCommitting]);
20621
- const handleBeginEdit = (0, import_react21.useCallback)((node) => {
21339
+ const handleBeginEdit = (0, import_react24.useCallback)((node) => {
20622
21340
  setEditingId(node.id);
20623
21341
  }, []);
20624
- const handleBeginEditEdge = (0, import_react21.useCallback)((edge) => {
21342
+ const handleBeginEditEdge = (0, import_react24.useCallback)((edge) => {
20625
21343
  setEditingEdgeId(edge.id);
20626
21344
  }, []);
20627
- const [contextMenuState, setContextMenuState] = (0, import_react21.useState)(null);
20628
- (0, import_react21.useEffect)(() => {
21345
+ const [contextMenuState, setContextMenuState] = (0, import_react24.useState)(null);
21346
+ (0, import_react24.useEffect)(() => {
20629
21347
  setContextMenuState(null);
20630
21348
  }, [currentCanvasRef]);
20631
- const handleContextMenu = (0, import_react21.useCallback)((event) => {
21349
+ const handleContextMenu = (0, import_react24.useCallback)((event) => {
20632
21350
  onContextMenu?.(event);
20633
21351
  if (!nodeContextMenu)
20634
21352
  return;
@@ -20660,32 +21378,38 @@ var SystemCanvas = (() => {
20660
21378
  onNavigableNodeClick: handleNavigableNodeClick,
20661
21379
  viewport: viewportStateRef,
20662
21380
  editable,
20663
- onSelect: setSelectedId,
21381
+ onSelect: (id2) => {
21382
+ if (id2)
21383
+ selectNode(id2);
21384
+ else
21385
+ clearSelection();
21386
+ },
21387
+ onToggleSelect: toggleNode,
20664
21388
  onBeginEdit: handleBeginEdit,
20665
21389
  onSelectEdge: setSelectedEdgeId,
20666
21390
  onBeginEditEdge: handleBeginEditEdge
20667
21391
  });
20668
- const handleEditorCommit = (0, import_react21.useCallback)((patch) => {
21392
+ const handleEditorCommit = (0, import_react24.useCallback)((patch) => {
20669
21393
  if (editingId) {
20670
- onNodeUpdate?.(editingId, patch, currentCanvasRef);
21394
+ wrappedOnNodeUpdate(editingId, patch, currentCanvasRef);
20671
21395
  }
20672
21396
  setEditingId(null);
20673
- }, [editingId, onNodeUpdate, currentCanvasRef]);
20674
- const handleEditorCancel = (0, import_react21.useCallback)(() => {
21397
+ }, [editingId, wrappedOnNodeUpdate, currentCanvasRef]);
21398
+ const handleEditorCancel = (0, import_react24.useCallback)(() => {
20675
21399
  setEditingId(null);
20676
21400
  }, []);
20677
- const handleEdgeEditorCommit = (0, import_react21.useCallback)((patch) => {
21401
+ const handleEdgeEditorCommit = (0, import_react24.useCallback)((patch) => {
20678
21402
  if (editingEdgeId) {
20679
- onEdgeUpdate?.(editingEdgeId, patch, currentCanvasRef);
21403
+ wrappedOnEdgeUpdate(editingEdgeId, patch, currentCanvasRef);
20680
21404
  }
20681
21405
  setEditingEdgeId(null);
20682
- }, [editingEdgeId, onEdgeUpdate, currentCanvasRef]);
20683
- const handleEdgeEditorCancel = (0, import_react21.useCallback)(() => {
21406
+ }, [editingEdgeId, wrappedOnEdgeUpdate, currentCanvasRef]);
21407
+ const handleEdgeEditorCancel = (0, import_react24.useCallback)(() => {
20684
21408
  setEditingEdgeId(null);
20685
21409
  }, []);
20686
- const lastAddRef = (0, import_react21.useRef)(null);
20687
- const menuOptions = (0, import_react21.useMemo)(() => getNodeMenuOptions(currentCanvas, theme), [currentCanvas, theme]);
20688
- const addNode2 = (0, import_react21.useCallback)((option, position) => {
21410
+ const lastAddRef = (0, import_react24.useRef)(null);
21411
+ const menuOptions = (0, import_react24.useMemo)(() => getNodeMenuOptions(currentCanvas, theme), [currentCanvas, theme]);
21412
+ const addNode2 = (0, import_react24.useCallback)((option, position) => {
20689
21413
  let x, y;
20690
21414
  if (position) {
20691
21415
  x = position.x;
@@ -20715,28 +21439,48 @@ var SystemCanvas = (() => {
20715
21439
  lastAddRef.current = { t: now2, offset: nextOffset };
20716
21440
  }
20717
21441
  const node = createNodeFromOption(option, Math.round(x), Math.round(y), void 0, theme);
20718
- onNodeAdd?.(node, currentCanvasRef);
20719
- }, [onNodeAdd, currentCanvasRef, theme]);
20720
- const handleKeyDown = (0, import_react21.useCallback)((e) => {
21442
+ wrappedOnNodeAdd(node, currentCanvasRef);
21443
+ }, [wrappedOnNodeAdd, currentCanvasRef, theme]);
21444
+ const handleKeyDown = (0, import_react24.useCallback)((e) => {
20721
21445
  if (!editable)
20722
21446
  return;
20723
21447
  if (e.key === "Escape") {
20724
21448
  setEditingId(null);
20725
- setSelectedId(null);
21449
+ clearSelection();
20726
21450
  setEditingEdgeId(null);
20727
21451
  setSelectedEdgeId(null);
20728
21452
  return;
20729
21453
  }
20730
21454
  if (editingId || editingEdgeId)
20731
21455
  return;
21456
+ if ((e.metaKey || e.ctrlKey) && !e.shiftKey && e.key === "z") {
21457
+ e.preventDefault();
21458
+ undo();
21459
+ return;
21460
+ }
21461
+ if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key === "z") {
21462
+ e.preventDefault();
21463
+ redo();
21464
+ return;
21465
+ }
21466
+ if ((e.metaKey || e.ctrlKey) && e.key === "a") {
21467
+ e.preventDefault();
21468
+ selectAll();
21469
+ return;
21470
+ }
20732
21471
  if (e.key === "Delete" || e.key === "Backspace") {
20733
- if (selectedId) {
21472
+ if (selectedIds.size > 1) {
21473
+ e.preventDefault();
21474
+ wrappedOnNodesDelete(Array.from(selectedIds), currentCanvasRef);
21475
+ clearSelection();
21476
+ } else if (selectedIds.size === 1) {
21477
+ const id2 = Array.from(selectedIds)[0];
20734
21478
  e.preventDefault();
20735
- onNodeDelete?.(selectedId, currentCanvasRef);
20736
- setSelectedId(null);
21479
+ wrappedOnNodeDelete(id2, currentCanvasRef);
21480
+ clearSelection();
20737
21481
  } else if (selectedEdgeId) {
20738
21482
  e.preventDefault();
20739
- onEdgeDelete?.(selectedEdgeId, currentCanvasRef);
21483
+ wrappedOnEdgeDelete(selectedEdgeId, currentCanvasRef);
20740
21484
  setSelectedEdgeId(null);
20741
21485
  }
20742
21486
  }
@@ -20744,11 +21488,16 @@ var SystemCanvas = (() => {
20744
21488
  editable,
20745
21489
  editingId,
20746
21490
  editingEdgeId,
20747
- selectedId,
21491
+ selectedIds,
20748
21492
  selectedEdgeId,
20749
- onNodeDelete,
20750
- onEdgeDelete,
20751
- currentCanvasRef
21493
+ wrappedOnNodeDelete,
21494
+ wrappedOnNodesDelete,
21495
+ wrappedOnEdgeDelete,
21496
+ currentCanvasRef,
21497
+ clearSelection,
21498
+ selectAll,
21499
+ undo,
21500
+ redo
20752
21501
  ]);
20753
21502
  const renderProps = { options: menuOptions, addNode: addNode2, theme };
20754
21503
  return (0, import_jsx_runtime28.jsxs)("div", { ref: containerRef, className: `system-canvas ${className ?? ""}`, tabIndex: editable ? 0 : -1, onKeyDown: handleKeyDown, style: {
@@ -20770,20 +21519,28 @@ var SystemCanvas = (() => {
20770
21519
  fontFamily: theme.node.fontFamily,
20771
21520
  fontSize: 12,
20772
21521
  backdropFilter: "blur(8px)"
20773
- }, children: "Loading..." }), (0, import_jsx_runtime28.jsx)(Viewport, { ref: viewportHandleRef, nodes, edges, nodeMap, theme, edgeStyle, columns: currentCanvas.columns, rows: currentCanvas.rows, canvases, minZoom: effectiveMinZoom, maxZoom: effectiveMaxZoom, defaultViewport, autoFit, canvasRef: currentCanvasRef, handoffTransform: pendingHandoff, onHandoffApplied: handleHandoffApplied, handoffFadeMs: zoomNavConfig.fadeDuration, onViewportChange: handleViewportChange, onNodeClick: handleNodeClick, onNodeDoubleClick: handleNodeDoubleClick, onNodeNavigate: handleNodeNavigate, onEdgeClick: handleEdgeClick, onEdgeDoubleClick: handleEdgeDoubleClick, onCanvasClick: editable ? handleCanvasClick : void 0, onCanvasContextMenu: handleCanvasContextMenu, onNodeContextMenu: handleNodeContextMenu, onEdgeContextMenu: handleEdgeContextMenu, onNodePointerDown: editable ? onNodePointerDown : void 0, selectedId: editable ? selectedId : null, editingId: editable ? editingId : null, selectedEdgeId: editable ? selectedEdgeId : null, editingEdgeId: editable ? editingEdgeId : null, dragOverrides, dropTargetId, resizeOverrides, onResizeHandlePointerDown: editable ? onResizeHandlePointerDown : void 0, onEditorCommit: handleEditorCommit, onEditorCancel: handleEditorCancel, onEdgeEditorCommit: handleEdgeEditorCommit, onEdgeEditorCancel: handleEdgeEditorCancel, pendingEdge: editable ? pendingEdge : null, onConnectionHandlePointerDown: editable ? onConnectionHandlePointerDown : void 0, edgeCreateEnabled: editable }), showLaneHeaders && (0, import_jsx_runtime28.jsx)(LaneHeaders, { columns: currentCanvas.columns, rows: currentCanvas.rows, theme, getViewport: getViewportState, width: containerSize.width, height: containerSize.height, pinned: laneHeaders === "pinned" }), editable && showNodeToolbar && selectedResolvedNode && !editingId && (0, import_jsx_runtime28.jsx)(NodeToolbar, { node: selectedResolvedNode, theme, onPatch: (update) => {
20774
- onNodeUpdate?.(selectedResolvedNode.id, update, currentCanvasRef);
21522
+ }, children: "Loading..." }), (0, import_jsx_runtime28.jsx)(Viewport, { ref: viewportHandleRef, nodes, edges, nodeMap, theme, edgeStyle, columns: currentCanvas.columns, rows: currentCanvas.rows, canvases, minZoom: effectiveMinZoom, maxZoom: effectiveMaxZoom, defaultViewport, autoFit, canvasRef: currentCanvasRef, handoffTransform: pendingHandoff, onHandoffApplied: handleHandoffApplied, handoffFadeMs: zoomNavConfig.fadeDuration, onViewportChange: handleViewportChange, onNodeClick: handleNodeClick, onNodeDoubleClick: handleNodeDoubleClick, onNodeNavigate: handleNodeNavigate, onEdgeClick: handleEdgeClick, onEdgeDoubleClick: handleEdgeDoubleClick, onCanvasClick: editable ? handleCanvasClick : void 0, onCanvasContextMenu: handleCanvasContextMenu, onNodeContextMenu: handleNodeContextMenu, onEdgeContextMenu: handleEdgeContextMenu, onNodePointerDown: editable ? onNodePointerDown : void 0, selectedIds: editable ? selectedIds : void 0, marqueeRect: editable ? marqueeRect : null, marqueeActiveRef: editable ? marqueeActiveRef : void 0, editingId: editable ? editingId : null, selectedEdgeId: editable ? selectedEdgeId : null, editingEdgeId: editable ? editingEdgeId : null, dragOverrides, dropTargetId, resizeOverrides, onResizeHandlePointerDown: editable ? onResizeHandlePointerDown : void 0, onEditorCommit: handleEditorCommit, onEditorCancel: handleEditorCancel, onEdgeEditorCommit: handleEdgeEditorCommit, onEdgeEditorCancel: handleEdgeEditorCancel, pendingEdge: editable ? pendingEdge : null, onConnectionHandlePointerDown: editable ? onConnectionHandlePointerDown : void 0, edgeCreateEnabled: editable }), showLaneHeaders && (0, import_jsx_runtime28.jsx)(LaneHeaders, { columns: currentCanvas.columns, rows: currentCanvas.rows, theme, getViewport: getViewportState, width: containerSize.width, height: containerSize.height, pinned: laneHeaders === "pinned" }), editable && showNodeToolbar && selectedIds.size === 1 && selectedResolvedNode && !editingId && (0, import_jsx_runtime28.jsx)(NodeToolbar, { node: selectedResolvedNode, theme, onPatch: (update) => {
21523
+ wrappedOnNodeUpdate(selectedResolvedNode.id, update, currentCanvasRef);
20775
21524
  }, onDelete: () => {
20776
- onNodeDelete?.(selectedResolvedNode.id, currentCanvasRef);
20777
- setSelectedId(null);
20778
- }, getViewport: getViewportState, containerWidth: containerSize.width, containerHeight: containerSize.height, render: renderNodeToolbar }), editable && (renderAddNodeButton ? renderAddNodeButton(renderProps) : (0, import_jsx_runtime28.jsx)(AddNodeButton, { ...renderProps })), nodeContextMenu && (0, import_jsx_runtime28.jsx)(NodeContextMenuOverlay, { state: contextMenuState, config: nodeContextMenu, theme, onClose: () => setContextMenuState(null) })] });
21525
+ wrappedOnNodeDelete(selectedResolvedNode.id, currentCanvasRef);
21526
+ clearSelection();
21527
+ }, getViewport: getViewportState, containerWidth: containerSize.width, containerHeight: containerSize.height, render: renderNodeToolbar }), editable && showNodeToolbar && selectedIds.size > 1 && !editingId && (() => {
21528
+ const selectedResolvedNodes = Array.from(selectedIds).map((id2) => nodeMap.get(id2)).filter((n) => n != null);
21529
+ if (selectedResolvedNodes.length === 0)
21530
+ return null;
21531
+ const anchorNode = selectedResolvedNodes[0];
21532
+ return (0, import_jsx_runtime28.jsx)(NodeToolbar, { node: anchorNode, selectedNodes: selectedResolvedNodes, theme, onPatch: () => {
21533
+ }, onMultiPatch: (patch) => {
21534
+ for (const id2 of selectedIds) {
21535
+ wrappedOnNodeUpdate(id2, patch, currentCanvasRef);
21536
+ }
21537
+ }, onDelete: () => {
21538
+ wrappedOnNodesDelete(Array.from(selectedIds), currentCanvasRef);
21539
+ clearSelection();
21540
+ }, getViewport: getViewportState, containerWidth: containerSize.width, containerHeight: containerSize.height });
21541
+ })(), editable && (renderAddNodeButton ? renderAddNodeButton(renderProps) : (0, import_jsx_runtime28.jsx)(AddNodeButton, { ...renderProps })), nodeContextMenu && (0, import_jsx_runtime28.jsx)(NodeContextMenuOverlay, { state: contextMenuState, config: nodeContextMenu, theme, onClose: () => setContextMenuState(null) })] });
20779
21542
  });
20780
21543
 
20781
- // ../react/dist/hooks/useMultiSelect.js
20782
- var import_react22 = __toESM(require_react(), 1);
20783
-
20784
- // ../react/dist/hooks/useMultiSelectClipboard.js
20785
- var import_react23 = __toESM(require_react(), 1);
20786
-
20787
21544
  // src/index.tsx
20788
21545
  function resolveThemeOption(theme) {
20789
21546
  if (typeof theme === "string") {
@@ -20892,7 +21649,7 @@ var SystemCanvas = (() => {
20892
21649
  onEdgeUpdate: handleEdgeUpdate,
20893
21650
  onEdgeDelete: handleEdgeDelete
20894
21651
  };
20895
- root2.render(import_react24.default.createElement(SystemCanvas, props));
21652
+ root2.render(import_react25.default.createElement(SystemCanvas, props));
20896
21653
  };
20897
21654
  doRender();
20898
21655
  return {