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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import { Dynamic, Portal, addEvent, claimElement, className, createComponent, delegateEvents, effect, insert, isServer, memo, mergeProps, ref, setAttribute, setStyleProperty, spread, style, template } from "@solidjs/web";
2
- import { ConnectionLineType, ConnectionMode, MarkerType, PanOnScrollMode, Position, Position as Position$1, ResizeControlVariant, SelectionMode as SelectionMode$1, XYDrag, XYHandle, XYMinimap, XYPanZoom, XYResizer, XY_RESIZER_HANDLE_POSITIONS, XY_RESIZER_LINE_POSITIONS, addEdge, addEdge as addEdge$1, areConnectionMapsEqual, calcAutoPan, calculateNodePosition, clampPosition, clampPositionToParent, createDevWarn, createMarkerIds, elementSelectionKeys, evaluateAbsolutePosition, fitViewport, getBezierEdgeCenter as getBezierEdgeCenter$1, getBezierPath, getBezierPath as getBezierPath$1, getBoundsOfRects, getConnectedEdges, getConnectionStatus, getDimensions, getEdgeCenter as getEdgeCenter$1, getEdgePosition, getEdgeToolbarTransform, getElementsToRemove, getElevatedEdgeZIndex, getEventPosition, getHandleBounds, getHostForElement, getIncomers, getInternalNodesBounds, getMarkerId, getNodeDimensions, getNodePositionWithOrigin, getNodeToolbarTransform, getNodesBounds, getNodesBounds as getNodesBounds$1, getNodesInside, getOutgoers, getOverlappingArea, getSmoothStepPath, getSmoothStepPath as getSmoothStepPath$1, getStraightPath, getStraightPath as getStraightPath$1, getViewportForBounds, getViewportForBounds as getViewportForBounds$1, handleConnectionChange, infiniteExtent, initialConnection, isCoordinateExtent, isEdgeBase, isInputDOMNode, isMacOs, isNodeBase, isNumeric, isRectObject, mergeAriaLabelConfig, nodeHasDimensions, nodeToRect, panBy, pointToRendererPoint, rendererPointToPoint, shallowNodeData, snapPosition } from "@xyflow/system";
2
+ import { ConnectionLineType, ConnectionMode, MarkerType, PanOnScrollMode, Position, Position as Position$1, ResizeControlVariant, SelectionMode as SelectionMode$1, XYDrag, XYHandle, XYMinimap, XYPanZoom, XYResizer, XY_RESIZER_HANDLE_POSITIONS, XY_RESIZER_LINE_POSITIONS, addEdge, addEdge as addEdge$1, areConnectionMapsEqual, calcAutoPan, calculateNodePosition, clampPosition, clampPositionToParent, createDevWarn, createMarkerIds, elementSelectionKeys, errorMessages, evaluateAbsolutePosition, fitViewport, getBezierEdgeCenter as getBezierEdgeCenter$1, getBezierPath, getBezierPath as getBezierPath$1, getBoundsOfRects, getConnectedEdges, getConnectionStatus, getDimensions, getEdgeCenter as getEdgeCenter$1, getEdgePosition, getEdgeToolbarTransform, getElementsToRemove, getElevatedEdgeZIndex, getEventPosition, getHandleBounds, getHostForElement, getIncomers, getInternalNodesBounds, getMarkerId, getNodeDimensions, getNodePositionWithOrigin, getNodeToolbarTransform, getNodesBounds, getNodesBounds as getNodesBounds$1, getNodesInside, getOutgoers, getOverlappingArea, getSmoothStepPath, getSmoothStepPath as getSmoothStepPath$1, getStraightPath, getStraightPath as getStraightPath$1, getViewportForBounds, getViewportForBounds as getViewportForBounds$1, handleConnectionChange, infiniteExtent, initialConnection, isCoordinateExtent, isEdgeBase, isInputDOMNode, isMacOs, isNodeBase, isNumeric, isRectObject, mergeAriaLabelConfig, nodeHasDimensions, nodeToRect, panBy, pointToRendererPoint, rendererPointToPoint, shallowNodeData, snapPosition } from "@xyflow/system";
3
3
  import { For, Show, createContext, createEffect, createMemo, createProjection, createSignal, createStore, flush, mapArray, merge, omit, onCleanup, onSettled, snapshot, untrack, useContext } from "solid-js";
4
4
  import { createMediaQuery } from "@solid-primitives/media";
5
5
  import { createEventListener, createEventListenerMap } from "@solid-primitives/event-listener";
@@ -65,7 +65,9 @@ function propDefaults(props, defaults) {
65
65
  const getEdgeId = (connection) => {
66
66
  let { source, sourceHandle, target, targetHandle } = connection;
67
67
  return `xy-edge__${source}${sourceHandle || ""}-${target}${targetHandle || ""}`;
68
- }, isEdgeSelectable = (edge, store) => edge.selectable ?? store.defaultEdgeOptions.selectable ?? store.elementsSelectable, EdgeLabelRenderer = (props) => {
68
+ }, isEdgeSelectable = (edge, store) => edge.selectable ?? store.defaultEdgeOptions.selectable ?? store.elementsSelectable, emitFlowError = (onError, id, message) => {
69
+ onError && onError(id, message);
70
+ }, EdgeLabelRenderer = (props) => {
69
71
  let { store } = useInternalSolidFlow(), labelNode = () => store.domNode?.querySelector(".solid-flow__edge-labels");
70
72
  return createComponent(Show, {
71
73
  get when() {
@@ -92,7 +94,7 @@ const EdgeLabel = (props) => {
92
94
  selectEdgeOnClick: !1,
93
95
  transparent: !1,
94
96
  style: {}
95
- }), rest = omit(_props, "x", "y", "width", "height", "selectEdgeOnClick", "transparent", "children", "class", "style"), { actions } = useInternalSolidFlow(), id = useEdgeId(), zIndex = () => actions.getEdge(id())?.zIndex;
97
+ }), rest = omit(_props, "x", "y", "width", "height", "selectEdgeOnClick", "transparent", "children", "class", "style"), { actions } = useInternalSolidFlow(), id = useEdgeId(), zIndex = () => actions.getLayoutedEdge(id())?.zIndex;
96
98
  return createComponent(EdgeLabelRenderer, { get children() {
97
99
  var _el$ = _tmpl$$34();
98
100
  return spread(_el$, mergeProps({
@@ -455,6 +457,30 @@ const armConnectionGestureLookup = (options) => {
455
457
  doc.removeEventListener("mousemove", update, !0), doc.removeEventListener("touchmove", update, !0), doc.removeEventListener("mouseup", dispose, !0), doc.removeEventListener("touchend", dispose, !0), lookup.disarm();
456
458
  };
457
459
  return doc.addEventListener("mousemove", update, !0), doc.addEventListener("touchmove", update, !0), doc.addEventListener("mouseup", dispose, !0), doc.addEventListener("touchend", dispose, !0), lookup;
460
+ }, buildConnectionGestureParams = (options) => {
461
+ let { event, store, actions, gestureLookup } = options;
462
+ return {
463
+ lib: store.lib,
464
+ flowId: store.id,
465
+ domNode: store.domNode,
466
+ autoPanOnConnect: store.autoPanOnConnect,
467
+ autoPanSpeed: store.autoPanSpeed,
468
+ connectionMode: store.connectionMode,
469
+ connectionRadius: store.connectionRadius,
470
+ nodeLookup: gestureLookup,
471
+ cancelConnection: actions.cancelConnection,
472
+ panBy: actions.panBy,
473
+ updateConnection: ((connection) => {
474
+ actions.setConnection(connection), flush();
475
+ }),
476
+ isValidConnection: store.isValidConnection,
477
+ onConnectStart: store.onConnectStart,
478
+ onConnectEnd: store.onConnectEnd,
479
+ getTransform: () => store.transform,
480
+ getFromHandle: () => store.connection.fromHandle,
481
+ dragThreshold: store.connectionDragThreshold,
482
+ handleDomNode: event.currentTarget
483
+ };
458
484
  };
459
485
  //#endregion
460
486
  //#region src/components/edge/EdgeReconnectAnchor.tsx
@@ -488,25 +514,16 @@ const EdgeReconnectAnchor = (props) => {
488
514
  connectionRadius: store.connectionRadius
489
515
  });
490
516
  XYHandle.onPointerDown(event, {
491
- lib: store.lib,
492
- flowId: store.id,
493
- domNode: store.domNode,
517
+ ...buildConnectionGestureParams({
518
+ event,
519
+ store,
520
+ actions,
521
+ gestureLookup
522
+ }),
494
523
  nodeId: opposite.nodeId,
495
524
  handleId: opposite.handleId,
496
- autoPanOnConnect: store.autoPanOnConnect,
497
- connectionMode: store.connectionMode,
498
- connectionRadius: store.connectionRadius,
499
- nodeLookup: gestureLookup,
500
525
  isTarget: opposite.type === "target",
501
526
  edgeUpdaterType: opposite.type,
502
- cancelConnection: actions.cancelConnection,
503
- panBy: actions.panBy,
504
- updateConnection: (connection) => {
505
- actions.setConnection(connection), flush();
506
- },
507
- isValidConnection: store.isValidConnection,
508
- onConnectStart: store.onConnectStart,
509
- onConnectEnd: store.onConnectEnd,
510
527
  onConnect: (connection) => {
511
528
  let newEdge = {
512
529
  ...edge(),
@@ -516,12 +533,7 @@ const EdgeReconnectAnchor = (props) => {
516
533
  },
517
534
  onReconnectEnd: (event, connectionState) => {
518
535
  setReconnectingState(!1), store.onReconnectEnd?.(event, edge(), opposite.type, connectionState);
519
- },
520
- getTransform: () => store.transform,
521
- getFromHandle: () => store.connection.fromHandle,
522
- autoPanSpeed: store.autoPanSpeed,
523
- dragThreshold: store.connectionDragThreshold,
524
- handleDomNode: event.currentTarget
536
+ }
525
537
  });
526
538
  };
527
539
  return createComponent(EdgeLabel, mergeProps({
@@ -630,14 +642,22 @@ const A11yDescriptions = () => {
630
642
  addSelectedEdges,
631
643
  handleNodeSelection: (id, unselect, nodeRef) => {
632
644
  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({
645
+ if (!node) {
646
+ emitFlowError(store.onError, "012", errorMessages.error012(id));
647
+ return;
648
+ }
649
+ setSelectionRect(void 0), setSelectionRectMode(void 0), node.selected ? (unselect || node.selected && store.multiselectionKeyPressed) && (unselectNodesAndEdges({
634
650
  nodes: [node],
635
651
  edges: []
636
- }), requestAnimationFrame(() => nodeRef?.blur())) : addSelectedNodes([id]));
652
+ }), requestAnimationFrame(() => nodeRef?.blur())) : addSelectedNodes([id]);
637
653
  },
638
654
  handleEdgeSelection: (id) => {
639
655
  let edge = edgeLookup[id];
640
- edge && isEdgeSelectable(edge, store) && (setSelectionRect(void 0), setSelectionRectMode(void 0), edge.selected ? edge.selected && store.multiselectionKeyPressed && unselectNodesAndEdges({
656
+ if (!edge) {
657
+ emitFlowError(store.onError, "012", errorMessages.error012(id));
658
+ return;
659
+ }
660
+ isEdgeSelectable(edge, store) && (setSelectionRect(void 0), setSelectionRectMode(void 0), edge.selected ? edge.selected && store.multiselectionKeyPressed && unselectNodesAndEdges({
641
661
  nodes: [],
642
662
  edges: [edge]
643
663
  }) : addSelectedEdges([id]));
@@ -854,7 +874,20 @@ const createMeasurementIngest = ({ setMeasurementsStore, setNodesStore, nodes })
854
874
  let out = {};
855
875
  for (let edge of source.edges) out[edge.id] = edge;
856
876
  return out;
857
- }, {}, { key: "id" });
877
+ }, {}, { key: "id" }), createRowRecordProjection = (rowStores) => {
878
+ let assigned = /* @__PURE__ */ new Map();
879
+ return createProjection((draft) => {
880
+ let seen = /* @__PURE__ */ new Set();
881
+ for (let { id, store } of rowStores()) {
882
+ let row = store.row;
883
+ row && (seen.add(id), assigned.get(id) !== row && (assigned.set(id, row), draft[id] = row));
884
+ }
885
+ for (let id of assigned.keys()) seen.has(id) || (assigned.delete(id), delete draft[id]);
886
+ }, {}, {
887
+ key: null,
888
+ shallow: !0
889
+ });
890
+ };
858
891
  function isManualZIndexMode(zIndexMode) {
859
892
  return zIndexMode === "manual";
860
893
  }
@@ -898,7 +931,7 @@ const EMPTY_AUTO_INDEX = /* @__PURE__ */ new Map(), createInternalNodes = (sourc
898
931
  x,
899
932
  y
900
933
  }, row.internals.z = z;
901
- } else source.nodes.length;
934
+ } else source.nodes.length, emitFlowError(source.onError, "parent-missing", `Parent node ${userNode.parentId} not found. Please make sure that parent nodes are in front of their child nodes in the nodes array.`);
902
935
  }
903
936
  return { row };
904
937
  }, {}, { key: "id" }), entry = {
@@ -911,19 +944,8 @@ const EMPTY_AUTO_INDEX = /* @__PURE__ */ new Map(), createInternalNodes = (sourc
911
944
  id,
912
945
  store
913
946
  };
914
- }, { keyed: (userNode) => userNode.id }), assigned = /* @__PURE__ */ new Map();
915
- return createProjection((draft) => {
916
- let seen = /* @__PURE__ */ new Set();
917
- for (let { id, store } of rowStores()) {
918
- seen.add(id);
919
- let row = store.row;
920
- assigned.get(id) !== row && (assigned.set(id, row), draft[id] = row);
921
- }
922
- for (let id of assigned.keys()) seen.has(id) || (assigned.delete(id), delete draft[id]);
923
- }, {}, {
924
- key: null,
925
- shallow: !0
926
- });
947
+ }, { keyed: (userNode) => userNode.id });
948
+ return createRowRecordProjection(rowStores);
927
949
  };
928
950
  function calculateChildXYZ(childNode, parentNode, nodeOrigin, nodeExtent, selectedNodeZ, zIndexMode) {
929
951
  let { x: parentX, y: parentY } = parentNode.internals.positionAbsolute, childDimensions = getNodeDimensions(childNode), positionWithOrigin = getNodePositionWithOrigin(childNode, nodeOrigin), clampedPosition = isCoordinateExtent(childNode.extent) ? clampPosition(positionWithOrigin, childNode.extent, childDimensions) : positionWithOrigin, absolutePosition = clampPosition({
@@ -971,18 +993,8 @@ const createLayoutedEdges = (source) => {
971
993
  let edge = edgeAccessor();
972
994
  return { row: buildRow(source, edge) };
973
995
  }, { row: null }, { key: "id" })
974
- }), { keyed: (edge) => edge.id }), assigned = /* @__PURE__ */ new Map();
975
- return createProjection((draft) => {
976
- let seen = /* @__PURE__ */ new Set();
977
- for (let { id, store } of rowStores()) {
978
- let row = store.row;
979
- row && (seen.add(id), assigned.get(id) !== row && (assigned.set(id, row), draft[id] = row));
980
- }
981
- for (let id of assigned.keys()) seen.has(id) || (assigned.delete(id), delete draft[id]);
982
- }, {}, {
983
- key: null,
984
- shallow: !0
985
- });
996
+ }), { keyed: (edge) => edge.id });
997
+ return createRowRecordProjection(rowStores);
986
998
  }, buildRow = (source, edge) => {
987
999
  let sourceNode = source.nodeLookup.get(edge.source), targetNode = source.nodeLookup.get(edge.target);
988
1000
  if (!sourceNode || !targetNode) return null;
@@ -1070,6 +1082,9 @@ const createLayoutedEdges = (source) => {
1070
1082
  },
1071
1083
  get zIndexMode() {
1072
1084
  return config().zIndexMode;
1085
+ },
1086
+ get onError() {
1087
+ return config().onFlowError;
1073
1088
  }
1074
1089
  }), nodeLookup = new RecordMapFacade(internalNodes), initialViewport = getInitialViewport(_props.fitView, _props.initialViewport, _props.width ?? 0, _props.height ?? 0, nodeLookup), [viewportStore, setViewportStore] = createStore(_props.viewport ?? initialViewport);
1075
1090
  createEffect(() => config().viewport, (next) => {
@@ -1097,6 +1112,10 @@ const createLayoutedEdges = (source) => {
1097
1112
  let state = connection(), toHandle = state.inProgress ? state.toHandle : null, key = toHandle ? connectionKey(toHandle.nodeId, toHandle.type, toHandle.id ?? null) : null;
1098
1113
  for (let existing of Object.keys(draft)) existing !== key && delete draft[existing];
1099
1114
  key && (draft[key] = state.isValid ? "valid" : "invalid");
1115
+ }, {}, { key: null }), connectionOriginByHandle = createProjection((draft) => {
1116
+ let fromHandle = connection().fromHandle ?? clickConnectStartHandle(), fromKey = fromHandle ? connectionKey(fromHandle.nodeId, fromHandle.type, fromHandle.id ?? null) : null, siblingKey = fromHandle ? connectionKey(fromHandle.nodeId, fromHandle.type === "source" ? "target" : "source", fromHandle.id ?? null) : null;
1117
+ for (let existing of Object.keys(draft)) existing !== fromKey && existing !== siblingKey && delete draft[existing];
1118
+ fromKey && (draft[fromKey] = "from"), siblingKey && (draft[siblingKey] = "excluded");
1100
1119
  }, {}, { key: null }), mergedNodeTypes = createMemo(() => ({
1101
1120
  ...initialNodeTypes,
1102
1121
  ...config().nodeTypes
@@ -1128,6 +1147,9 @@ const createLayoutedEdges = (source) => {
1128
1147
  get connectionTargetByHandle() {
1129
1148
  return connectionTargetByHandle;
1130
1149
  },
1150
+ get connectionOriginByHandle() {
1151
+ return connectionOriginByHandle;
1152
+ },
1131
1153
  get domNode() {
1132
1154
  return domNode();
1133
1155
  },
@@ -1266,7 +1288,7 @@ const createLayoutedEdges = (source) => {
1266
1288
  return store.onError;
1267
1289
  },
1268
1290
  nodeLookup
1269
- }), visibleEdgeIds = createMemo(() => Object.keys(layoutedEdges)), getEdge = (id) => layoutedEdges[id], fitView = async (options) => store.panZoom ? await fitViewport({
1291
+ }), visibleEdgeIds = createMemo(() => Object.keys(layoutedEdges)), getLayoutedEdge = (id) => layoutedEdges[id], fitView = async (options) => store.panZoom ? await fitViewport({
1270
1292
  nodes: nodeLookup,
1271
1293
  width: store.width,
1272
1294
  height: store.height,
@@ -1613,7 +1635,7 @@ const createLayoutedEdges = (source) => {
1613
1635
  parentIds,
1614
1636
  connections,
1615
1637
  actions: {
1616
- getEdge,
1638
+ getLayoutedEdge,
1617
1639
  applyInitialFitView,
1618
1640
  applyMeasurementWrites,
1619
1641
  applyNodeChanges,
@@ -1670,7 +1692,14 @@ const createLayoutedEdges = (source) => {
1670
1692
  var _tmpl$$30 = /* @__PURE__ */ template("<svg class=solid-flow__edge-wrapper><g>");
1671
1693
  /** Internal per-edge wrapper: interaction, a11y, viewport culling, and the dynamic edge component. */
1672
1694
  const EdgeWrapper = (props) => {
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) => {
1695
+ let edgeRef, { store, actions } = useInternalSolidFlow(), edgeId = () => props.edgeId, edge = () => actions.getLayoutedEdge(edgeId()), edgeType = () => edge().type ?? "default", selectable = () => isEdgeSelectable(edge(), store), focusable = () => edge().focusable ?? store.edgesFocusable, edgeTypeValid = () => edgeType() in store.edgeTypes, edgeComponent = () => store.edgeTypes[edgeTypeValid() ? edgeType() : "default"];
1696
+ createEffect(() => ({
1697
+ valid: edgeTypeValid(),
1698
+ edgeType: edgeType()
1699
+ }), ({ valid, edgeType }) => {
1700
+ valid || emitFlowError(store.onError, "011", errorMessages.error011(edgeType));
1701
+ });
1702
+ let markerStartUrl = () => edge().markerStart ? `url('#${getMarkerId(edge().markerStart, store.id)}')` : void 0, markerEndUrl = () => edge().markerEnd ? `url('#${getMarkerId(edge().markerEnd, store.id)}')` : void 0, onClick = (event) => {
1674
1703
  selectable() && actions.handleEdgeSelection(edgeId()), props.onEdgeClick?.({
1675
1704
  edge: edge(),
1676
1705
  event
@@ -2110,10 +2139,7 @@ const Handle = (props) => {
2110
2139
  position: "top",
2111
2140
  isConnectableStart: !0,
2112
2141
  isConnectableEnd: !0
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;
2142
+ }), { store, nodeLookup, connections, actions } = useInternalSolidFlow(), rest = omit(_props, "id", "type", "position", "isConnectable", "isConnectableStart", "isConnectableEnd", "isValidConnection", "onConnect", "onDisconnect", "children", "class", "style"), nodeId = useNodeId(), nodeConnectable = useNodeConnectable(), connectable = () => _props.isConnectable ?? nodeConnectable(), isTarget = () => _props.type === "target", handleId = () => _props.id ?? null, originState = () => store.connectionOriginByHandle[connectionKey(nodeId(), _props.type, handleId())], connectingFrom = () => originState() === "from", targetState = () => store.connectionTargetByHandle[connectionKey(nodeId(), _props.type, handleId())], connectingTo = () => targetState() !== void 0, valid = () => targetState() === "valid", prevConnections = null;
2117
2143
  createEffect(() => {
2118
2144
  if (!_props.onConnect && !_props.onDisconnect) return null;
2119
2145
  let rec = connections[connectionKey(nodeId(), _props.type, _props.id)], map = /* @__PURE__ */ new Map();
@@ -2139,36 +2165,17 @@ const Handle = (props) => {
2139
2165
  connectionRadius: store.connectionRadius
2140
2166
  });
2141
2167
  XYHandle.onPointerDown(event, {
2168
+ ...buildConnectionGestureParams({
2169
+ event,
2170
+ store,
2171
+ actions,
2172
+ gestureLookup
2173
+ }),
2142
2174
  handleId: handleId(),
2143
2175
  nodeId: nodeId(),
2144
2176
  isTarget: isTarget(),
2145
- connectionRadius: store.connectionRadius,
2146
- domNode: store.domNode,
2147
- nodeLookup: gestureLookup,
2148
- connectionMode: store.connectionMode,
2149
- lib: store.lib,
2150
- autoPanOnConnect: store.autoPanOnConnect,
2151
- flowId: store.id,
2152
2177
  isValidConnection: _props.isValidConnection ?? store.isValidConnection,
2153
- updateConnection: ((connection) => {
2154
- actions.setConnection(connection), flush();
2155
- }),
2156
- cancelConnection: actions.cancelConnection,
2157
- panBy: actions.panBy,
2158
- onConnect: onConnectExtended,
2159
- onConnectStart: (event, startParams) => {
2160
- store.onConnectStart?.(event, {
2161
- nodeId: startParams.nodeId,
2162
- handleId: startParams.handleId,
2163
- handleType: startParams.handleType
2164
- });
2165
- },
2166
- onConnectEnd: store.onConnectEnd,
2167
- getTransform: () => store.transform,
2168
- getFromHandle: () => store.connection.fromHandle,
2169
- autoPanSpeed: store.autoPanSpeed,
2170
- dragThreshold: store.connectionDragThreshold,
2171
- handleDomNode: event.currentTarget
2178
+ onConnect: onConnectExtended
2172
2179
  });
2173
2180
  }, onClick = (event) => {
2174
2181
  if (!nodeId() || !store.clickConnectStartHandle && !_props.isConnectableStart) return;
@@ -2203,7 +2210,7 @@ const Handle = (props) => {
2203
2210
  isValid && connection && onConnectExtended(connection);
2204
2211
  let connectionClone = structuredClone(snapshot(store.connection));
2205
2212
  delete connectionClone.inProgress, connectionClone.toPosition = connectionClone.toHandle ? connectionClone.toHandle.position : null, store.onClickConnectEnd?.(event, connectionClone), actions.setClickConnectStartHandle(void 0);
2206
- }, connectionIndicator = () => connectable() && (!connectionInProcess() || isPossibleTargetHandle()) && (connectionInProcess() || store.clickConnectStartHandle ? _props.isConnectableEnd : _props.isConnectableStart);
2213
+ };
2207
2214
  var _el$ = _tmpl$$29();
2208
2215
  return spread(_el$, mergeProps(rest, {
2209
2216
  role: "button",
@@ -2246,7 +2253,7 @@ const Handle = (props) => {
2246
2253
  connectablestart: _props.isConnectableStart,
2247
2254
  connectableend: _props.isConnectableEnd,
2248
2255
  connectable: !!connectable(),
2249
- connectionindicator: connectionIndicator()
2256
+ excluded: !!originState()
2250
2257
  }
2251
2258
  ];
2252
2259
  }
@@ -2374,7 +2381,7 @@ const NodeWrapper = (props) => {
2374
2381
  let el = nodeRef();
2375
2382
  el && props.resizeObserver?.unobserve(el);
2376
2383
  });
2377
- let nodeId = () => node().id, nodeType = () => node().type ?? "default", deletable = () => node().deletable ?? !0, selectable = () => node().selectable ?? store.elementsSelectable, focusable = () => node().focusable ?? store.nodesFocusable, draggable = () => node().draggable ?? store.nodesDraggable, connectable = () => node().connectable ?? store.nodesConnectable, userNode = () => node().internals.userNode, nodeTypeValid = () => nodeType() in store.nodeTypes, nodeComponent = () => store.nodeTypes[nodeType()], isParentNode = () => !!parentIds[node().id], transform = () => {
2384
+ let nodeId = () => node().id, nodeType = () => node().type ?? "default", deletable = () => node().deletable ?? !0, selectable = () => node().selectable ?? store.elementsSelectable, focusable = () => node().focusable ?? store.nodesFocusable, draggable = () => node().draggable ?? store.nodesDraggable, connectable = () => node().connectable ?? store.nodesConnectable, userNode = () => node().internals.userNode, nodeTypeValid = () => nodeType() in store.nodeTypes, nodeComponent = () => store.nodeTypes[nodeTypeValid() ? nodeType() : "default"], isParentNode = () => !!parentIds[node().id], transform = () => {
2378
2385
  let { x, y } = node().internals.positionAbsolute;
2379
2386
  return `translate(${x}px, ${y}px)`;
2380
2387
  }, sizeStyle = () => {
@@ -2394,7 +2401,9 @@ const NodeWrapper = (props) => {
2394
2401
  createEffect(() => ({
2395
2402
  valid: nodeTypeValid(),
2396
2403
  nodeType: nodeType()
2397
- }), ({ valid, nodeType }) => {}), createEffect(() => ({
2404
+ }), ({ valid, nodeType }) => {
2405
+ valid || emitFlowError(store.onError, "003", errorMessages.error003(nodeType));
2406
+ }), createEffect(() => ({
2398
2407
  id: node().id,
2399
2408
  nodeElement: nodeRef(),
2400
2409
  nodeType: nodeType(),
@@ -2771,21 +2780,29 @@ function useInternalSolidFlow() {
2771
2780
  var _tmpl$$26 = /* @__PURE__ */ template("<svg class=\"solid-flow__container solid-flow__connectionline\"><g>"), _tmpl$2$2 = /* @__PURE__ */ template("<svg><path class=solid-flow__connection-path fill=none></svg>", 2);
2772
2781
  /** Internal component rendering the in-progress connection line. */
2773
2782
  const ConnectionLine = (props) => {
2774
- let { store } = useInternalSolidFlow(), connectionStatus = () => getConnectionStatus(store.connection.isValid);
2783
+ let { store } = useInternalSolidFlow(), connectionStatus = () => getConnectionStatus(store.connection.isValid), inProgress = createMemo(() => {
2784
+ let state = store.connection;
2785
+ return state.inProgress ? state : null;
2786
+ });
2775
2787
  return createComponent(Show, {
2776
2788
  get when() {
2777
- return store.connection.inProgress;
2789
+ return inProgress();
2778
2790
  },
2779
- get children() {
2791
+ children: (connection) => (() => {
2780
2792
  var _el$ = _tmpl$$26(), _el$2 = _el$.firstChild;
2781
2793
  return insert(_el$2, createComponent(Show, {
2782
2794
  get when() {
2783
2795
  return props.component;
2784
2796
  },
2785
2797
  get fallback() {
2786
- return createComponent(InternalConnectionLine, { get style() {
2787
- return props.style;
2788
- } });
2798
+ return createComponent(InternalConnectionLine, {
2799
+ get style() {
2800
+ return props.style;
2801
+ },
2802
+ get connection() {
2803
+ return connection();
2804
+ }
2805
+ });
2789
2806
  },
2790
2807
  children: (CustomComponent) => {
2791
2808
  let UserConnectionLine = CustomComponent();
@@ -2797,37 +2814,37 @@ const ConnectionLine = (props) => {
2797
2814
  return props.style;
2798
2815
  },
2799
2816
  get fromNode() {
2800
- return store.connection.fromNode;
2817
+ return connection().fromNode;
2801
2818
  },
2802
2819
  get fromHandle() {
2803
- return store.connection.fromHandle;
2820
+ return connection().fromHandle;
2804
2821
  },
2805
2822
  get fromX() {
2806
- return store.connection.from.x;
2823
+ return connection().from.x;
2807
2824
  },
2808
2825
  get fromY() {
2809
- return store.connection.from.y;
2826
+ return connection().from.y;
2810
2827
  },
2811
2828
  get toX() {
2812
- return store.connection.to.x;
2829
+ return connection().to.x;
2813
2830
  },
2814
2831
  get toY() {
2815
- return store.connection.to.y;
2832
+ return connection().to.y;
2816
2833
  },
2817
2834
  get fromPosition() {
2818
- return store.connection.fromPosition;
2835
+ return connection().fromPosition;
2819
2836
  },
2820
2837
  get toPosition() {
2821
- return store.connection.toPosition;
2838
+ return connection().toPosition;
2822
2839
  },
2823
2840
  get connectionStatus() {
2824
2841
  return connectionStatus();
2825
2842
  },
2826
2843
  get toNode() {
2827
- return store.connection.toNode;
2844
+ return connection().toNode;
2828
2845
  },
2829
2846
  get toHandle() {
2830
- return store.connection.toHandle;
2847
+ return connection().toHandle;
2831
2848
  }
2832
2849
  });
2833
2850
  }
@@ -2839,18 +2856,17 @@ const ConnectionLine = (props) => {
2839
2856
  }), ({ e, t, a, o }, _p$) => {
2840
2857
  e !== _p$?.e && setAttribute(_el$, "width", e), t !== _p$?.t && setAttribute(_el$, "height", t), style(_el$, a, _p$?.a), className(_el$2, o, _p$?.o);
2841
2858
  }), _el$;
2842
- }
2859
+ })()
2843
2860
  });
2844
2861
  }, InternalConnectionLine = (props) => {
2845
2862
  let { store } = useInternalSolidFlow(), path = () => {
2846
- if (!store.connection.inProgress) return;
2847
2863
  let pathParams = {
2848
- sourceX: store.connection.from.x,
2849
- sourceY: store.connection.from.y,
2850
- sourcePosition: store.connection.fromPosition,
2851
- targetX: store.connection.to.x,
2852
- targetY: store.connection.to.y,
2853
- targetPosition: store.connection.toPosition
2864
+ sourceX: props.connection.from.x,
2865
+ sourceY: props.connection.from.y,
2866
+ sourcePosition: props.connection.fromPosition,
2867
+ targetX: props.connection.to.x,
2868
+ targetY: props.connection.to.y,
2869
+ targetPosition: props.connection.toPosition
2854
2870
  };
2855
2871
  switch (store.connectionLineType) {
2856
2872
  case "default": {
@@ -2950,25 +2966,32 @@ const MarkerDefinition = () => {
2950
2966
  })), _el$;
2951
2967
  }
2952
2968
  });
2969
+ }, createFocusedIdTracker = () => {
2970
+ let [focusedId, setFocusedId] = createSignal(null);
2971
+ return {
2972
+ focusedId,
2973
+ onFocusIn: (event) => {
2974
+ let element = event.target.closest("[data-id]");
2975
+ setFocusedId(element?.getAttribute("data-id") ?? null);
2976
+ },
2977
+ onFocusOut: () => setFocusedId(null)
2978
+ };
2953
2979
  };
2954
2980
  //#endregion
2955
2981
  //#region src/components/container/EdgeRenderer.tsx
2956
2982
  var _tmpl$$23 = /* @__PURE__ */ template("<div class=solid-flow__edges><!><!>");
2957
2983
  /** Internal renderer iterating the edge id list into `EdgeWrapper`s. */
2958
2984
  const EdgeRenderer = (props) => {
2959
- let { store, actions } = useInternalSolidFlow(), [focusedEdgeId, setFocusedEdgeId] = createSignal(null), onFocusIn = (event) => {
2960
- let edgeElement = event.target.closest("[data-id]");
2961
- setFocusedEdgeId(edgeElement?.getAttribute("data-id") ?? null);
2962
- };
2985
+ let { store, actions } = useInternalSolidFlow(), { focusedId: focusedEdgeId, onFocusIn, onFocusOut } = createFocusedIdTracker();
2963
2986
  var _el$ = _tmpl$$23(), _el$2 = _el$.firstChild, _el$3 = _el$2.nextSibling;
2964
- return _el$.$$focusout = () => setFocusedEdgeId(null), _el$.$$focusin = onFocusIn, insert(_el$, createComponent(MarkerDefinition, {}), _el$2), insert(_el$, createComponent(For, {
2987
+ return addEvent(_el$, "focusout", onFocusOut, !0), addEvent(_el$, "focusin", onFocusIn, !0), insert(_el$, createComponent(MarkerDefinition, {}), _el$2), insert(_el$, createComponent(For, {
2965
2988
  get each() {
2966
2989
  return store.visibleEdgeIds;
2967
2990
  },
2968
2991
  children: (edgeId) => {
2969
2992
  let unmounted = createMemo(() => {
2970
2993
  if (!store.onlyRenderVisibleElements || focusedEdgeId() === edgeId) return !1;
2971
- let edge = actions.getEdge(edgeId);
2994
+ let edge = actions.getLayoutedEdge(edgeId);
2972
2995
  return !!edge && isEdgeCulled(edge, store.cullingViewport);
2973
2996
  });
2974
2997
  return createComponent(Show, {
@@ -3015,12 +3038,9 @@ const NodeRenderer = (props) => {
3015
3038
  onCleanup(() => {
3016
3039
  resizeObserver?.disconnect();
3017
3040
  });
3018
- let [focusedNodeId, setFocusedNodeId] = createSignal(null), onFocusIn = (event) => {
3019
- let nodeElement = event.target.closest("[data-id]");
3020
- setFocusedNodeId(nodeElement?.getAttribute("data-id") ?? null);
3021
- };
3041
+ let { focusedId: focusedNodeId, onFocusIn, onFocusOut } = createFocusedIdTracker();
3022
3042
  var _el$ = _tmpl$$22();
3023
- return _el$.$$focusout = () => setFocusedNodeId(null), _el$.$$focusin = onFocusIn, insert(_el$, createComponent(For, {
3043
+ return addEvent(_el$, "focusout", onFocusOut, !0), addEvent(_el$, "focusin", onFocusIn, !0), insert(_el$, createComponent(For, {
3024
3044
  get each() {
3025
3045
  return store.visibleNodeIds;
3026
3046
  },
@@ -3083,7 +3103,7 @@ const isSetEqual = (a, b) => {
3083
3103
  let { store, nodeLookup, edgeLookup, connections, actions } = useInternalSolidFlow(), [containerRef, setContainerRef] = createSignal(), container, containerBounds = null, connectionEndedOnPane = !1, selectionInProgress = !1, selectionSpatialLookup = new GestureSpatialLookup(nodeLookup, 400), selectedNodeIds = /* @__PURE__ */ new Set(), selectedEdgeIds = /* @__PURE__ */ new Set(), autoPanId = 0, position = {
3084
3104
  x: 0,
3085
3105
  y: 0
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) => {
3106
+ }, autoPanStarted = !1, autoPanOnSelection = () => props.autoPanOnSelection ?? !0, paneClickDistance = () => props.paneClickDistance ?? 0, _panOnDrag = () => store.panActivationKeyPressed || props.panOnDrag, isSelecting = () => store.selectionKeyPressed || !!store.selectionRect || props.selectionOnDrag && _panOnDrag() !== !0, isSelectionEnabled = () => store.elementsSelectable && (isSelecting() || store.selectionRectMode === "user"), onClick = (event) => {
3087
3107
  if (event.target === container) {
3088
3108
  if (selectionInProgress || store.connection.inProgress || connectionEndedOnPane) {
3089
3109
  selectionInProgress = !1, connectionEndedOnPane = !1;
@@ -3468,29 +3488,13 @@ const Attribution = (props) => createComponent(Show, {
3468
3488
  }
3469
3489
  });
3470
3490
  }
3471
- });
3472
- //#endregion
3473
- //#region src/hooks/useSolidFlow.ts
3474
- /**
3475
- * Hook for accessing the flow instance: `{ flow, commands }` plus the
3476
- * commands spread at the top level for upstream familiarity.
3477
- *
3478
- * `flow` and `commands` are stable identities, so destructuring them is safe:
3479
- * `const { flow, commands } = useSolidFlow()`.
3480
- *
3481
- * @public
3482
- * @returns the flow's read struct and write surface
3483
- */
3484
- function useSolidFlow() {
3485
- let { flow, commands } = useInternalSolidFlow();
3486
- return {
3487
- ...commands,
3488
- flow,
3489
- commands
3490
- };
3491
- }
3492
- //#endregion
3493
- //#region src/components/utility/KeyHandler.ts
3491
+ }), MODIFIER_FLAG = {
3492
+ alt: "altKey",
3493
+ control: "ctrlKey",
3494
+ ctrl: "ctrlKey",
3495
+ meta: "metaKey",
3496
+ shift: "shiftKey"
3497
+ };
3494
3498
  function isKeyObject(key) {
3495
3499
  return typeof key == "object" && !!key;
3496
3500
  }
@@ -3522,18 +3526,13 @@ function matchesKey(event, keyDef) {
3522
3526
  function matchesKeyArray(event, keyDefs) {
3523
3527
  return keyDefs ? (Array.isArray(keyDefs) ? keyDefs : [keyDefs]).some((keyDef) => matchesKey(event, keyDef)) : !1;
3524
3528
  }
3525
- const MODIFIER_FLAG = {
3526
- alt: "altKey",
3527
- control: "ctrlKey",
3528
- ctrl: "ctrlKey",
3529
- meta: "metaKey",
3530
- shift: "shiftKey"
3531
- };
3532
3529
  /**
3533
3530
  * Whether an event's modifier flags PROVE this key definition cannot be held
3534
3531
  * right now: the key itself is a modifier whose flag is off, or one of its
3535
3532
  * required modifiers is off. Definitions built on non-modifier keys are never
3536
- * contradicted (their state isn't derivable from flags).
3533
+ * contradicted (their state isn't derivable from flags). This is the
3534
+ * self-heal for OS overlays that swallow keyups without blurring the window
3535
+ * (upstream xyflow#5679).
3537
3536
  */
3538
3537
  function isContradicted(flags, keyDef) {
3539
3538
  let keyFlag = MODIFIER_FLAG[getKeyString(keyDef).toLowerCase()];
@@ -3550,6 +3549,28 @@ function allContradicted(flags, keyDefs) {
3550
3549
  let keys = Array.isArray(keyDefs) ? keyDefs : [keyDefs];
3551
3550
  return keys.length > 0 && keys.every((keyDef) => isContradicted(flags, keyDef));
3552
3551
  }
3552
+ //#endregion
3553
+ //#region src/hooks/useSolidFlow.ts
3554
+ /**
3555
+ * Hook for accessing the flow instance: `{ flow, commands }` plus the
3556
+ * commands spread at the top level for upstream familiarity.
3557
+ *
3558
+ * `flow` and `commands` are stable identities, so destructuring them is safe:
3559
+ * `const { flow, commands } = useSolidFlow()`.
3560
+ *
3561
+ * @public
3562
+ * @returns the flow's read struct and write surface
3563
+ */
3564
+ function useSolidFlow() {
3565
+ let { flow, commands } = useInternalSolidFlow();
3566
+ return {
3567
+ ...commands,
3568
+ flow,
3569
+ commands
3570
+ };
3571
+ }
3572
+ //#endregion
3573
+ //#region src/components/utility/KeyHandler.ts
3553
3574
  const KeyHandler = (props) => {
3554
3575
  let { store, actions } = useInternalSolidFlow(), { deleteElements } = useSolidFlow(), _props = {
3555
3576
  get selectionKey() {
@@ -3660,7 +3681,13 @@ const SolidFlow = (props) => {
3660
3681
  "solid-flow",
3661
3682
  "solid-flow__container",
3662
3683
  _props.class,
3663
- store.colorMode
3684
+ store.colorMode,
3685
+ {
3686
+ connecting: !!store.connectionFromHandle || !!store.clickConnectStartHandle,
3687
+ "connecting-from-source": (store.connectionFromHandle ?? store.clickConnectStartHandle)?.type === "source",
3688
+ "connecting-from-target": (store.connectionFromHandle ?? store.clickConnectStartHandle)?.type === "target",
3689
+ "connection-strict": store.connectionMode === "strict"
3690
+ }
3664
3691
  ];
3665
3692
  },
3666
3693
  get style() {
@@ -3928,8 +3955,8 @@ function useConnection() {
3928
3955
  * @returns store with an array of nodes
3929
3956
  */
3930
3957
  function useNodes() {
3931
- let { store } = useInternalSolidFlow();
3932
- return () => store.nodes;
3958
+ let { flow } = useInternalSolidFlow();
3959
+ return () => flow.nodes;
3933
3960
  }
3934
3961
  /**
3935
3962
  * Hook for getting the current edges from the store.
@@ -3938,8 +3965,8 @@ function useNodes() {
3938
3965
  * @returns store with an array of edges
3939
3966
  */
3940
3967
  function useEdges() {
3941
- let { store } = useInternalSolidFlow();
3942
- return () => store.edges;
3968
+ let { flow } = useInternalSolidFlow();
3969
+ return () => flow.edges;
3943
3970
  }
3944
3971
  /**
3945
3972
  * Hook for getting the current viewport from the store.
@@ -3997,6 +4024,52 @@ function useInternalNode(id) {
3997
4024
  return () => flow.internalNodes[id()];
3998
4025
  }
3999
4026
  //#endregion
4027
+ //#region src/hooks/useKeyPress.ts
4028
+ /**
4029
+ * Reactive "is this key (combo) held right now?" — the Solid Flow
4030
+ * counterpart of React Flow's `useKeyPress`, usable anywhere (no flow
4031
+ * context required).
4032
+ *
4033
+ * The definition is an Accessor per house convention — `useKeyPress(() =>
4034
+ * "a")`, `useKeyPress(() => ["a", "d"])`, or `useKeyPress(() => ({ key:
4035
+ * "s", modifier: ["meta"] }))`; swapping the definition resets the state.
4036
+ *
4037
+ * Hardened beyond upstream:
4038
+ * - Combos re-activate when the base key is re-pressed while the modifier
4039
+ * stays held (upstream's oldest open key bug, xyflow#2248).
4040
+ * - Stuck modifiers self-heal from the flags later keyboard/pointer/wheel
4041
+ * events carry (OS overlays swallow keyups without blurring — the macOS
4042
+ * screenshot HUD; xyflow#5679), and window blur resets.
4043
+ */
4044
+ function useKeyPress(keys) {
4045
+ let [pressed, setPressed] = createSignal(!1);
4046
+ if (createEffect(() => keys(), () => {
4047
+ setPressed(!1);
4048
+ }, { defer: !0 }), !isServer) {
4049
+ let reconcile = (event) => {
4050
+ pressed() && allContradicted(event, keys()) && (setPressed(!1), flush());
4051
+ };
4052
+ createEventListenerMap(window, {
4053
+ keydown: (event) => {
4054
+ reconcile(event), matchesKeyArray(event, keys()) && (setPressed(!0), flush());
4055
+ },
4056
+ keyup: (event) => {
4057
+ reconcile(event), matchesKeyArray(event, keys()) && (setPressed(!1), flush());
4058
+ },
4059
+ blur: () => {
4060
+ setPressed(!1), flush();
4061
+ }
4062
+ }), createEventListenerMap(window, {
4063
+ pointerdown: reconcile,
4064
+ wheel: reconcile
4065
+ }, {
4066
+ capture: !0,
4067
+ passive: !0
4068
+ });
4069
+ }
4070
+ return pressed;
4071
+ }
4072
+ //#endregion
4000
4073
  //#region src/hooks/useNodeConnections.ts
4001
4074
  /**
4002
4075
  * Hook to retrieve all edges connected to a node. Can be filtered by handle type and id.
@@ -4366,7 +4439,7 @@ delegateEvents(["click"]);
4366
4439
  //#endregion
4367
4440
  //#region src/plugins/minimap/MiniMap.tsx
4368
4441
  var _tmpl$$3 = /* @__PURE__ */ template("<svg class=solid-flow__minimap-svg role=img><title></title><path class=solid-flow__minimap-mask fill-rule=evenodd pointer-events=none>");
4369
- const getAttrFunction = (func) => func instanceof Function ? func : () => func, MiniMap = (props) => {
4442
+ const getAttrFunction = (value) => value instanceof Function ? value : () => value, MiniMap = (props) => {
4370
4443
  let { store, nodeLookup } = useInternalSolidFlow(), _props = propDefaults(props, {
4371
4444
  position: "bottom-right",
4372
4445
  nodeClass: "",
@@ -4376,19 +4449,41 @@ const getAttrFunction = (func) => func instanceof Function ? func : () => func,
4376
4449
  width: 200,
4377
4450
  height: 150,
4378
4451
  nodeBorderRadius: 5,
4452
+ offsetScale: 5,
4379
4453
  nodeStrokeWidth: 2,
4380
4454
  style: {}
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(() => ({
4455
+ }), paneProps = omit(_props, "class", "style", "position", "nodeClass", "nodeStrokeColor", "nodeColor", "pannable", "zoomable", "inversePan", "zoomStep", "offsetScale", "bgColor", "width", "height", "maskColor", "maskStrokeColor", "maskStrokeWidth", "nodeBorderRadius", "nodeStrokeWidth", "nodeComponent", "onClick", "onNodeClick"), nodeColorFunc = () => _props.nodeColor === void 0 ? void 0 : getAttrFunction(_props.nodeColor), nodeStrokeColorFunc = () => getAttrFunction(_props.nodeStrokeColor), nodeClassFunc = () => getAttrFunction(_props.nodeClass), shapeRendering = typeof window > "u" || window.chrome ? "crispEdges" : "geometricPrecision", labelledBy = createMemo(() => `solid-flow__minimap-desc-${store.id}`), viewBB = createMemo(() => ({
4382
4456
  x: -store.viewport.x / store.viewport.zoom,
4383
4457
  y: -store.viewport.y / store.viewport.zoom,
4384
4458
  width: store.width / store.viewport.zoom,
4385
4459
  height: store.height / store.viewport.zoom
4386
- })), boundingRect = createMemo(() => {
4387
- let view = viewBB();
4388
- if (nodeLookup.size === 0) return view;
4460
+ })), rectsEqual = (a, b) => a === b || !!a && !!b && a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height, sampleBounds = () => untrack(() => {
4461
+ if (nodeLookup.size === 0) return null;
4389
4462
  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 = () => {
4463
+ return Number.isFinite(bounds.x) && Number.isFinite(bounds.width) ? bounds : null;
4464
+ }), [graphBounds, setGraphBounds] = createSignal(sampleBounds(), { equals: rectsEqual });
4465
+ createEffect(() => store.dragging, (dragging) => {
4466
+ if (!dragging) {
4467
+ setGraphBounds(sampleBounds());
4468
+ return;
4469
+ }
4470
+ let raf = requestAnimationFrame(function tick() {
4471
+ setGraphBounds(sampleBounds()), raf = requestAnimationFrame(tick);
4472
+ });
4473
+ return () => cancelAnimationFrame(raf);
4474
+ }), createEffect(() => ({
4475
+ count: store.nodes.length,
4476
+ initialized: store.nodesInitialized
4477
+ }), () => {
4478
+ setGraphBounds(sampleBounds());
4479
+ }), createEffect(() => null, () => {
4480
+ let interval = setInterval(() => setGraphBounds(sampleBounds()), 500);
4481
+ return () => clearInterval(interval);
4482
+ });
4483
+ let boundingRect = createMemo(() => {
4484
+ let view = viewBB(), bounds = graphBounds();
4485
+ return bounds ? getBoundsOfRects(bounds, view) : view;
4486
+ }), viewScale = createMemo(() => Math.max(boundingRect().width / _props.width, boundingRect().height / _props.height)), getViewWidth = () => viewScale() * _props.width, getViewHeight = () => viewScale() * _props.height, getOffset = () => _props.offsetScale * viewScale(), getX = () => {
4392
4487
  let rect = boundingRect();
4393
4488
  return rect.x - (getViewWidth() - rect.width) / 2 - getOffset();
4394
4489
  }, getY = () => {
@@ -4462,56 +4557,62 @@ const getAttrFunction = (func) => func instanceof Function ? func : () => func,
4462
4557
  return nodeIds();
4463
4558
  },
4464
4559
  children: (nodeId) => {
4465
- let node = createMemo(() => nodeLookup.get(nodeId())), nodeVisible = () => !!(node() && nodeHasDimensions(node()) && !node().hidden);
4560
+ let visibleNode = createMemo(() => {
4561
+ let row = nodeLookup.get(nodeId());
4562
+ return row && nodeHasDimensions(row) && !row.hidden ? row : null;
4563
+ });
4466
4564
  return createComponent(Show, {
4467
4565
  get when() {
4468
- return memo(() => !!nodeVisible())() ? getNodeDimensions(node()) : nodeVisible();
4566
+ return visibleNode();
4469
4567
  },
4470
- children: (nodeDimensions) => createComponent(Dynamic, {
4471
- get component() {
4472
- return _props.nodeComponent ?? MiniMapNode;
4473
- },
4474
- get id() {
4475
- return nodeId();
4476
- },
4477
- get x() {
4478
- return node().internals.positionAbsolute.x;
4479
- },
4480
- get y() {
4481
- return node().internals.positionAbsolute.y;
4482
- },
4483
- get borderRadius() {
4484
- return _props.nodeBorderRadius;
4485
- },
4486
- get strokeWidth() {
4487
- return _props.nodeStrokeWidth;
4488
- },
4489
- shapeRendering,
4490
- get width() {
4491
- return nodeDimensions().width;
4492
- },
4493
- get height() {
4494
- return nodeDimensions().height;
4495
- },
4496
- get selected() {
4497
- return node().selected;
4498
- },
4499
- get color() {
4500
- return nodeColorFunc()?.call(null, node());
4501
- },
4502
- get strokeColor() {
4503
- return nodeStrokeColorFunc().call(null, node());
4504
- },
4505
- get class() {
4506
- return nodeClassFunc().call(null, node());
4507
- },
4508
- get style() {
4509
- return node().style;
4510
- },
4511
- get onClick() {
4512
- return _props.onNodeClick ? onSvgNodeClick : void 0;
4513
- }
4514
- })
4568
+ children: (node) => {
4569
+ let dimensions = () => getNodeDimensions(node()), userNode = () => node().internals.userNode;
4570
+ return createComponent(Dynamic, {
4571
+ get component() {
4572
+ return _props.nodeComponent ?? MiniMapNode;
4573
+ },
4574
+ get id() {
4575
+ return nodeId();
4576
+ },
4577
+ get x() {
4578
+ return node().internals.positionAbsolute.x;
4579
+ },
4580
+ get y() {
4581
+ return node().internals.positionAbsolute.y;
4582
+ },
4583
+ get borderRadius() {
4584
+ return _props.nodeBorderRadius;
4585
+ },
4586
+ get strokeWidth() {
4587
+ return _props.nodeStrokeWidth;
4588
+ },
4589
+ shapeRendering,
4590
+ get width() {
4591
+ return dimensions().width;
4592
+ },
4593
+ get height() {
4594
+ return dimensions().height;
4595
+ },
4596
+ get selected() {
4597
+ return node().selected;
4598
+ },
4599
+ get color() {
4600
+ return nodeColorFunc()?.call(null, userNode());
4601
+ },
4602
+ get strokeColor() {
4603
+ return nodeStrokeColorFunc().call(null, userNode());
4604
+ },
4605
+ get class() {
4606
+ return nodeClassFunc().call(null, userNode());
4607
+ },
4608
+ get style() {
4609
+ return node().style;
4610
+ },
4611
+ get onClick() {
4612
+ return _props.onNodeClick ? onSvgNodeClick : void 0;
4613
+ }
4614
+ });
4615
+ }
4515
4616
  });
4516
4617
  }
4517
4618
  }), _el$2.nextSibling), effect(() => ({
@@ -4710,7 +4811,7 @@ const EdgeToolbar = (props) => {
4710
4811
  var _tmpl$ = /* @__PURE__ */ template("<div>");
4711
4812
  /** Toolbar attached to a node, rendered above the graph so it does not scale with zoom. */
4712
4813
  const NodeToolbar = (props) => {
4713
- let { store } = useInternalSolidFlow(), { flow, getNodesBounds } = useSolidFlow(), _props = propDefaults(props, {
4814
+ let { store, flow, commands } = useInternalSolidFlow(), _props = propDefaults(props, {
4714
4815
  offset: 10,
4715
4816
  position: "top",
4716
4817
  align: "center",
@@ -4722,7 +4823,7 @@ const NodeToolbar = (props) => {
4722
4823
  let node = flow.internalNodes[nodeId];
4723
4824
  return node && res.push(node), res;
4724
4825
  }, []), transform = () => {
4725
- let nodeRect = getNodesBounds(toolbarNodes());
4826
+ let nodeRect = commands.getNodesBounds(toolbarNodes());
4726
4827
  return nodeRect ? getNodeToolbarTransform(nodeRect, store.viewport, _props.position, _props.offset, _props.align) : "";
4727
4828
  }, zIndex = () => {
4728
4829
  let nodes = toolbarNodes();
@@ -4762,4 +4863,4 @@ const NodeToolbar = (props) => {
4762
4863
  });
4763
4864
  }, SelectionMode = SelectionMode$1, getEdgeCenter = getEdgeCenter$1, getBezierEdgeCenter = getBezierEdgeCenter$1;
4764
4865
  //#endregion
4765
- export { Background, BaseEdge, BezierEdge, BezierEdgeInternal, ConnectionLine, ConnectionLineType, ConnectionMode, ControlButton, Controls, DefaultNode, EdgeLabel, EdgeLabelRenderer, EdgeReconnectAnchor, EdgeRenderer, EdgeToolbar, EdgeWrapper, GroupNode, Handle, InputNode, Marker, MarkerDefinition, MarkerType, MiniMap, MiniMapNode, NodeRenderer, NodeResizer, NodeSelection, NodeToolbar, NodeWrapper, OutputNode, PanOnScrollMode, Pane, Panel, Position, ResizeControl, ResizeControlVariant, Selection, SelectionMode, SmoothStepEdge, SmoothStepEdgeInternal, SolidFlow, SolidFlowProvider, StepEdge, StepEdgeInternal, StraightEdge, StraightEdgeInternal, Viewport, ViewportPortal, Zoom, addEdge, connectionKey, createEdgeStore, createNodeStore, getBezierEdgeCenter, getBezierPath, getConnectedEdges, getEdgeCenter, getIncomers, getNodesBounds, getOutgoers, getSmoothStepPath, getStraightPath, getViewportForBounds, useColorMode, useConnection, useEdgeId, useEdges, useInternalNode, useNodeConnections, useNodeId, useNodes, useNodesData, useNodesInitialized, useSolidFlow, useUpdateNodeInternals, useViewport, useViewportInitialized };
4866
+ export { Background, BaseEdge, BezierEdge, BezierEdgeInternal, ConnectionLine, ConnectionLineType, ConnectionMode, ControlButton, Controls, DefaultNode, EdgeLabel, EdgeLabelRenderer, EdgeReconnectAnchor, EdgeRenderer, EdgeToolbar, EdgeWrapper, GroupNode, Handle, InputNode, Marker, MarkerDefinition, MarkerType, MiniMap, MiniMapNode, NodeRenderer, NodeResizer, NodeSelection, NodeToolbar, NodeWrapper, OutputNode, PanOnScrollMode, Pane, Panel, Position, ResizeControl, ResizeControlVariant, Selection, SelectionMode, SmoothStepEdge, SmoothStepEdgeInternal, SolidFlow, SolidFlowProvider, StepEdge, StepEdgeInternal, StraightEdge, StraightEdgeInternal, Viewport, ViewportPortal, Zoom, addEdge, connectionKey, createEdgeStore, createNodeStore, getBezierEdgeCenter, getBezierPath, getConnectedEdges, getEdgeCenter, getIncomers, getNodesBounds, getOutgoers, getSmoothStepPath, getStraightPath, getViewportForBounds, useColorMode, useConnection, useEdgeId, useEdges, useInternalNode, useKeyPress, useNodeConnections, useNodeId, useNodes, useNodesData, useNodesInitialized, useSolidFlow, useUpdateNodeInternals, useViewport, useViewportInitialized };