@xyflow/system 0.0.50 → 0.0.52

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.
Files changed (80) hide show
  1. package/dist/esm/constants.d.ts +1 -0
  2. package/dist/esm/constants.d.ts.map +1 -1
  3. package/dist/esm/index.js +292 -92
  4. package/dist/esm/index.mjs +292 -92
  5. package/dist/esm/types/changes.d.ts +12 -1
  6. package/dist/esm/types/changes.d.ts.map +1 -1
  7. package/dist/esm/types/edges.d.ts +37 -4
  8. package/dist/esm/types/edges.d.ts.map +1 -1
  9. package/dist/esm/types/general.d.ts +63 -0
  10. package/dist/esm/types/general.d.ts.map +1 -1
  11. package/dist/esm/types/handles.d.ts +8 -4
  12. package/dist/esm/types/handles.d.ts.map +1 -1
  13. package/dist/esm/types/nodes.d.ts +28 -8
  14. package/dist/esm/types/nodes.d.ts.map +1 -1
  15. package/dist/esm/types/utils.d.ts +22 -0
  16. package/dist/esm/types/utils.d.ts.map +1 -1
  17. package/dist/esm/utils/dom.d.ts.map +1 -1
  18. package/dist/esm/utils/edges/bezier-edge.d.ts +18 -11
  19. package/dist/esm/utils/edges/bezier-edge.d.ts.map +1 -1
  20. package/dist/esm/utils/edges/general.d.ts +16 -3
  21. package/dist/esm/utils/edges/general.d.ts.map +1 -1
  22. package/dist/esm/utils/edges/smoothstep-edge.d.ts +17 -11
  23. package/dist/esm/utils/edges/smoothstep-edge.d.ts.map +1 -1
  24. package/dist/esm/utils/edges/straight-edge.d.ts +15 -11
  25. package/dist/esm/utils/edges/straight-edge.d.ts.map +1 -1
  26. package/dist/esm/utils/general.d.ts +2 -2
  27. package/dist/esm/utils/graph.d.ts +82 -4
  28. package/dist/esm/utils/graph.d.ts.map +1 -1
  29. package/dist/esm/utils/node-toolbar.d.ts.map +1 -1
  30. package/dist/esm/utils/store.d.ts.map +1 -1
  31. package/dist/esm/xydrag/XYDrag.d.ts.map +1 -1
  32. package/dist/esm/xydrag/utils.d.ts.map +1 -1
  33. package/dist/esm/xyhandle/XYHandle.d.ts.map +1 -1
  34. package/dist/esm/xyhandle/types.d.ts.map +1 -1
  35. package/dist/esm/xyhandle/utils.d.ts.map +1 -1
  36. package/dist/esm/xypanzoom/XYPanZoom.d.ts.map +1 -1
  37. package/dist/esm/xypanzoom/eventhandler.d.ts.map +1 -1
  38. package/dist/esm/xyresizer/XYResizer.d.ts.map +1 -1
  39. package/dist/esm/xyresizer/types.d.ts +15 -0
  40. package/dist/esm/xyresizer/types.d.ts.map +1 -1
  41. package/dist/umd/constants.d.ts +1 -0
  42. package/dist/umd/constants.d.ts.map +1 -1
  43. package/dist/umd/index.js +1 -1
  44. package/dist/umd/types/changes.d.ts +12 -1
  45. package/dist/umd/types/changes.d.ts.map +1 -1
  46. package/dist/umd/types/edges.d.ts +37 -4
  47. package/dist/umd/types/edges.d.ts.map +1 -1
  48. package/dist/umd/types/general.d.ts +63 -0
  49. package/dist/umd/types/general.d.ts.map +1 -1
  50. package/dist/umd/types/handles.d.ts +8 -4
  51. package/dist/umd/types/handles.d.ts.map +1 -1
  52. package/dist/umd/types/nodes.d.ts +28 -8
  53. package/dist/umd/types/nodes.d.ts.map +1 -1
  54. package/dist/umd/types/utils.d.ts +22 -0
  55. package/dist/umd/types/utils.d.ts.map +1 -1
  56. package/dist/umd/utils/dom.d.ts.map +1 -1
  57. package/dist/umd/utils/edges/bezier-edge.d.ts +18 -11
  58. package/dist/umd/utils/edges/bezier-edge.d.ts.map +1 -1
  59. package/dist/umd/utils/edges/general.d.ts +16 -3
  60. package/dist/umd/utils/edges/general.d.ts.map +1 -1
  61. package/dist/umd/utils/edges/smoothstep-edge.d.ts +17 -11
  62. package/dist/umd/utils/edges/smoothstep-edge.d.ts.map +1 -1
  63. package/dist/umd/utils/edges/straight-edge.d.ts +15 -11
  64. package/dist/umd/utils/edges/straight-edge.d.ts.map +1 -1
  65. package/dist/umd/utils/general.d.ts +2 -2
  66. package/dist/umd/utils/graph.d.ts +82 -4
  67. package/dist/umd/utils/graph.d.ts.map +1 -1
  68. package/dist/umd/utils/node-toolbar.d.ts.map +1 -1
  69. package/dist/umd/utils/store.d.ts.map +1 -1
  70. package/dist/umd/xydrag/XYDrag.d.ts.map +1 -1
  71. package/dist/umd/xydrag/utils.d.ts.map +1 -1
  72. package/dist/umd/xyhandle/XYHandle.d.ts.map +1 -1
  73. package/dist/umd/xyhandle/types.d.ts.map +1 -1
  74. package/dist/umd/xyhandle/utils.d.ts.map +1 -1
  75. package/dist/umd/xypanzoom/XYPanZoom.d.ts.map +1 -1
  76. package/dist/umd/xypanzoom/eventhandler.d.ts.map +1 -1
  77. package/dist/umd/xyresizer/XYResizer.d.ts.map +1 -1
  78. package/dist/umd/xyresizer/types.d.ts +15 -0
  79. package/dist/umd/xyresizer/types.d.ts.map +1 -1
  80. package/package.json +3 -3
package/dist/esm/index.js CHANGED
@@ -17,6 +17,7 @@ const errorMessages = {
17
17
  error012: (id) => `Node with id "${id}" does not exist, it may have been removed. This can happen when a node is deleted before the "onNodeClick" handler is called.`,
18
18
  error013: (lib = 'react') => `It seems that you haven't loaded the styles. Please import '@xyflow/${lib}/dist/style.css' or base.css to make sure everything is working properly.`,
19
19
  error014: () => 'useNodeConnections: No node ID found. Call useNodeConnections inside a custom Node or provide a node ID.',
20
+ error015: () => 'It seems that you are trying to drag a node that is not initialized. Please use onNodesChange as explained in the docs.',
20
21
  };
21
22
  const infiniteExtent = [
22
23
  [Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY],
@@ -24,11 +25,26 @@ const infiniteExtent = [
24
25
  ];
25
26
  const elementSelectionKeys = ['Enter', ' ', 'Escape'];
26
27
 
28
+ /**
29
+ * The `ConnectionMode` is used to set the mode of connection between nodes.
30
+ * The `Strict` mode is the default one and only allows source to target edges.
31
+ * `Loose` mode allows source to source and target to target edges as well.
32
+ *
33
+ * @public
34
+ */
27
35
  var ConnectionMode;
28
36
  (function (ConnectionMode) {
29
37
  ConnectionMode["Strict"] = "strict";
30
38
  ConnectionMode["Loose"] = "loose";
31
39
  })(ConnectionMode || (ConnectionMode = {}));
40
+ /**
41
+ * This enum is used to set the different modes of panning the viewport when the
42
+ * user scrolls. The `Free` mode allows the user to pan in any direction by scrolling
43
+ * with a device like a trackpad. The `Vertical` and `Horizontal` modes restrict
44
+ * scroll panning to only the vertical or horizontal axis, respectively.
45
+ *
46
+ * @public
47
+ */
32
48
  var PanOnScrollMode;
33
49
  (function (PanOnScrollMode) {
34
50
  PanOnScrollMode["Free"] = "free";
@@ -53,6 +69,16 @@ const initialConnection = {
53
69
  toNode: null,
54
70
  };
55
71
 
72
+ /**
73
+ * If you set the `connectionLineType` prop on your [`<ReactFlow />`](/api-reference/react-flow#connection-connectionLineType)
74
+ *component, it will dictate the style of connection line rendered when creating
75
+ *new edges.
76
+ *
77
+ * @public
78
+ *
79
+ * @remarks If you choose to render a custom connection line component, this value will be
80
+ *passed to your component as part of its [`ConnectionLineComponentProps`](/api-reference/types/connection-line-component-props).
81
+ */
56
82
  var ConnectionLineType;
57
83
  (function (ConnectionLineType) {
58
84
  ConnectionLineType["Bezier"] = "default";
@@ -61,12 +87,25 @@ var ConnectionLineType;
61
87
  ConnectionLineType["SmoothStep"] = "smoothstep";
62
88
  ConnectionLineType["SimpleBezier"] = "simplebezier";
63
89
  })(ConnectionLineType || (ConnectionLineType = {}));
90
+ /**
91
+ * Edges may optionally have a marker on either end. The MarkerType type enumerates
92
+ * the options available to you when configuring a given marker.
93
+ *
94
+ * @public
95
+ */
64
96
  var MarkerType;
65
97
  (function (MarkerType) {
66
98
  MarkerType["Arrow"] = "arrow";
67
99
  MarkerType["ArrowClosed"] = "arrowclosed";
68
100
  })(MarkerType || (MarkerType = {}));
69
101
 
102
+ /**
103
+ * While [`PanelPosition`](/api-reference/types/panel-position) can be used to place a
104
+ * component in the corners of a container, the `Position` enum is less precise and used
105
+ * primarily in relation to edges and handles.
106
+ *
107
+ * @public
108
+ */
70
109
  var Position;
71
110
  (function (Position) {
72
111
  Position["Left"] = "left";
@@ -143,12 +182,27 @@ const isEdgeBase = (element) => 'id' in element && 'source' in element && 'targe
143
182
  const isNodeBase = (element) => 'id' in element && 'position' in element && !('source' in element) && !('target' in element);
144
183
  const isInternalNodeBase = (element) => 'id' in element && 'internals' in element && !('source' in element) && !('target' in element);
145
184
  /**
146
- * Pass in a node, and get connected nodes where edge.source === node.id
185
+ * This util is used to tell you what nodes, if any, are connected to the given node
186
+ * as the _target_ of an edge.
147
187
  * @public
148
188
  * @param node - The node to get the connected nodes from
149
189
  * @param nodes - The array of all nodes
150
190
  * @param edges - The array of all edges
151
191
  * @returns An array of nodes that are connected over eges where the source is the given node
192
+ *
193
+ * @example
194
+ * ```ts
195
+ *import { getOutgoers } from '@xyflow/react';
196
+ *
197
+ *const nodes = [];
198
+ *const edges = [];
199
+ *
200
+ *const outgoers = getOutgoers(
201
+ * { id: '1', position: { x: 0, y: 0 }, data: { label: 'node' } },
202
+ * nodes,
203
+ * edges,
204
+ *);
205
+ *```
152
206
  */
153
207
  const getOutgoers = (node, nodes, edges) => {
154
208
  if (!node.id) {
@@ -163,12 +217,27 @@ const getOutgoers = (node, nodes, edges) => {
163
217
  return nodes.filter((n) => outgoerIds.has(n.id));
164
218
  };
165
219
  /**
166
- * Pass in a node, and get connected nodes where edge.target === node.id
220
+ * This util is used to tell you what nodes, if any, are connected to the given node
221
+ * as the _source_ of an edge.
167
222
  * @public
168
223
  * @param node - The node to get the connected nodes from
169
224
  * @param nodes - The array of all nodes
170
225
  * @param edges - The array of all edges
171
226
  * @returns An array of nodes that are connected over eges where the target is the given node
227
+ *
228
+ * @example
229
+ * ```ts
230
+ *import { getIncomers } from '@xyflow/react';
231
+ *
232
+ *const nodes = [];
233
+ *const edges = [];
234
+ *
235
+ *const incomers = getIncomers(
236
+ * { id: '1', position: { x: 0, y: 0 }, data: { label: 'node' } },
237
+ * nodes,
238
+ * edges,
239
+ *);
240
+ *```
172
241
  */
173
242
  const getIncomers = (node, nodes, edges) => {
174
243
  if (!node.id) {
@@ -193,12 +262,40 @@ const getNodePositionWithOrigin = (node, nodeOrigin = [0, 0]) => {
193
262
  };
194
263
  };
195
264
  /**
196
- * Internal function for determining a bounding box that contains all given nodes in an array.
265
+ * Returns the bounding box that contains all the given nodes in an array. This can
266
+ * be useful when combined with [`getViewportForBounds`](/api-reference/utils/get-viewport-for-bounds)
267
+ * to calculate the correct transform to fit the given nodes in a viewport.
197
268
  * @public
198
269
  * @remarks Useful when combined with {@link getViewportForBounds} to calculate the correct transform to fit the given nodes in a viewport.
199
270
  * @param nodes - Nodes to calculate the bounds for
200
271
  * @param params.nodeOrigin - Origin of the nodes: [0, 0] - top left, [0.5, 0.5] - center
201
272
  * @returns Bounding box enclosing all nodes
273
+ *
274
+ * @remarks This function was previously called `getRectOfNodes`
275
+ *
276
+ * @example
277
+ * ```js
278
+ *import { getNodesBounds } from '@xyflow/react';
279
+ *
280
+ *const nodes = [
281
+ * {
282
+ * id: 'a',
283
+ * position: { x: 0, y: 0 },
284
+ * data: { label: 'a' },
285
+ * width: 50,
286
+ * height: 25,
287
+ * },
288
+ * {
289
+ * id: 'b',
290
+ * position: { x: 100, y: 100 },
291
+ * data: { label: 'b' },
292
+ * width: 50,
293
+ * height: 25,
294
+ * },
295
+ *];
296
+ *
297
+ *const bounds = getNodesBounds(nodes);
298
+ *```
202
299
  */
203
300
  const getNodesBounds = (nodes, params = { nodeOrigin: [0, 0], nodeLookup: undefined }) => {
204
301
  if (process.env.NODE_ENV === 'development' && !params.nodeLookup) {
@@ -267,10 +364,30 @@ excludeNonSelectableNodes = false) => {
267
364
  return visibleNodes;
268
365
  };
269
366
  /**
270
- * Get all connecting edges for a given set of nodes
367
+ * This utility filters an array of edges, keeping only those where either the source or target
368
+ * node is present in the given array of nodes.
369
+ * @public
271
370
  * @param nodes - Nodes you want to get the connected edges for
272
371
  * @param edges - All edges
273
372
  * @returns Array of edges that connect any of the given nodes with each other
373
+ *
374
+ * @example
375
+ * ```js
376
+ *import { getConnectedEdges } from '@xyflow/react';
377
+ *
378
+ *const nodes = [
379
+ * { id: 'a', position: { x: 0, y: 0 } },
380
+ * { id: 'b', position: { x: 100, y: 0 } },
381
+ *];
382
+ *
383
+ *const edges = [
384
+ * { id: 'a->c', source: 'a', target: 'c' },
385
+ * { id: 'c->d', source: 'c', target: 'd' },
386
+ *];
387
+ *
388
+ *const connectedEdges = getConnectedEdges(nodes, edges);
389
+ * // => [{ id: 'a->c', source: 'a', target: 'c' }]
390
+ *```
274
391
  */
275
392
  const getConnectedEdges = (nodes, edges) => {
276
393
  const nodeIds = new Set();
@@ -335,10 +452,13 @@ function calculateNodePosition({ nodeId, nextPosition, nodeLookup, nodeOrigin =
335
452
  const positionAbsolute = isCoordinateExtent(extent)
336
453
  ? clampPosition(nextPosition, extent, node.measured)
337
454
  : nextPosition;
455
+ if (node.measured.width === undefined || node.measured.height === undefined) {
456
+ onError?.('015', errorMessages['error015']());
457
+ }
338
458
  return {
339
459
  position: {
340
- x: positionAbsolute.x - parentX + node.measured.width * origin[0],
341
- y: positionAbsolute.y - parentY + node.measured.height * origin[1],
460
+ x: positionAbsolute.x - parentX + (node.measured.width ?? 0) * origin[0],
461
+ y: positionAbsolute.y - parentY + (node.measured.height ?? 0) * origin[1],
342
462
  },
343
463
  positionAbsolute,
344
464
  };
@@ -515,8 +635,8 @@ const rendererPointToPoint = ({ x, y }, [tx, ty, tScale]) => {
515
635
  * @returns A transforned {@link Viewport} that encloses the given bounds which you can pass to e.g. {@link setViewport}
516
636
  * @example
517
637
  * const { x, y, zoom } = getViewportForBounds(
518
- { x: 0, y: 0, width: 100, height: 100},
519
- 1200, 800, 0.5, 2);
638
+ *{ x: 0, y: 0, width: 100, height: 100},
639
+ *1200, 800, 0.5, 2);
520
640
  */
521
641
  const getViewportForBounds = (bounds, width, height, minZoom, maxZoom, padding) => {
522
642
  const xZoom = width / (bounds.width * (1 + padding));
@@ -611,9 +731,11 @@ const getEventPosition = (event, bounds) => {
611
731
  y: evtY - (bounds?.top ?? 0),
612
732
  };
613
733
  };
614
- // The handle bounds are calculated relative to the node element.
615
- // We store them in the internals object of the node in order to avoid
616
- // unnecessary recalculations.
734
+ /*
735
+ * The handle bounds are calculated relative to the node element.
736
+ * We store them in the internals object of the node in order to avoid
737
+ * unnecessary recalculations.
738
+ */
617
739
  const getHandleBounds = (type, nodeElement, nodeBounds, zoom, nodeId) => {
618
740
  const handles = nodeElement.querySelectorAll(`.${type}`);
619
741
  if (!handles || !handles.length) {
@@ -634,8 +756,10 @@ const getHandleBounds = (type, nodeElement, nodeBounds, zoom, nodeId) => {
634
756
  };
635
757
 
636
758
  function getBezierEdgeCenter({ sourceX, sourceY, targetX, targetY, sourceControlX, sourceControlY, targetControlX, targetControlY, }) {
637
- // cubic bezier t=0.5 mid point, not the actual mid point, but easy to calculate
638
- // https://stackoverflow.com/questions/67516101/how-to-find-distance-mid-point-of-bezier-curve
759
+ /*
760
+ * cubic bezier t=0.5 mid point, not the actual mid point, but easy to calculate
761
+ * https://stackoverflow.com/questions/67516101/how-to-find-distance-mid-point-of-bezier-curve
762
+ */
639
763
  const centerX = sourceX * 0.125 + sourceControlX * 0.375 + targetControlX * 0.375 + targetX * 0.125;
640
764
  const centerY = sourceY * 0.125 + sourceControlY * 0.375 + targetControlY * 0.375 + targetY * 0.125;
641
765
  const offsetX = Math.abs(centerX - sourceX);
@@ -661,7 +785,9 @@ function getControlWithCurvature({ pos, x1, y1, x2, y2, c }) {
661
785
  }
662
786
  }
663
787
  /**
664
- * Get a bezier path from source to target handle
788
+ * The `getBezierPath` util returns everything you need to render a bezier edge
789
+ *between two nodes.
790
+ * @public
665
791
  * @param params.sourceX - The x position of the source handle
666
792
  * @param params.sourceY - The y position of the source handle
667
793
  * @param params.sourcePosition - The position of the source handle (default: Position.Bottom)
@@ -671,17 +797,22 @@ function getControlWithCurvature({ pos, x1, y1, x2, y2, c }) {
671
797
  * @param params.curvature - The curvature of the bezier edge
672
798
  * @returns A path string you can use in an SVG, the labelX and labelY position (center of path) and offsetX, offsetY between source handle and label
673
799
  * @example
800
+ * ```js
674
801
  * const source = { x: 0, y: 20 };
675
- const target = { x: 150, y: 100 };
676
-
677
- const [path, labelX, labelY, offsetX, offsetY] = getBezierPath({
678
- sourceX: source.x,
679
- sourceY: source.y,
680
- sourcePosition: Position.Right,
681
- targetX: target.x,
682
- targetY: target.y,
683
- targetPosition: Position.Left,
684
- });
802
+ * const target = { x: 150, y: 100 };
803
+ *
804
+ * const [path, labelX, labelY, offsetX, offsetY] = getBezierPath({
805
+ * sourceX: source.x,
806
+ * sourceY: source.y,
807
+ * sourcePosition: Position.Right,
808
+ * targetX: target.x,
809
+ * targetY: target.y,
810
+ * targetPosition: Position.Left,
811
+ *});
812
+ *```
813
+ *
814
+ * @remarks This function returns a tuple (aka a fixed-size array) to make it easier to
815
+ *work with multiple edge paths at once.
685
816
  */
686
817
  function getBezierPath({ sourceX, sourceY, sourcePosition = Position.Bottom, targetX, targetY, targetPosition = Position.Top, curvature = 0.25, }) {
687
818
  const [sourceControlX, sourceControlY] = getControlWithCurvature({
@@ -759,12 +890,16 @@ const connectionExists = (edge, edges) => {
759
890
  (el.targetHandle === edge.targetHandle || (!el.targetHandle && !edge.targetHandle)));
760
891
  };
761
892
  /**
762
- * This util is a convenience function to add a new Edge to an array of edges
763
- * @remarks It also performs some validation to make sure you don't add an invalid edge or duplicate an existing one.
893
+ * This util is a convenience function to add a new Edge to an array of edges. It also performs some validation to make sure you don't add an invalid edge or duplicate an existing one.
764
894
  * @public
765
895
  * @param edgeParams - Either an Edge or a Connection you want to add
766
896
  * @param edges - The array of all current edges
767
897
  * @returns A new array of edges with the new edge added
898
+ *
899
+ * @remarks If an edge with the same `target` and `source` already exists (and the same
900
+ *`targetHandle` and `sourceHandle` if those are set), then this util won't add
901
+ *a new edge even if the `id` property is different.
902
+ *
768
903
  */
769
904
  const addEdge = (edgeParams, edges) => {
770
905
  if (!edgeParams.source || !edgeParams.target) {
@@ -793,12 +928,21 @@ const addEdge = (edgeParams, edges) => {
793
928
  return edges.concat(edge);
794
929
  };
795
930
  /**
796
- * A handy utility to reconnect an existing edge with new properties
931
+ * A handy utility to update an existing [`Edge`](/api-reference/types/edge) with new properties.
932
+ *This searches your edge array for an edge with a matching `id` and updates its
933
+ *properties with the connection you provide.
934
+ * @public
797
935
  * @param oldEdge - The edge you want to update
798
936
  * @param newConnection - The new connection you want to update the edge with
799
937
  * @param edges - The array of all current edges
800
938
  * @param options.shouldReplaceId - should the id of the old edge be replaced with the new connection id
801
939
  * @returns the updated edges array
940
+ *
941
+ * @example
942
+ * ```js
943
+ *const onReconnect = useCallback(
944
+ * (oldEdge: Edge, newConnection: Connection) => setEdges((els) => reconnectEdge(oldEdge, newConnection, els)),[]);
945
+ *```
802
946
  */
803
947
  const reconnectEdge = (oldEdge, newConnection, edges, options = { shouldReplaceId: true }) => {
804
948
  const { id: oldEdgeId, ...rest } = oldEdge;
@@ -824,24 +968,28 @@ const reconnectEdge = (oldEdge, newConnection, edges, options = { shouldReplaceI
824
968
  };
825
969
 
826
970
  /**
827
- * Get a straight path from source to target handle
971
+ * Calculates the straight line path between two points.
972
+ * @public
828
973
  * @param params.sourceX - The x position of the source handle
829
974
  * @param params.sourceY - The y position of the source handle
830
975
  * @param params.targetX - The x position of the target handle
831
976
  * @param params.targetY - The y position of the target handle
832
977
  * @returns A path string you can use in an SVG, the labelX and labelY position (center of path) and offsetX, offsetY between source handle and label
833
978
  * @example
979
+ * ```js
834
980
  * const source = { x: 0, y: 20 };
835
- const target = { x: 150, y: 100 };
836
-
837
- const [path, labelX, labelY, offsetX, offsetY] = getStraightPath({
838
- sourceX: source.x,
839
- sourceY: source.y,
840
- sourcePosition: Position.Right,
841
- targetX: target.x,
842
- targetY: target.y,
843
- targetPosition: Position.Left,
844
- });
981
+ * const target = { x: 150, y: 100 };
982
+ *
983
+ * const [path, labelX, labelY, offsetX, offsetY] = getStraightPath({
984
+ * sourceX: source.x,
985
+ * sourceY: source.y,
986
+ * sourcePosition: Position.Right,
987
+ * targetX: target.x,
988
+ * targetY: target.y,
989
+ * targetPosition: Position.Left,
990
+ * });
991
+ * ```
992
+ * @remarks This function returns a tuple (aka a fixed-size array) to make it easier to work with multiple edge paths at once.
845
993
  */
846
994
  function getStraightPath({ sourceX, sourceY, targetX, targetY, }) {
847
995
  const [labelX, labelY, offsetX, offsetY] = getEdgeCenter({
@@ -866,8 +1014,10 @@ const getDirection = ({ source, sourcePosition = Position.Bottom, target, }) =>
866
1014
  return source.y < target.y ? { x: 0, y: 1 } : { x: 0, y: -1 };
867
1015
  };
868
1016
  const distance = (a, b) => Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2));
869
- // ith this function we try to mimic a orthogonal edge routing behaviour
870
- // It's not as good as a real orthogonal edge routing but it's faster and good enough as a default for step and smooth step edges
1017
+ /*
1018
+ * ith this function we try to mimic a orthogonal edge routing behaviour
1019
+ * It's not as good as a real orthogonal edge routing but it's faster and good enough as a default for step and smooth step edges
1020
+ */
871
1021
  function getPoints({ source, sourcePosition = Position.Bottom, target, targetPosition = Position.Top, center, offset, }) {
872
1022
  const sourceDir = handleDirections[sourcePosition];
873
1023
  const targetDir = handleDirections[targetPosition];
@@ -894,16 +1044,20 @@ function getPoints({ source, sourcePosition = Position.Bottom, target, targetPos
894
1044
  if (sourceDir[dirAccessor] * targetDir[dirAccessor] === -1) {
895
1045
  centerX = center.x ?? defaultCenterX;
896
1046
  centerY = center.y ?? defaultCenterY;
897
- // --->
898
- // |
899
- // >---
1047
+ /*
1048
+ * --->
1049
+ * |
1050
+ * >---
1051
+ */
900
1052
  const verticalSplit = [
901
1053
  { x: centerX, y: sourceGapped.y },
902
1054
  { x: centerX, y: targetGapped.y },
903
1055
  ];
904
- // |
905
- // ---
906
- // |
1056
+ /*
1057
+ * |
1058
+ * ---
1059
+ * |
1060
+ */
907
1061
  const horizontalSplit = [
908
1062
  { x: sourceGapped.x, y: centerY },
909
1063
  { x: targetGapped.x, y: centerY },
@@ -992,7 +1146,10 @@ function getBend(a, b, c, size) {
992
1146
  return `L ${x},${y + bendSize * yDir}Q ${x},${y} ${x + bendSize * xDir},${y}`;
993
1147
  }
994
1148
  /**
995
- * Get a smooth step path from source to target handle
1149
+ * The `getSmoothStepPath` util returns everything you need to render a stepped path
1150
+ *between two nodes. The `borderRadius` property can be used to choose how rounded
1151
+ *the corners of those steps are.
1152
+ * @public
996
1153
  * @param params.sourceX - The x position of the source handle
997
1154
  * @param params.sourceY - The y position of the source handle
998
1155
  * @param params.sourcePosition - The position of the source handle (default: Position.Bottom)
@@ -1001,17 +1158,20 @@ function getBend(a, b, c, size) {
1001
1158
  * @param params.targetPosition - The position of the target handle (default: Position.Top)
1002
1159
  * @returns A path string you can use in an SVG, the labelX and labelY position (center of path) and offsetX, offsetY between source handle and label
1003
1160
  * @example
1161
+ * ```js
1004
1162
  * const source = { x: 0, y: 20 };
1005
- const target = { x: 150, y: 100 };
1006
-
1007
- const [path, labelX, labelY, offsetX, offsetY] = getSmoothStepPath({
1008
- sourceX: source.x,
1009
- sourceY: source.y,
1010
- sourcePosition: Position.Right,
1011
- targetX: target.x,
1012
- targetY: target.y,
1013
- targetPosition: Position.Left,
1014
- });
1163
+ * const target = { x: 150, y: 100 };
1164
+ *
1165
+ * const [path, labelX, labelY, offsetX, offsetY] = getSmoothStepPath({
1166
+ * sourceX: source.x,
1167
+ * sourceY: source.y,
1168
+ * sourcePosition: Position.Right,
1169
+ * targetX: target.x,
1170
+ * targetY: target.y,
1171
+ * targetPosition: Position.Left,
1172
+ * });
1173
+ * ```
1174
+ * @remarks This function returns a tuple (aka a fixed-size array) to make it easier to work with multiple edge paths at once.
1015
1175
  */
1016
1176
  function getSmoothStepPath({ sourceX, sourceY, sourcePosition = Position.Bottom, targetX, targetY, targetPosition = Position.Top, borderRadius = 5, centerX, centerY, offset = 20, }) {
1017
1177
  const [points, labelX, labelY, offsetX, offsetY] = getPoints({
@@ -1162,8 +1322,10 @@ function getNodeToolbarTransform(nodeRect, viewport, position, offset, align) {
1162
1322
  else if (align === 'end') {
1163
1323
  alignmentOffset = 1;
1164
1324
  }
1165
- // position === Position.Top
1166
- // we set the x any y position of the toolbar based on the nodes position
1325
+ /*
1326
+ * position === Position.Top
1327
+ * we set the x any y position of the toolbar based on the nodes position
1328
+ */
1167
1329
  let pos = [
1168
1330
  (nodeRect.x + nodeRect.width * alignmentOffset) * viewport.zoom + viewport.x,
1169
1331
  nodeRect.y * viewport.zoom + viewport.y - offset,
@@ -1362,8 +1524,10 @@ function handleExpandParent(children, nodeLookup, parentLookup, nodeOrigin = [0,
1362
1524
  y: parent.position.y - yChange + heightChange,
1363
1525
  },
1364
1526
  });
1365
- // We move all child nodes in the oppsite direction
1366
- // so the x,y changes of the parent do not move the children
1527
+ /*
1528
+ * We move all child nodes in the oppsite direction
1529
+ * so the x,y changes of the parent do not move the children
1530
+ */
1367
1531
  parentLookup.get(parentId)?.forEach((childNode) => {
1368
1532
  if (!children.some((child) => child.id === childNode.id)) {
1369
1533
  changes.push({
@@ -1501,9 +1665,11 @@ async function panBy({ delta, panZoom, transform, translateExtent, width, height
1501
1665
  * @param handleId handleId of the conneciton
1502
1666
  */
1503
1667
  function addConnectionToLookup(type, connection, connectionKey, connectionLookup, nodeId, handleId) {
1504
- // We add the connection to the connectionLookup at the following keys
1505
- // 1. nodeId, 2. nodeId-type, 3. nodeId-type-handleId
1506
- // If the key already exists, we add the connection to the existing map
1668
+ /*
1669
+ * We add the connection to the connectionLookup at the following keys
1670
+ * 1. nodeId, 2. nodeId-type, 3. nodeId-type-handleId
1671
+ * If the key already exists, we add the connection to the existing map
1672
+ */
1507
1673
  let key = nodeId;
1508
1674
  const nodeMap = connectionLookup.get(key) || new Map();
1509
1675
  connectionLookup.set(key, nodeMap.set(connectionKey, connection));
@@ -1604,9 +1770,11 @@ function getDragItems(nodeLookup, nodesDraggable, mousePos, nodeId) {
1604
1770
  }
1605
1771
  return dragItems;
1606
1772
  }
1607
- // returns two params:
1608
- // 1. the dragged node (or the first of the list, if we are dragging a node selection)
1609
- // 2. array of selected nodes (for multi selections)
1773
+ /*
1774
+ * returns two params:
1775
+ * 1. the dragged node (or the first of the list, if we are dragging a node selection)
1776
+ * 2. array of selected nodes (for multi selections)
1777
+ */
1610
1778
  function getEventHandlerParams({ nodeId, dragItems, nodeLookup, dragging = true, }) {
1611
1779
  const nodesFromDragItems = [];
1612
1780
  for (const [id, dragItem] of dragItems) {
@@ -1660,16 +1828,20 @@ function XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragSto
1660
1828
  }
1661
1829
  for (const [id, dragItem] of dragItems) {
1662
1830
  if (!nodeLookup.has(id)) {
1663
- // if the node is not in the nodeLookup anymore, it was probably deleted while dragging
1664
- // and we don't need to update it anymore
1831
+ /*
1832
+ * if the node is not in the nodeLookup anymore, it was probably deleted while dragging
1833
+ * and we don't need to update it anymore
1834
+ */
1665
1835
  continue;
1666
1836
  }
1667
1837
  let nextPosition = { x: x - dragItem.distance.x, y: y - dragItem.distance.y };
1668
1838
  if (snapToGrid) {
1669
1839
  nextPosition = snapPosition(nextPosition, snapGrid);
1670
1840
  }
1671
- // if there is selection with multiple nodes and a node extent is set, we need to adjust the node extent for each node
1672
- // based on its position so that the node stays at it's position relative to the selection.
1841
+ /*
1842
+ * if there is selection with multiple nodes and a node extent is set, we need to adjust the node extent for each node
1843
+ * based on its position so that the node stays at it's position relative to the selection.
1844
+ */
1673
1845
  let adjustedNodeExtent = [
1674
1846
  [nodeExtent[0][0], nodeExtent[0][1]],
1675
1847
  [nodeExtent[1][0], nodeExtent[1][1]],
@@ -1719,7 +1891,12 @@ function XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragSto
1719
1891
  if (!containerBounds) {
1720
1892
  return;
1721
1893
  }
1722
- const { transform, panBy, autoPanSpeed } = getStoreItems();
1894
+ const { transform, panBy, autoPanSpeed, autoPanOnNodeDrag } = getStoreItems();
1895
+ if (!autoPanOnNodeDrag) {
1896
+ autoPanStarted = false;
1897
+ cancelAnimationFrame(autoPanId);
1898
+ return;
1899
+ }
1723
1900
  const [xMovement, yMovement] = calcAutoPan(mousePosition, containerBounds, autoPanSpeed);
1724
1901
  if (xMovement !== 0 || yMovement !== 0) {
1725
1902
  lastPos.x = (lastPos.x ?? 0) - xMovement / transform[2];
@@ -1859,8 +2036,10 @@ function getNodesWithinDistance(position, nodeLookup, distance) {
1859
2036
  }
1860
2037
  return nodes;
1861
2038
  }
1862
- // this distance is used for the area around the user pointer
1863
- // while doing a connection for finding the closest nodes
2039
+ /*
2040
+ * this distance is used for the area around the user pointer
2041
+ * while doing a connection for finding the closest nodes
2042
+ */
1864
2043
  const ADDITIONAL_DISTANCE = 250;
1865
2044
  function getClosestHandle(position, connectionRadius, nodeLookup, fromHandle) {
1866
2045
  let closestHandles = [];
@@ -2028,8 +2207,10 @@ function onPointerDown(event, { connectionMode, connectionRadius, handleId, node
2028
2207
  toPosition: isValid && result.toHandle ? result.toHandle.position : oppositePosition[fromHandle.position],
2029
2208
  toNode: result.toHandle ? nodeLookup.get(result.toHandle.nodeId) : null,
2030
2209
  };
2031
- // we don't want to trigger an update when the connection
2032
- // is snapped to the same handle as before
2210
+ /*
2211
+ * we don't want to trigger an update when the connection
2212
+ * is snapped to the same handle as before
2213
+ */
2033
2214
  if (isValid &&
2034
2215
  closestHandle &&
2035
2216
  previousConnection.toHandle &&
@@ -2048,8 +2229,10 @@ function onPointerDown(event, { connectionMode, connectionRadius, handleId, node
2048
2229
  if ((closestHandle || handleDomNode) && connection && isValid) {
2049
2230
  onConnect?.(connection);
2050
2231
  }
2051
- // it's important to get a fresh reference from the store here
2052
- // in order to get the latest state of onConnectEnd
2232
+ /*
2233
+ * it's important to get a fresh reference from the store here
2234
+ * in order to get the latest state of onConnectEnd
2235
+ */
2053
2236
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
2054
2237
  const { inProgress, ...connectionState } = previousConnection;
2055
2238
  const finalConnectionState = {
@@ -2084,8 +2267,10 @@ function isValidHandle(event, { handle, connectionMode, fromNodeId, fromHandleId
2084
2267
  : null;
2085
2268
  const { x, y } = getEventPosition(event);
2086
2269
  const handleBelow = doc.elementFromPoint(x, y);
2087
- // we always want to prioritize the handle below the mouse cursor over the closest distance handle,
2088
- // because it could be that the center of another handle is closer to the mouse pointer than the handle below the cursor
2270
+ /*
2271
+ * we always want to prioritize the handle below the mouse cursor over the closest distance handle,
2272
+ * because it could be that the center of another handle is closer to the mouse pointer than the handle below the cursor
2273
+ */
2089
2274
  const handleToCheck = handleBelow?.classList.contains(`${lib}-flow__handle`) ? handleBelow : handleDomNode;
2090
2275
  const result = {
2091
2276
  handleDomNode: handleToCheck,
@@ -2236,8 +2421,10 @@ function createPanOnScrollHandler({ zoomPanValues, noWheelClassName, d3Selection
2236
2421
  d3Zoom.scaleTo(d3Selection, zoom, point, event);
2237
2422
  return;
2238
2423
  }
2239
- // increase scroll speed in firefox
2240
- // firefox: deltaMode === 1; chrome: deltaMode === 0
2424
+ /*
2425
+ * increase scroll speed in firefox
2426
+ * firefox: deltaMode === 1; chrome: deltaMode === 0
2427
+ */
2241
2428
  const deltaNormalize = event.deltaMode === 1 ? 20 : 1;
2242
2429
  let deltaX = panOnScrollMode === PanOnScrollMode.Vertical ? 0 : event.deltaX * deltaNormalize;
2243
2430
  let deltaY = panOnScrollMode === PanOnScrollMode.Horizontal ? 0 : event.deltaY * deltaNormalize;
@@ -2251,9 +2438,11 @@ function createPanOnScrollHandler({ zoomPanValues, noWheelClassName, d3Selection
2251
2438
  { internal: true });
2252
2439
  const nextViewport = transformToViewport(d3Selection.property('__zoom'));
2253
2440
  clearTimeout(zoomPanValues.panScrollTimeout);
2254
- // for pan on scroll we need to handle the event calls on our own
2255
- // we can't use the start, zoom and end events from d3-zoom
2256
- // because start and move gets called on every scroll event and not once at the beginning
2441
+ /*
2442
+ * for pan on scroll we need to handle the event calls on our own
2443
+ * we can't use the start, zoom and end events from d3-zoom
2444
+ * because start and move gets called on every scroll event and not once at the beginning
2445
+ */
2257
2446
  if (!zoomPanValues.isPanScrolling) {
2258
2447
  zoomPanValues.isPanScrolling = true;
2259
2448
  onPanZoomStart?.(event, nextViewport);
@@ -2488,9 +2677,11 @@ function XYPanZoom({ domNode, minZoom, maxZoom, paneClickDistance, translateExte
2488
2677
  lib,
2489
2678
  });
2490
2679
  d3ZoomInstance.filter(filter);
2491
- // We cannot add zoomOnDoubleClick to the filter above because
2492
- // double tapping on touch screens circumvents the filter and
2493
- // dblclick.zoom is fired on the selection directly
2680
+ /*
2681
+ * We cannot add zoomOnDoubleClick to the filter above because
2682
+ * double tapping on touch screens circumvents the filter and
2683
+ * dblclick.zoom is fired on the selection directly
2684
+ */
2494
2685
  if (zoomOnDoubleClick) {
2495
2686
  d3Selection.on('dblclick.zoom', d3DblClickZoomHandler);
2496
2687
  }
@@ -2572,6 +2763,11 @@ function XYPanZoom({ domNode, minZoom, maxZoom, paneClickDistance, translateExte
2572
2763
  };
2573
2764
  }
2574
2765
 
2766
+ /**
2767
+ * Used to determine the variant of the resize control
2768
+ *
2769
+ * @public
2770
+ */
2575
2771
  var ResizeControlVariant;
2576
2772
  (function (ResizeControlVariant) {
2577
2773
  ResizeControlVariant["Line"] = "line";
@@ -2867,8 +3063,10 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }) {
2867
3063
  parentNode = nodeLookup.get(node.parentId);
2868
3064
  parentExtent = parentNode && node.extent === 'parent' ? nodeToParentExtent(parentNode) : undefined;
2869
3065
  }
2870
- // Collect all child nodes to correct their relative positions when top/left changes
2871
- // Determine largest minimal extent the parent node is allowed to resize to
3066
+ /*
3067
+ * Collect all child nodes to correct their relative positions when top/left changes
3068
+ * Determine largest minimal extent the parent node is allowed to resize to
3069
+ */
2872
3070
  childNodes = [];
2873
3071
  childExtent = undefined;
2874
3072
  for (const [childId, child] of nodeLookup) {
@@ -2922,8 +3120,10 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }) {
2922
3120
  change.y = isYPosChange ? y : prevValues.y;
2923
3121
  prevValues.x = change.x;
2924
3122
  prevValues.y = change.y;
2925
- // when top/left changes, correct the relative positions of child nodes
2926
- // so that they stay in the same position
3123
+ /*
3124
+ * when top/left changes, correct the relative positions of child nodes
3125
+ * so that they stay in the same position
3126
+ */
2927
3127
  if (childNodes.length > 0) {
2928
3128
  const xChange = x - prevX;
2929
3129
  const yChange = y - prevY;