@dschz/solid-flow 0.3.0-next.5 → 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;
@@ -451,8 +696,6 @@ const A11yDescriptions = () => {
451
696
  }, cullingViewport);
452
697
  }, getDefaultFlowStateProps = () => ({
453
698
  id: "1",
454
- nodes: [],
455
- edges: [],
456
699
  nodeOrigin: [0, 0],
457
700
  nodeExtent: infiniteExtent,
458
701
  defaultEdgeOptions: {},
@@ -551,14 +794,48 @@ var RecordMapFacade = class {
551
794
  }
552
795
  };
553
796
  //#endregion
554
- //#region src/core/projections/connections.ts
797
+ //#region src/core/measurementIngest.ts
555
798
  /**
556
- * Lookup keys for the connection index. Each edge is registered under six
557
- * keys for both of its endpoints: the node, the node+handle-type, and (when
558
- * a handle id is present) the node+type+handle:
559
- * `${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.
560
804
  */
561
- 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(() => {
562
839
  let out = {}, add = (key, entry, connection) => {
563
840
  (out[key] ??= {})[entry] = connection;
564
841
  };
@@ -623,10 +900,6 @@ const EMPTY_AUTO_INDEX = /* @__PURE__ */ new Map(), createInternalNodes = (sourc
623
900
  }, row.internals.z = z;
624
901
  } else source.nodes.length;
625
902
  }
626
- if (userNode.parentId) {
627
- let parent = entryById.get(userNode.parentId);
628
- parent?.store.row.internals.positionAbsolute.x, parent?.store.row.internals.z;
629
- }
630
903
  return { row };
631
904
  }, {}, { key: "id" }), entry = {
632
905
  store,
@@ -695,8 +968,8 @@ const createLayoutedEdges = (source) => {
695
968
  let rowStores = mapArray(() => source.edges, (edgeAccessor) => ({
696
969
  id: edgeAccessor().id,
697
970
  store: createProjection(() => {
698
- let edge = edgeAccessor(), row = buildRow(source, edge);
699
- 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) };
700
973
  }, { row: null }, { key: "id" })
701
974
  }), { keyed: (edge) => edge.id }), assigned = /* @__PURE__ */ new Map();
702
975
  return createProjection((draft) => {
@@ -712,7 +985,7 @@ const createLayoutedEdges = (source) => {
712
985
  });
713
986
  }, buildRow = (source, edge) => {
714
987
  let sourceNode = source.nodeLookup.get(edge.source), targetNode = source.nodeLookup.get(edge.target);
715
- if (!sourceNode || !targetNode) return source.nodeLookup.size, null;
988
+ if (!sourceNode || !targetNode) return null;
716
989
  let edgePosition = getEdgePosition({
717
990
  id: edge.id,
718
991
  sourceNode,
@@ -742,7 +1015,33 @@ const createLayoutedEdges = (source) => {
742
1015
  let out = {};
743
1016
  for (let node of source.nodes) node.parentId && (out[node.parentId] = !0);
744
1017
  return out;
745
- }, {}, { 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) => {
746
1045
  if (fitView && !initialViewport && width && height) {
747
1046
  let bounds = getInternalNodesBounds(nodeLookup, { filter: (node) => !!((node.width || node.initialWidth) && (node.height || node.initialHeight)) });
748
1047
  return getViewportForBounds$1(bounds, width, height, .5, 2, .1);
@@ -753,7 +1052,7 @@ const createLayoutedEdges = (source) => {
753
1052
  zoom: 1
754
1053
  };
755
1054
  }, createFlowState = (props, injections = {}) => {
756
- 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), [nodesStore, setNodesStore] = createStore(_props.nodes), [edgesStore, setEdgesStore] = createStore(_props.edges), [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,19 +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
- for (let node of next);
779
- return { next };
780
- }, ({ next }) => {
781
- setNodesStore(() => next);
782
- }, { defer: !0 }), createEffect(() => {
783
- let next = config().edges;
784
- for (let edge of next);
785
- return { next };
786
- }, ({ next }) => {
787
- setEdgesStore(() => next);
788
- }, { defer: !0 }), createEffect(() => config().viewport, (next) => {
1075
+ createEffect(() => config().viewport, (next) => {
789
1076
  next && setViewportStore(() => next);
790
1077
  }, { defer: !0 });
791
1078
  let transform = createMemo(() => [
@@ -797,25 +1084,29 @@ const createLayoutedEdges = (source) => {
797
1084
  if (nodes.length === 0) return !1;
798
1085
  for (let node of nodes) if (!node.hidden && (node.measured?.width === void 0 || node.measured?.height === void 0)) return !1;
799
1086
  return !0;
800
- }), 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({
801
1107
  width: 0,
802
1108
  height: 0
803
1109
  }, config, {
804
- get _colorMode() {
805
- return config().colorMode;
806
- },
807
- get _colorModeSSR() {
808
- return config().colorModeSSR;
809
- },
810
- get _connection() {
811
- return connection();
812
- },
813
- get _nodeTypes() {
814
- return config().nodeTypes;
815
- },
816
- get _edgeTypes() {
817
- return config().edgeTypes;
818
- },
819
1110
  get ariaLabelConfig() {
820
1111
  return ariaLabelConfig();
821
1112
  },
@@ -826,14 +1117,16 @@ const createLayoutedEdges = (source) => {
826
1117
  return clickConnectStartHandle();
827
1118
  },
828
1119
  get colorMode() {
829
- return this._colorMode === "system" ? prefersDark() ? "dark" : "light" : this._colorMode;
1120
+ return resolvedColorMode();
830
1121
  },
831
1122
  get connection() {
832
- let state = connection();
833
- return {
834
- ...state,
835
- to: state.inProgress ? pointToRendererPoint(state.to, this.transform) : state.to
836
- };
1123
+ return projectedConnection();
1124
+ },
1125
+ get connectionFromHandle() {
1126
+ return connectionFromHandle();
1127
+ },
1128
+ get connectionTargetByHandle() {
1129
+ return connectionTargetByHandle;
837
1130
  },
838
1131
  get domNode() {
839
1132
  return domNode();
@@ -842,10 +1135,7 @@ const createLayoutedEdges = (source) => {
842
1135
  return dragging();
843
1136
  },
844
1137
  get edgeTypes() {
845
- return {
846
- ...initialEdgeTypes,
847
- ...this._edgeTypes
848
- };
1138
+ return mergedEdgeTypes();
849
1139
  },
850
1140
  get elementsSelectable() {
851
1141
  return elementsSelectable();
@@ -878,19 +1168,16 @@ const createLayoutedEdges = (source) => {
878
1168
  return nodesDraggable();
879
1169
  },
880
1170
  get nodeTypes() {
881
- return {
882
- ...initialNodeTypes,
883
- ...this._nodeTypes
884
- };
1171
+ return mergedNodeTypes();
885
1172
  },
886
1173
  get panZoom() {
887
1174
  return panZoom();
888
1175
  },
889
1176
  get selectedNodes() {
890
- return nodesStore.filter((node) => node.selected);
1177
+ return selectedNodesView();
891
1178
  },
892
1179
  get selectedEdges() {
893
- return edgesStore.filter((edge) => edge.selected);
1180
+ return selectedEdgesView();
894
1181
  },
895
1182
  get selectionRect() {
896
1183
  return selectionRect();
@@ -1005,33 +1292,11 @@ const createLayoutedEdges = (source) => {
1005
1292
  setNodesStore((nodes) => {
1006
1293
  for (let node of nodes) nodeDragItems.has(node.id) && (node.dragging = dragging, node.position = nodeDragItems.get(node.id).position);
1007
1294
  });
1008
- }, applyMeasurementWrites = (writes) => {
1009
- setMeasurementsStore((draft) => {
1010
- for (let write of writes) if (write.hidden) {
1011
- let entry = draft[write.id];
1012
- entry && (entry.handleBounds = void 0);
1013
- } else draft[write.id] = {
1014
- measured: write.measured,
1015
- handleBounds: write.handleBounds
1016
- };
1017
- });
1018
- }, applyNodeChanges = (changes) => {
1019
- changes.length !== 0 && setNodesStore((nodes) => {
1020
- let nodeById = new Map(nodes.map((node) => [node.id, node]));
1021
- for (let change of changes) {
1022
- let node = nodeById.get(change.id);
1023
- if (node) switch (change.type) {
1024
- case "dimensions":
1025
- change.setAttributes && (node.width = change.dimensions?.width ?? node.width, node.height = change.dimensions?.height ?? node.height), node.measured = {
1026
- ...node.measured,
1027
- ...change.dimensions
1028
- };
1029
- break;
1030
- case "position": node.position = change.position ?? node.position;
1031
- }
1032
- }
1033
- });
1034
- }, markInitialNodesMeasured = () => {
1295
+ }, { applyMeasurementWrites, applyNodeChanges } = createMeasurementIngest({
1296
+ setMeasurementsStore,
1297
+ setNodesStore,
1298
+ nodes: () => nodesStore
1299
+ }), markInitialNodesMeasured = () => {
1035
1300
  initialNodesMeasured = !0, tryInitialFitView();
1036
1301
  }, requestMeasure = () => {}, setMeasureRequester = (fn) => {
1037
1302
  requestMeasure = fn;
@@ -1046,66 +1311,16 @@ const createLayoutedEdges = (source) => {
1046
1311
  ease: options?.ease,
1047
1312
  interpolate: options?.interpolate
1048
1313
  }), Promise.resolve(!0)) : Promise.resolve(!1);
1049
- }, setPaneClickDistance = (distance) => {
1050
- store.panZoom?.setClickDistance(distance);
1051
- }, unselectNodesAndEdges = ({ nodes: _nodes, edges } = {}) => {
1052
- let nodesToUnselect = new Set((_nodes || store.nodes).map(({ id }) => id));
1053
- nodesToUnselect.size && setNodesStore((nodes) => {
1054
- for (let node of nodes) nodesToUnselect.has(node.id) && (node.selected = !1);
1055
- });
1056
- let edgesToUnselect = new Set((edges ?? store.edges).map(({ id }) => id));
1057
- edgesToUnselect.size && setEdgesStore((edges) => {
1058
- for (let edge of edges) edgesToUnselect.has(edge.id) && (edge.selected = !1);
1059
- }), flush();
1060
- }, addSelectedNodes = (ids) => {
1061
- let isMultiSelection = store.multiselectionKeyPressed;
1062
- setNodesStore((nodes) => {
1063
- for (let node of nodes) {
1064
- let nodeWillBeSelected = ids.includes(node.id), selected = isMultiSelection && node.selected || nodeWillBeSelected;
1065
- node.selected !== selected && (node.selected = selected);
1066
- }
1067
- }), isMultiSelection || unselectNodesAndEdges({ nodes: [] }), flush();
1068
- }, addSelectedEdges = (ids) => {
1069
- let isMultiSelection = store.multiselectionKeyPressed;
1070
- setEdgesStore((edges) => {
1071
- for (let edge of edges) {
1072
- let edgeWillBeSelected = ids.includes(edge.id), selected = isMultiSelection && edge.selected || edgeWillBeSelected;
1073
- edge.selected !== selected && (edge.selected = selected);
1074
- }
1075
- }), isMultiSelection || unselectNodesAndEdges({ edges: [] }), flush();
1076
- }, handleNodeSelection = (id, unselect, nodeRef) => {
1077
- let node = store.nodes.find((n) => n.id === id);
1078
- node && (setSelectionRect(void 0), setSelectionRectMode(void 0), node.selected ? (unselect || node.selected && store.multiselectionKeyPressed) && (unselectNodesAndEdges({
1079
- nodes: [node],
1080
- edges: []
1081
- }), requestAnimationFrame(() => nodeRef?.blur())) : addSelectedNodes([id]));
1082
- }, handleEdgeSelection = (id) => {
1083
- let edge = edgeLookup[id];
1084
- edge && (edge.selectable || store.elementsSelectable && edge.selectable === void 0) && (setSelectionRect(void 0), setSelectionRectMode(void 0), edge.selected ? edge.selected && store.multiselectionKeyPressed && unselectNodesAndEdges({
1085
- nodes: [],
1086
- edges: [edge]
1087
- }) : addSelectedEdges([id]));
1088
- }, moveSelectedNodes = (direction, factor) => {
1089
- 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;
1090
- for (let node of nodeLookup.values()) {
1091
- if (!(node.selected && (node.draggable || store.nodesDraggable && node.draggable === void 0))) continue;
1092
- let nextPosition = {
1093
- x: node.internals.positionAbsolute.x + xDiff,
1094
- y: node.internals.positionAbsolute.y + yDiff
1095
- };
1096
- store.snapGrid && (nextPosition = snapPosition(nextPosition, store.snapGrid));
1097
- let { position } = calculateNodePosition({
1098
- nodeId: node.id,
1099
- nextPosition,
1100
- nodeLookup,
1101
- nodeExtent: store.nodeExtent,
1102
- nodeOrigin: store.nodeOrigin,
1103
- onError: store.onError
1104
- });
1105
- nodeUpdates.set(node.id, { position });
1106
- }
1107
- updateNodePositions(nodeUpdates);
1108
- }, 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({
1109
1324
  delta,
1110
1325
  panZoom: store.panZoom,
1111
1326
  transform: store.transform,
@@ -1182,8 +1397,27 @@ const createLayoutedEdges = (source) => {
1182
1397
  get snapGrid() {
1183
1398
  return store.snapGrid;
1184
1399
  }
1185
- }, getNodeRect = (node) => {
1186
- 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 = {
1187
1421
  ...nodeToUse,
1188
1422
  position,
1189
1423
  width: nodeToUse.measured?.width ?? nodeToUse.width,
@@ -1237,7 +1471,7 @@ const createLayoutedEdges = (source) => {
1237
1471
  x,
1238
1472
  y,
1239
1473
  zoom
1240
- ], _snapGrid !== null, _snapGrid || [1, 1]);
1474
+ ], !!_snapGrid, _snapGrid || [1, 1]);
1241
1475
  },
1242
1476
  flowToScreenPosition: (position) => {
1243
1477
  if (!store.domNode) return position;
@@ -1301,14 +1535,18 @@ const createLayoutedEdges = (source) => {
1301
1535
  let remainingNodes = store.nodes.filter((node) => !matchingNodes.some(({ id }) => id === node.id));
1302
1536
  store.onNodesDelete?.(matchingNodes), setNodesStore(() => remainingNodes);
1303
1537
  }
1304
- return {
1538
+ let deletedNodes = matchingNodes ?? [], deletedEdges = matchingEdges ?? [];
1539
+ return (deletedNodes.length > 0 || deletedEdges.length > 0) && store.onDelete?.({
1540
+ nodes: deletedNodes,
1541
+ edges: deletedEdges
1542
+ }), {
1305
1543
  deletedNodes: matchingNodes,
1306
1544
  deletedEdges: matchingEdges
1307
1545
  };
1308
1546
  },
1309
1547
  getIntersectingNodes: (nodeOrRect, partially = !0, nodesToIntersect) => {
1310
1548
  let isRect = isRectObject(nodeOrRect), nodeRect = isRect ? nodeOrRect : getNodeRect(nodeOrRect);
1311
- return nodeRect ? (nodesToIntersect || store.nodes).filter((n) => {
1549
+ return nodeRect ? (nodesToIntersect ?? queryIntersectionCandidates(nodeRect)).filter((n) => {
1312
1550
  let internalNode = nodeLookup.get(n.id);
1313
1551
  if (!internalNode || !isRect && n.id === nodeOrRect.id) return !1;
1314
1552
  let currNodeRect = nodeToRect(internalNode), overlappingArea = getOverlappingArea(currNodeRect, nodeRect);
@@ -1364,10 +1602,6 @@ const createLayoutedEdges = (source) => {
1364
1602
  extent: store.translateExtent
1365
1603
  }), ({ panZoom, extent }) => {
1366
1604
  panZoom?.setTranslateExtent(extent);
1367
- }), createEffect(() => new Set(store.nodes.map((n) => n.id)), (currentIds) => {
1368
- setMeasurementsStore((draft) => {
1369
- for (let id of Object.keys(draft)) currentIds.has(id) || delete draft[id];
1370
- });
1371
1605
  }), {
1372
1606
  store,
1373
1607
  flow,
@@ -1385,8 +1619,6 @@ const createLayoutedEdges = (source) => {
1385
1619
  applyNodeChanges,
1386
1620
  markInitialNodesMeasured,
1387
1621
  setMeasureRequester,
1388
- resetStoreValues,
1389
- setAriaLabelConfig,
1390
1622
  setAriaLiveMessage,
1391
1623
  setClickConnectStartHandle,
1392
1624
  setConfig,
@@ -1394,15 +1626,11 @@ const createLayoutedEdges = (source) => {
1394
1626
  setDeleteKeyPressed,
1395
1627
  setDomNode,
1396
1628
  setDragging,
1397
- get setEdges() {
1398
- return setEdgesStore;
1399
- },
1629
+ setEdges: setEdgesStore,
1400
1630
  setElementsSelectable,
1401
1631
  setHeight,
1402
1632
  setMultiselectionKeyPressed,
1403
- get setNodes() {
1404
- return setNodesStore;
1405
- },
1633
+ setNodes: setNodesStore,
1406
1634
  setNodesConnectable,
1407
1635
  setNodesDraggable,
1408
1636
  setPanActivationKeyPressed,
@@ -1410,9 +1638,7 @@ const createLayoutedEdges = (source) => {
1410
1638
  setSelectionKeyPressed,
1411
1639
  setSelectionRect,
1412
1640
  setSelectionRectMode,
1413
- get setViewport() {
1414
- return (viewport) => setViewportStore(() => viewport);
1415
- },
1641
+ setViewport: stableSetViewport,
1416
1642
  setWidth,
1417
1643
  setZoomActivationKeyPressed,
1418
1644
  addEdge,
@@ -1421,7 +1647,6 @@ const createLayoutedEdges = (source) => {
1421
1647
  zoomOut,
1422
1648
  fitView,
1423
1649
  setCenter,
1424
- setPaneClickDistance,
1425
1650
  unselectNodesAndEdges,
1426
1651
  addSelectedNodes,
1427
1652
  addSelectedEdges,
@@ -1433,8 +1658,11 @@ const createLayoutedEdges = (source) => {
1433
1658
  reset
1434
1659
  }
1435
1660
  };
1661
+ }, createEdgeStore = (edges) => {
1662
+ let [store, setStore] = typeof edges == "function" ? createStore(edges, []) : createStore(edges);
1663
+ return [store, setStore];
1436
1664
  }, createNodeStore = (nodes) => {
1437
- let [store, setStore] = createStore(nodes);
1665
+ let [store, setStore] = typeof nodes == "function" ? createStore(nodes, []) : createStore(nodes);
1438
1666
  return [store, setStore];
1439
1667
  };
1440
1668
  //#endregion
@@ -1442,21 +1670,21 @@ const createLayoutedEdges = (source) => {
1442
1670
  var _tmpl$$30 = /* @__PURE__ */ template("<svg class=solid-flow__edge-wrapper><g>");
1443
1671
  /** Internal per-edge wrapper: interaction, a11y, viewport culling, and the dynamic edge component. */
1444
1672
  const EdgeWrapper = (props) => {
1445
- 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) => {
1446
1674
  selectable() && actions.handleEdgeSelection(edgeId()), props.onEdgeClick?.({
1447
1675
  edge: edge(),
1448
1676
  event
1449
1677
  });
1450
- }, onPointerEvent = (event, type) => {
1451
- ({
1452
- contextmenu: props.onEdgeContextMenu,
1453
- pointerenter: props.onEdgePointerEnter,
1454
- pointerleave: props.onEdgePointerLeave
1455
- })[type]?.({
1456
- edge: edge(),
1457
- event
1458
- });
1459
- }, 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) => {
1460
1688
  store.disableKeyboardA11y || !elementSelectionKeys.includes(event.key) || !selectable() || (event.key === "Escape" ? (edgeRef?.blur(), actions.unselectNodesAndEdges({ edges: [edge()] })) : actions.addSelectedEdges([edge().id]));
1461
1689
  }, ariaLabel = () => edge().ariaLabel ?? `Edge from ${edge().source} to ${edge().target}`, culled = createMemo(() => isEdgeCulled(edge(), store.cullingViewport));
1462
1690
  return createComponent(EdgeIdContext, {
@@ -1499,9 +1727,9 @@ const EdgeWrapper = (props) => {
1499
1727
  },
1500
1728
  onClick,
1501
1729
  onKeyDown: (e) => focusable() && onKeyDown(e),
1502
- onContextMenu: (e) => onPointerEvent(e, "contextmenu"),
1503
- onPointerEnter: (e) => onPointerEvent(e, "pointerenter"),
1504
- onPointerLeave: (e) => onPointerEvent(e, "pointerleave")
1730
+ onContextMenu,
1731
+ onPointerEnter,
1732
+ onPointerLeave
1505
1733
  }, () => edge().domAttributes), !0), insert(_el$2, createComponent(Dynamic, {
1506
1734
  get component() {
1507
1735
  return edgeComponent();
@@ -1882,7 +2110,10 @@ const Handle = (props) => {
1882
2110
  position: "top",
1883
2111
  isConnectableStart: !0,
1884
2112
  isConnectableEnd: !0
1885
- }), { 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;
1886
2117
  createEffect(() => {
1887
2118
  if (!_props.onConnect && !_props.onDisconnect) return null;
1888
2119
  let rec = connections[connectionKey(nodeId(), _props.type, _props.id)], map = /* @__PURE__ */ new Map();
@@ -1900,13 +2131,20 @@ const Handle = (props) => {
1900
2131
  }, edge = store.onBeforeConnect?.(handleConnection) ?? handleConnection;
1901
2132
  actions.addEdge(edge), store.onConnect?.(handleConnection);
1902
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
+ });
1903
2141
  XYHandle.onPointerDown(event, {
1904
2142
  handleId: handleId(),
1905
2143
  nodeId: nodeId(),
1906
2144
  isTarget: isTarget(),
1907
2145
  connectionRadius: store.connectionRadius,
1908
2146
  domNode: store.domNode,
1909
- nodeLookup,
2147
+ nodeLookup: gestureLookup,
1910
2148
  connectionMode: store.connectionMode,
1911
2149
  lib: store.lib,
1912
2150
  autoPanOnConnect: store.autoPanOnConnect,
@@ -2147,12 +2385,11 @@ const NodeWrapper = (props) => {
2147
2385
  ...h ? { height: toPxString(h) } : {}
2148
2386
  };
2149
2387
  }, culled = createMemo(() => isNodeCulled(node(), store.cullingViewport)), style = () => ({
2388
+ ...sizeStyle(),
2150
2389
  "z-index": node().internals.z,
2151
2390
  transform: transform(),
2152
2391
  visibility: culled() || !nodeHasDimensions(node()) ? "hidden" : "visible",
2153
- "pointer-events": culled() ? "none" : void 0,
2154
- ...sizeStyle(),
2155
- ...node().style ?? {}
2392
+ "pointer-events": culled() ? "none" : void 0
2156
2393
  });
2157
2394
  createEffect(() => ({
2158
2395
  valid: nodeTypeValid(),
@@ -2512,7 +2749,7 @@ const InitialNodeTypesMap = {
2512
2749
  pendingEntries = updateEntries, scheduleIdleCallback(() => {
2513
2750
  let updates = new Map(pendingEntries);
2514
2751
  pendingEntries = void 0;
2515
- let { updatedInternals, measurementWrites, changes, parentExpandChildren } = measureNodeInternals(updates, nodeLookup, store.domNode);
2752
+ let { updatedInternals, measurementWrites, changes, parentExpandChildren } = measureNodeInternals(updates, nodeLookup, store.domNode, store.nodeExtent);
2516
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());
2517
2754
  });
2518
2755
  };
@@ -2843,7 +3080,7 @@ const isSetEqual = (a, b) => {
2843
3080
  for (let item of a) if (!b.has(item)) return !1;
2844
3081
  return !0;
2845
3082
  }, Pane = (props) => {
2846
- 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 = {
2847
3084
  x: 0,
2848
3085
  y: 0
2849
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) => {
@@ -2858,7 +3095,7 @@ const isSetEqual = (a, b) => {
2858
3095
  if (event.pointerType === "touch" && _panOnDrag() !== !1 && !store.selectionKeyPressed || (containerBounds = container?.getBoundingClientRect() ?? null, !containerBounds)) return;
2859
3096
  let eventTargetIsContainer = event.target === container, isNoKeyEvent = !eventTargetIsContainer && !!event.target.closest(".nokey"), isSelectionActive = props.selectionOnDrag && eventTargetIsContainer || store.selectionKeyPressed;
2860
3097
  if (isNoKeyEvent || !isSelecting() || !isSelectionActive || event.button !== 0 || !event.isPrimary) return;
2861
- event.target?.setPointerCapture?.(event.pointerId), selectionInProgress = !1, autoPanStarted = !1;
3098
+ event.target?.setPointerCapture?.(event.pointerId), selectionSpatialLookup.arm((node) => nodeToRect(node)), selectionInProgress = !1, autoPanStarted = !1;
2862
3099
  let { x, y } = getEventPosition(event, containerBounds), userSelectionFlowOrigin = pointToRendererPoint({
2863
3100
  x,
2864
3101
  y
@@ -2885,14 +3122,21 @@ const isSetEqual = (a, b) => {
2885
3122
  width: Math.abs(mouseX - screenStart.x),
2886
3123
  height: Math.abs(mouseY - screenStart.y)
2887
3124
  }, prevSelectedNodeIds = selectedNodeIds, prevSelectedEdgeIds = selectedEdgeIds;
2888
- selectedNodeIds = new Set(getNodesInside(nodeLookup, nextUserSelectRect, store.transform, store.selectionMode === SelectionMode$1.Partial, !0).map((n) => n.id));
2889
- let edgesSelectable = store.defaultEdgeOptions.selectable ?? !0;
2890
- 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();
2891
3135
  for (let nodeId of selectedNodeIds) {
2892
3136
  let nodeConnections = connections[nodeId];
2893
3137
  if (nodeConnections) for (let { edgeId } of Object.values(nodeConnections)) {
2894
3138
  let edge = edgeLookup[edgeId];
2895
- edge && (edge.selectable ?? edgesSelectable) && selectedEdgeIds.add(edgeId);
3139
+ edge && isEdgeSelectable(edge, store) && selectedEdgeIds.add(edgeId);
2896
3140
  }
2897
3141
  }
2898
3142
  isSetEqual(prevSelectedNodeIds, selectedNodeIds) || actions.setNodes((nodes) => {
@@ -3127,7 +3371,7 @@ const Selection = (props) => {
3127
3371
  var _tmpl$$16 = /* @__PURE__ */ template("<div>");
3128
3372
  /** Internal draggable bounding box rendered around multi-selected nodes. */
3129
3373
  const NodeSelection = (props) => {
3130
- 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);
3131
3375
  createEffect(() => ({
3132
3376
  el: ref$2(),
3133
3377
  focusable: !store.disableKeyboardA11y
@@ -3135,13 +3379,13 @@ const NodeSelection = (props) => {
3135
3379
  focusable && el?.focus({ preventScroll: !0 });
3136
3380
  });
3137
3381
  let onContextMenu = (event) => {
3138
- let selectedNodes = store.nodes.filter((n) => n.selected);
3382
+ let selectedNodes = store.selectedNodes;
3139
3383
  props.onSelectionContextMenu?.({
3140
3384
  nodes: selectedNodes,
3141
3385
  event
3142
3386
  });
3143
3387
  }, onClick = (event) => {
3144
- let selectedNodes = store.nodes.filter((n) => n.selected);
3388
+ let selectedNodes = store.selectedNodes;
3145
3389
  props.onSelectionClick?.({
3146
3390
  nodes: selectedNodes,
3147
3391
  event
@@ -3340,14 +3584,11 @@ const KeyHandler = (props) => {
3340
3584
  }, handleWindowBlur = () => {
3341
3585
  resetKeysAndSelection(), cancelPointerGestures();
3342
3586
  }, handleDelete = async () => {
3343
- 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({
3344
3589
  nodes: selectedNodes,
3345
3590
  edges: selectedEdges
3346
3591
  });
3347
- (deletedNodes.length > 0 || deletedEdges.length > 0) && store.onDelete?.({
3348
- nodes: deletedNodes,
3349
- edges: deletedEdges
3350
- });
3351
3592
  };
3352
3593
  return isServer || (createEventListenerMap(window, {
3353
3594
  keydown: (event) => {
@@ -3365,7 +3606,7 @@ const KeyHandler = (props) => {
3365
3606
  capture: !0,
3366
3607
  passive: !0
3367
3608
  })), null;
3368
- };
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(".");
3369
3610
  //#endregion
3370
3611
  //#region src/components/SolidFlow.tsx
3371
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>");
@@ -3374,30 +3615,19 @@ const SolidFlow = (props) => {
3374
3615
  let [domNodeRef, setDomNodeRef] = createSignal(), domNode, _props = merge({
3375
3616
  ...getDefaultFlowStateProps(),
3376
3617
  colorMode: "light",
3377
- deleteKeyCode: "Backspace",
3378
- defaultViewport: {
3379
- x: 0,
3380
- y: 0,
3381
- zoom: 1
3382
- },
3383
- multiSelectionKeyCode: isMacOs() ? "Meta" : "Control",
3384
3618
  nodeClickDistance: 0,
3385
3619
  panOnScroll: !1,
3386
- panActivationKeyCode: "Space",
3387
3620
  preventScrolling: !0,
3388
3621
  panOnDrag: !0,
3389
3622
  panOnScrollSpeed: .5,
3390
3623
  panOnScrollMode: "free",
3391
3624
  paneClickDistance: 0,
3392
- reconnectRadius: 10,
3393
- selectionKeyCode: "Shift",
3394
3625
  selectionOnDrag: !1,
3395
3626
  translateExtent: infiniteExtent,
3396
- zoomActivationKeyCode: isMacOs() ? "Meta" : "Control",
3397
3627
  zoomOnPinch: !0,
3398
3628
  zoomOnDoubleClick: !0,
3399
3629
  zoomOnScroll: !0
3400
- }, props), htmlProps = omit(_props, "nodes", "edges", "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;
3401
3631
  onSettled(() => (actions.applyInitialFitView(_props.fitView), actions.setConfig(_props), actions.setDomNode(domNode), () => {
3402
3632
  actions.reset();
3403
3633
  })), createEffect(() => domNodeRef(), (el) => {
@@ -3406,11 +3636,6 @@ const SolidFlow = (props) => {
3406
3636
  actions.setWidth(el.clientWidth), actions.setHeight(el.clientHeight);
3407
3637
  });
3408
3638
  return observer.observe(el), () => observer.disconnect();
3409
- }), createEffect(() => ({
3410
- panZoom: store.panZoom,
3411
- distance: _props.paneClickDistance
3412
- }), ({ panZoom, distance }) => {
3413
- panZoom?.setClickDistance(distance);
3414
3639
  });
3415
3640
  let selectedElements = createMemo(() => ({
3416
3641
  nodes: store.selectedNodes,
@@ -3419,7 +3644,7 @@ const SolidFlow = (props) => {
3419
3644
  createEffect(() => selectedElements(), (params) => {
3420
3645
  untrack(() => _props.onSelectionChange)?.(params);
3421
3646
  });
3422
- let rootStyle = () => ({
3647
+ let asyncSeedGuard = () => (_props.nodes?.length, _props.edges?.length, null), rootStyle = () => ({
3423
3648
  width: toPxString(_props.width),
3424
3649
  height: toPxString(_props.height),
3425
3650
  ..._props.style
@@ -3452,6 +3677,7 @@ const SolidFlow = (props) => {
3452
3677
  value: solidFlow,
3453
3678
  get children() {
3454
3679
  return [
3680
+ memo(() => asyncSeedGuard()),
3455
3681
  createComponent(KeyHandler, {
3456
3682
  get selectionKey() {
3457
3683
  return _props.selectionKey;
@@ -3546,9 +3772,6 @@ const SolidFlow = (props) => {
3546
3772
  return [
3547
3773
  _tmpl$$14(),
3548
3774
  createComponent(EdgeRenderer, {
3549
- get reconnectRadius() {
3550
- return _props.reconnectRadius;
3551
- },
3552
3775
  get onEdgeClick() {
3553
3776
  return _props.onEdgeClick;
3554
3777
  },
@@ -3560,9 +3783,6 @@ const SolidFlow = (props) => {
3560
3783
  },
3561
3784
  get onEdgePointerLeave() {
3562
3785
  return _props.onEdgePointerLeave;
3563
- },
3564
- get defaultEdgeOptions() {
3565
- return _props.defaultEdgeOptions;
3566
3786
  }
3567
3787
  }),
3568
3788
  _tmpl$2(),
@@ -4158,24 +4378,23 @@ const getAttrFunction = (func) => func instanceof Function ? func : () => func,
4158
4378
  nodeBorderRadius: 5,
4159
4379
  nodeStrokeWidth: 2,
4160
4380
  style: {}
4161
- }), 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(() => ({
4162
4382
  x: -store.viewport.x / store.viewport.zoom,
4163
4383
  y: -store.viewport.y / store.viewport.zoom,
4164
4384
  width: store.width / store.viewport.zoom,
4165
4385
  height: store.height / store.viewport.zoom
4166
- }), getBoundingRect = () => {
4167
- let viewBB = getViewBB();
4168
- return nodeLookup.size > 0 ? getBoundsOfRects(getInternalNodesBounds(nodeLookup), viewBB) : viewBB;
4169
- }, 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 = () => {
4170
- let boundingRect = getBoundingRect();
4171
- 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();
4172
4394
  }, getY = () => {
4173
- let boundingRect = getBoundingRect();
4174
- return boundingRect.y - (getViewHeight() - boundingRect.height) / 2 - getOffset();
4175
- }, getViewboxWidth = () => getViewWidth() + getOffset() * 2, getViewboxHeight = () => getViewHeight() + getOffset() * 2, strokeWidth = () => _props.maskStrokeWidth ? _props.maskStrokeWidth * getViewScale() : void 0, prevNodeIds = [], nodeIds = () => {
4176
- let currentNodeIds = store.nodes.map((node) => node.id), currentSet = new Set(currentNodeIds);
4177
- return (prevNodeIds.length !== currentNodeIds.length || !prevNodeIds.every((id) => currentSet.has(id))) && (prevNodeIds = currentNodeIds), prevNodeIds;
4178
- };
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]) });
4179
4398
  return createComponent(Panel, mergeProps({
4180
4399
  get position() {
4181
4400
  return _props.position;
@@ -4206,7 +4425,7 @@ const getAttrFunction = (func) => func instanceof Function ? func : () => func,
4206
4425
  domNode: el,
4207
4426
  panZoom,
4208
4427
  getTransform: () => store.transform,
4209
- getViewScale
4428
+ getViewScale: viewScale
4210
4429
  });
4211
4430
  return setMinimap(instance), () => {
4212
4431
  instance.destroy();
@@ -4267,9 +4486,7 @@ const getAttrFunction = (func) => func instanceof Function ? func : () => func,
4267
4486
  get strokeWidth() {
4268
4487
  return _props.nodeStrokeWidth;
4269
4488
  },
4270
- get shapeRendering() {
4271
- return shapeRendering();
4272
- },
4489
+ shapeRendering,
4273
4490
  get width() {
4274
4491
  return nodeDimensions().width;
4275
4492
  },
@@ -4307,7 +4524,7 @@ const getAttrFunction = (func) => func instanceof Function ? func : () => func,
4307
4524
  s: strokeWidth(),
4308
4525
  h: labelledBy(),
4309
4526
  r: `M${getX() - getOffset()},${getY() - getOffset()}h${getViewboxWidth() + getOffset() * 2}v${getViewboxHeight() + getOffset() * 2}h${-getViewboxWidth() - getOffset() * 2}z
4310
- 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`
4311
4528
  }), ({ e, t, a, o, i, n, s, h, r }, _p$) => {
4312
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);
4313
4530
  }), _el$;