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

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.
@@ -65,7 +65,7 @@ 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
- }, EdgeLabelRenderer = (props) => {
68
+ }, isEdgeSelectable = (edge, store) => edge.selectable ?? store.defaultEdgeOptions.selectable ?? store.elementsSelectable, EdgeLabelRenderer = (props) => {
69
69
  let { store } = useInternalSolidFlow(), labelNode = () => store.domNode?.querySelector(".solid-flow__edge-labels");
70
70
  return createComponent(Show, {
71
71
  get when() {
@@ -282,6 +282,181 @@ const BaseEdge = (props) => {
282
282
  });
283
283
  };
284
284
  //#endregion
285
+ //#region src/core/spatial/grid.ts
286
+ /**
287
+ * A uniform spatial hash over axis-aligned rects — the plain, NON-reactive
288
+ * building block behind the flow's spatial queries (RFC-4239 dossier:
289
+ * gesture-scoped snapshots and epoch-rebuilt indexes; deliberately never a
290
+ * live-maintained reactive structure, which would re-create the round-6
291
+ * central-collection anti-pattern).
292
+ *
293
+ * Every operation is O(cells touched); with cellSize on the order of the
294
+ * query radius or median node size, inserts and queries touch O(1) cells.
295
+ * No balancing, no extent-known-up-front requirement, no dependency —
296
+ * upstream's own bake-off (quadtree vs BVH vs rbush) is why: fixed-radius
297
+ * neighborhood and rect-vs-box queries are the textbook grid case.
298
+ */
299
+ var SpatialGrid = class {
300
+ cellSize;
301
+ cells = /* @__PURE__ */ new Map();
302
+ rects = /* @__PURE__ */ new Map();
303
+ constructor(cellSize) {
304
+ this.cellSize = cellSize;
305
+ }
306
+ cellRange(rect) {
307
+ let size = this.cellSize;
308
+ return {
309
+ minX: Math.floor(rect.x / size),
310
+ maxX: Math.floor((rect.x + rect.width) / size),
311
+ minY: Math.floor(rect.y / size),
312
+ maxY: Math.floor((rect.y + rect.height) / size)
313
+ };
314
+ }
315
+ insert(id, rect) {
316
+ this.rects.set(id, rect);
317
+ let { minX, maxX, minY, maxY } = this.cellRange(rect);
318
+ for (let cx = minX; cx <= maxX; cx++) for (let cy = minY; cy <= maxY; cy++) {
319
+ let key = `${cx}:${cy}`, bucket = this.cells.get(key);
320
+ bucket ? bucket.push(id) : this.cells.set(key, [id]);
321
+ }
322
+ }
323
+ /** Ids of entries whose rect overlaps the query rect (touching counts). */
324
+ queryRect(query) {
325
+ let { minX, maxX, minY, maxY } = this.cellRange(query), seen = /* @__PURE__ */ new Set(), result = [];
326
+ for (let cx = minX; cx <= maxX; cx++) for (let cy = minY; cy <= maxY; cy++) {
327
+ let bucket = this.cells.get(`${cx}:${cy}`);
328
+ if (bucket) for (let id of bucket) {
329
+ if (seen.has(id)) continue;
330
+ seen.add(id);
331
+ let rect = this.rects.get(id);
332
+ 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);
333
+ }
334
+ }
335
+ return result;
336
+ }
337
+ get size() {
338
+ return this.rects.size;
339
+ }
340
+ }, GestureSpatialLookup = class {
341
+ #real;
342
+ #cellSize;
343
+ #grid = null;
344
+ #queryRect = null;
345
+ constructor(real, cellSize) {
346
+ this.#real = real, this.#cellSize = cellSize;
347
+ }
348
+ /** Snapshot the current geometry into the grid (gesture start). */
349
+ arm(rectOf) {
350
+ let grid = new SpatialGrid(this.#cellSize);
351
+ for (let [id, value] of this.#real.entries()) grid.insert(id, rectOf(value));
352
+ this.#grid = grid, this.#queryRect = null;
353
+ }
354
+ /** Focus iteration on the neighborhood of the pointer (per move). */
355
+ setQueryCenter(center, radius) {
356
+ this.#queryRect = {
357
+ x: center.x - radius,
358
+ y: center.y - radius,
359
+ width: radius * 2,
360
+ height: radius * 2
361
+ };
362
+ }
363
+ /** Focus iteration on an explicit rect (box-selection gestures). */
364
+ setQueryRect(rect) {
365
+ this.#queryRect = rect;
366
+ }
367
+ /** Back to plain pass-through (gesture end). */
368
+ disarm() {
369
+ this.#grid = null, this.#queryRect = null;
370
+ }
371
+ #candidateIds() {
372
+ return !this.#grid || !this.#queryRect ? null : this.#grid.queryRect(this.#queryRect);
373
+ }
374
+ get(key) {
375
+ return this.#real.get(key);
376
+ }
377
+ has(key) {
378
+ return this.#real.has(key);
379
+ }
380
+ get size() {
381
+ return this.#real.size;
382
+ }
383
+ *keys() {
384
+ let candidates = this.#candidateIds();
385
+ if (!candidates) {
386
+ yield* this.#real.keys();
387
+ return;
388
+ }
389
+ for (let id of candidates) this.#real.has(id) && (yield id);
390
+ }
391
+ *values() {
392
+ let candidates = this.#candidateIds();
393
+ if (!candidates) {
394
+ yield* this.#real.values();
395
+ return;
396
+ }
397
+ for (let id of candidates) {
398
+ let value = this.#real.get(id);
399
+ value !== void 0 && (yield value);
400
+ }
401
+ }
402
+ *entries() {
403
+ let candidates = this.#candidateIds();
404
+ if (!candidates) {
405
+ yield* this.#real.entries();
406
+ return;
407
+ }
408
+ for (let id of candidates) {
409
+ let value = this.#real.get(id);
410
+ value !== void 0 && (yield [id, value]);
411
+ }
412
+ }
413
+ [Symbol.iterator]() {
414
+ return this.entries();
415
+ }
416
+ forEach(callback, thisArg) {
417
+ for (let [key, value] of this.entries()) callback.call(thisArg, value, key, this);
418
+ }
419
+ [Symbol.toStringTag] = "GestureSpatialLookup";
420
+ set() {
421
+ throw Error("GestureSpatialLookup is read-only");
422
+ }
423
+ getOrInsert() {
424
+ throw Error("GestureSpatialLookup is read-only");
425
+ }
426
+ getOrInsertComputed() {
427
+ throw Error("GestureSpatialLookup is read-only");
428
+ }
429
+ delete() {
430
+ throw Error("GestureSpatialLookup is read-only");
431
+ }
432
+ clear() {
433
+ throw Error("GestureSpatialLookup is read-only");
434
+ }
435
+ };
436
+ //#endregion
437
+ //#region src/components/handle/connectionGestureLookup.ts
438
+ /**
439
+ * Upstream `getClosestHandle` prefilters nodes within
440
+ * `connectionRadius + ADDITIONAL_DISTANCE` of the pointer; ADDITIONAL_DISTANCE
441
+ * is hardcoded to 250 in @xyflow/system (xyhandle/utils.ts). Tracked here with
442
+ * a safety pad: a superset of candidates is always correct (their exact
443
+ * distance filter runs after), so the pad only costs a few extra candidates.
444
+ */
445
+ const armConnectionGestureLookup = (options) => {
446
+ let { event, real, domNode, getTransform, connectionRadius } = options, containerBounds = domNode?.getBoundingClientRect();
447
+ if (!containerBounds) return real;
448
+ let radius = connectionRadius + 250 + 50, lookup = new GestureSpatialLookup(real, radius);
449
+ lookup.arm((node) => nodeToRect(node));
450
+ let update = (moveEvent) => {
451
+ lookup.setQueryCenter(pointToRendererPoint(getEventPosition(moveEvent, containerBounds), getTransform(), !1, [1, 1]), radius);
452
+ };
453
+ update(event);
454
+ let doc = getHostForElement(event.target), dispose = () => {
455
+ doc.removeEventListener("mousemove", update, !0), doc.removeEventListener("touchmove", update, !0), doc.removeEventListener("mouseup", dispose, !0), doc.removeEventListener("touchend", dispose, !0), lookup.disarm();
456
+ };
457
+ return doc.addEventListener("mousemove", update, !0), doc.addEventListener("touchmove", update, !0), doc.addEventListener("mouseup", dispose, !0), doc.addEventListener("touchend", dispose, !0), lookup;
458
+ };
459
+ //#endregion
285
460
  //#region src/components/edge/EdgeReconnectAnchor.tsx
286
461
  var _tmpl$$32 = /* @__PURE__ */ template("<div style=background:transparent;border:none;cursor:move>");
287
462
  /** Grab area that lets an edge end be dragged off its handle and reconnected. */
@@ -305,7 +480,13 @@ const EdgeReconnectAnchor = (props) => {
305
480
  nodeId: edge().target,
306
481
  handleId: edge().targetHandle ?? null,
307
482
  type: "target"
308
- };
483
+ }, gestureLookup = armConnectionGestureLookup({
484
+ event,
485
+ real: nodeLookup,
486
+ domNode: store.domNode,
487
+ getTransform: () => store.transform,
488
+ connectionRadius: store.connectionRadius
489
+ });
309
490
  XYHandle.onPointerDown(event, {
310
491
  lib: store.lib,
311
492
  flowId: store.id,
@@ -315,7 +496,7 @@ const EdgeReconnectAnchor = (props) => {
315
496
  autoPanOnConnect: store.autoPanOnConnect,
316
497
  connectionMode: store.connectionMode,
317
498
  connectionRadius: store.connectionRadius,
318
- nodeLookup,
499
+ nodeLookup: gestureLookup,
319
500
  isTarget: opposite.type === "target",
320
501
  edgeUpdaterType: opposite.type,
321
502
  cancelConnection: actions.cancelConnection,
@@ -416,9 +597,73 @@ const A11yDescriptions = () => {
416
597
  }
417
598
  })
418
599
  ];
419
- }, createEdgeStore = (edges) => {
420
- let [store, setStore] = createStore(edges);
421
- return [store, setStore];
600
+ }, createSelectionCommands = ({ store, setNodesStore, setEdgesStore, setSelectionRect, setSelectionRectMode, nodeLookup, edgeLookup, updateNodePositions }) => {
601
+ let unselectNodesAndEdges = ({ nodes: _nodes, edges } = {}) => {
602
+ let nodesToUnselect = new Set((_nodes || store.nodes).map(({ id }) => id));
603
+ nodesToUnselect.size && setNodesStore((nodes) => {
604
+ for (let node of nodes) nodesToUnselect.has(node.id) && (node.selected = !1);
605
+ });
606
+ let edgesToUnselect = new Set((edges ?? store.edges).map(({ id }) => id));
607
+ edgesToUnselect.size && setEdgesStore((edges) => {
608
+ for (let edge of edges) edgesToUnselect.has(edge.id) && (edge.selected = !1);
609
+ }), flush();
610
+ }, addSelectedNodes = (ids) => {
611
+ let isMultiSelection = store.multiselectionKeyPressed, idSet = new Set(ids);
612
+ setNodesStore((nodes) => {
613
+ for (let node of nodes) {
614
+ let nodeWillBeSelected = idSet.has(node.id), selected = isMultiSelection && node.selected || nodeWillBeSelected;
615
+ node.selected !== selected && (node.selected = selected);
616
+ }
617
+ }), isMultiSelection || unselectNodesAndEdges({ nodes: [] }), flush();
618
+ }, addSelectedEdges = (ids) => {
619
+ let isMultiSelection = store.multiselectionKeyPressed, idSet = new Set(ids);
620
+ setEdgesStore((edges) => {
621
+ for (let edge of edges) {
622
+ let edgeWillBeSelected = idSet.has(edge.id), selected = isMultiSelection && edge.selected || edgeWillBeSelected;
623
+ edge.selected !== selected && (edge.selected = selected);
624
+ }
625
+ }), isMultiSelection || unselectNodesAndEdges({ edges: [] }), flush();
626
+ };
627
+ return {
628
+ unselectNodesAndEdges,
629
+ addSelectedNodes,
630
+ addSelectedEdges,
631
+ handleNodeSelection: (id, unselect, nodeRef) => {
632
+ let node = store.nodes.find((n) => n.id === id);
633
+ node && (setSelectionRect(void 0), setSelectionRectMode(void 0), node.selected ? (unselect || node.selected && store.multiselectionKeyPressed) && (unselectNodesAndEdges({
634
+ nodes: [node],
635
+ edges: []
636
+ }), requestAnimationFrame(() => nodeRef?.blur())) : addSelectedNodes([id]));
637
+ },
638
+ handleEdgeSelection: (id) => {
639
+ let edge = edgeLookup[id];
640
+ edge && isEdgeSelectable(edge, store) && (setSelectionRect(void 0), setSelectionRectMode(void 0), edge.selected ? edge.selected && store.multiselectionKeyPressed && unselectNodesAndEdges({
641
+ nodes: [],
642
+ edges: [edge]
643
+ }) : addSelectedEdges([id]));
644
+ },
645
+ moveSelectedNodes: (direction, factor) => {
646
+ 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;
647
+ for (let node of nodeLookup.values()) {
648
+ if (!(node.selected && (node.draggable || store.nodesDraggable && node.draggable === void 0))) continue;
649
+ let nextPosition = {
650
+ x: node.internals.positionAbsolute.x + xDiff,
651
+ y: node.internals.positionAbsolute.y + yDiff
652
+ };
653
+ store.snapGrid && (nextPosition = snapPosition(nextPosition, store.snapGrid));
654
+ let { position } = calculateNodePosition({
655
+ nodeId: node.id,
656
+ nextPosition,
657
+ nodeLookup,
658
+ nodeExtent: store.nodeExtent,
659
+ nodeOrigin: store.nodeOrigin,
660
+ onError: store.onError
661
+ });
662
+ nodeUpdates.set(node.id, { position });
663
+ }
664
+ updateNodePositions(nodeUpdates);
665
+ }
666
+ };
422
667
  }, 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
668
  let { width, height } = source;
424
669
  if (!width || !height) return null;
@@ -549,14 +794,48 @@ var RecordMapFacade = class {
549
794
  }
550
795
  };
551
796
  //#endregion
552
- //#region src/core/projections/connections.ts
797
+ //#region src/core/measurementIngest.ts
553
798
  /**
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}`
799
+ * The measurement ingest lifecycle (WP3): everything that flows FROM the DOM
800
+ * measuring pass INTO the data graph, plus the garbage collection that keeps
801
+ * the measurements root aligned with graph membership. The DOM side (resize
802
+ * observers, the idle-scheduled measuring pass) lives in createSolidFlow;
803
+ * headless usage never calls these.
558
804
  */
559
- const connectionKey = (nodeId, type, handleId) => `${nodeId}${type ? handleId ? `-${type}-${handleId}` : `-${type}` : ""}`, pairKey = (aNode, aHandle, bNode, bHandle) => `${aNode}-${aHandle}--${bNode}-${bHandle}`, createConnections = (source) => createProjection(() => {
805
+ const createMeasurementIngest = ({ setMeasurementsStore, setNodesStore, nodes }) => (createEffect(() => new Set(nodes().map((n) => n.id)), (currentIds) => {
806
+ setMeasurementsStore((draft) => {
807
+ for (let id of Object.keys(draft)) currentIds.has(id) || delete draft[id];
808
+ });
809
+ }), {
810
+ applyMeasurementWrites: (writes) => {
811
+ setMeasurementsStore((draft) => {
812
+ for (let write of writes) if (write.hidden) {
813
+ let entry = draft[write.id];
814
+ entry && (entry.handleBounds = void 0);
815
+ } else draft[write.id] = {
816
+ measured: write.measured,
817
+ handleBounds: write.handleBounds
818
+ };
819
+ });
820
+ },
821
+ applyNodeChanges: (changes) => {
822
+ changes.length !== 0 && setNodesStore((nodes) => {
823
+ let nodeById = new Map(nodes.map((node) => [node.id, node]));
824
+ for (let change of changes) {
825
+ let node = nodeById.get(change.id);
826
+ if (node) switch (change.type) {
827
+ case "dimensions":
828
+ change.setAttributes && (node.width = change.dimensions?.width ?? node.width, node.height = change.dimensions?.height ?? node.height), node.measured = {
829
+ ...node.measured,
830
+ ...change.dimensions
831
+ };
832
+ break;
833
+ case "position": node.position = change.position ?? node.position;
834
+ }
835
+ }
836
+ });
837
+ }
838
+ }), connectionKey = (nodeId, type, handleId) => `${nodeId}${type ? handleId ? `-${type}-${handleId}` : `-${type}` : ""}`, pairKey = (aNode, aHandle, bNode, bHandle) => `${aNode}-${aHandle}--${bNode}-${bHandle}`, createConnections = (source) => createProjection(() => {
560
839
  let out = {}, add = (key, entry, connection) => {
561
840
  (out[key] ??= {})[entry] = connection;
562
841
  };
@@ -621,10 +900,6 @@ const EMPTY_AUTO_INDEX = /* @__PURE__ */ new Map(), createInternalNodes = (sourc
621
900
  }, row.internals.z = z;
622
901
  } else source.nodes.length;
623
902
  }
624
- if (userNode.parentId) {
625
- let parent = entryById.get(userNode.parentId);
626
- parent?.store.row.internals.positionAbsolute.x, parent?.store.row.internals.z;
627
- }
628
903
  return { row };
629
904
  }, {}, { key: "id" }), entry = {
630
905
  store,
@@ -693,8 +968,8 @@ const createLayoutedEdges = (source) => {
693
968
  let rowStores = mapArray(() => source.edges, (edgeAccessor) => ({
694
969
  id: edgeAccessor().id,
695
970
  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 };
971
+ let edge = edgeAccessor();
972
+ return { row: buildRow(source, edge) };
698
973
  }, { row: null }, { key: "id" })
699
974
  }), { keyed: (edge) => edge.id }), assigned = /* @__PURE__ */ new Map();
700
975
  return createProjection((draft) => {
@@ -710,7 +985,7 @@ const createLayoutedEdges = (source) => {
710
985
  });
711
986
  }, buildRow = (source, edge) => {
712
987
  let sourceNode = source.nodeLookup.get(edge.source), targetNode = source.nodeLookup.get(edge.target);
713
- if (!sourceNode || !targetNode) return source.nodeLookup.size, null;
988
+ if (!sourceNode || !targetNode) return null;
714
989
  let edgePosition = getEdgePosition({
715
990
  id: edge.id,
716
991
  sourceNode,
@@ -740,7 +1015,33 @@ const createLayoutedEdges = (source) => {
740
1015
  let out = {};
741
1016
  for (let node of source.nodes) node.parentId && (out[node.parentId] = !0);
742
1017
  return out;
743
- }, {}, { key: "id" }), getInitialViewport = (fitView, initialViewport, width, height, nodeLookup) => {
1018
+ }, {}, { key: "id" }), createSeededGraphStores = (props, config) => {
1019
+ props.nodes !== void 0 && props.defaultNodes, props.edges !== void 0 && props.defaultEdges;
1020
+ 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;
1021
+ return createEffect(() => {
1022
+ let next = config().nodes;
1023
+ if (next) for (let node of next);
1024
+ return { next };
1025
+ }, ({ next }) => {
1026
+ next && (nodeSeedAdopted = !0, setNodesStore(() => next));
1027
+ }, { defer: !0 }), createEffect(() => {
1028
+ let next = config().edges;
1029
+ if (next) for (let edge of next);
1030
+ return { next };
1031
+ }, ({ next }) => {
1032
+ next && (edgeSeedAdopted = !0, setEdgesStore(() => next));
1033
+ }, { defer: !0 }), createEffect(() => ({
1034
+ nodes: config().defaultNodes,
1035
+ edges: config().defaultEdges
1036
+ }), ({ nodes: defaultNodes, edges: defaultEdges }) => {
1037
+ defaultNodes && !nodeSeedAdopted && config().nodes === void 0 && (nodeSeedAdopted = !0, setNodesStore(() => [...defaultNodes])), defaultEdges && !edgeSeedAdopted && config().edges === void 0 && (edgeSeedAdopted = !0, setEdgesStore(() => [...defaultEdges]));
1038
+ }, { defer: !0 }), {
1039
+ nodesStore,
1040
+ setNodesStore,
1041
+ edgesStore,
1042
+ setEdgesStore
1043
+ };
1044
+ }, getInitialViewport = (fitView, initialViewport, width, height, nodeLookup) => {
744
1045
  if (fitView && !initialViewport && width && height) {
745
1046
  let bounds = getInternalNodesBounds(nodeLookup, { filter: (node) => !!((node.width || node.initialWidth) && (node.height || node.initialHeight)) });
746
1047
  return getViewportForBounds$1(bounds, width, height, .5, 2, .1);
@@ -751,9 +1052,7 @@ const createLayoutedEdges = (source) => {
751
1052
  zoom: 1
752
1053
  };
753
1054
  }, 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({
1055
+ 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
1056
  get nodes() {
758
1057
  return nodesStore;
759
1058
  },
@@ -773,24 +1072,7 @@ const createLayoutedEdges = (source) => {
773
1072
  return config().zIndexMode;
774
1073
  }
775
1074
  }), 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) => {
1075
+ createEffect(() => config().viewport, (next) => {
794
1076
  next && setViewportStore(() => next);
795
1077
  }, { defer: !0 });
796
1078
  let transform = createMemo(() => [
@@ -802,25 +1084,29 @@ const createLayoutedEdges = (source) => {
802
1084
  if (nodes.length === 0) return !1;
803
1085
  for (let node of nodes) if (!node.hidden && (node.measured?.width === void 0 || node.measured?.height === void 0)) return !1;
804
1086
  return !0;
805
- }), store = merge({
1087
+ }), resolvedColorMode = createMemo(() => {
1088
+ let mode = config().colorMode;
1089
+ return mode === "system" ? prefersDark() ? "dark" : "light" : mode;
1090
+ }), projectedConnection = createMemo(() => {
1091
+ let state = connection();
1092
+ return state.inProgress ? {
1093
+ ...state,
1094
+ to: pointToRendererPoint(state.to, transform())
1095
+ } : state;
1096
+ }), 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) => {
1097
+ let state = connection(), toHandle = state.inProgress ? state.toHandle : null, key = toHandle ? connectionKey(toHandle.nodeId, toHandle.type, toHandle.id ?? null) : null;
1098
+ for (let existing of Object.keys(draft)) existing !== key && delete draft[existing];
1099
+ key && (draft[key] = state.isValid ? "valid" : "invalid");
1100
+ }, {}, { key: null }), mergedNodeTypes = createMemo(() => ({
1101
+ ...initialNodeTypes,
1102
+ ...config().nodeTypes
1103
+ })), mergedEdgeTypes = createMemo(() => ({
1104
+ ...initialEdgeTypes,
1105
+ ...config().edgeTypes
1106
+ })), selectedNodesView = createMemo(() => nodesStore.filter((node) => node.selected)), selectedEdgesView = createMemo(() => edgesStore.filter((edge) => edge.selected)), store = merge({
806
1107
  width: 0,
807
1108
  height: 0
808
1109
  }, 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
1110
  get ariaLabelConfig() {
825
1111
  return ariaLabelConfig();
826
1112
  },
@@ -831,14 +1117,16 @@ const createLayoutedEdges = (source) => {
831
1117
  return clickConnectStartHandle();
832
1118
  },
833
1119
  get colorMode() {
834
- return this._colorMode === "system" ? prefersDark() ? "dark" : "light" : this._colorMode;
1120
+ return resolvedColorMode();
835
1121
  },
836
1122
  get connection() {
837
- let state = connection();
838
- return {
839
- ...state,
840
- to: state.inProgress ? pointToRendererPoint(state.to, this.transform) : state.to
841
- };
1123
+ return projectedConnection();
1124
+ },
1125
+ get connectionFromHandle() {
1126
+ return connectionFromHandle();
1127
+ },
1128
+ get connectionTargetByHandle() {
1129
+ return connectionTargetByHandle;
842
1130
  },
843
1131
  get domNode() {
844
1132
  return domNode();
@@ -847,10 +1135,7 @@ const createLayoutedEdges = (source) => {
847
1135
  return dragging();
848
1136
  },
849
1137
  get edgeTypes() {
850
- return {
851
- ...initialEdgeTypes,
852
- ...this._edgeTypes
853
- };
1138
+ return mergedEdgeTypes();
854
1139
  },
855
1140
  get elementsSelectable() {
856
1141
  return elementsSelectable();
@@ -883,19 +1168,16 @@ const createLayoutedEdges = (source) => {
883
1168
  return nodesDraggable();
884
1169
  },
885
1170
  get nodeTypes() {
886
- return {
887
- ...initialNodeTypes,
888
- ...this._nodeTypes
889
- };
1171
+ return mergedNodeTypes();
890
1172
  },
891
1173
  get panZoom() {
892
1174
  return panZoom();
893
1175
  },
894
1176
  get selectedNodes() {
895
- return nodesStore.filter((node) => node.selected);
1177
+ return selectedNodesView();
896
1178
  },
897
1179
  get selectedEdges() {
898
- return edgesStore.filter((edge) => edge.selected);
1180
+ return selectedEdgesView();
899
1181
  },
900
1182
  get selectionRect() {
901
1183
  return selectionRect();
@@ -1010,33 +1292,11 @@ const createLayoutedEdges = (source) => {
1010
1292
  setNodesStore((nodes) => {
1011
1293
  for (let node of nodes) nodeDragItems.has(node.id) && (node.dragging = dragging, node.position = nodeDragItems.get(node.id).position);
1012
1294
  });
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 = () => {
1295
+ }, { applyMeasurementWrites, applyNodeChanges } = createMeasurementIngest({
1296
+ setMeasurementsStore,
1297
+ setNodesStore,
1298
+ nodes: () => nodesStore
1299
+ }), markInitialNodesMeasured = () => {
1040
1300
  initialNodesMeasured = !0, tryInitialFitView();
1041
1301
  }, requestMeasure = () => {}, setMeasureRequester = (fn) => {
1042
1302
  requestMeasure = fn;
@@ -1051,66 +1311,16 @@ const createLayoutedEdges = (source) => {
1051
1311
  ease: options?.ease,
1052
1312
  interpolate: options?.interpolate
1053
1313
  }), 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({
1314
+ }, stableSetViewport = (viewport) => setViewportStore(() => viewport), { unselectNodesAndEdges, addSelectedNodes, addSelectedEdges, handleNodeSelection, handleEdgeSelection, moveSelectedNodes } = createSelectionCommands({
1315
+ store,
1316
+ setNodesStore,
1317
+ setEdgesStore,
1318
+ setSelectionRect,
1319
+ setSelectionRectMode,
1320
+ nodeLookup,
1321
+ edgeLookup,
1322
+ updateNodePositions
1323
+ }), panBy$1 = (delta) => panBy({
1114
1324
  delta,
1115
1325
  panZoom: store.panZoom,
1116
1326
  transform: store.transform,
@@ -1187,8 +1397,27 @@ const createLayoutedEdges = (source) => {
1187
1397
  get snapGrid() {
1188
1398
  return store.snapGrid;
1189
1399
  }
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 = {
1400
+ }, intersectionGrid = null, intersectionRows = null, queryIntersectionCandidates = (rect) => untrack(() => {
1401
+ if (!intersectionGrid) {
1402
+ let grid = new SpatialGrid(300), rows = /* @__PURE__ */ new Map();
1403
+ for (let node of store.nodes) {
1404
+ let internalNode = nodeLookup.get(node.id);
1405
+ internalNode && (grid.insert(node.id, nodeToRect(internalNode)), rows.set(node.id, node));
1406
+ }
1407
+ intersectionGrid = grid, intersectionRows = rows, queueMicrotask(() => {
1408
+ intersectionGrid = null, intersectionRows = null;
1409
+ });
1410
+ }
1411
+ let rows = intersectionRows, result = [];
1412
+ for (let id of intersectionGrid.queryRect(rect)) {
1413
+ let row = rows.get(id);
1414
+ row && result.push(row);
1415
+ }
1416
+ return result;
1417
+ }), getNodeRect = (node) => {
1418
+ let nodeToUse = isNode(node) ? node : nodeLookup.get(node.id);
1419
+ if (!nodeToUse) return null;
1420
+ let position = nodeToUse.parentId ? evaluateAbsolutePosition(nodeToUse.position, nodeToUse.measured, nodeToUse.parentId, nodeLookup, store.nodeOrigin) : nodeToUse.position, nodeWithPosition = {
1192
1421
  ...nodeToUse,
1193
1422
  position,
1194
1423
  width: nodeToUse.measured?.width ?? nodeToUse.width,
@@ -1242,7 +1471,7 @@ const createLayoutedEdges = (source) => {
1242
1471
  x,
1243
1472
  y,
1244
1473
  zoom
1245
- ], _snapGrid !== null, _snapGrid || [1, 1]);
1474
+ ], !!_snapGrid, _snapGrid || [1, 1]);
1246
1475
  },
1247
1476
  flowToScreenPosition: (position) => {
1248
1477
  if (!store.domNode) return position;
@@ -1306,14 +1535,18 @@ const createLayoutedEdges = (source) => {
1306
1535
  let remainingNodes = store.nodes.filter((node) => !matchingNodes.some(({ id }) => id === node.id));
1307
1536
  store.onNodesDelete?.(matchingNodes), setNodesStore(() => remainingNodes);
1308
1537
  }
1309
- return {
1538
+ let deletedNodes = matchingNodes ?? [], deletedEdges = matchingEdges ?? [];
1539
+ return (deletedNodes.length > 0 || deletedEdges.length > 0) && store.onDelete?.({
1540
+ nodes: deletedNodes,
1541
+ edges: deletedEdges
1542
+ }), {
1310
1543
  deletedNodes: matchingNodes,
1311
1544
  deletedEdges: matchingEdges
1312
1545
  };
1313
1546
  },
1314
1547
  getIntersectingNodes: (nodeOrRect, partially = !0, nodesToIntersect) => {
1315
1548
  let isRect = isRectObject(nodeOrRect), nodeRect = isRect ? nodeOrRect : getNodeRect(nodeOrRect);
1316
- return nodeRect ? (nodesToIntersect || store.nodes).filter((n) => {
1549
+ return nodeRect ? (nodesToIntersect ?? queryIntersectionCandidates(nodeRect)).filter((n) => {
1317
1550
  let internalNode = nodeLookup.get(n.id);
1318
1551
  if (!internalNode || !isRect && n.id === nodeOrRect.id) return !1;
1319
1552
  let currNodeRect = nodeToRect(internalNode), overlappingArea = getOverlappingArea(currNodeRect, nodeRect);
@@ -1369,10 +1602,6 @@ const createLayoutedEdges = (source) => {
1369
1602
  extent: store.translateExtent
1370
1603
  }), ({ panZoom, extent }) => {
1371
1604
  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
1605
  }), {
1377
1606
  store,
1378
1607
  flow,
@@ -1390,8 +1619,6 @@ const createLayoutedEdges = (source) => {
1390
1619
  applyNodeChanges,
1391
1620
  markInitialNodesMeasured,
1392
1621
  setMeasureRequester,
1393
- resetStoreValues,
1394
- setAriaLabelConfig,
1395
1622
  setAriaLiveMessage,
1396
1623
  setClickConnectStartHandle,
1397
1624
  setConfig,
@@ -1399,15 +1626,11 @@ const createLayoutedEdges = (source) => {
1399
1626
  setDeleteKeyPressed,
1400
1627
  setDomNode,
1401
1628
  setDragging,
1402
- get setEdges() {
1403
- return setEdgesStore;
1404
- },
1629
+ setEdges: setEdgesStore,
1405
1630
  setElementsSelectable,
1406
1631
  setHeight,
1407
1632
  setMultiselectionKeyPressed,
1408
- get setNodes() {
1409
- return setNodesStore;
1410
- },
1633
+ setNodes: setNodesStore,
1411
1634
  setNodesConnectable,
1412
1635
  setNodesDraggable,
1413
1636
  setPanActivationKeyPressed,
@@ -1415,9 +1638,7 @@ const createLayoutedEdges = (source) => {
1415
1638
  setSelectionKeyPressed,
1416
1639
  setSelectionRect,
1417
1640
  setSelectionRectMode,
1418
- get setViewport() {
1419
- return (viewport) => setViewportStore(() => viewport);
1420
- },
1641
+ setViewport: stableSetViewport,
1421
1642
  setWidth,
1422
1643
  setZoomActivationKeyPressed,
1423
1644
  addEdge,
@@ -1426,7 +1647,6 @@ const createLayoutedEdges = (source) => {
1426
1647
  zoomOut,
1427
1648
  fitView,
1428
1649
  setCenter,
1429
- setPaneClickDistance,
1430
1650
  unselectNodesAndEdges,
1431
1651
  addSelectedNodes,
1432
1652
  addSelectedEdges,
@@ -1438,8 +1658,11 @@ const createLayoutedEdges = (source) => {
1438
1658
  reset
1439
1659
  }
1440
1660
  };
1661
+ }, createEdgeStore = (edges) => {
1662
+ let [store, setStore] = typeof edges == "function" ? createStore(edges, []) : createStore(edges);
1663
+ return [store, setStore];
1441
1664
  }, createNodeStore = (nodes) => {
1442
- let [store, setStore] = createStore(nodes);
1665
+ let [store, setStore] = typeof nodes == "function" ? createStore(nodes, []) : createStore(nodes);
1443
1666
  return [store, setStore];
1444
1667
  };
1445
1668
  //#endregion
@@ -1447,21 +1670,21 @@ const createLayoutedEdges = (source) => {
1447
1670
  var _tmpl$$30 = /* @__PURE__ */ template("<svg class=solid-flow__edge-wrapper><g>");
1448
1671
  /** Internal per-edge wrapper: interaction, a11y, viewport culling, and the dynamic edge component. */
1449
1672
  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) => {
1673
+ let edgeRef, { store, actions } = useInternalSolidFlow(), edgeId = () => props.edgeId, edge = () => actions.getEdge(edgeId()), edgeType = () => edge().type ?? "default", selectable = () => isEdgeSelectable(edge(), store), 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) => {
1451
1674
  selectable() && actions.handleEdgeSelection(edgeId()), props.onEdgeClick?.({
1452
1675
  edge: edge(),
1453
1676
  event
1454
1677
  });
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) => {
1678
+ }, onContextMenu = (event) => props.onEdgeContextMenu?.({
1679
+ edge: edge(),
1680
+ event
1681
+ }), onPointerEnter = (event) => props.onEdgePointerEnter?.({
1682
+ edge: edge(),
1683
+ event
1684
+ }), onPointerLeave = (event) => props.onEdgePointerLeave?.({
1685
+ edge: edge(),
1686
+ event
1687
+ }), onKeyDown = (event) => {
1465
1688
  store.disableKeyboardA11y || !elementSelectionKeys.includes(event.key) || !selectable() || (event.key === "Escape" ? (edgeRef?.blur(), actions.unselectNodesAndEdges({ edges: [edge()] })) : actions.addSelectedEdges([edge().id]));
1466
1689
  }, ariaLabel = () => edge().ariaLabel ?? `Edge from ${edge().source} to ${edge().target}`, culled = createMemo(() => isEdgeCulled(edge(), store.cullingViewport));
1467
1690
  return createComponent(EdgeIdContext, {
@@ -1504,9 +1727,9 @@ const EdgeWrapper = (props) => {
1504
1727
  },
1505
1728
  onClick,
1506
1729
  onKeyDown: (e) => focusable() && onKeyDown(e),
1507
- onContextMenu: (e) => onPointerEvent(e, "contextmenu"),
1508
- onPointerEnter: (e) => onPointerEvent(e, "pointerenter"),
1509
- onPointerLeave: (e) => onPointerEvent(e, "pointerleave")
1730
+ onContextMenu,
1731
+ onPointerEnter,
1732
+ onPointerLeave
1510
1733
  }, () => edge().domAttributes), !0), insert(_el$2, createComponent(Dynamic, {
1511
1734
  get component() {
1512
1735
  return edgeComponent();
@@ -1887,7 +2110,10 @@ const Handle = (props) => {
1887
2110
  position: "top",
1888
2111
  isConnectableStart: !0,
1889
2112
  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;
2113
+ }), { 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.connectionFromHandle, connectingFrom = () => {
2114
+ let fromHandle = store.connectionFromHandle;
2115
+ return fromHandle && fromHandle.nodeId === nodeId() && fromHandle.type === _props.type && fromHandle.id === handleId();
2116
+ }, targetState = () => store.connectionTargetByHandle[connectionKey(nodeId(), _props.type, handleId())], connectingTo = () => targetState() !== void 0, isPossibleTargetHandle = () => store.connectionMode === "strict" ? store.connectionFromHandle?.type !== _props.type : nodeId() !== store.connectionFromHandle?.nodeId || handleId() !== store.connectionFromHandle?.id, valid = () => targetState() === "valid", prevConnections = null;
1891
2117
  createEffect(() => {
1892
2118
  if (!_props.onConnect && !_props.onDisconnect) return null;
1893
2119
  let rec = connections[connectionKey(nodeId(), _props.type, _props.id)], map = /* @__PURE__ */ new Map();
@@ -1905,13 +2131,20 @@ const Handle = (props) => {
1905
2131
  }, edge = store.onBeforeConnect?.(handleConnection) ?? handleConnection;
1906
2132
  actions.addEdge(edge), store.onConnect?.(handleConnection);
1907
2133
  }, onPointerDown = (event) => {
2134
+ let gestureLookup = armConnectionGestureLookup({
2135
+ event,
2136
+ real: nodeLookup,
2137
+ domNode: store.domNode,
2138
+ getTransform: () => store.transform,
2139
+ connectionRadius: store.connectionRadius
2140
+ });
1908
2141
  XYHandle.onPointerDown(event, {
1909
2142
  handleId: handleId(),
1910
2143
  nodeId: nodeId(),
1911
2144
  isTarget: isTarget(),
1912
2145
  connectionRadius: store.connectionRadius,
1913
2146
  domNode: store.domNode,
1914
- nodeLookup,
2147
+ nodeLookup: gestureLookup,
1915
2148
  connectionMode: store.connectionMode,
1916
2149
  lib: store.lib,
1917
2150
  autoPanOnConnect: store.autoPanOnConnect,
@@ -2152,12 +2385,11 @@ const NodeWrapper = (props) => {
2152
2385
  ...h ? { height: toPxString(h) } : {}
2153
2386
  };
2154
2387
  }, culled = createMemo(() => isNodeCulled(node(), store.cullingViewport)), style = () => ({
2388
+ ...sizeStyle(),
2155
2389
  "z-index": node().internals.z,
2156
2390
  transform: transform(),
2157
2391
  visibility: culled() || !nodeHasDimensions(node()) ? "hidden" : "visible",
2158
- "pointer-events": culled() ? "none" : void 0,
2159
- ...sizeStyle(),
2160
- ...node().style ?? {}
2392
+ "pointer-events": culled() ? "none" : void 0
2161
2393
  });
2162
2394
  createEffect(() => ({
2163
2395
  valid: nodeTypeValid(),
@@ -2517,7 +2749,7 @@ const InitialNodeTypesMap = {
2517
2749
  pendingEntries = updateEntries, scheduleIdleCallback(() => {
2518
2750
  let updates = new Map(pendingEntries);
2519
2751
  pendingEntries = void 0;
2520
- let { updatedInternals, measurementWrites, changes, parentExpandChildren } = measureNodeInternals(updates, nodeLookup, store.domNode);
2752
+ let { updatedInternals, measurementWrites, changes, parentExpandChildren } = measureNodeInternals(updates, nodeLookup, store.domNode, store.nodeExtent);
2521
2753
  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
2754
  });
2523
2755
  };
@@ -2848,7 +3080,7 @@ const isSetEqual = (a, b) => {
2848
3080
  for (let item of a) if (!b.has(item)) return !1;
2849
3081
  return !0;
2850
3082
  }, 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 = {
3083
+ 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
3084
  x: 0,
2853
3085
  y: 0
2854
3086
  }, 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) => {
@@ -2863,7 +3095,7 @@ const isSetEqual = (a, b) => {
2863
3095
  if (event.pointerType === "touch" && _panOnDrag() !== !1 && !store.selectionKeyPressed || (containerBounds = container?.getBoundingClientRect() ?? null, !containerBounds)) return;
2864
3096
  let eventTargetIsContainer = event.target === container, isNoKeyEvent = !eventTargetIsContainer && !!event.target.closest(".nokey"), isSelectionActive = props.selectionOnDrag && eventTargetIsContainer || store.selectionKeyPressed;
2865
3097
  if (isNoKeyEvent || !isSelecting() || !isSelectionActive || event.button !== 0 || !event.isPrimary) return;
2866
- event.target?.setPointerCapture?.(event.pointerId), selectionInProgress = !1, autoPanStarted = !1;
3098
+ event.target?.setPointerCapture?.(event.pointerId), selectionSpatialLookup.arm((node) => nodeToRect(node)), selectionInProgress = !1, autoPanStarted = !1;
2867
3099
  let { x, y } = getEventPosition(event, containerBounds), userSelectionFlowOrigin = pointToRendererPoint({
2868
3100
  x,
2869
3101
  y
@@ -2890,14 +3122,21 @@ const isSetEqual = (a, b) => {
2890
3122
  width: Math.abs(mouseX - screenStart.x),
2891
3123
  height: Math.abs(mouseY - screenStart.y)
2892
3124
  }, 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();
3125
+ {
3126
+ let [tx, ty, zoom] = store.transform;
3127
+ selectionSpatialLookup.setQueryRect({
3128
+ x: (nextUserSelectRect.x - tx) / zoom,
3129
+ y: (nextUserSelectRect.y - ty) / zoom,
3130
+ width: nextUserSelectRect.width / zoom,
3131
+ height: nextUserSelectRect.height / zoom
3132
+ });
3133
+ }
3134
+ selectedNodeIds = new Set(getNodesInside(selectionSpatialLookup, nextUserSelectRect, store.transform, store.selectionMode === SelectionMode$1.Partial, !0).map((n) => n.id)), selectedEdgeIds = /* @__PURE__ */ new Set();
2896
3135
  for (let nodeId of selectedNodeIds) {
2897
3136
  let nodeConnections = connections[nodeId];
2898
3137
  if (nodeConnections) for (let { edgeId } of Object.values(nodeConnections)) {
2899
3138
  let edge = edgeLookup[edgeId];
2900
- edge && (edge.selectable ?? edgesSelectable) && selectedEdgeIds.add(edgeId);
3139
+ edge && isEdgeSelectable(edge, store) && selectedEdgeIds.add(edgeId);
2901
3140
  }
2902
3141
  }
2903
3142
  isSetEqual(prevSelectedNodeIds, selectedNodeIds) || actions.setNodes((nodes) => {
@@ -3132,7 +3371,7 @@ const Selection = (props) => {
3132
3371
  var _tmpl$$16 = /* @__PURE__ */ template("<div>");
3133
3372
  /** Internal draggable bounding box rendered around multi-selected nodes. */
3134
3373
  const NodeSelection = (props) => {
3135
- let { store, nodeLookup, actions } = useInternalSolidFlow(), [ref$2, setRef] = createSignal(), bounds = () => store.selectionRectMode === "nodes" ? getInternalNodesBounds(nodeLookup, { filter: (node) => !!node.selected }) : null;
3374
+ let { store, nodeLookup, actions } = useInternalSolidFlow(), [ref$2, setRef] = createSignal(), bounds = createMemo(() => store.selectionRectMode === "nodes" ? getInternalNodesBounds(nodeLookup, { filter: (node) => !!node.selected }) : null);
3136
3375
  createEffect(() => ({
3137
3376
  el: ref$2(),
3138
3377
  focusable: !store.disableKeyboardA11y
@@ -3140,13 +3379,13 @@ const NodeSelection = (props) => {
3140
3379
  focusable && el?.focus({ preventScroll: !0 });
3141
3380
  });
3142
3381
  let onContextMenu = (event) => {
3143
- let selectedNodes = store.nodes.filter((n) => n.selected);
3382
+ let selectedNodes = store.selectedNodes;
3144
3383
  props.onSelectionContextMenu?.({
3145
3384
  nodes: selectedNodes,
3146
3385
  event
3147
3386
  });
3148
3387
  }, onClick = (event) => {
3149
- let selectedNodes = store.nodes.filter((n) => n.selected);
3388
+ let selectedNodes = store.selectedNodes;
3150
3389
  props.onSelectionClick?.({
3151
3390
  nodes: selectedNodes,
3152
3391
  event
@@ -3345,14 +3584,11 @@ const KeyHandler = (props) => {
3345
3584
  }, handleWindowBlur = () => {
3346
3585
  resetKeysAndSelection(), cancelPointerGestures();
3347
3586
  }, handleDelete = async () => {
3348
- let selectedNodes = store.nodes.filter((node) => node.selected), selectedEdges = store.edges.filter((edge) => edge.selected), { deletedNodes, deletedEdges } = await deleteElements({
3587
+ let selectedNodes = store.selectedNodes, selectedEdges = store.selectedEdges;
3588
+ await deleteElements({
3349
3589
  nodes: selectedNodes,
3350
3590
  edges: selectedEdges
3351
3591
  });
3352
- (deletedNodes.length > 0 || deletedEdges.length > 0) && store.onDelete?.({
3353
- nodes: deletedNodes,
3354
- edges: deletedEdges
3355
- });
3356
3592
  };
3357
3593
  return isServer || (createEventListenerMap(window, {
3358
3594
  keydown: (event) => {
@@ -3370,7 +3606,7 @@ const KeyHandler = (props) => {
3370
3606
  capture: !0,
3371
3607
  passive: !0
3372
3608
  })), null;
3373
- };
3609
+ }, 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
3610
  //#endregion
3375
3611
  //#region src/components/SolidFlow.tsx
3376
3612
  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 +3615,19 @@ const SolidFlow = (props) => {
3379
3615
  let [domNodeRef, setDomNodeRef] = createSignal(), domNode, _props = merge({
3380
3616
  ...getDefaultFlowStateProps(),
3381
3617
  colorMode: "light",
3382
- deleteKeyCode: "Backspace",
3383
- defaultViewport: {
3384
- x: 0,
3385
- y: 0,
3386
- zoom: 1
3387
- },
3388
- multiSelectionKeyCode: isMacOs() ? "Meta" : "Control",
3389
3618
  nodeClickDistance: 0,
3390
3619
  panOnScroll: !1,
3391
- panActivationKeyCode: "Space",
3392
3620
  preventScrolling: !0,
3393
3621
  panOnDrag: !0,
3394
3622
  panOnScrollSpeed: .5,
3395
3623
  panOnScrollMode: "free",
3396
3624
  paneClickDistance: 0,
3397
- reconnectRadius: 10,
3398
- selectionKeyCode: "Shift",
3399
3625
  selectionOnDrag: !1,
3400
3626
  translateExtent: infiniteExtent,
3401
- zoomActivationKeyCode: isMacOs() ? "Meta" : "Control",
3402
3627
  zoomOnPinch: !0,
3403
3628
  zoomOnDoubleClick: !0,
3404
3629
  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;
3630
+ }, props), htmlProps = omit(_props, ...FLOW_PROP_KEYS, "children"), TypedSolidFlowContext = SolidFlowContext, solidFlow = useContext(TypedSolidFlowContext) ?? createSolidFlow(_props), { store, actions } = solidFlow;
3406
3631
  onSettled(() => (actions.applyInitialFitView(_props.fitView), actions.setConfig(_props), actions.setDomNode(domNode), () => {
3407
3632
  actions.reset();
3408
3633
  })), createEffect(() => domNodeRef(), (el) => {
@@ -3411,11 +3636,6 @@ const SolidFlow = (props) => {
3411
3636
  actions.setWidth(el.clientWidth), actions.setHeight(el.clientHeight);
3412
3637
  });
3413
3638
  return observer.observe(el), () => observer.disconnect();
3414
- }), createEffect(() => ({
3415
- panZoom: store.panZoom,
3416
- distance: _props.paneClickDistance
3417
- }), ({ panZoom, distance }) => {
3418
- panZoom?.setClickDistance(distance);
3419
3639
  });
3420
3640
  let selectedElements = createMemo(() => ({
3421
3641
  nodes: store.selectedNodes,
@@ -3424,7 +3644,7 @@ const SolidFlow = (props) => {
3424
3644
  createEffect(() => selectedElements(), (params) => {
3425
3645
  untrack(() => _props.onSelectionChange)?.(params);
3426
3646
  });
3427
- let rootStyle = () => ({
3647
+ let asyncSeedGuard = () => (_props.nodes?.length, _props.edges?.length, null), rootStyle = () => ({
3428
3648
  width: toPxString(_props.width),
3429
3649
  height: toPxString(_props.height),
3430
3650
  ..._props.style
@@ -3457,6 +3677,7 @@ const SolidFlow = (props) => {
3457
3677
  value: solidFlow,
3458
3678
  get children() {
3459
3679
  return [
3680
+ memo(() => asyncSeedGuard()),
3460
3681
  createComponent(KeyHandler, {
3461
3682
  get selectionKey() {
3462
3683
  return _props.selectionKey;
@@ -3551,9 +3772,6 @@ const SolidFlow = (props) => {
3551
3772
  return [
3552
3773
  _tmpl$$14(),
3553
3774
  createComponent(EdgeRenderer, {
3554
- get reconnectRadius() {
3555
- return _props.reconnectRadius;
3556
- },
3557
3775
  get onEdgeClick() {
3558
3776
  return _props.onEdgeClick;
3559
3777
  },
@@ -3565,9 +3783,6 @@ const SolidFlow = (props) => {
3565
3783
  },
3566
3784
  get onEdgePointerLeave() {
3567
3785
  return _props.onEdgePointerLeave;
3568
- },
3569
- get defaultEdgeOptions() {
3570
- return _props.defaultEdgeOptions;
3571
3786
  }
3572
3787
  }),
3573
3788
  _tmpl$2(),
@@ -4163,24 +4378,23 @@ const getAttrFunction = (func) => func instanceof Function ? func : () => func,
4163
4378
  nodeBorderRadius: 5,
4164
4379
  nodeStrokeWidth: 2,
4165
4380
  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 = () => ({
4381
+ }), 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}`), viewBB = createMemo(() => ({
4167
4382
  x: -store.viewport.x / store.viewport.zoom,
4168
4383
  y: -store.viewport.y / store.viewport.zoom,
4169
4384
  width: store.width / store.viewport.zoom,
4170
4385
  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();
4386
+ })), boundingRect = createMemo(() => {
4387
+ let view = viewBB();
4388
+ if (nodeLookup.size === 0) return view;
4389
+ let bounds = getInternalNodesBounds(nodeLookup);
4390
+ return !Number.isFinite(bounds.x) || !Number.isFinite(bounds.width) ? view : getBoundsOfRects(bounds, view);
4391
+ }), viewScale = createMemo(() => Math.max(boundingRect().width / _props.width, boundingRect().height / _props.height)), getViewWidth = () => viewScale() * _props.width, getViewHeight = () => viewScale() * _props.height, getOffset = () => 5 * viewScale(), getX = () => {
4392
+ let rect = boundingRect();
4393
+ return rect.x - (getViewWidth() - rect.width) / 2 - getOffset();
4177
4394
  }, 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
- };
4395
+ let rect = boundingRect();
4396
+ return rect.y - (getViewHeight() - rect.height) / 2 - getOffset();
4397
+ }, 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
4398
  return createComponent(Panel, mergeProps({
4185
4399
  get position() {
4186
4400
  return _props.position;
@@ -4211,7 +4425,7 @@ const getAttrFunction = (func) => func instanceof Function ? func : () => func,
4211
4425
  domNode: el,
4212
4426
  panZoom,
4213
4427
  getTransform: () => store.transform,
4214
- getViewScale
4428
+ getViewScale: viewScale
4215
4429
  });
4216
4430
  return setMinimap(instance), () => {
4217
4431
  instance.destroy();
@@ -4272,9 +4486,7 @@ const getAttrFunction = (func) => func instanceof Function ? func : () => func,
4272
4486
  get strokeWidth() {
4273
4487
  return _props.nodeStrokeWidth;
4274
4488
  },
4275
- get shapeRendering() {
4276
- return shapeRendering();
4277
- },
4489
+ shapeRendering,
4278
4490
  get width() {
4279
4491
  return nodeDimensions().width;
4280
4492
  },
@@ -4312,7 +4524,7 @@ const getAttrFunction = (func) => func instanceof Function ? func : () => func,
4312
4524
  s: strokeWidth(),
4313
4525
  h: labelledBy(),
4314
4526
  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`
4527
+ M${viewBB().x},${viewBB().y}h${viewBB().width}v${viewBB().height}h${-viewBB().width}z`
4316
4528
  }), ({ e, t, a, o, i, n, s, h, r }, _p$) => {
4317
4529
  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
4530
  }), _el$;