@dschz/solid-flow 1.0.0-next.6 → 1.0.0-next.8

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.
@@ -1,5 +1,5 @@
1
1
  import { Dynamic, Portal, addEvent, claimElement, className, createComponent, delegateEvents, effect, insert, isServer, memo, mergeProps, ref, setAttribute, setStyleProperty, spread, style, template } from "@solidjs/web";
2
- import { ConnectionLineType, ConnectionMode, MarkerType, PanOnScrollMode, Position, Position as Position$1, ResizeControlVariant, SelectionMode as SelectionMode$1, XYDrag, XYHandle, XYMinimap, XYPanZoom, XYResizer, XY_RESIZER_HANDLE_POSITIONS, XY_RESIZER_LINE_POSITIONS, addEdge, addEdge as addEdge$1, areConnectionMapsEqual, calcAutoPan, calculateNodePosition, clampPosition, clampPositionToParent, createDevWarn, createMarkerIds, elementSelectionKeys, evaluateAbsolutePosition, fitViewport, getBezierEdgeCenter as getBezierEdgeCenter$1, getBezierPath, getBezierPath as getBezierPath$1, getBoundsOfRects, getConnectedEdges, getConnectionStatus, getDimensions, getEdgeCenter as getEdgeCenter$1, getEdgePosition, getEdgeToolbarTransform, getElementsToRemove, getElevatedEdgeZIndex, getEventPosition, getHandleBounds, getHostForElement, getIncomers, getInternalNodesBounds, getMarkerId, getNodeDimensions, getNodePositionWithOrigin, getNodeToolbarTransform, getNodesBounds, getNodesBounds as getNodesBounds$1, getNodesInside, getOutgoers, getOverlappingArea, getSmoothStepPath, getSmoothStepPath as getSmoothStepPath$1, getStraightPath, getStraightPath as getStraightPath$1, getViewportForBounds, getViewportForBounds as getViewportForBounds$1, handleConnectionChange, infiniteExtent, initialConnection, isCoordinateExtent, isEdgeBase, isInputDOMNode, isMacOs, isNodeBase, isNumeric, isRectObject, mergeAriaLabelConfig, nodeHasDimensions, nodeToRect, panBy, pointToRendererPoint, rendererPointToPoint, shallowNodeData, snapPosition } from "@xyflow/system";
2
+ import { ConnectionLineType, ConnectionMode, MarkerType, PanOnScrollMode, Position, Position as Position$1, ResizeControlVariant, SelectionMode as SelectionMode$1, XYDrag, XYHandle, XYMinimap, XYPanZoom, XYResizer, XY_RESIZER_HANDLE_POSITIONS, XY_RESIZER_LINE_POSITIONS, addEdge, addEdge as addEdge$1, areConnectionMapsEqual, calcAutoPan, calculateNodePosition, clampPosition, clampPositionToParent, createDevWarn, createMarkerIds, elementSelectionKeys, errorMessages, evaluateAbsolutePosition, fitViewport, getBezierEdgeCenter as getBezierEdgeCenter$1, getBezierPath, getBezierPath as getBezierPath$1, getBoundsOfRects, getConnectedEdges, getConnectionStatus, getDimensions, getEdgeCenter as getEdgeCenter$1, getEdgePosition, getEdgeToolbarTransform, getElementsToRemove, getElevatedEdgeZIndex, getEventPosition, getHandleBounds, getHostForElement, getIncomers, getInternalNodesBounds, getMarkerId, getNodeDimensions, getNodePositionWithOrigin, getNodeToolbarTransform, getNodesBounds, getNodesBounds as getNodesBounds$1, getNodesInside, getOutgoers, getOverlappingArea, getSmoothStepPath, getSmoothStepPath as getSmoothStepPath$1, getStraightPath, getStraightPath as getStraightPath$1, getViewportForBounds, getViewportForBounds as getViewportForBounds$1, handleConnectionChange, infiniteExtent, initialConnection, isCoordinateExtent, isEdgeBase, isInputDOMNode, isMacOs, isNodeBase, isNumeric, isRectObject, mergeAriaLabelConfig, nodeHasDimensions, nodeToRect, panBy, pointToRendererPoint, rendererPointToPoint, shallowNodeData, snapPosition } from "@xyflow/system";
3
3
  import { For, Show, createContext, createEffect, createMemo, createProjection, createSignal, createStore, flush, mapArray, merge, omit, onCleanup, onSettled, snapshot, untrack, useContext } from "solid-js";
4
4
  import { createMediaQuery } from "@solid-primitives/media";
5
5
  import { createEventListener, createEventListenerMap } from "@solid-primitives/event-listener";
@@ -65,6 +65,8 @@ function propDefaults(props, defaults) {
65
65
  const getEdgeId = (connection) => {
66
66
  let { source, sourceHandle, target, targetHandle } = connection;
67
67
  return `xy-edge__${source}${sourceHandle || ""}-${target}${targetHandle || ""}`;
68
+ }, isEdgeSelectable = (edge, store) => edge.selectable ?? store.defaultEdgeOptions.selectable ?? store.elementsSelectable, emitFlowError = (onError, id, message) => {
69
+ onError && onError(id, message);
68
70
  }, EdgeLabelRenderer = (props) => {
69
71
  let { store } = useInternalSolidFlow(), labelNode = () => store.domNode?.querySelector(".solid-flow__edge-labels");
70
72
  return createComponent(Show, {
@@ -92,7 +94,7 @@ const EdgeLabel = (props) => {
92
94
  selectEdgeOnClick: !1,
93
95
  transparent: !1,
94
96
  style: {}
95
- }), rest = omit(_props, "x", "y", "width", "height", "selectEdgeOnClick", "transparent", "children", "class", "style"), { actions } = useInternalSolidFlow(), id = useEdgeId(), zIndex = () => actions.getEdge(id())?.zIndex;
97
+ }), rest = omit(_props, "x", "y", "width", "height", "selectEdgeOnClick", "transparent", "children", "class", "style"), { actions } = useInternalSolidFlow(), id = useEdgeId(), zIndex = () => actions.getLayoutedEdge(id())?.zIndex;
96
98
  return createComponent(EdgeLabelRenderer, { get children() {
97
99
  var _el$ = _tmpl$$34();
98
100
  return spread(_el$, mergeProps({
@@ -282,6 +284,205 @@ const BaseEdge = (props) => {
282
284
  });
283
285
  };
284
286
  //#endregion
287
+ //#region src/core/spatial/grid.ts
288
+ /**
289
+ * A uniform spatial hash over axis-aligned rects — the plain, NON-reactive
290
+ * building block behind the flow's spatial queries (RFC-4239 dossier:
291
+ * gesture-scoped snapshots and epoch-rebuilt indexes; deliberately never a
292
+ * live-maintained reactive structure, which would re-create the round-6
293
+ * central-collection anti-pattern).
294
+ *
295
+ * Every operation is O(cells touched); with cellSize on the order of the
296
+ * query radius or median node size, inserts and queries touch O(1) cells.
297
+ * No balancing, no extent-known-up-front requirement, no dependency —
298
+ * upstream's own bake-off (quadtree vs BVH vs rbush) is why: fixed-radius
299
+ * neighborhood and rect-vs-box queries are the textbook grid case.
300
+ */
301
+ var SpatialGrid = class {
302
+ cellSize;
303
+ cells = /* @__PURE__ */ new Map();
304
+ rects = /* @__PURE__ */ new Map();
305
+ constructor(cellSize) {
306
+ this.cellSize = cellSize;
307
+ }
308
+ cellRange(rect) {
309
+ let size = this.cellSize;
310
+ return {
311
+ minX: Math.floor(rect.x / size),
312
+ maxX: Math.floor((rect.x + rect.width) / size),
313
+ minY: Math.floor(rect.y / size),
314
+ maxY: Math.floor((rect.y + rect.height) / size)
315
+ };
316
+ }
317
+ insert(id, rect) {
318
+ this.rects.set(id, rect);
319
+ let { minX, maxX, minY, maxY } = this.cellRange(rect);
320
+ for (let cx = minX; cx <= maxX; cx++) for (let cy = minY; cy <= maxY; cy++) {
321
+ let key = `${cx}:${cy}`, bucket = this.cells.get(key);
322
+ bucket ? bucket.push(id) : this.cells.set(key, [id]);
323
+ }
324
+ }
325
+ /** Ids of entries whose rect overlaps the query rect (touching counts). */
326
+ queryRect(query) {
327
+ let { minX, maxX, minY, maxY } = this.cellRange(query), seen = /* @__PURE__ */ new Set(), result = [];
328
+ for (let cx = minX; cx <= maxX; cx++) for (let cy = minY; cy <= maxY; cy++) {
329
+ let bucket = this.cells.get(`${cx}:${cy}`);
330
+ if (bucket) for (let id of bucket) {
331
+ if (seen.has(id)) continue;
332
+ seen.add(id);
333
+ let rect = this.rects.get(id);
334
+ rect.x <= query.x + query.width && rect.x + rect.width >= query.x && rect.y <= query.y + query.height && rect.y + rect.height >= query.y && result.push(id);
335
+ }
336
+ }
337
+ return result;
338
+ }
339
+ get size() {
340
+ return this.rects.size;
341
+ }
342
+ }, GestureSpatialLookup = class {
343
+ #real;
344
+ #cellSize;
345
+ #grid = null;
346
+ #queryRect = null;
347
+ constructor(real, cellSize) {
348
+ this.#real = real, this.#cellSize = cellSize;
349
+ }
350
+ /** Snapshot the current geometry into the grid (gesture start). */
351
+ arm(rectOf) {
352
+ let grid = new SpatialGrid(this.#cellSize);
353
+ for (let [id, value] of this.#real.entries()) grid.insert(id, rectOf(value));
354
+ this.#grid = grid, this.#queryRect = null;
355
+ }
356
+ /** Focus iteration on the neighborhood of the pointer (per move). */
357
+ setQueryCenter(center, radius) {
358
+ this.#queryRect = {
359
+ x: center.x - radius,
360
+ y: center.y - radius,
361
+ width: radius * 2,
362
+ height: radius * 2
363
+ };
364
+ }
365
+ /** Focus iteration on an explicit rect (box-selection gestures). */
366
+ setQueryRect(rect) {
367
+ this.#queryRect = rect;
368
+ }
369
+ /** Back to plain pass-through (gesture end). */
370
+ disarm() {
371
+ this.#grid = null, this.#queryRect = null;
372
+ }
373
+ #candidateIds() {
374
+ return !this.#grid || !this.#queryRect ? null : this.#grid.queryRect(this.#queryRect);
375
+ }
376
+ get(key) {
377
+ return this.#real.get(key);
378
+ }
379
+ has(key) {
380
+ return this.#real.has(key);
381
+ }
382
+ get size() {
383
+ return this.#real.size;
384
+ }
385
+ *keys() {
386
+ let candidates = this.#candidateIds();
387
+ if (!candidates) {
388
+ yield* this.#real.keys();
389
+ return;
390
+ }
391
+ for (let id of candidates) this.#real.has(id) && (yield id);
392
+ }
393
+ *values() {
394
+ let candidates = this.#candidateIds();
395
+ if (!candidates) {
396
+ yield* this.#real.values();
397
+ return;
398
+ }
399
+ for (let id of candidates) {
400
+ let value = this.#real.get(id);
401
+ value !== void 0 && (yield value);
402
+ }
403
+ }
404
+ *entries() {
405
+ let candidates = this.#candidateIds();
406
+ if (!candidates) {
407
+ yield* this.#real.entries();
408
+ return;
409
+ }
410
+ for (let id of candidates) {
411
+ let value = this.#real.get(id);
412
+ value !== void 0 && (yield [id, value]);
413
+ }
414
+ }
415
+ [Symbol.iterator]() {
416
+ return this.entries();
417
+ }
418
+ forEach(callback, thisArg) {
419
+ for (let [key, value] of this.entries()) callback.call(thisArg, value, key, this);
420
+ }
421
+ [Symbol.toStringTag] = "GestureSpatialLookup";
422
+ set() {
423
+ throw Error("GestureSpatialLookup is read-only");
424
+ }
425
+ getOrInsert() {
426
+ throw Error("GestureSpatialLookup is read-only");
427
+ }
428
+ getOrInsertComputed() {
429
+ throw Error("GestureSpatialLookup is read-only");
430
+ }
431
+ delete() {
432
+ throw Error("GestureSpatialLookup is read-only");
433
+ }
434
+ clear() {
435
+ throw Error("GestureSpatialLookup is read-only");
436
+ }
437
+ };
438
+ //#endregion
439
+ //#region src/components/handle/connectionGestureLookup.ts
440
+ /**
441
+ * Upstream `getClosestHandle` prefilters nodes within
442
+ * `connectionRadius + ADDITIONAL_DISTANCE` of the pointer; ADDITIONAL_DISTANCE
443
+ * is hardcoded to 250 in @xyflow/system (xyhandle/utils.ts). Tracked here with
444
+ * a safety pad: a superset of candidates is always correct (their exact
445
+ * distance filter runs after), so the pad only costs a few extra candidates.
446
+ */
447
+ const armConnectionGestureLookup = (options) => {
448
+ let { event, real, domNode, getTransform, connectionRadius } = options, containerBounds = domNode?.getBoundingClientRect();
449
+ if (!containerBounds) return real;
450
+ let radius = connectionRadius + 250 + 50, lookup = new GestureSpatialLookup(real, radius);
451
+ lookup.arm((node) => nodeToRect(node));
452
+ let update = (moveEvent) => {
453
+ lookup.setQueryCenter(pointToRendererPoint(getEventPosition(moveEvent, containerBounds), getTransform(), !1, [1, 1]), radius);
454
+ };
455
+ update(event);
456
+ let doc = getHostForElement(event.target), dispose = () => {
457
+ doc.removeEventListener("mousemove", update, !0), doc.removeEventListener("touchmove", update, !0), doc.removeEventListener("mouseup", dispose, !0), doc.removeEventListener("touchend", dispose, !0), lookup.disarm();
458
+ };
459
+ return doc.addEventListener("mousemove", update, !0), doc.addEventListener("touchmove", update, !0), doc.addEventListener("mouseup", dispose, !0), doc.addEventListener("touchend", dispose, !0), lookup;
460
+ }, buildConnectionGestureParams = (options) => {
461
+ let { event, store, actions, gestureLookup } = options;
462
+ return {
463
+ lib: store.lib,
464
+ flowId: store.id,
465
+ domNode: store.domNode,
466
+ autoPanOnConnect: store.autoPanOnConnect,
467
+ autoPanSpeed: store.autoPanSpeed,
468
+ connectionMode: store.connectionMode,
469
+ connectionRadius: store.connectionRadius,
470
+ nodeLookup: gestureLookup,
471
+ cancelConnection: actions.cancelConnection,
472
+ panBy: actions.panBy,
473
+ updateConnection: ((connection) => {
474
+ actions.setConnection(connection), flush();
475
+ }),
476
+ isValidConnection: store.isValidConnection,
477
+ onConnectStart: store.onConnectStart,
478
+ onConnectEnd: store.onConnectEnd,
479
+ getTransform: () => store.transform,
480
+ getFromHandle: () => store.connection.fromHandle,
481
+ dragThreshold: store.connectionDragThreshold,
482
+ handleDomNode: event.currentTarget
483
+ };
484
+ };
485
+ //#endregion
285
486
  //#region src/components/edge/EdgeReconnectAnchor.tsx
286
487
  var _tmpl$$32 = /* @__PURE__ */ template("<div style=background:transparent;border:none;cursor:move>");
287
488
  /** Grab area that lets an edge end be dragged off its handle and reconnected. */
@@ -305,27 +506,24 @@ const EdgeReconnectAnchor = (props) => {
305
506
  nodeId: edge().target,
306
507
  handleId: edge().targetHandle ?? null,
307
508
  type: "target"
308
- };
309
- XYHandle.onPointerDown(event, {
310
- lib: store.lib,
311
- flowId: store.id,
509
+ }, gestureLookup = armConnectionGestureLookup({
510
+ event,
511
+ real: nodeLookup,
312
512
  domNode: store.domNode,
513
+ getTransform: () => store.transform,
514
+ connectionRadius: store.connectionRadius
515
+ });
516
+ XYHandle.onPointerDown(event, {
517
+ ...buildConnectionGestureParams({
518
+ event,
519
+ store,
520
+ actions,
521
+ gestureLookup
522
+ }),
313
523
  nodeId: opposite.nodeId,
314
524
  handleId: opposite.handleId,
315
- autoPanOnConnect: store.autoPanOnConnect,
316
- connectionMode: store.connectionMode,
317
- connectionRadius: store.connectionRadius,
318
- nodeLookup,
319
525
  isTarget: opposite.type === "target",
320
526
  edgeUpdaterType: opposite.type,
321
- cancelConnection: actions.cancelConnection,
322
- panBy: actions.panBy,
323
- updateConnection: (connection) => {
324
- actions.setConnection(connection), flush();
325
- },
326
- isValidConnection: store.isValidConnection,
327
- onConnectStart: store.onConnectStart,
328
- onConnectEnd: store.onConnectEnd,
329
527
  onConnect: (connection) => {
330
528
  let newEdge = {
331
529
  ...edge(),
@@ -335,12 +533,7 @@ const EdgeReconnectAnchor = (props) => {
335
533
  },
336
534
  onReconnectEnd: (event, connectionState) => {
337
535
  setReconnectingState(!1), store.onReconnectEnd?.(event, edge(), opposite.type, connectionState);
338
- },
339
- getTransform: () => store.transform,
340
- getFromHandle: () => store.connection.fromHandle,
341
- autoPanSpeed: store.autoPanSpeed,
342
- dragThreshold: store.connectionDragThreshold,
343
- handleDomNode: event.currentTarget
536
+ }
344
537
  });
345
538
  };
346
539
  return createComponent(EdgeLabel, mergeProps({
@@ -416,9 +609,81 @@ const A11yDescriptions = () => {
416
609
  }
417
610
  })
418
611
  ];
419
- }, createEdgeStore = (edges) => {
420
- let [store, setStore] = createStore(edges);
421
- return [store, setStore];
612
+ }, createSelectionCommands = ({ store, setNodesStore, setEdgesStore, setSelectionRect, setSelectionRectMode, nodeLookup, edgeLookup, updateNodePositions }) => {
613
+ let unselectNodesAndEdges = ({ nodes: _nodes, edges } = {}) => {
614
+ let nodesToUnselect = new Set((_nodes || store.nodes).map(({ id }) => id));
615
+ nodesToUnselect.size && setNodesStore((nodes) => {
616
+ for (let node of nodes) nodesToUnselect.has(node.id) && (node.selected = !1);
617
+ });
618
+ let edgesToUnselect = new Set((edges ?? store.edges).map(({ id }) => id));
619
+ edgesToUnselect.size && setEdgesStore((edges) => {
620
+ for (let edge of edges) edgesToUnselect.has(edge.id) && (edge.selected = !1);
621
+ }), flush();
622
+ }, addSelectedNodes = (ids) => {
623
+ let isMultiSelection = store.multiselectionKeyPressed, idSet = new Set(ids);
624
+ setNodesStore((nodes) => {
625
+ for (let node of nodes) {
626
+ let nodeWillBeSelected = idSet.has(node.id), selected = isMultiSelection && node.selected || nodeWillBeSelected;
627
+ node.selected !== selected && (node.selected = selected);
628
+ }
629
+ }), isMultiSelection || unselectNodesAndEdges({ nodes: [] }), flush();
630
+ }, addSelectedEdges = (ids) => {
631
+ let isMultiSelection = store.multiselectionKeyPressed, idSet = new Set(ids);
632
+ setEdgesStore((edges) => {
633
+ for (let edge of edges) {
634
+ let edgeWillBeSelected = idSet.has(edge.id), selected = isMultiSelection && edge.selected || edgeWillBeSelected;
635
+ edge.selected !== selected && (edge.selected = selected);
636
+ }
637
+ }), isMultiSelection || unselectNodesAndEdges({ edges: [] }), flush();
638
+ };
639
+ return {
640
+ unselectNodesAndEdges,
641
+ addSelectedNodes,
642
+ addSelectedEdges,
643
+ handleNodeSelection: (id, unselect, nodeRef) => {
644
+ let node = store.nodes.find((n) => n.id === id);
645
+ if (!node) {
646
+ emitFlowError(store.onError, "012", errorMessages.error012(id));
647
+ return;
648
+ }
649
+ setSelectionRect(void 0), setSelectionRectMode(void 0), node.selected ? (unselect || node.selected && store.multiselectionKeyPressed) && (unselectNodesAndEdges({
650
+ nodes: [node],
651
+ edges: []
652
+ }), requestAnimationFrame(() => nodeRef?.blur())) : addSelectedNodes([id]);
653
+ },
654
+ handleEdgeSelection: (id) => {
655
+ let edge = edgeLookup[id];
656
+ if (!edge) {
657
+ emitFlowError(store.onError, "012", errorMessages.error012(id));
658
+ return;
659
+ }
660
+ isEdgeSelectable(edge, store) && (setSelectionRect(void 0), setSelectionRectMode(void 0), edge.selected ? edge.selected && store.multiselectionKeyPressed && unselectNodesAndEdges({
661
+ nodes: [],
662
+ edges: [edge]
663
+ }) : addSelectedEdges([id]));
664
+ },
665
+ moveSelectedNodes: (direction, factor) => {
666
+ let nodeUpdates = /* @__PURE__ */ new Map(), xVelo = store.snapGrid?.[0] ?? 5, yVelo = store.snapGrid?.[1] ?? 5, xDiff = direction.x * xVelo * factor, yDiff = direction.y * yVelo * factor;
667
+ for (let node of nodeLookup.values()) {
668
+ if (!(node.selected && (node.draggable || store.nodesDraggable && node.draggable === void 0))) continue;
669
+ let nextPosition = {
670
+ x: node.internals.positionAbsolute.x + xDiff,
671
+ y: node.internals.positionAbsolute.y + yDiff
672
+ };
673
+ store.snapGrid && (nextPosition = snapPosition(nextPosition, store.snapGrid));
674
+ let { position } = calculateNodePosition({
675
+ nodeId: node.id,
676
+ nextPosition,
677
+ nodeLookup,
678
+ nodeExtent: store.nodeExtent,
679
+ nodeOrigin: store.nodeOrigin,
680
+ onError: store.onError
681
+ });
682
+ nodeUpdates.set(node.id, { position });
683
+ }
684
+ updateNodePositions(nodeUpdates);
685
+ }
686
+ };
422
687
  }, STEP = .5 / 2, rectsEqual = (a, b) => a === b || !!a && !!b && a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height, rectsOverlap = (a, b) => a.x <= b.x + b.width && a.x + a.width >= b.x && a.y <= b.y + b.height && a.y + a.height >= b.y, createCullingViewport = (source) => createMemo(() => {
423
688
  let { width, height } = source;
424
689
  if (!width || !height) return null;
@@ -549,14 +814,48 @@ var RecordMapFacade = class {
549
814
  }
550
815
  };
551
816
  //#endregion
552
- //#region src/core/projections/connections.ts
817
+ //#region src/core/measurementIngest.ts
553
818
  /**
554
- * Lookup keys for the connection index. Each edge is registered under six
555
- * keys for both of its endpoints: the node, the node+handle-type, and (when
556
- * a handle id is present) the node+type+handle:
557
- * `${nodeId}` · `${nodeId}-${type}` · `${nodeId}-${type}-${handleId}`
819
+ * The measurement ingest lifecycle (WP3): everything that flows FROM the DOM
820
+ * measuring pass INTO the data graph, plus the garbage collection that keeps
821
+ * the measurements root aligned with graph membership. The DOM side (resize
822
+ * observers, the idle-scheduled measuring pass) lives in createSolidFlow;
823
+ * headless usage never calls these.
558
824
  */
559
- const connectionKey = (nodeId, type, handleId) => `${nodeId}${type ? handleId ? `-${type}-${handleId}` : `-${type}` : ""}`, pairKey = (aNode, aHandle, bNode, bHandle) => `${aNode}-${aHandle}--${bNode}-${bHandle}`, createConnections = (source) => createProjection(() => {
825
+ const createMeasurementIngest = ({ setMeasurementsStore, setNodesStore, nodes }) => (createEffect(() => new Set(nodes().map((n) => n.id)), (currentIds) => {
826
+ setMeasurementsStore((draft) => {
827
+ for (let id of Object.keys(draft)) currentIds.has(id) || delete draft[id];
828
+ });
829
+ }), {
830
+ applyMeasurementWrites: (writes) => {
831
+ setMeasurementsStore((draft) => {
832
+ for (let write of writes) if (write.hidden) {
833
+ let entry = draft[write.id];
834
+ entry && (entry.handleBounds = void 0);
835
+ } else draft[write.id] = {
836
+ measured: write.measured,
837
+ handleBounds: write.handleBounds
838
+ };
839
+ });
840
+ },
841
+ applyNodeChanges: (changes) => {
842
+ changes.length !== 0 && setNodesStore((nodes) => {
843
+ let nodeById = new Map(nodes.map((node) => [node.id, node]));
844
+ for (let change of changes) {
845
+ let node = nodeById.get(change.id);
846
+ if (node) switch (change.type) {
847
+ case "dimensions":
848
+ change.setAttributes && (node.width = change.dimensions?.width ?? node.width, node.height = change.dimensions?.height ?? node.height), node.measured = {
849
+ ...node.measured,
850
+ ...change.dimensions
851
+ };
852
+ break;
853
+ case "position": node.position = change.position ?? node.position;
854
+ }
855
+ }
856
+ });
857
+ }
858
+ }), connectionKey = (nodeId, type, handleId) => `${nodeId}${type ? handleId ? `-${type}-${handleId}` : `-${type}` : ""}`, pairKey = (aNode, aHandle, bNode, bHandle) => `${aNode}-${aHandle}--${bNode}-${bHandle}`, createConnections = (source) => createProjection(() => {
560
859
  let out = {}, add = (key, entry, connection) => {
561
860
  (out[key] ??= {})[entry] = connection;
562
861
  };
@@ -575,7 +874,20 @@ const connectionKey = (nodeId, type, handleId) => `${nodeId}${type ? handleId ?
575
874
  let out = {};
576
875
  for (let edge of source.edges) out[edge.id] = edge;
577
876
  return out;
578
- }, {}, { key: "id" });
877
+ }, {}, { key: "id" }), createRowRecordProjection = (rowStores) => {
878
+ let assigned = /* @__PURE__ */ new Map();
879
+ return createProjection((draft) => {
880
+ let seen = /* @__PURE__ */ new Set();
881
+ for (let { id, store } of rowStores()) {
882
+ let row = store.row;
883
+ row && (seen.add(id), assigned.get(id) !== row && (assigned.set(id, row), draft[id] = row));
884
+ }
885
+ for (let id of assigned.keys()) seen.has(id) || (assigned.delete(id), delete draft[id]);
886
+ }, {}, {
887
+ key: null,
888
+ shallow: !0
889
+ });
890
+ };
579
891
  function isManualZIndexMode(zIndexMode) {
580
892
  return zIndexMode === "manual";
581
893
  }
@@ -619,11 +931,7 @@ const EMPTY_AUTO_INDEX = /* @__PURE__ */ new Map(), createInternalNodes = (sourc
619
931
  x,
620
932
  y
621
933
  }, row.internals.z = z;
622
- } else source.nodes.length;
623
- }
624
- if (userNode.parentId) {
625
- let parent = entryById.get(userNode.parentId);
626
- parent?.store.row.internals.positionAbsolute.x, parent?.store.row.internals.z;
934
+ } else source.nodes.length, emitFlowError(source.onError, "parent-missing", `Parent node ${userNode.parentId} not found. Please make sure that parent nodes are in front of their child nodes in the nodes array.`);
627
935
  }
628
936
  return { row };
629
937
  }, {}, { key: "id" }), entry = {
@@ -636,19 +944,8 @@ const EMPTY_AUTO_INDEX = /* @__PURE__ */ new Map(), createInternalNodes = (sourc
636
944
  id,
637
945
  store
638
946
  };
639
- }, { keyed: (userNode) => userNode.id }), assigned = /* @__PURE__ */ new Map();
640
- return createProjection((draft) => {
641
- let seen = /* @__PURE__ */ new Set();
642
- for (let { id, store } of rowStores()) {
643
- seen.add(id);
644
- let row = store.row;
645
- assigned.get(id) !== row && (assigned.set(id, row), draft[id] = row);
646
- }
647
- for (let id of assigned.keys()) seen.has(id) || (assigned.delete(id), delete draft[id]);
648
- }, {}, {
649
- key: null,
650
- shallow: !0
651
- });
947
+ }, { keyed: (userNode) => userNode.id });
948
+ return createRowRecordProjection(rowStores);
652
949
  };
653
950
  function calculateChildXYZ(childNode, parentNode, nodeOrigin, nodeExtent, selectedNodeZ, zIndexMode) {
654
951
  let { x: parentX, y: parentY } = parentNode.internals.positionAbsolute, childDimensions = getNodeDimensions(childNode), positionWithOrigin = getNodePositionWithOrigin(childNode, nodeOrigin), clampedPosition = isCoordinateExtent(childNode.extent) ? clampPosition(positionWithOrigin, childNode.extent, childDimensions) : positionWithOrigin, absolutePosition = clampPosition({
@@ -693,24 +990,14 @@ const createLayoutedEdges = (source) => {
693
990
  let rowStores = mapArray(() => source.edges, (edgeAccessor) => ({
694
991
  id: edgeAccessor().id,
695
992
  store: createProjection(() => {
696
- let edge = edgeAccessor(), row = buildRow(source, edge);
697
- return source.nodeLookup.get(edge.source)?.internals.handleBounds, source.nodeLookup.get(edge.target)?.internals.handleBounds, { row };
993
+ let edge = edgeAccessor();
994
+ return { row: buildRow(source, edge) };
698
995
  }, { row: null }, { key: "id" })
699
- }), { keyed: (edge) => edge.id }), assigned = /* @__PURE__ */ new Map();
700
- return createProjection((draft) => {
701
- let seen = /* @__PURE__ */ new Set();
702
- for (let { id, store } of rowStores()) {
703
- let row = store.row;
704
- row && (seen.add(id), assigned.get(id) !== row && (assigned.set(id, row), draft[id] = row));
705
- }
706
- for (let id of assigned.keys()) seen.has(id) || (assigned.delete(id), delete draft[id]);
707
- }, {}, {
708
- key: null,
709
- shallow: !0
710
- });
996
+ }), { keyed: (edge) => edge.id });
997
+ return createRowRecordProjection(rowStores);
711
998
  }, buildRow = (source, edge) => {
712
999
  let sourceNode = source.nodeLookup.get(edge.source), targetNode = source.nodeLookup.get(edge.target);
713
- if (!sourceNode || !targetNode) return source.nodeLookup.size, null;
1000
+ if (!sourceNode || !targetNode) return null;
714
1001
  let edgePosition = getEdgePosition({
715
1002
  id: edge.id,
716
1003
  sourceNode,
@@ -740,7 +1027,33 @@ const createLayoutedEdges = (source) => {
740
1027
  let out = {};
741
1028
  for (let node of source.nodes) node.parentId && (out[node.parentId] = !0);
742
1029
  return out;
743
- }, {}, { key: "id" }), getInitialViewport = (fitView, initialViewport, width, height, nodeLookup) => {
1030
+ }, {}, { key: "id" }), createSeededGraphStores = (props, config) => {
1031
+ props.nodes !== void 0 && props.defaultNodes, props.edges !== void 0 && props.defaultEdges;
1032
+ let [nodesStore, setNodesStore] = createStore(props.nodes ?? [...props.defaultNodes ?? []]), [edgesStore, setEdgesStore] = createStore(props.edges ?? [...props.defaultEdges ?? []]), nodeSeedAdopted = props.nodes !== void 0 || props.defaultNodes !== void 0, edgeSeedAdopted = props.edges !== void 0 || props.defaultEdges !== void 0;
1033
+ return createEffect(() => {
1034
+ let next = config().nodes;
1035
+ if (next) for (let node of next);
1036
+ return { next };
1037
+ }, ({ next }) => {
1038
+ next && (nodeSeedAdopted = !0, setNodesStore(() => next));
1039
+ }, { defer: !0 }), createEffect(() => {
1040
+ let next = config().edges;
1041
+ if (next) for (let edge of next);
1042
+ return { next };
1043
+ }, ({ next }) => {
1044
+ next && (edgeSeedAdopted = !0, setEdgesStore(() => next));
1045
+ }, { defer: !0 }), createEffect(() => ({
1046
+ nodes: config().defaultNodes,
1047
+ edges: config().defaultEdges
1048
+ }), ({ nodes: defaultNodes, edges: defaultEdges }) => {
1049
+ defaultNodes && !nodeSeedAdopted && config().nodes === void 0 && (nodeSeedAdopted = !0, setNodesStore(() => [...defaultNodes])), defaultEdges && !edgeSeedAdopted && config().edges === void 0 && (edgeSeedAdopted = !0, setEdgesStore(() => [...defaultEdges]));
1050
+ }, { defer: !0 }), {
1051
+ nodesStore,
1052
+ setNodesStore,
1053
+ edgesStore,
1054
+ setEdgesStore
1055
+ };
1056
+ }, getInitialViewport = (fitView, initialViewport, width, height, nodeLookup) => {
744
1057
  if (fitView && !initialViewport && width && height) {
745
1058
  let bounds = getInternalNodesBounds(nodeLookup, { filter: (node) => !!((node.width || node.initialWidth) && (node.height || node.initialHeight)) });
746
1059
  return getViewportForBounds$1(bounds, width, height, .5, 2, .1);
@@ -751,9 +1064,7 @@ const createLayoutedEdges = (source) => {
751
1064
  zoom: 1
752
1065
  };
753
1066
  }, createFlowState = (props, injections = {}) => {
754
- let _props = merge(getDefaultFlowStateProps(), props), initialNodeTypes = injections.initialNodeTypes ?? {}, initialEdgeTypes = injections.initialEdgeTypes ?? {}, prefersDark = injections.prefersDark ?? (() => _props.colorModeSSR === "dark"), [config, setConfig] = createSignal(_props), [ariaLabelConfig, setAriaLabelConfig] = createSignal(() => mergeAriaLabelConfig(config().ariaLabelConfig)), [ariaLiveMessage, setAriaLiveMessage] = createSignal(() => config().ariaLiveMessage), [clickConnectStartHandle, setClickConnectStartHandle] = createSignal(void 0), [connection, setConnection] = createSignal(initialConnection), [domNode, setDomNode] = createSignal(null), [dragging, setDragging] = createSignal(!1), [elementsSelectable, setElementsSelectable] = createSignal(() => config().elementsSelectable), [height, setHeight] = createSignal(() => config().height), [minZoom, _setMinZoom] = createSignal(() => config().minZoom), [maxZoom, _setMaxZoom] = createSignal(() => config().maxZoom), [nodesConnectable, setNodesConnectable] = createSignal(() => config().nodesDraggable), [nodesDraggable, setNodesDraggable] = createSignal(() => config().nodesDraggable), [panZoom, setPanZoom] = createSignal(null), [selectionRect, setSelectionRect] = createSignal(), [selectionRectMode, setSelectionRectMode] = createSignal(), [snapGrid, setSnapGrid] = createSignal(() => config().snapGrid), [translateExtent, _setTranslateExtent] = createSignal(() => config().translateExtent ?? infiniteExtent), [width, setWidth] = createSignal(() => config().width), [selectionKeyPressed, setSelectionKeyPressed] = createSignal(!1), [multiselectionKeyPressed, setMultiselectionKeyPressed] = createSignal(!1), [deleteKeyPressed, setDeleteKeyPressed] = createSignal(!1), [panActivationKeyPressed, setPanActivationKeyPressed] = createSignal(!1), [zoomActivationKeyPressed, setZoomActivationKeyPressed] = createSignal(!1);
755
- props.nodes !== void 0 && props.defaultNodes, props.edges !== void 0 && props.defaultEdges;
756
- let [nodesStore, setNodesStore] = createStore(props.nodes ?? [...props.defaultNodes ?? []]), [edgesStore, setEdgesStore] = createStore(props.edges ?? [...props.defaultEdges ?? []]), nodeSeedAdopted = props.nodes !== void 0 || props.defaultNodes !== void 0, edgeSeedAdopted = props.edges !== void 0 || props.defaultEdges !== void 0, [measurementsStore, setMeasurementsStore] = createStore({}), internalNodes = createInternalNodes({
1067
+ let _props = merge(getDefaultFlowStateProps(), props), initialNodeTypes = injections.initialNodeTypes ?? {}, initialEdgeTypes = injections.initialEdgeTypes ?? {}, prefersDark = injections.prefersDark ?? (() => _props.colorModeSSR === "dark"), [config, setConfig] = createSignal(_props), ariaLabelConfig = createMemo(() => mergeAriaLabelConfig(config().ariaLabelConfig)), [ariaLiveMessage, setAriaLiveMessage] = createSignal(() => config().ariaLiveMessage), [clickConnectStartHandle, setClickConnectStartHandle] = createSignal(void 0), [connection, setConnection] = createSignal(initialConnection), [domNode, setDomNode] = createSignal(null), [dragging, setDragging] = createSignal(!1), [elementsSelectable, setElementsSelectable] = createSignal(() => config().elementsSelectable), [height, setHeight] = createSignal(() => config().height), minZoom = createMemo(() => config().minZoom), maxZoom = createMemo(() => config().maxZoom), [nodesConnectable, setNodesConnectable] = createSignal(() => config().nodesConnectable), [nodesDraggable, setNodesDraggable] = createSignal(() => config().nodesDraggable), [panZoom, setPanZoom] = createSignal(null), [selectionRect, setSelectionRect] = createSignal(), [selectionRectMode, setSelectionRectMode] = createSignal(), [snapGrid, setSnapGrid] = createSignal(() => config().snapGrid), translateExtent = createMemo(() => config().translateExtent ?? infiniteExtent), [width, setWidth] = createSignal(() => config().width), [selectionKeyPressed, setSelectionKeyPressed] = createSignal(!1), [multiselectionKeyPressed, setMultiselectionKeyPressed] = createSignal(!1), [deleteKeyPressed, setDeleteKeyPressed] = createSignal(!1), [panActivationKeyPressed, setPanActivationKeyPressed] = createSignal(!1), [zoomActivationKeyPressed, setZoomActivationKeyPressed] = createSignal(!1), { nodesStore, setNodesStore, edgesStore, setEdgesStore } = createSeededGraphStores(props, config), [measurementsStore, setMeasurementsStore] = createStore({}), internalNodes = createInternalNodes({
757
1068
  get nodes() {
758
1069
  return nodesStore;
759
1070
  },
@@ -771,26 +1082,12 @@ const createLayoutedEdges = (source) => {
771
1082
  },
772
1083
  get zIndexMode() {
773
1084
  return config().zIndexMode;
1085
+ },
1086
+ get onError() {
1087
+ return config().onFlowError;
774
1088
  }
775
1089
  }), nodeLookup = new RecordMapFacade(internalNodes), initialViewport = getInitialViewport(_props.fitView, _props.initialViewport, _props.width ?? 0, _props.height ?? 0, nodeLookup), [viewportStore, setViewportStore] = createStore(_props.viewport ?? initialViewport);
776
- createEffect(() => {
777
- let next = config().nodes;
778
- if (next) for (let node of next);
779
- return { next };
780
- }, ({ next }) => {
781
- next && (nodeSeedAdopted = !0, setNodesStore(() => next));
782
- }, { defer: !0 }), createEffect(() => {
783
- let next = config().edges;
784
- if (next) for (let edge of next);
785
- return { next };
786
- }, ({ next }) => {
787
- next && (edgeSeedAdopted = !0, setEdgesStore(() => next));
788
- }, { defer: !0 }), createEffect(() => ({
789
- nodes: config().defaultNodes,
790
- edges: config().defaultEdges
791
- }), ({ nodes: defaultNodes, edges: defaultEdges }) => {
792
- defaultNodes && !nodeSeedAdopted && config().nodes === void 0 && (nodeSeedAdopted = !0, setNodesStore(() => [...defaultNodes])), defaultEdges && !edgeSeedAdopted && config().edges === void 0 && (edgeSeedAdopted = !0, setEdgesStore(() => [...defaultEdges]));
793
- }, { defer: !0 }), createEffect(() => config().viewport, (next) => {
1090
+ createEffect(() => config().viewport, (next) => {
794
1091
  next && setViewportStore(() => next);
795
1092
  }, { defer: !0 });
796
1093
  let transform = createMemo(() => [
@@ -802,25 +1099,33 @@ const createLayoutedEdges = (source) => {
802
1099
  if (nodes.length === 0) return !1;
803
1100
  for (let node of nodes) if (!node.hidden && (node.measured?.width === void 0 || node.measured?.height === void 0)) return !1;
804
1101
  return !0;
805
- }), store = merge({
1102
+ }), resolvedColorMode = createMemo(() => {
1103
+ let mode = config().colorMode;
1104
+ return mode === "system" ? prefersDark() ? "dark" : "light" : mode;
1105
+ }), projectedConnection = createMemo(() => {
1106
+ let state = connection();
1107
+ return state.inProgress ? {
1108
+ ...state,
1109
+ to: pointToRendererPoint(state.to, transform())
1110
+ } : state;
1111
+ }), connectionFromHandle = createMemo(() => connection().fromHandle ?? null, { equals: (a, b) => a === b || !!a && !!b && a.nodeId === b.nodeId && a.type === b.type && a.id === b.id }), connectionTargetByHandle = createProjection((draft) => {
1112
+ let state = connection(), toHandle = state.inProgress ? state.toHandle : null, key = toHandle ? connectionKey(toHandle.nodeId, toHandle.type, toHandle.id ?? null) : null;
1113
+ for (let existing of Object.keys(draft)) existing !== key && delete draft[existing];
1114
+ key && (draft[key] = state.isValid ? "valid" : "invalid");
1115
+ }, {}, { key: null }), connectionOriginByHandle = createProjection((draft) => {
1116
+ let fromHandle = connection().fromHandle ?? clickConnectStartHandle(), fromKey = fromHandle ? connectionKey(fromHandle.nodeId, fromHandle.type, fromHandle.id ?? null) : null, siblingKey = fromHandle ? connectionKey(fromHandle.nodeId, fromHandle.type === "source" ? "target" : "source", fromHandle.id ?? null) : null;
1117
+ for (let existing of Object.keys(draft)) existing !== fromKey && existing !== siblingKey && delete draft[existing];
1118
+ fromKey && (draft[fromKey] = "from"), siblingKey && (draft[siblingKey] = "excluded");
1119
+ }, {}, { key: null }), mergedNodeTypes = createMemo(() => ({
1120
+ ...initialNodeTypes,
1121
+ ...config().nodeTypes
1122
+ })), mergedEdgeTypes = createMemo(() => ({
1123
+ ...initialEdgeTypes,
1124
+ ...config().edgeTypes
1125
+ })), selectedNodesView = createMemo(() => nodesStore.filter((node) => node.selected)), selectedEdgesView = createMemo(() => edgesStore.filter((edge) => edge.selected)), store = merge({
806
1126
  width: 0,
807
1127
  height: 0
808
1128
  }, config, {
809
- get _colorMode() {
810
- return config().colorMode;
811
- },
812
- get _colorModeSSR() {
813
- return config().colorModeSSR;
814
- },
815
- get _connection() {
816
- return connection();
817
- },
818
- get _nodeTypes() {
819
- return config().nodeTypes;
820
- },
821
- get _edgeTypes() {
822
- return config().edgeTypes;
823
- },
824
1129
  get ariaLabelConfig() {
825
1130
  return ariaLabelConfig();
826
1131
  },
@@ -831,14 +1136,19 @@ const createLayoutedEdges = (source) => {
831
1136
  return clickConnectStartHandle();
832
1137
  },
833
1138
  get colorMode() {
834
- return this._colorMode === "system" ? prefersDark() ? "dark" : "light" : this._colorMode;
1139
+ return resolvedColorMode();
835
1140
  },
836
1141
  get connection() {
837
- let state = connection();
838
- return {
839
- ...state,
840
- to: state.inProgress ? pointToRendererPoint(state.to, this.transform) : state.to
841
- };
1142
+ return projectedConnection();
1143
+ },
1144
+ get connectionFromHandle() {
1145
+ return connectionFromHandle();
1146
+ },
1147
+ get connectionTargetByHandle() {
1148
+ return connectionTargetByHandle;
1149
+ },
1150
+ get connectionOriginByHandle() {
1151
+ return connectionOriginByHandle;
842
1152
  },
843
1153
  get domNode() {
844
1154
  return domNode();
@@ -847,10 +1157,7 @@ const createLayoutedEdges = (source) => {
847
1157
  return dragging();
848
1158
  },
849
1159
  get edgeTypes() {
850
- return {
851
- ...initialEdgeTypes,
852
- ...this._edgeTypes
853
- };
1160
+ return mergedEdgeTypes();
854
1161
  },
855
1162
  get elementsSelectable() {
856
1163
  return elementsSelectable();
@@ -883,19 +1190,16 @@ const createLayoutedEdges = (source) => {
883
1190
  return nodesDraggable();
884
1191
  },
885
1192
  get nodeTypes() {
886
- return {
887
- ...initialNodeTypes,
888
- ...this._nodeTypes
889
- };
1193
+ return mergedNodeTypes();
890
1194
  },
891
1195
  get panZoom() {
892
1196
  return panZoom();
893
1197
  },
894
1198
  get selectedNodes() {
895
- return nodesStore.filter((node) => node.selected);
1199
+ return selectedNodesView();
896
1200
  },
897
1201
  get selectedEdges() {
898
- return edgesStore.filter((edge) => edge.selected);
1202
+ return selectedEdgesView();
899
1203
  },
900
1204
  get selectionRect() {
901
1205
  return selectionRect();
@@ -984,7 +1288,7 @@ const createLayoutedEdges = (source) => {
984
1288
  return store.onError;
985
1289
  },
986
1290
  nodeLookup
987
- }), visibleEdgeIds = createMemo(() => Object.keys(layoutedEdges)), getEdge = (id) => layoutedEdges[id], fitView = async (options) => store.panZoom ? await fitViewport({
1291
+ }), visibleEdgeIds = createMemo(() => Object.keys(layoutedEdges)), getLayoutedEdge = (id) => layoutedEdges[id], fitView = async (options) => store.panZoom ? await fitViewport({
988
1292
  nodes: nodeLookup,
989
1293
  width: store.width,
990
1294
  height: store.height,
@@ -1010,33 +1314,11 @@ const createLayoutedEdges = (source) => {
1010
1314
  setNodesStore((nodes) => {
1011
1315
  for (let node of nodes) nodeDragItems.has(node.id) && (node.dragging = dragging, node.position = nodeDragItems.get(node.id).position);
1012
1316
  });
1013
- }, applyMeasurementWrites = (writes) => {
1014
- setMeasurementsStore((draft) => {
1015
- for (let write of writes) if (write.hidden) {
1016
- let entry = draft[write.id];
1017
- entry && (entry.handleBounds = void 0);
1018
- } else draft[write.id] = {
1019
- measured: write.measured,
1020
- handleBounds: write.handleBounds
1021
- };
1022
- });
1023
- }, applyNodeChanges = (changes) => {
1024
- changes.length !== 0 && setNodesStore((nodes) => {
1025
- let nodeById = new Map(nodes.map((node) => [node.id, node]));
1026
- for (let change of changes) {
1027
- let node = nodeById.get(change.id);
1028
- if (node) switch (change.type) {
1029
- case "dimensions":
1030
- change.setAttributes && (node.width = change.dimensions?.width ?? node.width, node.height = change.dimensions?.height ?? node.height), node.measured = {
1031
- ...node.measured,
1032
- ...change.dimensions
1033
- };
1034
- break;
1035
- case "position": node.position = change.position ?? node.position;
1036
- }
1037
- }
1038
- });
1039
- }, markInitialNodesMeasured = () => {
1317
+ }, { applyMeasurementWrites, applyNodeChanges } = createMeasurementIngest({
1318
+ setMeasurementsStore,
1319
+ setNodesStore,
1320
+ nodes: () => nodesStore
1321
+ }), markInitialNodesMeasured = () => {
1040
1322
  initialNodesMeasured = !0, tryInitialFitView();
1041
1323
  }, requestMeasure = () => {}, setMeasureRequester = (fn) => {
1042
1324
  requestMeasure = fn;
@@ -1051,66 +1333,16 @@ const createLayoutedEdges = (source) => {
1051
1333
  ease: options?.ease,
1052
1334
  interpolate: options?.interpolate
1053
1335
  }), Promise.resolve(!0)) : Promise.resolve(!1);
1054
- }, setPaneClickDistance = (distance) => {
1055
- store.panZoom?.setClickDistance(distance);
1056
- }, unselectNodesAndEdges = ({ nodes: _nodes, edges } = {}) => {
1057
- let nodesToUnselect = new Set((_nodes || store.nodes).map(({ id }) => id));
1058
- nodesToUnselect.size && setNodesStore((nodes) => {
1059
- for (let node of nodes) nodesToUnselect.has(node.id) && (node.selected = !1);
1060
- });
1061
- let edgesToUnselect = new Set((edges ?? store.edges).map(({ id }) => id));
1062
- edgesToUnselect.size && setEdgesStore((edges) => {
1063
- for (let edge of edges) edgesToUnselect.has(edge.id) && (edge.selected = !1);
1064
- }), flush();
1065
- }, addSelectedNodes = (ids) => {
1066
- let isMultiSelection = store.multiselectionKeyPressed;
1067
- setNodesStore((nodes) => {
1068
- for (let node of nodes) {
1069
- let nodeWillBeSelected = ids.includes(node.id), selected = isMultiSelection && node.selected || nodeWillBeSelected;
1070
- node.selected !== selected && (node.selected = selected);
1071
- }
1072
- }), isMultiSelection || unselectNodesAndEdges({ nodes: [] }), flush();
1073
- }, addSelectedEdges = (ids) => {
1074
- let isMultiSelection = store.multiselectionKeyPressed;
1075
- setEdgesStore((edges) => {
1076
- for (let edge of edges) {
1077
- let edgeWillBeSelected = ids.includes(edge.id), selected = isMultiSelection && edge.selected || edgeWillBeSelected;
1078
- edge.selected !== selected && (edge.selected = selected);
1079
- }
1080
- }), isMultiSelection || unselectNodesAndEdges({ edges: [] }), flush();
1081
- }, handleNodeSelection = (id, unselect, nodeRef) => {
1082
- let node = store.nodes.find((n) => n.id === id);
1083
- node && (setSelectionRect(void 0), setSelectionRectMode(void 0), node.selected ? (unselect || node.selected && store.multiselectionKeyPressed) && (unselectNodesAndEdges({
1084
- nodes: [node],
1085
- edges: []
1086
- }), requestAnimationFrame(() => nodeRef?.blur())) : addSelectedNodes([id]));
1087
- }, handleEdgeSelection = (id) => {
1088
- let edge = edgeLookup[id];
1089
- edge && (edge.selectable || store.elementsSelectable && edge.selectable === void 0) && (setSelectionRect(void 0), setSelectionRectMode(void 0), edge.selected ? edge.selected && store.multiselectionKeyPressed && unselectNodesAndEdges({
1090
- nodes: [],
1091
- edges: [edge]
1092
- }) : addSelectedEdges([id]));
1093
- }, moveSelectedNodes = (direction, factor) => {
1094
- let nodeUpdates = /* @__PURE__ */ new Map(), xVelo = store.snapGrid?.[0] ?? 5, yVelo = store.snapGrid?.[1] ?? 5, xDiff = direction.x * xVelo * factor, yDiff = direction.y * yVelo * factor;
1095
- for (let node of nodeLookup.values()) {
1096
- if (!(node.selected && (node.draggable || store.nodesDraggable && node.draggable === void 0))) continue;
1097
- let nextPosition = {
1098
- x: node.internals.positionAbsolute.x + xDiff,
1099
- y: node.internals.positionAbsolute.y + yDiff
1100
- };
1101
- store.snapGrid && (nextPosition = snapPosition(nextPosition, store.snapGrid));
1102
- let { position } = calculateNodePosition({
1103
- nodeId: node.id,
1104
- nextPosition,
1105
- nodeLookup,
1106
- nodeExtent: store.nodeExtent,
1107
- nodeOrigin: store.nodeOrigin,
1108
- onError: store.onError
1109
- });
1110
- nodeUpdates.set(node.id, { position });
1111
- }
1112
- updateNodePositions(nodeUpdates);
1113
- }, panBy$1 = (delta) => panBy({
1336
+ }, stableSetViewport = (viewport) => setViewportStore(() => viewport), { unselectNodesAndEdges, addSelectedNodes, addSelectedEdges, handleNodeSelection, handleEdgeSelection, moveSelectedNodes } = createSelectionCommands({
1337
+ store,
1338
+ setNodesStore,
1339
+ setEdgesStore,
1340
+ setSelectionRect,
1341
+ setSelectionRectMode,
1342
+ nodeLookup,
1343
+ edgeLookup,
1344
+ updateNodePositions
1345
+ }), panBy$1 = (delta) => panBy({
1114
1346
  delta,
1115
1347
  panZoom: store.panZoom,
1116
1348
  transform: store.transform,
@@ -1187,8 +1419,27 @@ const createLayoutedEdges = (source) => {
1187
1419
  get snapGrid() {
1188
1420
  return store.snapGrid;
1189
1421
  }
1190
- }, getNodeRect = (node) => {
1191
- let nodeToUse = isNode(node) ? node : nodeLookup.get(node.id), position = nodeToUse.parentId ? evaluateAbsolutePosition(nodeToUse.position, nodeToUse.measured, nodeToUse.parentId, nodeLookup, store.nodeOrigin) : nodeToUse.position, nodeWithPosition = {
1422
+ }, intersectionGrid = null, intersectionRows = null, queryIntersectionCandidates = (rect) => untrack(() => {
1423
+ if (!intersectionGrid) {
1424
+ let grid = new SpatialGrid(300), rows = /* @__PURE__ */ new Map();
1425
+ for (let node of store.nodes) {
1426
+ let internalNode = nodeLookup.get(node.id);
1427
+ internalNode && (grid.insert(node.id, nodeToRect(internalNode)), rows.set(node.id, node));
1428
+ }
1429
+ intersectionGrid = grid, intersectionRows = rows, queueMicrotask(() => {
1430
+ intersectionGrid = null, intersectionRows = null;
1431
+ });
1432
+ }
1433
+ let rows = intersectionRows, result = [];
1434
+ for (let id of intersectionGrid.queryRect(rect)) {
1435
+ let row = rows.get(id);
1436
+ row && result.push(row);
1437
+ }
1438
+ return result;
1439
+ }), getNodeRect = (node) => {
1440
+ let nodeToUse = isNode(node) ? node : nodeLookup.get(node.id);
1441
+ if (!nodeToUse) return null;
1442
+ let position = nodeToUse.parentId ? evaluateAbsolutePosition(nodeToUse.position, nodeToUse.measured, nodeToUse.parentId, nodeLookup, store.nodeOrigin) : nodeToUse.position, nodeWithPosition = {
1192
1443
  ...nodeToUse,
1193
1444
  position,
1194
1445
  width: nodeToUse.measured?.width ?? nodeToUse.width,
@@ -1242,7 +1493,7 @@ const createLayoutedEdges = (source) => {
1242
1493
  x,
1243
1494
  y,
1244
1495
  zoom
1245
- ], _snapGrid !== null, _snapGrid || [1, 1]);
1496
+ ], !!_snapGrid, _snapGrid || [1, 1]);
1246
1497
  },
1247
1498
  flowToScreenPosition: (position) => {
1248
1499
  if (!store.domNode) return position;
@@ -1306,14 +1557,18 @@ const createLayoutedEdges = (source) => {
1306
1557
  let remainingNodes = store.nodes.filter((node) => !matchingNodes.some(({ id }) => id === node.id));
1307
1558
  store.onNodesDelete?.(matchingNodes), setNodesStore(() => remainingNodes);
1308
1559
  }
1309
- return {
1560
+ let deletedNodes = matchingNodes ?? [], deletedEdges = matchingEdges ?? [];
1561
+ return (deletedNodes.length > 0 || deletedEdges.length > 0) && store.onDelete?.({
1562
+ nodes: deletedNodes,
1563
+ edges: deletedEdges
1564
+ }), {
1310
1565
  deletedNodes: matchingNodes,
1311
1566
  deletedEdges: matchingEdges
1312
1567
  };
1313
1568
  },
1314
1569
  getIntersectingNodes: (nodeOrRect, partially = !0, nodesToIntersect) => {
1315
1570
  let isRect = isRectObject(nodeOrRect), nodeRect = isRect ? nodeOrRect : getNodeRect(nodeOrRect);
1316
- return nodeRect ? (nodesToIntersect || store.nodes).filter((n) => {
1571
+ return nodeRect ? (nodesToIntersect ?? queryIntersectionCandidates(nodeRect)).filter((n) => {
1317
1572
  let internalNode = nodeLookup.get(n.id);
1318
1573
  if (!internalNode || !isRect && n.id === nodeOrRect.id) return !1;
1319
1574
  let currNodeRect = nodeToRect(internalNode), overlappingArea = getOverlappingArea(currNodeRect, nodeRect);
@@ -1369,10 +1624,6 @@ const createLayoutedEdges = (source) => {
1369
1624
  extent: store.translateExtent
1370
1625
  }), ({ panZoom, extent }) => {
1371
1626
  panZoom?.setTranslateExtent(extent);
1372
- }), createEffect(() => new Set(store.nodes.map((n) => n.id)), (currentIds) => {
1373
- setMeasurementsStore((draft) => {
1374
- for (let id of Object.keys(draft)) currentIds.has(id) || delete draft[id];
1375
- });
1376
1627
  }), {
1377
1628
  store,
1378
1629
  flow,
@@ -1384,14 +1635,12 @@ const createLayoutedEdges = (source) => {
1384
1635
  parentIds,
1385
1636
  connections,
1386
1637
  actions: {
1387
- getEdge,
1638
+ getLayoutedEdge,
1388
1639
  applyInitialFitView,
1389
1640
  applyMeasurementWrites,
1390
1641
  applyNodeChanges,
1391
1642
  markInitialNodesMeasured,
1392
1643
  setMeasureRequester,
1393
- resetStoreValues,
1394
- setAriaLabelConfig,
1395
1644
  setAriaLiveMessage,
1396
1645
  setClickConnectStartHandle,
1397
1646
  setConfig,
@@ -1399,15 +1648,11 @@ const createLayoutedEdges = (source) => {
1399
1648
  setDeleteKeyPressed,
1400
1649
  setDomNode,
1401
1650
  setDragging,
1402
- get setEdges() {
1403
- return setEdgesStore;
1404
- },
1651
+ setEdges: setEdgesStore,
1405
1652
  setElementsSelectable,
1406
1653
  setHeight,
1407
1654
  setMultiselectionKeyPressed,
1408
- get setNodes() {
1409
- return setNodesStore;
1410
- },
1655
+ setNodes: setNodesStore,
1411
1656
  setNodesConnectable,
1412
1657
  setNodesDraggable,
1413
1658
  setPanActivationKeyPressed,
@@ -1415,9 +1660,7 @@ const createLayoutedEdges = (source) => {
1415
1660
  setSelectionKeyPressed,
1416
1661
  setSelectionRect,
1417
1662
  setSelectionRectMode,
1418
- get setViewport() {
1419
- return (viewport) => setViewportStore(() => viewport);
1420
- },
1663
+ setViewport: stableSetViewport,
1421
1664
  setWidth,
1422
1665
  setZoomActivationKeyPressed,
1423
1666
  addEdge,
@@ -1426,7 +1669,6 @@ const createLayoutedEdges = (source) => {
1426
1669
  zoomOut,
1427
1670
  fitView,
1428
1671
  setCenter,
1429
- setPaneClickDistance,
1430
1672
  unselectNodesAndEdges,
1431
1673
  addSelectedNodes,
1432
1674
  addSelectedEdges,
@@ -1438,8 +1680,11 @@ const createLayoutedEdges = (source) => {
1438
1680
  reset
1439
1681
  }
1440
1682
  };
1683
+ }, createEdgeStore = (edges) => {
1684
+ let [store, setStore] = typeof edges == "function" ? createStore(edges, []) : createStore(edges);
1685
+ return [store, setStore];
1441
1686
  }, createNodeStore = (nodes) => {
1442
- let [store, setStore] = createStore(nodes);
1687
+ let [store, setStore] = typeof nodes == "function" ? createStore(nodes, []) : createStore(nodes);
1443
1688
  return [store, setStore];
1444
1689
  };
1445
1690
  //#endregion
@@ -1447,21 +1692,28 @@ const createLayoutedEdges = (source) => {
1447
1692
  var _tmpl$$30 = /* @__PURE__ */ template("<svg class=solid-flow__edge-wrapper><g>");
1448
1693
  /** Internal per-edge wrapper: interaction, a11y, viewport culling, and the dynamic edge component. */
1449
1694
  const EdgeWrapper = (props) => {
1450
- let edgeRef, { store, actions } = useInternalSolidFlow(), edgeId = () => props.edgeId, edge = () => actions.getEdge(edgeId()), edgeType = () => edge().type ?? "default", selectable = () => edge().selectable ?? store.elementsSelectable, focusable = () => edge().focusable ?? store.edgesFocusable, edgeComponent = () => store.edgeTypes[edgeType()], markerStartUrl = () => edge().markerStart ? `url('#${getMarkerId(edge().markerStart, store.id)}')` : void 0, markerEndUrl = () => edge().markerEnd ? `url('#${getMarkerId(edge().markerEnd, store.id)}')` : void 0, onClick = (event) => {
1695
+ let edgeRef, { store, actions } = useInternalSolidFlow(), edgeId = () => props.edgeId, edge = () => actions.getLayoutedEdge(edgeId()), edgeType = () => edge().type ?? "default", selectable = () => isEdgeSelectable(edge(), store), focusable = () => edge().focusable ?? store.edgesFocusable, edgeTypeValid = () => edgeType() in store.edgeTypes, edgeComponent = () => store.edgeTypes[edgeTypeValid() ? edgeType() : "default"];
1696
+ createEffect(() => ({
1697
+ valid: edgeTypeValid(),
1698
+ edgeType: edgeType()
1699
+ }), ({ valid, edgeType }) => {
1700
+ valid || emitFlowError(store.onError, "011", errorMessages.error011(edgeType));
1701
+ });
1702
+ let markerStartUrl = () => edge().markerStart ? `url('#${getMarkerId(edge().markerStart, store.id)}')` : void 0, markerEndUrl = () => edge().markerEnd ? `url('#${getMarkerId(edge().markerEnd, store.id)}')` : void 0, onClick = (event) => {
1451
1703
  selectable() && actions.handleEdgeSelection(edgeId()), props.onEdgeClick?.({
1452
1704
  edge: edge(),
1453
1705
  event
1454
1706
  });
1455
- }, onPointerEvent = (event, type) => {
1456
- ({
1457
- contextmenu: props.onEdgeContextMenu,
1458
- pointerenter: props.onEdgePointerEnter,
1459
- pointerleave: props.onEdgePointerLeave
1460
- })[type]?.({
1461
- edge: edge(),
1462
- event
1463
- });
1464
- }, onKeyDown = (event) => {
1707
+ }, onContextMenu = (event) => props.onEdgeContextMenu?.({
1708
+ edge: edge(),
1709
+ event
1710
+ }), onPointerEnter = (event) => props.onEdgePointerEnter?.({
1711
+ edge: edge(),
1712
+ event
1713
+ }), onPointerLeave = (event) => props.onEdgePointerLeave?.({
1714
+ edge: edge(),
1715
+ event
1716
+ }), onKeyDown = (event) => {
1465
1717
  store.disableKeyboardA11y || !elementSelectionKeys.includes(event.key) || !selectable() || (event.key === "Escape" ? (edgeRef?.blur(), actions.unselectNodesAndEdges({ edges: [edge()] })) : actions.addSelectedEdges([edge().id]));
1466
1718
  }, ariaLabel = () => edge().ariaLabel ?? `Edge from ${edge().source} to ${edge().target}`, culled = createMemo(() => isEdgeCulled(edge(), store.cullingViewport));
1467
1719
  return createComponent(EdgeIdContext, {
@@ -1504,9 +1756,9 @@ const EdgeWrapper = (props) => {
1504
1756
  },
1505
1757
  onClick,
1506
1758
  onKeyDown: (e) => focusable() && onKeyDown(e),
1507
- onContextMenu: (e) => onPointerEvent(e, "contextmenu"),
1508
- onPointerEnter: (e) => onPointerEvent(e, "pointerenter"),
1509
- onPointerLeave: (e) => onPointerEvent(e, "pointerleave")
1759
+ onContextMenu,
1760
+ onPointerEnter,
1761
+ onPointerLeave
1510
1762
  }, () => edge().domAttributes), !0), insert(_el$2, createComponent(Dynamic, {
1511
1763
  get component() {
1512
1764
  return edgeComponent();
@@ -1887,7 +2139,7 @@ const Handle = (props) => {
1887
2139
  position: "top",
1888
2140
  isConnectableStart: !0,
1889
2141
  isConnectableEnd: !0
1890
- }), { store, nodeLookup, connections, actions } = useInternalSolidFlow(), rest = omit(_props, "id", "type", "position", "isConnectable", "isConnectableStart", "isConnectableEnd", "isValidConnection", "onConnect", "onDisconnect", "children", "class", "style"), nodeId = useNodeId(), nodeConnectable = useNodeConnectable(), connectable = () => _props.isConnectable ?? nodeConnectable(), isTarget = () => _props.type === "target", handleId = () => _props.id ?? null, connectionInProcess = () => !!store.connection.fromHandle, connectingFrom = () => store.connection.fromHandle && store.connection.fromHandle.nodeId === nodeId() && store.connection.fromHandle.type === _props.type && store.connection.fromHandle.id === handleId(), connectingTo = () => store.connection.toHandle && store.connection.toHandle.nodeId === nodeId() && store.connection.toHandle.type === _props.type && store.connection.toHandle.id === handleId(), isPossibleTargetHandle = () => store.connectionMode === "strict" ? store.connection.fromHandle?.type !== _props.type : nodeId() !== store.connection.fromHandle?.nodeId || handleId() !== store.connection.fromHandle?.id, valid = () => !!(connectingTo() && store.connection.isValid), prevConnections = null;
2142
+ }), { store, nodeLookup, connections, actions } = useInternalSolidFlow(), rest = omit(_props, "id", "type", "position", "isConnectable", "isConnectableStart", "isConnectableEnd", "isValidConnection", "onConnect", "onDisconnect", "children", "class", "style"), nodeId = useNodeId(), nodeConnectable = useNodeConnectable(), connectable = () => _props.isConnectable ?? nodeConnectable(), isTarget = () => _props.type === "target", handleId = () => _props.id ?? null, originState = () => store.connectionOriginByHandle[connectionKey(nodeId(), _props.type, handleId())], connectingFrom = () => originState() === "from", targetState = () => store.connectionTargetByHandle[connectionKey(nodeId(), _props.type, handleId())], connectingTo = () => targetState() !== void 0, valid = () => targetState() === "valid", prevConnections = null;
1891
2143
  createEffect(() => {
1892
2144
  if (!_props.onConnect && !_props.onDisconnect) return null;
1893
2145
  let rec = connections[connectionKey(nodeId(), _props.type, _props.id)], map = /* @__PURE__ */ new Map();
@@ -1905,37 +2157,25 @@ const Handle = (props) => {
1905
2157
  }, edge = store.onBeforeConnect?.(handleConnection) ?? handleConnection;
1906
2158
  actions.addEdge(edge), store.onConnect?.(handleConnection);
1907
2159
  }, onPointerDown = (event) => {
2160
+ let gestureLookup = armConnectionGestureLookup({
2161
+ event,
2162
+ real: nodeLookup,
2163
+ domNode: store.domNode,
2164
+ getTransform: () => store.transform,
2165
+ connectionRadius: store.connectionRadius
2166
+ });
1908
2167
  XYHandle.onPointerDown(event, {
2168
+ ...buildConnectionGestureParams({
2169
+ event,
2170
+ store,
2171
+ actions,
2172
+ gestureLookup
2173
+ }),
1909
2174
  handleId: handleId(),
1910
2175
  nodeId: nodeId(),
1911
2176
  isTarget: isTarget(),
1912
- connectionRadius: store.connectionRadius,
1913
- domNode: store.domNode,
1914
- nodeLookup,
1915
- connectionMode: store.connectionMode,
1916
- lib: store.lib,
1917
- autoPanOnConnect: store.autoPanOnConnect,
1918
- flowId: store.id,
1919
2177
  isValidConnection: _props.isValidConnection ?? store.isValidConnection,
1920
- updateConnection: ((connection) => {
1921
- actions.setConnection(connection), flush();
1922
- }),
1923
- cancelConnection: actions.cancelConnection,
1924
- panBy: actions.panBy,
1925
- onConnect: onConnectExtended,
1926
- onConnectStart: (event, startParams) => {
1927
- store.onConnectStart?.(event, {
1928
- nodeId: startParams.nodeId,
1929
- handleId: startParams.handleId,
1930
- handleType: startParams.handleType
1931
- });
1932
- },
1933
- onConnectEnd: store.onConnectEnd,
1934
- getTransform: () => store.transform,
1935
- getFromHandle: () => store.connection.fromHandle,
1936
- autoPanSpeed: store.autoPanSpeed,
1937
- dragThreshold: store.connectionDragThreshold,
1938
- handleDomNode: event.currentTarget
2178
+ onConnect: onConnectExtended
1939
2179
  });
1940
2180
  }, onClick = (event) => {
1941
2181
  if (!nodeId() || !store.clickConnectStartHandle && !_props.isConnectableStart) return;
@@ -1970,7 +2210,7 @@ const Handle = (props) => {
1970
2210
  isValid && connection && onConnectExtended(connection);
1971
2211
  let connectionClone = structuredClone(snapshot(store.connection));
1972
2212
  delete connectionClone.inProgress, connectionClone.toPosition = connectionClone.toHandle ? connectionClone.toHandle.position : null, store.onClickConnectEnd?.(event, connectionClone), actions.setClickConnectStartHandle(void 0);
1973
- }, connectionIndicator = () => connectable() && (!connectionInProcess() || isPossibleTargetHandle()) && (connectionInProcess() || store.clickConnectStartHandle ? _props.isConnectableEnd : _props.isConnectableStart);
2213
+ };
1974
2214
  var _el$ = _tmpl$$29();
1975
2215
  return spread(_el$, mergeProps(rest, {
1976
2216
  role: "button",
@@ -2013,7 +2253,7 @@ const Handle = (props) => {
2013
2253
  connectablestart: _props.isConnectableStart,
2014
2254
  connectableend: _props.isConnectableEnd,
2015
2255
  connectable: !!connectable(),
2016
- connectionindicator: connectionIndicator()
2256
+ excluded: !!originState()
2017
2257
  }
2018
2258
  ];
2019
2259
  }
@@ -2141,7 +2381,7 @@ const NodeWrapper = (props) => {
2141
2381
  let el = nodeRef();
2142
2382
  el && props.resizeObserver?.unobserve(el);
2143
2383
  });
2144
- let nodeId = () => node().id, nodeType = () => node().type ?? "default", deletable = () => node().deletable ?? !0, selectable = () => node().selectable ?? store.elementsSelectable, focusable = () => node().focusable ?? store.nodesFocusable, draggable = () => node().draggable ?? store.nodesDraggable, connectable = () => node().connectable ?? store.nodesConnectable, userNode = () => node().internals.userNode, nodeTypeValid = () => nodeType() in store.nodeTypes, nodeComponent = () => store.nodeTypes[nodeType()], isParentNode = () => !!parentIds[node().id], transform = () => {
2384
+ let nodeId = () => node().id, nodeType = () => node().type ?? "default", deletable = () => node().deletable ?? !0, selectable = () => node().selectable ?? store.elementsSelectable, focusable = () => node().focusable ?? store.nodesFocusable, draggable = () => node().draggable ?? store.nodesDraggable, connectable = () => node().connectable ?? store.nodesConnectable, userNode = () => node().internals.userNode, nodeTypeValid = () => nodeType() in store.nodeTypes, nodeComponent = () => store.nodeTypes[nodeTypeValid() ? nodeType() : "default"], isParentNode = () => !!parentIds[node().id], transform = () => {
2145
2385
  let { x, y } = node().internals.positionAbsolute;
2146
2386
  return `translate(${x}px, ${y}px)`;
2147
2387
  }, sizeStyle = () => {
@@ -2152,17 +2392,18 @@ const NodeWrapper = (props) => {
2152
2392
  ...h ? { height: toPxString(h) } : {}
2153
2393
  };
2154
2394
  }, culled = createMemo(() => isNodeCulled(node(), store.cullingViewport)), style = () => ({
2395
+ ...sizeStyle(),
2155
2396
  "z-index": node().internals.z,
2156
2397
  transform: transform(),
2157
2398
  visibility: culled() || !nodeHasDimensions(node()) ? "hidden" : "visible",
2158
- "pointer-events": culled() ? "none" : void 0,
2159
- ...sizeStyle(),
2160
- ...node().style ?? {}
2399
+ "pointer-events": culled() ? "none" : void 0
2161
2400
  });
2162
2401
  createEffect(() => ({
2163
2402
  valid: nodeTypeValid(),
2164
2403
  nodeType: nodeType()
2165
- }), ({ valid, nodeType }) => {}), createEffect(() => ({
2404
+ }), ({ valid, nodeType }) => {
2405
+ valid || emitFlowError(store.onError, "003", errorMessages.error003(nodeType));
2406
+ }), createEffect(() => ({
2166
2407
  id: node().id,
2167
2408
  nodeElement: nodeRef(),
2168
2409
  nodeType: nodeType(),
@@ -2517,7 +2758,7 @@ const InitialNodeTypesMap = {
2517
2758
  pendingEntries = updateEntries, scheduleIdleCallback(() => {
2518
2759
  let updates = new Map(pendingEntries);
2519
2760
  pendingEntries = void 0;
2520
- let { updatedInternals, measurementWrites, changes, parentExpandChildren } = measureNodeInternals(updates, nodeLookup, store.domNode);
2761
+ let { updatedInternals, measurementWrites, changes, parentExpandChildren } = measureNodeInternals(updates, nodeLookup, store.domNode, store.nodeExtent);
2521
2762
  updatedInternals && (actions.applyMeasurementWrites(measurementWrites), flush(), parentExpandChildren.length > 0 && changes.push(...handleExpandParent(parentExpandChildren, nodeLookup, (parentId) => store.nodes.filter((node) => node.parentId === parentId), store.nodeOrigin)), actions.applyNodeChanges(changes), flush(), actions.markInitialNodesMeasured());
2522
2763
  });
2523
2764
  };
@@ -2539,21 +2780,29 @@ function useInternalSolidFlow() {
2539
2780
  var _tmpl$$26 = /* @__PURE__ */ template("<svg class=\"solid-flow__container solid-flow__connectionline\"><g>"), _tmpl$2$2 = /* @__PURE__ */ template("<svg><path class=solid-flow__connection-path fill=none></svg>", 2);
2540
2781
  /** Internal component rendering the in-progress connection line. */
2541
2782
  const ConnectionLine = (props) => {
2542
- let { store } = useInternalSolidFlow(), connectionStatus = () => getConnectionStatus(store.connection.isValid);
2783
+ let { store } = useInternalSolidFlow(), connectionStatus = () => getConnectionStatus(store.connection.isValid), inProgress = createMemo(() => {
2784
+ let state = store.connection;
2785
+ return state.inProgress ? state : null;
2786
+ });
2543
2787
  return createComponent(Show, {
2544
2788
  get when() {
2545
- return store.connection.inProgress;
2789
+ return inProgress();
2546
2790
  },
2547
- get children() {
2791
+ children: (connection) => (() => {
2548
2792
  var _el$ = _tmpl$$26(), _el$2 = _el$.firstChild;
2549
2793
  return insert(_el$2, createComponent(Show, {
2550
2794
  get when() {
2551
2795
  return props.component;
2552
2796
  },
2553
2797
  get fallback() {
2554
- return createComponent(InternalConnectionLine, { get style() {
2555
- return props.style;
2556
- } });
2798
+ return createComponent(InternalConnectionLine, {
2799
+ get style() {
2800
+ return props.style;
2801
+ },
2802
+ get connection() {
2803
+ return connection();
2804
+ }
2805
+ });
2557
2806
  },
2558
2807
  children: (CustomComponent) => {
2559
2808
  let UserConnectionLine = CustomComponent();
@@ -2565,37 +2814,37 @@ const ConnectionLine = (props) => {
2565
2814
  return props.style;
2566
2815
  },
2567
2816
  get fromNode() {
2568
- return store.connection.fromNode;
2817
+ return connection().fromNode;
2569
2818
  },
2570
2819
  get fromHandle() {
2571
- return store.connection.fromHandle;
2820
+ return connection().fromHandle;
2572
2821
  },
2573
2822
  get fromX() {
2574
- return store.connection.from.x;
2823
+ return connection().from.x;
2575
2824
  },
2576
2825
  get fromY() {
2577
- return store.connection.from.y;
2826
+ return connection().from.y;
2578
2827
  },
2579
2828
  get toX() {
2580
- return store.connection.to.x;
2829
+ return connection().to.x;
2581
2830
  },
2582
2831
  get toY() {
2583
- return store.connection.to.y;
2832
+ return connection().to.y;
2584
2833
  },
2585
2834
  get fromPosition() {
2586
- return store.connection.fromPosition;
2835
+ return connection().fromPosition;
2587
2836
  },
2588
2837
  get toPosition() {
2589
- return store.connection.toPosition;
2838
+ return connection().toPosition;
2590
2839
  },
2591
2840
  get connectionStatus() {
2592
2841
  return connectionStatus();
2593
2842
  },
2594
2843
  get toNode() {
2595
- return store.connection.toNode;
2844
+ return connection().toNode;
2596
2845
  },
2597
2846
  get toHandle() {
2598
- return store.connection.toHandle;
2847
+ return connection().toHandle;
2599
2848
  }
2600
2849
  });
2601
2850
  }
@@ -2607,18 +2856,17 @@ const ConnectionLine = (props) => {
2607
2856
  }), ({ e, t, a, o }, _p$) => {
2608
2857
  e !== _p$?.e && setAttribute(_el$, "width", e), t !== _p$?.t && setAttribute(_el$, "height", t), style(_el$, a, _p$?.a), className(_el$2, o, _p$?.o);
2609
2858
  }), _el$;
2610
- }
2859
+ })()
2611
2860
  });
2612
2861
  }, InternalConnectionLine = (props) => {
2613
2862
  let { store } = useInternalSolidFlow(), path = () => {
2614
- if (!store.connection.inProgress) return;
2615
2863
  let pathParams = {
2616
- sourceX: store.connection.from.x,
2617
- sourceY: store.connection.from.y,
2618
- sourcePosition: store.connection.fromPosition,
2619
- targetX: store.connection.to.x,
2620
- targetY: store.connection.to.y,
2621
- targetPosition: store.connection.toPosition
2864
+ sourceX: props.connection.from.x,
2865
+ sourceY: props.connection.from.y,
2866
+ sourcePosition: props.connection.fromPosition,
2867
+ targetX: props.connection.to.x,
2868
+ targetY: props.connection.to.y,
2869
+ targetPosition: props.connection.toPosition
2622
2870
  };
2623
2871
  switch (store.connectionLineType) {
2624
2872
  case "default": {
@@ -2718,25 +2966,32 @@ const MarkerDefinition = () => {
2718
2966
  })), _el$;
2719
2967
  }
2720
2968
  });
2969
+ }, createFocusedIdTracker = () => {
2970
+ let [focusedId, setFocusedId] = createSignal(null);
2971
+ return {
2972
+ focusedId,
2973
+ onFocusIn: (event) => {
2974
+ let element = event.target.closest("[data-id]");
2975
+ setFocusedId(element?.getAttribute("data-id") ?? null);
2976
+ },
2977
+ onFocusOut: () => setFocusedId(null)
2978
+ };
2721
2979
  };
2722
2980
  //#endregion
2723
2981
  //#region src/components/container/EdgeRenderer.tsx
2724
2982
  var _tmpl$$23 = /* @__PURE__ */ template("<div class=solid-flow__edges><!><!>");
2725
2983
  /** Internal renderer iterating the edge id list into `EdgeWrapper`s. */
2726
2984
  const EdgeRenderer = (props) => {
2727
- let { store, actions } = useInternalSolidFlow(), [focusedEdgeId, setFocusedEdgeId] = createSignal(null), onFocusIn = (event) => {
2728
- let edgeElement = event.target.closest("[data-id]");
2729
- setFocusedEdgeId(edgeElement?.getAttribute("data-id") ?? null);
2730
- };
2985
+ let { store, actions } = useInternalSolidFlow(), { focusedId: focusedEdgeId, onFocusIn, onFocusOut } = createFocusedIdTracker();
2731
2986
  var _el$ = _tmpl$$23(), _el$2 = _el$.firstChild, _el$3 = _el$2.nextSibling;
2732
- return _el$.$$focusout = () => setFocusedEdgeId(null), _el$.$$focusin = onFocusIn, insert(_el$, createComponent(MarkerDefinition, {}), _el$2), insert(_el$, createComponent(For, {
2987
+ return addEvent(_el$, "focusout", onFocusOut, !0), addEvent(_el$, "focusin", onFocusIn, !0), insert(_el$, createComponent(MarkerDefinition, {}), _el$2), insert(_el$, createComponent(For, {
2733
2988
  get each() {
2734
2989
  return store.visibleEdgeIds;
2735
2990
  },
2736
2991
  children: (edgeId) => {
2737
2992
  let unmounted = createMemo(() => {
2738
2993
  if (!store.onlyRenderVisibleElements || focusedEdgeId() === edgeId) return !1;
2739
- let edge = actions.getEdge(edgeId);
2994
+ let edge = actions.getLayoutedEdge(edgeId);
2740
2995
  return !!edge && isEdgeCulled(edge, store.cullingViewport);
2741
2996
  });
2742
2997
  return createComponent(Show, {
@@ -2783,12 +3038,9 @@ const NodeRenderer = (props) => {
2783
3038
  onCleanup(() => {
2784
3039
  resizeObserver?.disconnect();
2785
3040
  });
2786
- let [focusedNodeId, setFocusedNodeId] = createSignal(null), onFocusIn = (event) => {
2787
- let nodeElement = event.target.closest("[data-id]");
2788
- setFocusedNodeId(nodeElement?.getAttribute("data-id") ?? null);
2789
- };
3041
+ let { focusedId: focusedNodeId, onFocusIn, onFocusOut } = createFocusedIdTracker();
2790
3042
  var _el$ = _tmpl$$22();
2791
- return _el$.$$focusout = () => setFocusedNodeId(null), _el$.$$focusin = onFocusIn, insert(_el$, createComponent(For, {
3043
+ return addEvent(_el$, "focusout", onFocusOut, !0), addEvent(_el$, "focusin", onFocusIn, !0), insert(_el$, createComponent(For, {
2792
3044
  get each() {
2793
3045
  return store.visibleNodeIds;
2794
3046
  },
@@ -2848,10 +3100,10 @@ const isSetEqual = (a, b) => {
2848
3100
  for (let item of a) if (!b.has(item)) return !1;
2849
3101
  return !0;
2850
3102
  }, Pane = (props) => {
2851
- let { store, nodeLookup, edgeLookup, connections, actions } = useInternalSolidFlow(), [containerRef, setContainerRef] = createSignal(), container, containerBounds = null, connectionEndedOnPane = !1, selectionInProgress = !1, selectedNodeIds = /* @__PURE__ */ new Set(), selectedEdgeIds = /* @__PURE__ */ new Set(), autoPanId = 0, position = {
3103
+ let { store, nodeLookup, edgeLookup, connections, actions } = useInternalSolidFlow(), [containerRef, setContainerRef] = createSignal(), container, containerBounds = null, connectionEndedOnPane = !1, selectionInProgress = !1, selectionSpatialLookup = new GestureSpatialLookup(nodeLookup, 400), selectedNodeIds = /* @__PURE__ */ new Set(), selectedEdgeIds = /* @__PURE__ */ new Set(), autoPanId = 0, position = {
2852
3104
  x: 0,
2853
3105
  y: 0
2854
- }, autoPanStarted = !1, autoPanOnSelection = () => props.autoPanOnSelection ?? !0, paneClickDistance = () => props.paneClickDistance ?? 1, _panOnDrag = () => store.panActivationKeyPressed || props.panOnDrag, isSelecting = () => store.selectionKeyPressed || !!store.selectionRect || props.selectionOnDrag && _panOnDrag() !== !0, isSelectionEnabled = () => store.elementsSelectable && (isSelecting() || store.selectionRectMode === "user"), onClick = (event) => {
3106
+ }, autoPanStarted = !1, autoPanOnSelection = () => props.autoPanOnSelection ?? !0, paneClickDistance = () => props.paneClickDistance ?? 0, _panOnDrag = () => store.panActivationKeyPressed || props.panOnDrag, isSelecting = () => store.selectionKeyPressed || !!store.selectionRect || props.selectionOnDrag && _panOnDrag() !== !0, isSelectionEnabled = () => store.elementsSelectable && (isSelecting() || store.selectionRectMode === "user"), onClick = (event) => {
2855
3107
  if (event.target === container) {
2856
3108
  if (selectionInProgress || store.connection.inProgress || connectionEndedOnPane) {
2857
3109
  selectionInProgress = !1, connectionEndedOnPane = !1;
@@ -2863,7 +3115,7 @@ const isSetEqual = (a, b) => {
2863
3115
  if (event.pointerType === "touch" && _panOnDrag() !== !1 && !store.selectionKeyPressed || (containerBounds = container?.getBoundingClientRect() ?? null, !containerBounds)) return;
2864
3116
  let eventTargetIsContainer = event.target === container, isNoKeyEvent = !eventTargetIsContainer && !!event.target.closest(".nokey"), isSelectionActive = props.selectionOnDrag && eventTargetIsContainer || store.selectionKeyPressed;
2865
3117
  if (isNoKeyEvent || !isSelecting() || !isSelectionActive || event.button !== 0 || !event.isPrimary) return;
2866
- event.target?.setPointerCapture?.(event.pointerId), selectionInProgress = !1, autoPanStarted = !1;
3118
+ event.target?.setPointerCapture?.(event.pointerId), selectionSpatialLookup.arm((node) => nodeToRect(node)), selectionInProgress = !1, autoPanStarted = !1;
2867
3119
  let { x, y } = getEventPosition(event, containerBounds), userSelectionFlowOrigin = pointToRendererPoint({
2868
3120
  x,
2869
3121
  y
@@ -2890,14 +3142,21 @@ const isSetEqual = (a, b) => {
2890
3142
  width: Math.abs(mouseX - screenStart.x),
2891
3143
  height: Math.abs(mouseY - screenStart.y)
2892
3144
  }, prevSelectedNodeIds = selectedNodeIds, prevSelectedEdgeIds = selectedEdgeIds;
2893
- selectedNodeIds = new Set(getNodesInside(nodeLookup, nextUserSelectRect, store.transform, store.selectionMode === SelectionMode$1.Partial, !0).map((n) => n.id));
2894
- let edgesSelectable = store.defaultEdgeOptions.selectable ?? !0;
2895
- selectedEdgeIds = /* @__PURE__ */ new Set();
3145
+ {
3146
+ let [tx, ty, zoom] = store.transform;
3147
+ selectionSpatialLookup.setQueryRect({
3148
+ x: (nextUserSelectRect.x - tx) / zoom,
3149
+ y: (nextUserSelectRect.y - ty) / zoom,
3150
+ width: nextUserSelectRect.width / zoom,
3151
+ height: nextUserSelectRect.height / zoom
3152
+ });
3153
+ }
3154
+ selectedNodeIds = new Set(getNodesInside(selectionSpatialLookup, nextUserSelectRect, store.transform, store.selectionMode === SelectionMode$1.Partial, !0).map((n) => n.id)), selectedEdgeIds = /* @__PURE__ */ new Set();
2896
3155
  for (let nodeId of selectedNodeIds) {
2897
3156
  let nodeConnections = connections[nodeId];
2898
3157
  if (nodeConnections) for (let { edgeId } of Object.values(nodeConnections)) {
2899
3158
  let edge = edgeLookup[edgeId];
2900
- edge && (edge.selectable ?? edgesSelectable) && selectedEdgeIds.add(edgeId);
3159
+ edge && isEdgeSelectable(edge, store) && selectedEdgeIds.add(edgeId);
2901
3160
  }
2902
3161
  }
2903
3162
  isSetEqual(prevSelectedNodeIds, selectedNodeIds) || actions.setNodes((nodes) => {
@@ -3132,7 +3391,7 @@ const Selection = (props) => {
3132
3391
  var _tmpl$$16 = /* @__PURE__ */ template("<div>");
3133
3392
  /** Internal draggable bounding box rendered around multi-selected nodes. */
3134
3393
  const NodeSelection = (props) => {
3135
- let { store, nodeLookup, actions } = useInternalSolidFlow(), [ref$2, setRef] = createSignal(), bounds = () => store.selectionRectMode === "nodes" ? getInternalNodesBounds(nodeLookup, { filter: (node) => !!node.selected }) : null;
3394
+ let { store, nodeLookup, actions } = useInternalSolidFlow(), [ref$2, setRef] = createSignal(), bounds = createMemo(() => store.selectionRectMode === "nodes" ? getInternalNodesBounds(nodeLookup, { filter: (node) => !!node.selected }) : null);
3136
3395
  createEffect(() => ({
3137
3396
  el: ref$2(),
3138
3397
  focusable: !store.disableKeyboardA11y
@@ -3140,13 +3399,13 @@ const NodeSelection = (props) => {
3140
3399
  focusable && el?.focus({ preventScroll: !0 });
3141
3400
  });
3142
3401
  let onContextMenu = (event) => {
3143
- let selectedNodes = store.nodes.filter((n) => n.selected);
3402
+ let selectedNodes = store.selectedNodes;
3144
3403
  props.onSelectionContextMenu?.({
3145
3404
  nodes: selectedNodes,
3146
3405
  event
3147
3406
  });
3148
3407
  }, onClick = (event) => {
3149
- let selectedNodes = store.nodes.filter((n) => n.selected);
3408
+ let selectedNodes = store.selectedNodes;
3150
3409
  props.onSelectionClick?.({
3151
3410
  nodes: selectedNodes,
3152
3411
  event
@@ -3229,29 +3488,13 @@ const Attribution = (props) => createComponent(Show, {
3229
3488
  }
3230
3489
  });
3231
3490
  }
3232
- });
3233
- //#endregion
3234
- //#region src/hooks/useSolidFlow.ts
3235
- /**
3236
- * Hook for accessing the flow instance: `{ flow, commands }` plus the
3237
- * commands spread at the top level for upstream familiarity.
3238
- *
3239
- * `flow` and `commands` are stable identities, so destructuring them is safe:
3240
- * `const { flow, commands } = useSolidFlow()`.
3241
- *
3242
- * @public
3243
- * @returns the flow's read struct and write surface
3244
- */
3245
- function useSolidFlow() {
3246
- let { flow, commands } = useInternalSolidFlow();
3247
- return {
3248
- ...commands,
3249
- flow,
3250
- commands
3251
- };
3252
- }
3253
- //#endregion
3254
- //#region src/components/utility/KeyHandler.ts
3491
+ }), MODIFIER_FLAG = {
3492
+ alt: "altKey",
3493
+ control: "ctrlKey",
3494
+ ctrl: "ctrlKey",
3495
+ meta: "metaKey",
3496
+ shift: "shiftKey"
3497
+ };
3255
3498
  function isKeyObject(key) {
3256
3499
  return typeof key == "object" && !!key;
3257
3500
  }
@@ -3283,18 +3526,13 @@ function matchesKey(event, keyDef) {
3283
3526
  function matchesKeyArray(event, keyDefs) {
3284
3527
  return keyDefs ? (Array.isArray(keyDefs) ? keyDefs : [keyDefs]).some((keyDef) => matchesKey(event, keyDef)) : !1;
3285
3528
  }
3286
- const MODIFIER_FLAG = {
3287
- alt: "altKey",
3288
- control: "ctrlKey",
3289
- ctrl: "ctrlKey",
3290
- meta: "metaKey",
3291
- shift: "shiftKey"
3292
- };
3293
3529
  /**
3294
3530
  * Whether an event's modifier flags PROVE this key definition cannot be held
3295
3531
  * right now: the key itself is a modifier whose flag is off, or one of its
3296
3532
  * required modifiers is off. Definitions built on non-modifier keys are never
3297
- * contradicted (their state isn't derivable from flags).
3533
+ * contradicted (their state isn't derivable from flags). This is the
3534
+ * self-heal for OS overlays that swallow keyups without blurring the window
3535
+ * (upstream xyflow#5679).
3298
3536
  */
3299
3537
  function isContradicted(flags, keyDef) {
3300
3538
  let keyFlag = MODIFIER_FLAG[getKeyString(keyDef).toLowerCase()];
@@ -3311,6 +3549,28 @@ function allContradicted(flags, keyDefs) {
3311
3549
  let keys = Array.isArray(keyDefs) ? keyDefs : [keyDefs];
3312
3550
  return keys.length > 0 && keys.every((keyDef) => isContradicted(flags, keyDef));
3313
3551
  }
3552
+ //#endregion
3553
+ //#region src/hooks/useSolidFlow.ts
3554
+ /**
3555
+ * Hook for accessing the flow instance: `{ flow, commands }` plus the
3556
+ * commands spread at the top level for upstream familiarity.
3557
+ *
3558
+ * `flow` and `commands` are stable identities, so destructuring them is safe:
3559
+ * `const { flow, commands } = useSolidFlow()`.
3560
+ *
3561
+ * @public
3562
+ * @returns the flow's read struct and write surface
3563
+ */
3564
+ function useSolidFlow() {
3565
+ let { flow, commands } = useInternalSolidFlow();
3566
+ return {
3567
+ ...commands,
3568
+ flow,
3569
+ commands
3570
+ };
3571
+ }
3572
+ //#endregion
3573
+ //#region src/components/utility/KeyHandler.ts
3314
3574
  const KeyHandler = (props) => {
3315
3575
  let { store, actions } = useInternalSolidFlow(), { deleteElements } = useSolidFlow(), _props = {
3316
3576
  get selectionKey() {
@@ -3345,14 +3605,11 @@ const KeyHandler = (props) => {
3345
3605
  }, handleWindowBlur = () => {
3346
3606
  resetKeysAndSelection(), cancelPointerGestures();
3347
3607
  }, handleDelete = async () => {
3348
- let selectedNodes = store.nodes.filter((node) => node.selected), selectedEdges = store.edges.filter((edge) => edge.selected), { deletedNodes, deletedEdges } = await deleteElements({
3608
+ let selectedNodes = store.selectedNodes, selectedEdges = store.selectedEdges;
3609
+ await deleteElements({
3349
3610
  nodes: selectedNodes,
3350
3611
  edges: selectedEdges
3351
3612
  });
3352
- (deletedNodes.length > 0 || deletedEdges.length > 0) && store.onDelete?.({
3353
- nodes: deletedNodes,
3354
- edges: deletedEdges
3355
- });
3356
3613
  };
3357
3614
  return isServer || (createEventListenerMap(window, {
3358
3615
  keydown: (event) => {
@@ -3370,7 +3627,7 @@ const KeyHandler = (props) => {
3370
3627
  capture: !0,
3371
3628
  passive: !0
3372
3629
  })), null;
3373
- };
3630
+ }, FLOW_PROP_KEYS = /* @__PURE__ */ "ariaLabelConfig.ariaLiveMessage.attributionPosition.autoPanOnConnect.autoPanOnNodeDrag.autoPanOnNodeFocus.autoPanOnSelection.autoPanSpeed.class.clickConnect.colorMode.colorModeSSR.connectionDragThreshold.connectionLineComponent.connectionLineContainerStyle.connectionLineStyle.connectionLineType.connectionMode.connectionRadius.defaultEdgeOptions.defaultEdges.defaultMarkerColor.defaultNodes.deleteKey.disableKeyboardA11y.edgeTypes.edges.edgesFocusable.elementsSelectable.elevateEdgesOnSelect.elevateNodesOnSelect.fitView.fitViewOptions.height.id.initialViewport.isValidConnection.maxZoom.minZoom.multiSelectionKey.noDragClass.noPanClass.noWheelClass.nodeClickDistance.nodeDragThreshold.nodeExtent.nodeOrigin.nodeTypes.nodes.nodesConnectable.nodesDraggable.nodesFocusable.onBeforeConnect.onBeforeDelete.onBeforeReconnect.onClickConnectEnd.onClickConnectStart.onConnect.onConnectEnd.onConnectStart.onDelete.onEdgeClick.onEdgeContextMenu.onEdgePointerEnter.onEdgePointerLeave.onEdgesDelete.onFlowError.onInit.onMove.onMoveEnd.onMoveStart.onNodeClick.onNodeContextMenu.onNodeDrag.onNodeDragStart.onNodeDragStop.onNodePointerEnter.onNodePointerLeave.onNodePointerMove.onNodesDelete.onPaneClick.onPaneContextMenu.onReconnect.onReconnectEnd.onReconnectStart.onSelectionChange.onSelectionClick.onSelectionContextMenu.onSelectionDrag.onSelectionDragStart.onSelectionDragStop.onSelectionEnd.onSelectionStart.onlyRenderVisibleElements.panActivationKey.panOnDrag.panOnScroll.panOnScrollMode.panOnScrollSpeed.paneClickDistance.preventScrolling.proOptions.selectNodesOnDrag.selectionKey.selectionMode.selectionOnDrag.snapGrid.style.translateExtent.viewport.width.zIndexMode.zoomActivationKey.zoomOnDoubleClick.zoomOnPinch.zoomOnScroll".split(".");
3374
3631
  //#endregion
3375
3632
  //#region src/components/SolidFlow.tsx
3376
3633
  var _tmpl$$14 = /* @__PURE__ */ template("<div class=\"solid-flow__container solid-flow__viewport-back\">"), _tmpl$2 = /* @__PURE__ */ template("<div class=\"solid-flow__container solid-flow__edge-labels\">"), _tmpl$3 = /* @__PURE__ */ template("<div>");
@@ -3379,30 +3636,19 @@ const SolidFlow = (props) => {
3379
3636
  let [domNodeRef, setDomNodeRef] = createSignal(), domNode, _props = merge({
3380
3637
  ...getDefaultFlowStateProps(),
3381
3638
  colorMode: "light",
3382
- deleteKeyCode: "Backspace",
3383
- defaultViewport: {
3384
- x: 0,
3385
- y: 0,
3386
- zoom: 1
3387
- },
3388
- multiSelectionKeyCode: isMacOs() ? "Meta" : "Control",
3389
3639
  nodeClickDistance: 0,
3390
3640
  panOnScroll: !1,
3391
- panActivationKeyCode: "Space",
3392
3641
  preventScrolling: !0,
3393
3642
  panOnDrag: !0,
3394
3643
  panOnScrollSpeed: .5,
3395
3644
  panOnScrollMode: "free",
3396
3645
  paneClickDistance: 0,
3397
- reconnectRadius: 10,
3398
- selectionKeyCode: "Shift",
3399
3646
  selectionOnDrag: !1,
3400
3647
  translateExtent: infiniteExtent,
3401
- zoomActivationKeyCode: isMacOs() ? "Meta" : "Control",
3402
3648
  zoomOnPinch: !0,
3403
3649
  zoomOnDoubleClick: !0,
3404
3650
  zoomOnScroll: !0
3405
- }, props), htmlProps = omit(_props, "nodes", "edges", "defaultNodes", "defaultEdges", "nodeTypes", "edgeTypes", "width", "height", "fitView", "fitViewOptions", "nodeOrigin", "nodeDragThreshold", "paneClickDistance", "nodeClickDistance", "minZoom", "maxZoom", "zIndexMode", "initialViewport", "viewport", "translateExtent", "nodeExtent", "selectionKey", "panActivationKey", "deleteKey", "multiSelectionKey", "zoomActivationKey", "panOnDrag", "panOnScroll", "panOnScrollMode", "panOnScrollSpeed", "selectionOnDrag", "selectNodesOnDrag", "preventScrolling", "zoomOnScroll", "zoomOnDoubleClick", "zoomOnPinch", "onlyRenderVisibleElements", "autoPanOnConnect", "autoPanOnNodeDrag", "autoPanOnNodeFocus", "autoPanOnSelection", "autoPanSpeed", "connectionRadius", "connectionMode", "connectionLineType", "connectionLineComponent", "connectionLineStyle", "connectionLineContainerStyle", "connectionDragThreshold", "isValidConnection", "clickConnect", "reconnectRadius", "selectionMode", "elementsSelectable", "nodesDraggable", "nodesConnectable", "nodesFocusable", "edgesFocusable", "disableKeyboardA11y", "ariaLabelConfig", "ariaLiveMessage", "colorMode", "colorModeSSR", "class", "style", "snapGrid", "defaultMarkerColor", "defaultEdgeOptions", "elevateNodesOnSelect", "elevateEdgesOnSelect", "noDragClass", "noPanClass", "noWheelClass", "attributionPosition", "proOptions", "onInit", "onMoveStart", "onMove", "onMoveEnd", "onFlowError", "onNodeClick", "onNodeContextMenu", "onNodeDrag", "onNodeDragStart", "onNodeDragStop", "onNodePointerEnter", "onNodePointerMove", "onNodePointerLeave", "onEdgeClick", "onEdgeContextMenu", "onEdgePointerEnter", "onEdgePointerLeave", "onPaneClick", "onPaneContextMenu", "onSelectionChange", "onSelectionClick", "onSelectionContextMenu", "onSelectionDrag", "onSelectionDragStart", "onSelectionDragStop", "onSelectionStart", "onSelectionEnd", "onConnect", "onConnectStart", "onConnectEnd", "onReconnect", "onReconnectStart", "onReconnectEnd", "onClickConnectStart", "onClickConnectEnd", "onBeforeConnect", "onBeforeReconnect", "onDelete", "onBeforeDelete", "deleteKeyCode", "selectionKeyCode", "panActivationKeyCode", "multiSelectionKeyCode", "zoomActivationKeyCode", "children"), TypedSolidFlowContext = SolidFlowContext, solidFlow = useContext(TypedSolidFlowContext) ?? createSolidFlow(_props), { store, actions } = solidFlow;
3651
+ }, props), htmlProps = omit(_props, ...FLOW_PROP_KEYS, "children"), TypedSolidFlowContext = SolidFlowContext, solidFlow = useContext(TypedSolidFlowContext) ?? createSolidFlow(_props), { store, actions } = solidFlow;
3406
3652
  onSettled(() => (actions.applyInitialFitView(_props.fitView), actions.setConfig(_props), actions.setDomNode(domNode), () => {
3407
3653
  actions.reset();
3408
3654
  })), createEffect(() => domNodeRef(), (el) => {
@@ -3411,11 +3657,6 @@ const SolidFlow = (props) => {
3411
3657
  actions.setWidth(el.clientWidth), actions.setHeight(el.clientHeight);
3412
3658
  });
3413
3659
  return observer.observe(el), () => observer.disconnect();
3414
- }), createEffect(() => ({
3415
- panZoom: store.panZoom,
3416
- distance: _props.paneClickDistance
3417
- }), ({ panZoom, distance }) => {
3418
- panZoom?.setClickDistance(distance);
3419
3660
  });
3420
3661
  let selectedElements = createMemo(() => ({
3421
3662
  nodes: store.selectedNodes,
@@ -3424,7 +3665,7 @@ const SolidFlow = (props) => {
3424
3665
  createEffect(() => selectedElements(), (params) => {
3425
3666
  untrack(() => _props.onSelectionChange)?.(params);
3426
3667
  });
3427
- let rootStyle = () => ({
3668
+ let asyncSeedGuard = () => (_props.nodes?.length, _props.edges?.length, null), rootStyle = () => ({
3428
3669
  width: toPxString(_props.width),
3429
3670
  height: toPxString(_props.height),
3430
3671
  ..._props.style
@@ -3440,7 +3681,13 @@ const SolidFlow = (props) => {
3440
3681
  "solid-flow",
3441
3682
  "solid-flow__container",
3442
3683
  _props.class,
3443
- store.colorMode
3684
+ store.colorMode,
3685
+ {
3686
+ connecting: !!store.connectionFromHandle || !!store.clickConnectStartHandle,
3687
+ "connecting-from-source": (store.connectionFromHandle ?? store.clickConnectStartHandle)?.type === "source",
3688
+ "connecting-from-target": (store.connectionFromHandle ?? store.clickConnectStartHandle)?.type === "target",
3689
+ "connection-strict": store.connectionMode === "strict"
3690
+ }
3444
3691
  ];
3445
3692
  },
3446
3693
  get style() {
@@ -3457,6 +3704,7 @@ const SolidFlow = (props) => {
3457
3704
  value: solidFlow,
3458
3705
  get children() {
3459
3706
  return [
3707
+ memo(() => asyncSeedGuard()),
3460
3708
  createComponent(KeyHandler, {
3461
3709
  get selectionKey() {
3462
3710
  return _props.selectionKey;
@@ -3551,9 +3799,6 @@ const SolidFlow = (props) => {
3551
3799
  return [
3552
3800
  _tmpl$$14(),
3553
3801
  createComponent(EdgeRenderer, {
3554
- get reconnectRadius() {
3555
- return _props.reconnectRadius;
3556
- },
3557
3802
  get onEdgeClick() {
3558
3803
  return _props.onEdgeClick;
3559
3804
  },
@@ -3565,9 +3810,6 @@ const SolidFlow = (props) => {
3565
3810
  },
3566
3811
  get onEdgePointerLeave() {
3567
3812
  return _props.onEdgePointerLeave;
3568
- },
3569
- get defaultEdgeOptions() {
3570
- return _props.defaultEdgeOptions;
3571
3813
  }
3572
3814
  }),
3573
3815
  _tmpl$2(),
@@ -3713,8 +3955,8 @@ function useConnection() {
3713
3955
  * @returns store with an array of nodes
3714
3956
  */
3715
3957
  function useNodes() {
3716
- let { store } = useInternalSolidFlow();
3717
- return () => store.nodes;
3958
+ let { flow } = useInternalSolidFlow();
3959
+ return () => flow.nodes;
3718
3960
  }
3719
3961
  /**
3720
3962
  * Hook for getting the current edges from the store.
@@ -3723,8 +3965,8 @@ function useNodes() {
3723
3965
  * @returns store with an array of edges
3724
3966
  */
3725
3967
  function useEdges() {
3726
- let { store } = useInternalSolidFlow();
3727
- return () => store.edges;
3968
+ let { flow } = useInternalSolidFlow();
3969
+ return () => flow.edges;
3728
3970
  }
3729
3971
  /**
3730
3972
  * Hook for getting the current viewport from the store.
@@ -3782,6 +4024,52 @@ function useInternalNode(id) {
3782
4024
  return () => flow.internalNodes[id()];
3783
4025
  }
3784
4026
  //#endregion
4027
+ //#region src/hooks/useKeyPress.ts
4028
+ /**
4029
+ * Reactive "is this key (combo) held right now?" — the Solid Flow
4030
+ * counterpart of React Flow's `useKeyPress`, usable anywhere (no flow
4031
+ * context required).
4032
+ *
4033
+ * The definition is an Accessor per house convention — `useKeyPress(() =>
4034
+ * "a")`, `useKeyPress(() => ["a", "d"])`, or `useKeyPress(() => ({ key:
4035
+ * "s", modifier: ["meta"] }))`; swapping the definition resets the state.
4036
+ *
4037
+ * Hardened beyond upstream:
4038
+ * - Combos re-activate when the base key is re-pressed while the modifier
4039
+ * stays held (upstream's oldest open key bug, xyflow#2248).
4040
+ * - Stuck modifiers self-heal from the flags later keyboard/pointer/wheel
4041
+ * events carry (OS overlays swallow keyups without blurring — the macOS
4042
+ * screenshot HUD; xyflow#5679), and window blur resets.
4043
+ */
4044
+ function useKeyPress(keys) {
4045
+ let [pressed, setPressed] = createSignal(!1);
4046
+ if (createEffect(() => keys(), () => {
4047
+ setPressed(!1);
4048
+ }, { defer: !0 }), !isServer) {
4049
+ let reconcile = (event) => {
4050
+ pressed() && allContradicted(event, keys()) && (setPressed(!1), flush());
4051
+ };
4052
+ createEventListenerMap(window, {
4053
+ keydown: (event) => {
4054
+ reconcile(event), matchesKeyArray(event, keys()) && (setPressed(!0), flush());
4055
+ },
4056
+ keyup: (event) => {
4057
+ reconcile(event), matchesKeyArray(event, keys()) && (setPressed(!1), flush());
4058
+ },
4059
+ blur: () => {
4060
+ setPressed(!1), flush();
4061
+ }
4062
+ }), createEventListenerMap(window, {
4063
+ pointerdown: reconcile,
4064
+ wheel: reconcile
4065
+ }, {
4066
+ capture: !0,
4067
+ passive: !0
4068
+ });
4069
+ }
4070
+ return pressed;
4071
+ }
4072
+ //#endregion
3785
4073
  //#region src/hooks/useNodeConnections.ts
3786
4074
  /**
3787
4075
  * Hook to retrieve all edges connected to a node. Can be filtered by handle type and id.
@@ -4151,7 +4439,7 @@ delegateEvents(["click"]);
4151
4439
  //#endregion
4152
4440
  //#region src/plugins/minimap/MiniMap.tsx
4153
4441
  var _tmpl$$3 = /* @__PURE__ */ template("<svg class=solid-flow__minimap-svg role=img><title></title><path class=solid-flow__minimap-mask fill-rule=evenodd pointer-events=none>");
4154
- const getAttrFunction = (func) => func instanceof Function ? func : () => func, MiniMap = (props) => {
4442
+ const getAttrFunction = (value) => value instanceof Function ? value : () => value, MiniMap = (props) => {
4155
4443
  let { store, nodeLookup } = useInternalSolidFlow(), _props = propDefaults(props, {
4156
4444
  position: "bottom-right",
4157
4445
  nodeClass: "",
@@ -4161,26 +4449,47 @@ const getAttrFunction = (func) => func instanceof Function ? func : () => func,
4161
4449
  width: 200,
4162
4450
  height: 150,
4163
4451
  nodeBorderRadius: 5,
4452
+ offsetScale: 5,
4164
4453
  nodeStrokeWidth: 2,
4165
4454
  style: {}
4166
- }), paneProps = omit(_props, "class", "style", "position", "nodeClass", "nodeStrokeColor", "nodeColor", "pannable", "zoomable", "inversePan", "zoomStep", "bgColor", "width", "height", "maskColor", "maskStrokeColor", "maskStrokeWidth", "nodeBorderRadius", "nodeStrokeWidth", "nodeComponent", "onClick", "onNodeClick"), nodeColorFunc = () => _props.nodeColor === void 0 ? void 0 : getAttrFunction(_props.nodeColor), nodeStrokeColorFunc = () => getAttrFunction(_props.nodeStrokeColor), nodeClassFunc = () => getAttrFunction(_props.nodeClass), shapeRendering = () => typeof window > "u" || window.chrome ? "crispEdges" : "geometricPrecision", labelledBy = createMemo(() => `solid-flow__minimap-desc-${store.id}`), getViewBB = () => ({
4455
+ }), paneProps = omit(_props, "class", "style", "position", "nodeClass", "nodeStrokeColor", "nodeColor", "pannable", "zoomable", "inversePan", "zoomStep", "offsetScale", "bgColor", "width", "height", "maskColor", "maskStrokeColor", "maskStrokeWidth", "nodeBorderRadius", "nodeStrokeWidth", "nodeComponent", "onClick", "onNodeClick"), nodeColorFunc = () => _props.nodeColor === void 0 ? void 0 : getAttrFunction(_props.nodeColor), nodeStrokeColorFunc = () => getAttrFunction(_props.nodeStrokeColor), nodeClassFunc = () => getAttrFunction(_props.nodeClass), shapeRendering = typeof window > "u" || window.chrome ? "crispEdges" : "geometricPrecision", labelledBy = createMemo(() => `solid-flow__minimap-desc-${store.id}`), viewBB = createMemo(() => ({
4167
4456
  x: -store.viewport.x / store.viewport.zoom,
4168
4457
  y: -store.viewport.y / store.viewport.zoom,
4169
4458
  width: store.width / store.viewport.zoom,
4170
4459
  height: store.height / store.viewport.zoom
4171
- }), getBoundingRect = () => {
4172
- let viewBB = getViewBB();
4173
- return nodeLookup.size > 0 ? getBoundsOfRects(getInternalNodesBounds(nodeLookup), viewBB) : viewBB;
4174
- }, getScaledWidth = () => getBoundingRect().width / _props.width, getScaledHeight = () => getBoundingRect().height / _props.height, getViewScale = () => Math.max(getScaledWidth(), getScaledHeight()), getViewWidth = () => getViewScale() * _props.width, getViewHeight = () => getViewScale() * _props.height, getOffset = () => 5 * getViewScale(), getX = () => {
4175
- let boundingRect = getBoundingRect();
4176
- return boundingRect.x - (getViewWidth() - boundingRect.width) / 2 - getOffset();
4460
+ })), rectsEqual = (a, b) => a === b || !!a && !!b && a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height, sampleBounds = () => untrack(() => {
4461
+ if (nodeLookup.size === 0) return null;
4462
+ let bounds = getInternalNodesBounds(nodeLookup);
4463
+ return Number.isFinite(bounds.x) && Number.isFinite(bounds.width) ? bounds : null;
4464
+ }), [graphBounds, setGraphBounds] = createSignal(sampleBounds(), { equals: rectsEqual });
4465
+ createEffect(() => store.dragging, (dragging) => {
4466
+ if (!dragging) {
4467
+ setGraphBounds(sampleBounds());
4468
+ return;
4469
+ }
4470
+ let raf = requestAnimationFrame(function tick() {
4471
+ setGraphBounds(sampleBounds()), raf = requestAnimationFrame(tick);
4472
+ });
4473
+ return () => cancelAnimationFrame(raf);
4474
+ }), createEffect(() => ({
4475
+ count: store.nodes.length,
4476
+ initialized: store.nodesInitialized
4477
+ }), () => {
4478
+ setGraphBounds(sampleBounds());
4479
+ }), createEffect(() => null, () => {
4480
+ let interval = setInterval(() => setGraphBounds(sampleBounds()), 500);
4481
+ return () => clearInterval(interval);
4482
+ });
4483
+ let boundingRect = createMemo(() => {
4484
+ let view = viewBB(), bounds = graphBounds();
4485
+ return bounds ? getBoundsOfRects(bounds, view) : view;
4486
+ }), viewScale = createMemo(() => Math.max(boundingRect().width / _props.width, boundingRect().height / _props.height)), getViewWidth = () => viewScale() * _props.width, getViewHeight = () => viewScale() * _props.height, getOffset = () => _props.offsetScale * viewScale(), getX = () => {
4487
+ let rect = boundingRect();
4488
+ return rect.x - (getViewWidth() - rect.width) / 2 - getOffset();
4177
4489
  }, getY = () => {
4178
- let boundingRect = getBoundingRect();
4179
- return boundingRect.y - (getViewHeight() - boundingRect.height) / 2 - getOffset();
4180
- }, getViewboxWidth = () => getViewWidth() + getOffset() * 2, getViewboxHeight = () => getViewHeight() + getOffset() * 2, strokeWidth = () => _props.maskStrokeWidth ? _props.maskStrokeWidth * getViewScale() : void 0, prevNodeIds = [], nodeIds = () => {
4181
- let currentNodeIds = store.nodes.map((node) => node.id), currentSet = new Set(currentNodeIds);
4182
- return (prevNodeIds.length !== currentNodeIds.length || !prevNodeIds.every((id) => currentSet.has(id))) && (prevNodeIds = currentNodeIds), prevNodeIds;
4183
- };
4490
+ let rect = boundingRect();
4491
+ return rect.y - (getViewHeight() - rect.height) / 2 - getOffset();
4492
+ }, getViewboxWidth = () => getViewWidth() + getOffset() * 2, getViewboxHeight = () => getViewHeight() + getOffset() * 2, strokeWidth = () => _props.maskStrokeWidth ? _props.maskStrokeWidth * viewScale() : void 0, nodeIds = createMemo(() => store.nodes.map((node) => node.id), { equals: (a, b) => a.length === b.length && a.every((id, i) => id === b[i]) });
4184
4493
  return createComponent(Panel, mergeProps({
4185
4494
  get position() {
4186
4495
  return _props.position;
@@ -4211,7 +4520,7 @@ const getAttrFunction = (func) => func instanceof Function ? func : () => func,
4211
4520
  domNode: el,
4212
4521
  panZoom,
4213
4522
  getTransform: () => store.transform,
4214
- getViewScale
4523
+ getViewScale: viewScale
4215
4524
  });
4216
4525
  return setMinimap(instance), () => {
4217
4526
  instance.destroy();
@@ -4248,58 +4557,62 @@ const getAttrFunction = (func) => func instanceof Function ? func : () => func,
4248
4557
  return nodeIds();
4249
4558
  },
4250
4559
  children: (nodeId) => {
4251
- let node = createMemo(() => nodeLookup.get(nodeId())), nodeVisible = () => !!(node() && nodeHasDimensions(node()) && !node().hidden);
4560
+ let visibleNode = createMemo(() => {
4561
+ let row = nodeLookup.get(nodeId());
4562
+ return row && nodeHasDimensions(row) && !row.hidden ? row : null;
4563
+ });
4252
4564
  return createComponent(Show, {
4253
4565
  get when() {
4254
- return memo(() => !!nodeVisible())() ? getNodeDimensions(node()) : nodeVisible();
4566
+ return visibleNode();
4255
4567
  },
4256
- children: (nodeDimensions) => createComponent(Dynamic, {
4257
- get component() {
4258
- return _props.nodeComponent ?? MiniMapNode;
4259
- },
4260
- get id() {
4261
- return nodeId();
4262
- },
4263
- get x() {
4264
- return node().internals.positionAbsolute.x;
4265
- },
4266
- get y() {
4267
- return node().internals.positionAbsolute.y;
4268
- },
4269
- get borderRadius() {
4270
- return _props.nodeBorderRadius;
4271
- },
4272
- get strokeWidth() {
4273
- return _props.nodeStrokeWidth;
4274
- },
4275
- get shapeRendering() {
4276
- return shapeRendering();
4277
- },
4278
- get width() {
4279
- return nodeDimensions().width;
4280
- },
4281
- get height() {
4282
- return nodeDimensions().height;
4283
- },
4284
- get selected() {
4285
- return node().selected;
4286
- },
4287
- get color() {
4288
- return nodeColorFunc()?.call(null, node());
4289
- },
4290
- get strokeColor() {
4291
- return nodeStrokeColorFunc().call(null, node());
4292
- },
4293
- get class() {
4294
- return nodeClassFunc().call(null, node());
4295
- },
4296
- get style() {
4297
- return node().style;
4298
- },
4299
- get onClick() {
4300
- return _props.onNodeClick ? onSvgNodeClick : void 0;
4301
- }
4302
- })
4568
+ children: (node) => {
4569
+ let dimensions = () => getNodeDimensions(node()), userNode = () => node().internals.userNode;
4570
+ return createComponent(Dynamic, {
4571
+ get component() {
4572
+ return _props.nodeComponent ?? MiniMapNode;
4573
+ },
4574
+ get id() {
4575
+ return nodeId();
4576
+ },
4577
+ get x() {
4578
+ return node().internals.positionAbsolute.x;
4579
+ },
4580
+ get y() {
4581
+ return node().internals.positionAbsolute.y;
4582
+ },
4583
+ get borderRadius() {
4584
+ return _props.nodeBorderRadius;
4585
+ },
4586
+ get strokeWidth() {
4587
+ return _props.nodeStrokeWidth;
4588
+ },
4589
+ shapeRendering,
4590
+ get width() {
4591
+ return dimensions().width;
4592
+ },
4593
+ get height() {
4594
+ return dimensions().height;
4595
+ },
4596
+ get selected() {
4597
+ return node().selected;
4598
+ },
4599
+ get color() {
4600
+ return nodeColorFunc()?.call(null, userNode());
4601
+ },
4602
+ get strokeColor() {
4603
+ return nodeStrokeColorFunc().call(null, userNode());
4604
+ },
4605
+ get class() {
4606
+ return nodeClassFunc().call(null, userNode());
4607
+ },
4608
+ get style() {
4609
+ return node().style;
4610
+ },
4611
+ get onClick() {
4612
+ return _props.onNodeClick ? onSvgNodeClick : void 0;
4613
+ }
4614
+ });
4615
+ }
4303
4616
  });
4304
4617
  }
4305
4618
  }), _el$2.nextSibling), effect(() => ({
@@ -4312,7 +4625,7 @@ const getAttrFunction = (func) => func instanceof Function ? func : () => func,
4312
4625
  s: strokeWidth(),
4313
4626
  h: labelledBy(),
4314
4627
  r: `M${getX() - getOffset()},${getY() - getOffset()}h${getViewboxWidth() + getOffset() * 2}v${getViewboxHeight() + getOffset() * 2}h${-getViewboxWidth() - getOffset() * 2}z
4315
- M${getViewBB().x},${getViewBB().y}h${getViewBB().width}v${getViewBB().height}h${-getViewBB().width}z`
4628
+ M${viewBB().x},${viewBB().y}h${viewBB().width}v${viewBB().height}h${-viewBB().width}z`
4316
4629
  }), ({ e, t, a, o, i, n, s, h, r }, _p$) => {
4317
4630
  e !== _p$?.e && setAttribute(_el$, "width", e), t !== _p$?.t && setAttribute(_el$, "height", t), a !== _p$?.a && setAttribute(_el$, "viewBox", a), o !== _p$?.o && setAttribute(_el$, "aria-labelledby", o), i !== _p$?.i && setStyleProperty(_el$, "--xy-minimap-mask-background-color-props", i), n !== _p$?.n && setStyleProperty(_el$, "--xy-minimap-mask-stroke-color-props", n), s !== _p$?.s && setStyleProperty(_el$, "--xy-minimap-mask-stroke-width-props", s), h !== _p$?.h && setAttribute(_el$2, "id", h), r !== _p$?.r && setAttribute(_el$3, "d", r);
4318
4631
  }), _el$;
@@ -4498,7 +4811,7 @@ const EdgeToolbar = (props) => {
4498
4811
  var _tmpl$ = /* @__PURE__ */ template("<div>");
4499
4812
  /** Toolbar attached to a node, rendered above the graph so it does not scale with zoom. */
4500
4813
  const NodeToolbar = (props) => {
4501
- let { store } = useInternalSolidFlow(), { flow, getNodesBounds } = useSolidFlow(), _props = propDefaults(props, {
4814
+ let { store, flow, commands } = useInternalSolidFlow(), _props = propDefaults(props, {
4502
4815
  offset: 10,
4503
4816
  position: "top",
4504
4817
  align: "center",
@@ -4510,7 +4823,7 @@ const NodeToolbar = (props) => {
4510
4823
  let node = flow.internalNodes[nodeId];
4511
4824
  return node && res.push(node), res;
4512
4825
  }, []), transform = () => {
4513
- let nodeRect = getNodesBounds(toolbarNodes());
4826
+ let nodeRect = commands.getNodesBounds(toolbarNodes());
4514
4827
  return nodeRect ? getNodeToolbarTransform(nodeRect, store.viewport, _props.position, _props.offset, _props.align) : "";
4515
4828
  }, zIndex = () => {
4516
4829
  let nodes = toolbarNodes();
@@ -4550,4 +4863,4 @@ const NodeToolbar = (props) => {
4550
4863
  });
4551
4864
  }, SelectionMode = SelectionMode$1, getEdgeCenter = getEdgeCenter$1, getBezierEdgeCenter = getBezierEdgeCenter$1;
4552
4865
  //#endregion
4553
- export { Background, BaseEdge, BezierEdge, BezierEdgeInternal, ConnectionLine, ConnectionLineType, ConnectionMode, ControlButton, Controls, DefaultNode, EdgeLabel, EdgeLabelRenderer, EdgeReconnectAnchor, EdgeRenderer, EdgeToolbar, EdgeWrapper, GroupNode, Handle, InputNode, Marker, MarkerDefinition, MarkerType, MiniMap, MiniMapNode, NodeRenderer, NodeResizer, NodeSelection, NodeToolbar, NodeWrapper, OutputNode, PanOnScrollMode, Pane, Panel, Position, ResizeControl, ResizeControlVariant, Selection, SelectionMode, SmoothStepEdge, SmoothStepEdgeInternal, SolidFlow, SolidFlowProvider, StepEdge, StepEdgeInternal, StraightEdge, StraightEdgeInternal, Viewport, ViewportPortal, Zoom, addEdge, connectionKey, createEdgeStore, createNodeStore, getBezierEdgeCenter, getBezierPath, getConnectedEdges, getEdgeCenter, getIncomers, getNodesBounds, getOutgoers, getSmoothStepPath, getStraightPath, getViewportForBounds, useColorMode, useConnection, useEdgeId, useEdges, useInternalNode, useNodeConnections, useNodeId, useNodes, useNodesData, useNodesInitialized, useSolidFlow, useUpdateNodeInternals, useViewport, useViewportInitialized };
4866
+ export { Background, BaseEdge, BezierEdge, BezierEdgeInternal, ConnectionLine, ConnectionLineType, ConnectionMode, ControlButton, Controls, DefaultNode, EdgeLabel, EdgeLabelRenderer, EdgeReconnectAnchor, EdgeRenderer, EdgeToolbar, EdgeWrapper, GroupNode, Handle, InputNode, Marker, MarkerDefinition, MarkerType, MiniMap, MiniMapNode, NodeRenderer, NodeResizer, NodeSelection, NodeToolbar, NodeWrapper, OutputNode, PanOnScrollMode, Pane, Panel, Position, ResizeControl, ResizeControlVariant, Selection, SelectionMode, SmoothStepEdge, SmoothStepEdgeInternal, SolidFlow, SolidFlowProvider, StepEdge, StepEdgeInternal, StraightEdge, StraightEdgeInternal, Viewport, ViewportPortal, Zoom, addEdge, connectionKey, createEdgeStore, createNodeStore, getBezierEdgeCenter, getBezierPath, getConnectedEdges, getEdgeCenter, getIncomers, getNodesBounds, getOutgoers, getSmoothStepPath, getStraightPath, getViewportForBounds, useColorMode, useConnection, useEdgeId, useEdges, useInternalNode, useKeyPress, useNodeConnections, useNodeId, useNodes, useNodesData, useNodesInitialized, useSolidFlow, useUpdateNodeInternals, useViewport, useViewportInitialized };