@xyflow/react 12.0.0-next.12 → 12.0.0-next.13

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 (78) hide show
  1. package/dist/base.css +7 -0
  2. package/dist/esm/additional-components/Controls/Controls.d.ts +1 -1
  3. package/dist/esm/additional-components/Controls/Controls.d.ts.map +1 -1
  4. package/dist/esm/additional-components/Controls/types.d.ts +1 -0
  5. package/dist/esm/additional-components/Controls/types.d.ts.map +1 -1
  6. package/dist/esm/additional-components/MiniMap/MiniMap.d.ts.map +1 -1
  7. package/dist/esm/additional-components/MiniMap/MiniMapNodes.d.ts.map +1 -1
  8. package/dist/esm/additional-components/NodeResizer/NodeResizeControl.d.ts.map +1 -1
  9. package/dist/esm/components/ConnectionLine/index.d.ts.map +1 -1
  10. package/dist/esm/components/NodeWrapper/index.d.ts.map +1 -1
  11. package/dist/esm/components/NodeWrapper/utils.d.ts +2 -2
  12. package/dist/esm/components/NodeWrapper/utils.d.ts.map +1 -1
  13. package/dist/esm/components/NodesSelection/index.d.ts.map +1 -1
  14. package/dist/esm/components/StoreUpdater/index.d.ts.map +1 -1
  15. package/dist/esm/container/NodeRenderer/useResizeObserver.d.ts.map +1 -1
  16. package/dist/esm/container/Pane/index.d.ts.map +1 -1
  17. package/dist/esm/hooks/useInternalNode.d.ts +10 -0
  18. package/dist/esm/hooks/useInternalNode.d.ts.map +1 -0
  19. package/dist/esm/hooks/useKeyPress.d.ts.map +1 -1
  20. package/dist/esm/hooks/useMoveSelectedNodes.d.ts.map +1 -1
  21. package/dist/esm/hooks/useNodesInitialized.d.ts.map +1 -1
  22. package/dist/esm/hooks/useReactFlow.d.ts.map +1 -1
  23. package/dist/esm/index.d.ts +3 -2
  24. package/dist/esm/index.d.ts.map +1 -1
  25. package/dist/esm/index.js +160 -172
  26. package/dist/esm/index.mjs +160 -172
  27. package/dist/esm/store/index.d.ts.map +1 -1
  28. package/dist/esm/types/general.d.ts +2 -2
  29. package/dist/esm/types/general.d.ts.map +1 -1
  30. package/dist/esm/types/index.d.ts +0 -1
  31. package/dist/esm/types/index.d.ts.map +1 -1
  32. package/dist/esm/types/instance.d.ts +9 -1
  33. package/dist/esm/types/instance.d.ts.map +1 -1
  34. package/dist/esm/types/nodes.d.ts +2 -1
  35. package/dist/esm/types/nodes.d.ts.map +1 -1
  36. package/dist/esm/types/store.d.ts +4 -4
  37. package/dist/esm/types/store.d.ts.map +1 -1
  38. package/dist/esm/utils/changes.d.ts +4 -5
  39. package/dist/esm/utils/changes.d.ts.map +1 -1
  40. package/dist/style.css +8 -3
  41. package/dist/umd/additional-components/Controls/Controls.d.ts +1 -1
  42. package/dist/umd/additional-components/Controls/Controls.d.ts.map +1 -1
  43. package/dist/umd/additional-components/Controls/types.d.ts +1 -0
  44. package/dist/umd/additional-components/Controls/types.d.ts.map +1 -1
  45. package/dist/umd/additional-components/MiniMap/MiniMap.d.ts.map +1 -1
  46. package/dist/umd/additional-components/MiniMap/MiniMapNodes.d.ts.map +1 -1
  47. package/dist/umd/additional-components/NodeResizer/NodeResizeControl.d.ts.map +1 -1
  48. package/dist/umd/components/ConnectionLine/index.d.ts.map +1 -1
  49. package/dist/umd/components/NodeWrapper/index.d.ts.map +1 -1
  50. package/dist/umd/components/NodeWrapper/utils.d.ts +2 -2
  51. package/dist/umd/components/NodeWrapper/utils.d.ts.map +1 -1
  52. package/dist/umd/components/NodesSelection/index.d.ts.map +1 -1
  53. package/dist/umd/components/StoreUpdater/index.d.ts.map +1 -1
  54. package/dist/umd/container/NodeRenderer/useResizeObserver.d.ts.map +1 -1
  55. package/dist/umd/container/Pane/index.d.ts.map +1 -1
  56. package/dist/umd/hooks/useInternalNode.d.ts +10 -0
  57. package/dist/umd/hooks/useInternalNode.d.ts.map +1 -0
  58. package/dist/umd/hooks/useKeyPress.d.ts.map +1 -1
  59. package/dist/umd/hooks/useMoveSelectedNodes.d.ts.map +1 -1
  60. package/dist/umd/hooks/useNodesInitialized.d.ts.map +1 -1
  61. package/dist/umd/hooks/useReactFlow.d.ts.map +1 -1
  62. package/dist/umd/index.d.ts +3 -2
  63. package/dist/umd/index.d.ts.map +1 -1
  64. package/dist/umd/index.js +2 -2
  65. package/dist/umd/store/index.d.ts.map +1 -1
  66. package/dist/umd/types/general.d.ts +2 -2
  67. package/dist/umd/types/general.d.ts.map +1 -1
  68. package/dist/umd/types/index.d.ts +0 -1
  69. package/dist/umd/types/index.d.ts.map +1 -1
  70. package/dist/umd/types/instance.d.ts +9 -1
  71. package/dist/umd/types/instance.d.ts.map +1 -1
  72. package/dist/umd/types/nodes.d.ts +2 -1
  73. package/dist/umd/types/nodes.d.ts.map +1 -1
  74. package/dist/umd/types/store.d.ts +4 -4
  75. package/dist/umd/types/store.d.ts.map +1 -1
  76. package/dist/umd/utils/changes.d.ts +4 -5
  77. package/dist/umd/utils/changes.d.ts.map +1 -1
  78. package/package.json +4 -4
@@ -1,8 +1,8 @@
1
1
  "use client"
2
2
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
3
3
  import cc from 'classcat';
4
- import { errorMessages, infiniteExtent, isInputDOMNode, fitView, getViewportForBounds, pointToRendererPoint, rendererPointToPoint, isNodeBase, isEdgeBase, getElementsToRemove, nodeHasDimensions, nodeToRect, isRectObject, getOverlappingArea, getDimensions, XYPanZoom, PanOnScrollMode, SelectionMode, getEventPosition, getNodesInside, XYDrag, snapPosition, calculateNodePosition, Position, ConnectionMode, isMouseEvent, XYHandle, getHostForElement, addEdge, getNodesBounds, clampPosition, internalsSymbol, getNodeDimensions, getPositionWithOrigin, elementSelectionKeys, isEdgeVisible, MarkerType, createMarkerIds, isNumeric, getBezierEdgeCenter, getSmoothStepPath, getStraightPath, getBezierPath, getEdgePosition, getElevatedEdgeZIndex, getMarkerId, ConnectionLineType, updateConnectionLookup, adoptUserProvidedNodes, devWarn, updateNodeDimensions, updateAbsolutePositions, panBy, isMacOs, areConnectionMapsEqual, handleConnectionChange, shallowNodeData, getNodePositionWithOrigin, XYMinimap, getBoundsOfRects, ResizeControlVariant, XYResizer, XY_RESIZER_LINE_POSITIONS, XY_RESIZER_HANDLE_POSITIONS, getNodeToolbarTransform } from '@xyflow/system';
5
- export { ConnectionLineType, ConnectionMode, MarkerType, PanOnScrollMode, Position, SelectionMode, addEdge, getBezierEdgeCenter, getBezierPath, getConnectedEdges, getEdgeCenter, getIncomers, getNodesBounds, getOutgoers, getSmoothStepPath, getStraightPath, getViewportForBounds, internalsSymbol, updateEdge } from '@xyflow/system';
4
+ import { errorMessages, infiniteExtent, isInputDOMNode, fitView, getViewportForBounds, pointToRendererPoint, rendererPointToPoint, isNodeBase, isEdgeBase, getElementsToRemove, nodeToRect, isRectObject, getOverlappingArea, getDimensions, XYPanZoom, PanOnScrollMode, SelectionMode, getEventPosition, getNodesInside, XYDrag, snapPosition, calculateNodePosition, Position, ConnectionMode, isMouseEvent, XYHandle, getHostForElement, addEdge, getNodesBounds, clampPosition, getNodeDimensions, nodeHasDimensions, getPositionWithOrigin, elementSelectionKeys, isEdgeVisible, MarkerType, createMarkerIds, isNumeric, getBezierEdgeCenter, getSmoothStepPath, getStraightPath, getBezierPath, getEdgePosition, getElevatedEdgeZIndex, getMarkerId, ConnectionLineType, updateConnectionLookup, adoptUserNodes, devWarn, updateNodeDimensions, updateAbsolutePositions, handleParentExpand, panBy, isMacOs, areConnectionMapsEqual, handleConnectionChange, shallowNodeData, getNodePositionWithOrigin, XYMinimap, getBoundsOfRects, getInternalNodesBounds, ResizeControlVariant, XYResizer, XY_RESIZER_LINE_POSITIONS, XY_RESIZER_HANDLE_POSITIONS, getNodeToolbarTransform } from '@xyflow/system';
5
+ export { ConnectionLineType, ConnectionMode, MarkerType, PanOnScrollMode, Position, SelectionMode, addEdge, getBezierEdgeCenter, getBezierPath, getConnectedEdges, getEdgeCenter, getIncomers, getNodesBounds, getOutgoers, getSmoothStepPath, getStraightPath, getViewportForBounds, updateEdge } from '@xyflow/system';
6
6
  import { createContext, useContext, useMemo, useEffect, useRef, useState, forwardRef, useLayoutEffect, useCallback, memo } from 'react';
7
7
  import { useStoreWithEqualityFn, createWithEqualityFn } from 'zustand/traditional';
8
8
  import { shallow } from 'zustand/shallow';
@@ -83,7 +83,7 @@ function Attribution({ proOptions, position = 'bottom-right' }) {
83
83
  }
84
84
 
85
85
  const selector$o = (s) => ({
86
- selectedNodes: s.nodes.filter((n) => n.selected),
86
+ selectedNodes: Array.from(s.nodeLookup.values()).filter((n) => n.selected),
87
87
  selectedEdges: s.edges.filter((e) => e.selected),
88
88
  });
89
89
  const selectId = (obj) => obj.id;
@@ -356,10 +356,12 @@ keyCode = null, options = { target: defaultDoc, actInsideInputWithModifier: true
356
356
  target?.addEventListener('keydown', downHandler);
357
357
  target?.addEventListener('keyup', upHandler);
358
358
  window.addEventListener('blur', resetHandler);
359
+ window.addEventListener('contextmenu', resetHandler);
359
360
  return () => {
360
361
  target?.removeEventListener('keydown', downHandler);
361
362
  target?.removeEventListener('keyup', upHandler);
362
363
  window.removeEventListener('blur', resetHandler);
364
+ window.removeEventListener('contextmenu', resetHandler);
363
365
  };
364
366
  }
365
367
  }, [keyCode, setKeyPressed]);
@@ -409,10 +411,10 @@ const useViewportHelper = () => {
409
411
  return { x, y, zoom };
410
412
  },
411
413
  fitView: (options) => {
412
- const { nodes, width, height, nodeOrigin, minZoom, maxZoom, panZoom } = store.getState();
414
+ const { nodeLookup, width, height, nodeOrigin, minZoom, maxZoom, panZoom } = store.getState();
413
415
  return panZoom
414
416
  ? fitView({
415
- nodes,
417
+ nodeLookup,
416
418
  width,
417
419
  height,
418
420
  nodeOrigin,
@@ -468,42 +470,6 @@ const useViewportHelper = () => {
468
470
  return viewportHelperFunctions;
469
471
  };
470
472
 
471
- function handleParentExpand(updatedElements, updateItem) {
472
- for (const [index, item] of updatedElements.entries()) {
473
- if (item.id === updateItem.parentNode) {
474
- const parent = { ...item };
475
- parent.computed ??= {};
476
- const extendWidth = updateItem.position.x + updateItem.computed.width - parent.computed.width;
477
- const extendHeight = updateItem.position.y + updateItem.computed.height - parent.computed.height;
478
- if (extendWidth > 0 || extendHeight > 0 || updateItem.position.x < 0 || updateItem.position.y < 0) {
479
- parent.width = parent.width ?? parent.computed.width;
480
- parent.height = parent.height ?? parent.computed.height;
481
- if (extendWidth > 0) {
482
- parent.width += extendWidth;
483
- }
484
- if (extendHeight > 0) {
485
- parent.height += extendHeight;
486
- }
487
- if (updateItem.position.x < 0) {
488
- const xDiff = Math.abs(updateItem.position.x);
489
- parent.position.x = parent.position.x - xDiff;
490
- parent.width += xDiff;
491
- updateItem.position.x = 0;
492
- }
493
- if (updateItem.position.y < 0) {
494
- const yDiff = Math.abs(updateItem.position.y);
495
- parent.position.y = parent.position.y - yDiff;
496
- parent.height += yDiff;
497
- updateItem.position.y = 0;
498
- }
499
- parent.computed.width = parent.width;
500
- parent.computed.height = parent.height;
501
- updatedElements[index] = parent;
502
- }
503
- break;
504
- }
505
- }
506
- }
507
473
  // This function applies changes to nodes or edges that are triggered by React Flow internally.
508
474
  // When you drag a node for example, React Flow will send a position change update.
509
475
  // This function then applies the changes and returns the updated elements.
@@ -555,14 +521,14 @@ function applyChanges(changes, elements) {
555
521
  /// each _mutate_ this object, so there's only ever one copy.
556
522
  const updatedElement = { ...element };
557
523
  for (const change of changes) {
558
- applyChange(change, updatedElement, updatedElements);
524
+ applyChange(change, updatedElement);
559
525
  }
560
526
  updatedElements.push(updatedElement);
561
527
  }
562
528
  return updatedElements;
563
529
  }
564
530
  // Applies a single change to an element. This is a *mutable* update.
565
- function applyChange(change, element, elements = []) {
531
+ function applyChange(change, element) {
566
532
  switch (change.type) {
567
533
  case 'select': {
568
534
  element.selected = change.selected;
@@ -572,23 +538,16 @@ function applyChange(change, element, elements = []) {
572
538
  if (typeof change.position !== 'undefined') {
573
539
  element.position = change.position;
574
540
  }
575
- if (typeof change.positionAbsolute !== 'undefined') {
576
- element.computed ??= {};
577
- element.computed.positionAbsolute = change.positionAbsolute;
578
- }
579
541
  if (typeof change.dragging !== 'undefined') {
580
542
  element.dragging = change.dragging;
581
543
  }
582
- if (element.expandParent) {
583
- handleParentExpand(elements, element);
584
- }
585
544
  break;
586
545
  }
587
546
  case 'dimensions': {
588
547
  if (typeof change.dimensions !== 'undefined') {
589
- element.computed ??= {};
590
- element.computed.width = change.dimensions.width;
591
- element.computed.height = change.dimensions.height;
548
+ element.measured ??= {};
549
+ element.measured.width = change.dimensions.width;
550
+ element.measured.height = change.dimensions.height;
592
551
  if (change.resizing) {
593
552
  element.width = change.dimensions.width;
594
553
  element.height = change.dimensions.height;
@@ -597,9 +556,6 @@ function applyChange(change, element, elements = []) {
597
556
  if (typeof change.resizing === 'boolean') {
598
557
  element.resizing = change.resizing;
599
558
  }
600
- if (element.expandParent) {
601
- handleParentExpand(elements, element);
602
- }
603
559
  break;
604
560
  }
605
561
  }
@@ -659,7 +615,7 @@ function createSelectionChange(id, selected) {
659
615
  }
660
616
  function getSelectionChanges(items, selectedIds = new Set(), mutateItem = false) {
661
617
  const changes = [];
662
- for (const item of items) {
618
+ for (const [, item] of items) {
663
619
  const willBeSelected = selectedIds.has(item.id);
664
620
  // we don't want to set all items to selected=false on the first selection
665
621
  if (!(item.selected === undefined && !willBeSelected) && item.selected !== willBeSelected) {
@@ -729,12 +685,9 @@ const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffec
729
685
  function useReactFlow() {
730
686
  const viewportHelper = useViewportHelper();
731
687
  const store = useStoreApi();
732
- const getNodes = useCallback(() => {
733
- return store.getState().nodes.map((n) => ({ ...n }));
734
- }, []);
735
- const getNode = useCallback((id) => {
736
- return store.getState().nodeLookup.get(id);
737
- }, []);
688
+ const getNodes = useCallback(() => store.getState().nodes.map((n) => ({ ...n })), []);
689
+ const getInternalNode = useCallback((id) => store.getState().nodeLookup.get(id), []);
690
+ const getNode = useCallback((id) => getInternalNode(id)?.internals.userNode, [getInternalNode]);
738
691
  const getEdges = useCallback(() => {
739
692
  const { edges = [] } = store.getState();
740
693
  return edges.map((e) => ({ ...e }));
@@ -872,11 +825,9 @@ function useReactFlow() {
872
825
  }
873
826
  return { deletedNodes: matchingNodes, deletedEdges: matchingEdges };
874
827
  }, []);
875
- const getNodeRect = useCallback((nodeOrRect) => {
876
- const node = isNode(nodeOrRect) && nodeHasDimensions(nodeOrRect)
877
- ? nodeOrRect
878
- : store.getState().nodeLookup.get(nodeOrRect.id);
879
- return node ? nodeToRect(node) : null;
828
+ const getNodeRect = useCallback(({ id }) => {
829
+ const internalNode = store.getState().nodeLookup.get(id);
830
+ return internalNode ? nodeToRect(internalNode) : null;
880
831
  }, []);
881
832
  const getIntersectingNodes = useCallback((nodeOrRect, partially = true, nodes) => {
882
833
  const isRect = isRectObject(nodeOrRect);
@@ -885,7 +836,8 @@ function useReactFlow() {
885
836
  return [];
886
837
  }
887
838
  return (nodes || store.getState().nodes).filter((n) => {
888
- if (!isRect && (n.id === nodeOrRect.id || !n.computed?.positionAbsolute)) {
839
+ const internalNode = store.getState().nodeLookup.get(n.id);
840
+ if (internalNode && !isRect && (n.id === nodeOrRect.id || !internalNode.internals.positionAbsolute)) {
889
841
  return false;
890
842
  }
891
843
  const currNodeRect = nodeToRect(n);
@@ -924,6 +876,7 @@ function useReactFlow() {
924
876
  ...viewportHelper,
925
877
  getNodes,
926
878
  getNode,
879
+ getInternalNode,
927
880
  getEdges,
928
881
  getEdge,
929
882
  setNodes,
@@ -941,6 +894,7 @@ function useReactFlow() {
941
894
  viewportHelper,
942
895
  getNodes,
943
896
  getNode,
897
+ getInternalNode,
944
898
  getEdges,
945
899
  getEdge,
946
900
  setNodes,
@@ -1190,7 +1144,7 @@ function Pane({ isSelecting, selectionMode = SelectionMode.Full, panOnDrag, onSe
1190
1144
  onSelectionStart?.(event);
1191
1145
  };
1192
1146
  const onMouseMove = (event) => {
1193
- const { userSelectionRect, edges, transform, nodeOrigin, nodes, triggerNodeChanges, triggerEdgeChanges } = store.getState();
1147
+ const { userSelectionRect, edgeLookup, transform, nodeOrigin, nodeLookup, triggerNodeChanges, triggerEdgeChanges } = store.getState();
1194
1148
  if (!isSelecting || !containerBounds.current || !userSelectionRect) {
1195
1149
  return;
1196
1150
  }
@@ -1205,25 +1159,25 @@ function Pane({ isSelecting, selectionMode = SelectionMode.Full, panOnDrag, onSe
1205
1159
  width: Math.abs(mousePos.x - startX),
1206
1160
  height: Math.abs(mousePos.y - startY),
1207
1161
  };
1208
- const selectedNodes = getNodesInside(nodes, nextUserSelectRect, transform, selectionMode === SelectionMode.Partial, true, nodeOrigin);
1162
+ const selectedNodes = getNodesInside(nodeLookup, nextUserSelectRect, transform, selectionMode === SelectionMode.Partial, true, nodeOrigin);
1209
1163
  const selectedEdgeIds = new Set();
1210
1164
  const selectedNodeIds = new Set();
1211
1165
  for (const selectedNode of selectedNodes) {
1212
1166
  selectedNodeIds.add(selectedNode.id);
1213
- for (const edge of edges) {
1167
+ for (const [edgeId, edge] of edgeLookup) {
1214
1168
  if (edge.source === selectedNode.id || edge.target === selectedNode.id) {
1215
- selectedEdgeIds.add(edge.id);
1169
+ selectedEdgeIds.add(edgeId);
1216
1170
  }
1217
1171
  }
1218
1172
  }
1219
1173
  if (prevSelectedNodesCount.current !== selectedNodeIds.size) {
1220
1174
  prevSelectedNodesCount.current = selectedNodeIds.size;
1221
- const changes = getSelectionChanges(nodes, selectedNodeIds, true);
1175
+ const changes = getSelectionChanges(nodeLookup, selectedNodeIds, true);
1222
1176
  triggerNodeChanges(changes);
1223
1177
  }
1224
1178
  if (prevSelectedEdgesCount.current !== selectedEdgeIds.size) {
1225
1179
  prevSelectedEdgesCount.current = selectedEdgeIds.size;
1226
- const changes = getSelectionChanges(edges, selectedEdgeIds);
1180
+ const changes = getSelectionChanges(edgeLookup, selectedEdgeIds);
1227
1181
  triggerEdgeChanges(changes);
1228
1182
  }
1229
1183
  store.setState({
@@ -1333,36 +1287,38 @@ const selectedAndDraggable = (nodesDraggable) => (n) => n.selected && (n.draggab
1333
1287
  function useMoveSelectedNodes() {
1334
1288
  const store = useStoreApi();
1335
1289
  const moveSelectedNodes = useCallback((params) => {
1336
- const { nodeExtent, nodes, snapToGrid, snapGrid, nodesDraggable, onError, updateNodePositions, nodeLookup, nodeOrigin, } = store.getState();
1337
- const selectedNodes = nodes.filter(selectedAndDraggable(nodesDraggable));
1290
+ const { nodeExtent, snapToGrid, snapGrid, nodesDraggable, onError, updateNodePositions, nodeLookup, nodeOrigin } = store.getState();
1291
+ const nodeUpdates = [];
1292
+ const isSelected = selectedAndDraggable(nodesDraggable);
1338
1293
  // by default a node moves 5px on each key press
1339
1294
  // if snap grid is enabled, we use that for the velocity
1340
1295
  const xVelo = snapToGrid ? snapGrid[0] : 5;
1341
1296
  const yVelo = snapToGrid ? snapGrid[1] : 5;
1342
1297
  const xDiff = params.direction.x * xVelo * params.factor;
1343
1298
  const yDiff = params.direction.y * yVelo * params.factor;
1344
- const nodeUpdates = selectedNodes.map((node) => {
1345
- if (node.computed?.positionAbsolute) {
1346
- let nextPosition = {
1347
- x: node.computed.positionAbsolute.x + xDiff,
1348
- y: node.computed.positionAbsolute.y + yDiff,
1349
- };
1350
- if (snapToGrid) {
1351
- nextPosition = snapPosition(nextPosition, snapGrid);
1352
- }
1353
- const { position, positionAbsolute } = calculateNodePosition({
1354
- nodeId: node.id,
1355
- nextPosition,
1356
- nodeLookup,
1357
- nodeExtent,
1358
- nodeOrigin,
1359
- onError,
1360
- });
1361
- node.position = position;
1362
- node.computed.positionAbsolute = positionAbsolute;
1299
+ for (const [, node] of nodeLookup) {
1300
+ if (!isSelected(node)) {
1301
+ continue;
1363
1302
  }
1364
- return node;
1365
- });
1303
+ let nextPosition = {
1304
+ x: node.internals.positionAbsolute.x + xDiff,
1305
+ y: node.internals.positionAbsolute.y + yDiff,
1306
+ };
1307
+ if (snapToGrid) {
1308
+ nextPosition = snapPosition(nextPosition, snapGrid);
1309
+ }
1310
+ const { position, positionAbsolute } = calculateNodePosition({
1311
+ nodeId: node.id,
1312
+ nextPosition,
1313
+ nodeLookup,
1314
+ nodeExtent,
1315
+ nodeOrigin,
1316
+ onError,
1317
+ });
1318
+ node.position = position;
1319
+ node.internals.positionAbsolute = positionAbsolute;
1320
+ nodeUpdates.push(node);
1321
+ }
1366
1322
  updateNodePositions(nodeUpdates);
1367
1323
  }, []);
1368
1324
  return moveSelectedNodes;
@@ -1431,7 +1387,7 @@ function HandleComponent({ type = 'source', position = Position.Top, isValidConn
1431
1387
  connectionMode: currentStore.connectionMode,
1432
1388
  connectionRadius: currentStore.connectionRadius,
1433
1389
  domNode: currentStore.domNode,
1434
- nodes: currentStore.nodes,
1390
+ nodeLookup: currentStore.nodeLookup,
1435
1391
  lib: currentStore.lib,
1436
1392
  isTarget,
1437
1393
  handleId,
@@ -1546,7 +1502,7 @@ const builtinNodeTypes = {
1546
1502
  group: GroupNode,
1547
1503
  };
1548
1504
  function getNodeInlineStyleDimensions(node) {
1549
- if (!node.computed) {
1505
+ if (node.internals.handleBounds === undefined) {
1550
1506
  return {
1551
1507
  width: node.width ?? node.initialWidth ?? node.style?.width,
1552
1508
  height: node.height ?? node.initialHeight ?? node.style?.height,
@@ -1559,7 +1515,12 @@ function getNodeInlineStyleDimensions(node) {
1559
1515
  }
1560
1516
 
1561
1517
  const selector$h = (s) => {
1562
- const selectedNodes = s.nodes.filter((n) => n.selected);
1518
+ const selectedNodes = [];
1519
+ for (const [, node] of s.nodeLookup) {
1520
+ if (node.selected) {
1521
+ selectedNodes.push(node);
1522
+ }
1523
+ }
1563
1524
  const { width, height, x, y } = getNodesBounds(selectedNodes, { nodeOrigin: s.nodeOrigin });
1564
1525
  return {
1565
1526
  width,
@@ -1626,7 +1587,7 @@ const FlowRenderer = memo(FlowRendererComponent);
1626
1587
 
1627
1588
  const selector$f = (onlyRenderVisible) => (s) => {
1628
1589
  return onlyRenderVisible
1629
- ? getNodesInside(s.nodes, { x: 0, y: 0, width: s.width, height: s.height }, s.transform, true).map((node) => node.id)
1590
+ ? getNodesInside(s.nodeLookup, { x: 0, y: 0, width: s.width, height: s.height }, s.transform, true).map((node) => node.id)
1630
1591
  : Array.from(s.nodeLookup.keys());
1631
1592
  };
1632
1593
  /**
@@ -1656,7 +1617,6 @@ function useResizeObserver() {
1656
1617
  updates.set(id, {
1657
1618
  id,
1658
1619
  nodeElement: entry.target,
1659
- forceUpdate: true,
1660
1620
  });
1661
1621
  });
1662
1622
  updateNodeDimensions(updates);
@@ -1676,16 +1636,16 @@ function NodeWrapper({ id, onClick, onMouseEnter, onMouseMove, onMouseLeave, onC
1676
1636
  const { node, positionAbsoluteX, positionAbsoluteY, zIndex, isParent } = useStore((s) => {
1677
1637
  const node = s.nodeLookup.get(id);
1678
1638
  const positionAbsolute = nodeExtent
1679
- ? clampPosition(node.computed?.positionAbsolute, nodeExtent)
1680
- : node.computed?.positionAbsolute || { x: 0, y: 0 };
1639
+ ? clampPosition(node.internals.positionAbsolute, nodeExtent)
1640
+ : node.internals.positionAbsolute || { x: 0, y: 0 };
1681
1641
  return {
1682
1642
  node,
1683
1643
  // we are mutating positionAbsolute, z and isParent attributes for sub flows
1684
1644
  // so we we need to force a re-render when some change
1685
1645
  positionAbsoluteX: positionAbsolute.x,
1686
1646
  positionAbsoluteY: positionAbsolute.y,
1687
- zIndex: node[internalsSymbol]?.z ?? 0,
1688
- isParent: !!node[internalsSymbol]?.isParent,
1647
+ zIndex: node.internals.z,
1648
+ isParent: node.internals.isParent,
1689
1649
  };
1690
1650
  }, shallow);
1691
1651
  let nodeType = node.type || 'default';
@@ -1707,12 +1667,13 @@ function NodeWrapper({ id, onClick, onMouseEnter, onMouseMove, onMouseLeave, onC
1707
1667
  const nodeDimensions = getNodeDimensions(node);
1708
1668
  const inlineDimensions = getNodeInlineStyleDimensions(node);
1709
1669
  const initialized = nodeHasDimensions(node);
1710
- const hasHandleBounds = !!node[internalsSymbol]?.handleBounds;
1670
+ const hasHandleBounds = !!node.internals.handleBounds;
1711
1671
  const moveSelectedNodes = useMoveSelectedNodes();
1712
1672
  useEffect(() => {
1673
+ const currNode = nodeRef.current;
1713
1674
  return () => {
1714
- if (nodeRef.current) {
1715
- resizeObserver?.unobserve(nodeRef.current);
1675
+ if (currNode) {
1676
+ resizeObserver?.unobserve(currNode);
1716
1677
  }
1717
1678
  };
1718
1679
  }, []);
@@ -1740,7 +1701,7 @@ function NodeWrapper({ id, onClick, onMouseEnter, onMouseMove, onMouseLeave, onC
1740
1701
  if (targetPosChanged) {
1741
1702
  prevTargetPosition.current = node.targetPosition;
1742
1703
  }
1743
- store.getState().updateNodeDimensions(new Map([[id, { id, nodeElement: nodeRef.current, forceUpdate: true }]]));
1704
+ store.getState().updateNodeDimensions(new Map([[id, { id, nodeElement: nodeRef.current, force: true }]]));
1744
1705
  }
1745
1706
  }, [id, nodeType, node.sourcePosition, node.targetPosition]);
1746
1707
  const dragging = useDrag({
@@ -2163,7 +2124,7 @@ function EdgeUpdateAnchors({ isUpdatable, edgeUpdaterRadius, edge, targetHandleI
2163
2124
  if (event.button !== 0) {
2164
2125
  return;
2165
2126
  }
2166
- const { autoPanOnConnect, domNode, isValidConnection, connectionMode, connectionRadius, lib, onConnectStart, onConnectEnd, cancelConnection, nodes, rfId: flowId, panBy, updateConnection, } = store.getState();
2127
+ const { autoPanOnConnect, domNode, isValidConnection, connectionMode, connectionRadius, lib, onConnectStart, onConnectEnd, cancelConnection, nodeLookup, rfId: flowId, panBy, updateConnection, } = store.getState();
2167
2128
  const nodeId = isSourceHandle ? edge.target : edge.source;
2168
2129
  const handleId = (isSourceHandle ? targetHandleId : sourceHandleId) || null;
2169
2130
  const handleType = isSourceHandle ? 'target' : 'source';
@@ -2182,7 +2143,7 @@ function EdgeUpdateAnchors({ isUpdatable, edgeUpdaterRadius, edge, targetHandleI
2182
2143
  domNode,
2183
2144
  handleId,
2184
2145
  nodeId,
2185
- nodes,
2146
+ nodeLookup,
2186
2147
  isTarget,
2187
2148
  edgeUpdaterType: handleType,
2188
2149
  lib,
@@ -2403,7 +2364,7 @@ const ConnectionLine = ({ nodeId, handleType, style, type = ConnectionLineType.B
2403
2364
  toY: (s.connectionPosition.y - s.transform[1]) / s.transform[2],
2404
2365
  connectionMode: s.connectionMode,
2405
2366
  }), [nodeId]), shallow);
2406
- const fromHandleBounds = fromNode?.[internalsSymbol]?.handleBounds;
2367
+ const fromHandleBounds = fromNode?.internals?.handleBounds;
2407
2368
  let handleBounds = fromHandleBounds?.[handleType];
2408
2369
  if (connectionMode === ConnectionMode.Loose) {
2409
2370
  handleBounds = handleBounds ? handleBounds : fromHandleBounds?.[handleType === 'source' ? 'target' : 'source'];
@@ -2412,10 +2373,10 @@ const ConnectionLine = ({ nodeId, handleType, style, type = ConnectionLineType.B
2412
2373
  return null;
2413
2374
  }
2414
2375
  const fromHandle = handleId ? handleBounds.find((d) => d.id === handleId) : handleBounds[0];
2415
- const fromHandleX = fromHandle ? fromHandle.x + fromHandle.width / 2 : (fromNode.computed?.width ?? 0) / 2;
2416
- const fromHandleY = fromHandle ? fromHandle.y + fromHandle.height / 2 : fromNode.computed?.height ?? 0;
2417
- const fromX = (fromNode.computed?.positionAbsolute?.x ?? 0) + fromHandleX;
2418
- const fromY = (fromNode.computed?.positionAbsolute?.y ?? 0) + fromHandleY;
2376
+ const fromHandleX = fromHandle ? fromHandle.x + fromHandle.width / 2 : (fromNode.measured.width ?? 0) / 2;
2377
+ const fromHandleY = fromHandle ? fromHandle.y + fromHandle.height / 2 : fromNode.measured.height ?? 0;
2378
+ const fromX = (fromNode.internals.positionAbsolute.x ?? 0) + fromHandleX;
2379
+ const fromY = (fromNode.internals.positionAbsolute.y ?? 0) + fromHandleY;
2419
2380
  const fromPosition = fromHandle?.position;
2420
2381
  const toPosition = fromPosition ? oppositePosition[fromPosition] : null;
2421
2382
  if (!fromPosition || !toPosition) {
@@ -2504,13 +2465,13 @@ const getInitialState = ({ nodes, edges, defaultNodes, defaultEdges, width, heig
2504
2465
  const storeEdges = defaultEdges ?? edges ?? [];
2505
2466
  const storeNodes = defaultNodes ?? nodes ?? [];
2506
2467
  updateConnectionLookup(connectionLookup, edgeLookup, storeEdges);
2507
- const nextNodes = adoptUserProvidedNodes(storeNodes, nodeLookup, {
2468
+ adoptUserNodes(storeNodes, nodeLookup, {
2508
2469
  nodeOrigin: [0, 0],
2509
2470
  elevateNodesOnSelect: false,
2510
2471
  });
2511
2472
  let transform = [0, 0, 1];
2512
2473
  if (fitView && width && height) {
2513
- const nodesWithDimensions = nextNodes.filter((node) => (node.width || node.initialWidth) && (node.height || node.initialHeight));
2474
+ const nodesWithDimensions = storeNodes.filter((node) => (node.width || node.initialWidth) && (node.height || node.initialHeight));
2514
2475
  // @todo users nodeOrigin should be used here
2515
2476
  const bounds = getNodesBounds(nodesWithDimensions, { nodeOrigin: [0, 0] });
2516
2477
  const { x, y, zoom } = getViewportForBounds(bounds, width, height, 0.5, 2, 0.1);
@@ -2521,7 +2482,7 @@ const getInitialState = ({ nodes, edges, defaultNodes, defaultEdges, width, heig
2521
2482
  width: 0,
2522
2483
  height: 0,
2523
2484
  transform,
2524
- nodes: nextNodes,
2485
+ nodes: storeNodes,
2525
2486
  nodeLookup,
2526
2487
  edges: storeEdges,
2527
2488
  edgeLookup,
@@ -2587,8 +2548,8 @@ const createRFStore = ({ nodes, edges, defaultNodes, defaultEdges, width, height
2587
2548
  //
2588
2549
  // When this happens, we take the note objects passed by the user and extend them with fields
2589
2550
  // relevant for internal React Flow operations.
2590
- const nodesWithInternalData = adoptUserProvidedNodes(nodes, nodeLookup, { nodeOrigin, elevateNodesOnSelect });
2591
- set({ nodes: nodesWithInternalData });
2551
+ adoptUserNodes(nodes, nodeLookup, { nodeOrigin, elevateNodesOnSelect });
2552
+ set({ nodes });
2592
2553
  },
2593
2554
  setEdges: (edges) => {
2594
2555
  const { connectionLookup, edgeLookup } = get();
@@ -2611,25 +2572,18 @@ const createRFStore = ({ nodes, edges, defaultNodes, defaultEdges, width, height
2611
2572
  // changes its dimensions, this function is called to measure the
2612
2573
  // new dimensions and update the nodes.
2613
2574
  updateNodeDimensions: (updates) => {
2614
- const { onNodesChange, fitView, nodes, nodeLookup, fitViewOnInit, fitViewDone, fitViewOnInitOptions, domNode, nodeOrigin, debug, } = get();
2615
- const changes = [];
2616
- const updatedNodes = updateNodeDimensions(updates, nodes, nodeLookup, domNode, nodeOrigin, (id, dimensions) => {
2617
- changes.push({
2618
- id: id,
2619
- type: 'dimensions',
2620
- dimensions,
2621
- });
2622
- });
2623
- if (!updatedNodes) {
2575
+ const { onNodesChange, fitView, nodeLookup, fitViewOnInit, fitViewDone, fitViewOnInitOptions, domNode, nodeOrigin, debug, } = get();
2576
+ const changes = updateNodeDimensions(updates, nodeLookup, domNode, nodeOrigin);
2577
+ if (changes.length === 0) {
2624
2578
  return;
2625
2579
  }
2626
- const nextNodes = updateAbsolutePositions(updatedNodes, nodeLookup, nodeOrigin);
2580
+ updateAbsolutePositions(nodeLookup, { nodeOrigin });
2627
2581
  // we call fitView once initially after all dimensions are set
2628
2582
  let nextFitViewDone = fitViewDone;
2629
2583
  if (!fitViewDone && fitViewOnInit) {
2630
- nextFitViewDone = fitView(nextNodes, {
2584
+ nextFitViewDone = fitView({
2631
2585
  ...fitViewOnInitOptions,
2632
- nodes: fitViewOnInitOptions?.nodes || nextNodes,
2586
+ nodes: fitViewOnInitOptions?.nodes,
2633
2587
  });
2634
2588
  }
2635
2589
  // here we are cirmumventing the onNodesChange handler
@@ -2637,7 +2591,7 @@ const createRFStore = ({ nodes, edges, defaultNodes, defaultEdges, width, height
2637
2591
  // has not provided an onNodesChange handler.
2638
2592
  // Nodes are only rendered if they have a width and height
2639
2593
  // attribute which they get from this handler.
2640
- set({ nodes: nextNodes, fitViewDone: nextFitViewDone });
2594
+ set({ fitViewDone: nextFitViewDone });
2641
2595
  if (changes?.length > 0) {
2642
2596
  if (debug) {
2643
2597
  console.log('React Flow: trigger node changes', changes);
@@ -2646,16 +2600,35 @@ const createRFStore = ({ nodes, edges, defaultNodes, defaultEdges, width, height
2646
2600
  }
2647
2601
  },
2648
2602
  updateNodePositions: (nodeDragItems, dragging = false) => {
2603
+ const { nodeLookup } = get();
2604
+ const triggerChangeNodes = [];
2649
2605
  const changes = nodeDragItems.map((node) => {
2606
+ // @todo add expandParent to drag item so that we can get rid of the look up here
2607
+ const internalNode = nodeLookup.get(node.id);
2650
2608
  const change = {
2651
2609
  id: node.id,
2652
2610
  type: 'position',
2653
2611
  position: node.position,
2654
- positionAbsolute: node.computed?.positionAbsolute,
2655
2612
  dragging,
2656
2613
  };
2614
+ if (internalNode?.expandParent && change.position) {
2615
+ triggerChangeNodes.push({
2616
+ ...internalNode,
2617
+ position: change.position,
2618
+ internals: {
2619
+ ...internalNode.internals,
2620
+ positionAbsolute: node.internals.positionAbsolute,
2621
+ },
2622
+ });
2623
+ change.position.x = Math.max(0, change.position.x);
2624
+ change.position.y = Math.max(0, change.position.y);
2625
+ }
2657
2626
  return change;
2658
2627
  });
2628
+ if (triggerChangeNodes.length > 0) {
2629
+ const parentExpandChanges = handleParentExpand(triggerChangeNodes, nodeLookup);
2630
+ changes.push(...parentExpandChanges);
2631
+ }
2659
2632
  get().triggerNodeChanges(changes);
2660
2633
  },
2661
2634
  triggerNodeChanges: (changes) => {
@@ -2685,24 +2658,24 @@ const createRFStore = ({ nodes, edges, defaultNodes, defaultEdges, width, height
2685
2658
  }
2686
2659
  },
2687
2660
  addSelectedNodes: (selectedNodeIds) => {
2688
- const { multiSelectionActive, edges, nodes, triggerNodeChanges, triggerEdgeChanges } = get();
2661
+ const { multiSelectionActive, edgeLookup, nodeLookup, triggerNodeChanges, triggerEdgeChanges } = get();
2689
2662
  if (multiSelectionActive) {
2690
2663
  const nodeChanges = selectedNodeIds.map((nodeId) => createSelectionChange(nodeId, true));
2691
2664
  triggerNodeChanges(nodeChanges);
2692
2665
  return;
2693
2666
  }
2694
- triggerNodeChanges(getSelectionChanges(nodes, new Set([...selectedNodeIds]), true));
2695
- triggerEdgeChanges(getSelectionChanges(edges));
2667
+ triggerNodeChanges(getSelectionChanges(nodeLookup, new Set([...selectedNodeIds]), true));
2668
+ triggerEdgeChanges(getSelectionChanges(edgeLookup));
2696
2669
  },
2697
2670
  addSelectedEdges: (selectedEdgeIds) => {
2698
- const { multiSelectionActive, edges, nodes, triggerNodeChanges, triggerEdgeChanges } = get();
2671
+ const { multiSelectionActive, edgeLookup, nodeLookup, triggerNodeChanges, triggerEdgeChanges } = get();
2699
2672
  if (multiSelectionActive) {
2700
2673
  const changedEdges = selectedEdgeIds.map((edgeId) => createSelectionChange(edgeId, true));
2701
2674
  triggerEdgeChanges(changedEdges);
2702
2675
  return;
2703
2676
  }
2704
- triggerEdgeChanges(getSelectionChanges(edges, new Set([...selectedEdgeIds])));
2705
- triggerNodeChanges(getSelectionChanges(nodes, new Set(), true));
2677
+ triggerEdgeChanges(getSelectionChanges(edgeLookup, new Set([...selectedEdgeIds])));
2678
+ triggerNodeChanges(getSelectionChanges(nodeLookup, new Set(), true));
2706
2679
  },
2707
2680
  unselectNodesAndEdges: ({ nodes, edges } = {}) => {
2708
2681
  const { edges: storeEdges, nodes: storeNodes, triggerNodeChanges, triggerEdgeChanges } = get();
@@ -2738,32 +2711,32 @@ const createRFStore = ({ nodes, edges, defaultNodes, defaultEdges, width, height
2738
2711
  triggerEdgeChanges(edgeChanges);
2739
2712
  },
2740
2713
  setNodeExtent: (nodeExtent) => {
2741
- const { nodes } = get();
2714
+ const { nodeLookup } = get();
2715
+ for (const [, node] of nodeLookup) {
2716
+ const positionAbsolute = clampPosition(node.position, nodeExtent);
2717
+ nodeLookup.set(node.id, {
2718
+ ...node,
2719
+ internals: {
2720
+ ...node.internals,
2721
+ positionAbsolute,
2722
+ },
2723
+ });
2724
+ }
2742
2725
  set({
2743
2726
  nodeExtent,
2744
- nodes: nodes.map((node) => {
2745
- const positionAbsolute = clampPosition(node.position, nodeExtent);
2746
- return {
2747
- ...node,
2748
- computed: {
2749
- ...node.computed,
2750
- positionAbsolute,
2751
- },
2752
- };
2753
- }),
2754
2727
  });
2755
2728
  },
2756
2729
  panBy: (delta) => {
2757
2730
  const { transform, width, height, panZoom, translateExtent } = get();
2758
2731
  return panBy({ delta, panZoom, transform, translateExtent, width, height });
2759
2732
  },
2760
- fitView: (nodes, options) => {
2761
- const { panZoom, width, height, minZoom, maxZoom, nodeOrigin } = get();
2733
+ fitView: (options) => {
2734
+ const { panZoom, width, height, minZoom, maxZoom, nodeOrigin, nodeLookup } = get();
2762
2735
  if (!panZoom) {
2763
2736
  return false;
2764
2737
  }
2765
2738
  return fitView({
2766
- nodes,
2739
+ nodeLookup,
2767
2740
  width,
2768
2741
  height,
2769
2742
  panZoom,
@@ -2861,7 +2834,7 @@ function useUpdateNodeInternals() {
2861
2834
  updateIds.forEach((updateId) => {
2862
2835
  const nodeElement = domNode?.querySelector(`.react-flow__node[data-id="${updateId}"]`);
2863
2836
  if (nodeElement) {
2864
- updates.set(updateId, { id: updateId, nodeElement, forceUpdate: true });
2837
+ updates.set(updateId, { id: updateId, nodeElement, force: true });
2865
2838
  }
2866
2839
  });
2867
2840
  requestAnimationFrame(() => updateNodeDimensions(updates));
@@ -2973,12 +2946,12 @@ function useOnSelectionChange({ onChange }) {
2973
2946
  }
2974
2947
 
2975
2948
  const selector$6 = (options) => (s) => {
2976
- if (s.nodes.length === 0) {
2949
+ if (s.nodeLookup.size === 0) {
2977
2950
  return false;
2978
2951
  }
2979
- for (const node of s.nodes) {
2952
+ for (const [, node] of s.nodeLookup) {
2980
2953
  if (options.includeHiddenNodes || !node.hidden) {
2981
- if (node[internalsSymbol]?.handleBounds === undefined) {
2954
+ if (node.internals.handleBounds === undefined) {
2982
2955
  return false;
2983
2956
  }
2984
2957
  }
@@ -3066,6 +3039,18 @@ function useConnection() {
3066
3039
  return ongoingConnection;
3067
3040
  }
3068
3041
 
3042
+ /**
3043
+ * Hook for getting an internal node by id
3044
+ *
3045
+ * @public
3046
+ * @param id - id of the node
3047
+ * @returns array with visible node ids
3048
+ */
3049
+ function useInternalNode(id) {
3050
+ const node = useStore(useCallback((s) => s.nodeLookup.get(id), [id]), shallow);
3051
+ return node;
3052
+ }
3053
+
3069
3054
  function LinePattern({ dimensions, lineWidth, variant, className }) {
3070
3055
  return (jsx("path", { strokeWidth: lineWidth, d: `M${dimensions[0] / 2} 0 V${dimensions[1]} M0 ${dimensions[1] / 2} H${dimensions[0]}`, className: cc(['react-flow__background-pattern', variant, className]) }));
3071
3056
  }
@@ -3143,7 +3128,7 @@ const selector$3 = (s) => ({
3143
3128
  minZoomReached: s.transform[2] <= s.minZoom,
3144
3129
  maxZoomReached: s.transform[2] >= s.maxZoom,
3145
3130
  });
3146
- function ControlsComponent({ style, showZoom = true, showFitView = true, showInteractive = true, fitViewOptions, onZoomIn, onZoomOut, onFitView, onInteractiveChange, className, children, position = 'bottom-left', 'aria-label': ariaLabel = 'React Flow controls', }) {
3131
+ function ControlsComponent({ style, showZoom = true, showFitView = true, showInteractive = true, fitViewOptions, onZoomIn, onZoomOut, onFitView, onInteractiveChange, className, children, position = 'bottom-left', orientation = 'vertical', 'aria-label': ariaLabel = 'React Flow controls', }) {
3147
3132
  const store = useStoreApi();
3148
3133
  const { isInteractive, minZoomReached, maxZoomReached } = useStore(selector$3, shallow);
3149
3134
  const { zoomIn, zoomOut, fitView } = useReactFlow();
@@ -3167,7 +3152,8 @@ function ControlsComponent({ style, showZoom = true, showFitView = true, showInt
3167
3152
  });
3168
3153
  onInteractiveChange?.(!isInteractive);
3169
3154
  };
3170
- return (jsxs(Panel, { className: cc(['react-flow__controls', className]), position: position, style: style, "data-testid": "rf__controls", "aria-label": ariaLabel, children: [showZoom && (jsxs(Fragment, { children: [jsx(ControlButton, { onClick: onZoomInHandler, className: "react-flow__controls-zoomin", title: "zoom in", "aria-label": "zoom in", disabled: maxZoomReached, children: jsx(PlusIcon, {}) }), jsx(ControlButton, { onClick: onZoomOutHandler, className: "react-flow__controls-zoomout", title: "zoom out", "aria-label": "zoom out", disabled: minZoomReached, children: jsx(MinusIcon, {}) })] })), showFitView && (jsx(ControlButton, { className: "react-flow__controls-fitview", onClick: onFitViewHandler, title: "fit view", "aria-label": "fit view", children: jsx(FitViewIcon, {}) })), showInteractive && (jsx(ControlButton, { className: "react-flow__controls-interactive", onClick: onToggleInteractivity, title: "toggle interactivity", "aria-label": "toggle interactivity", children: isInteractive ? jsx(UnlockIcon, {}) : jsx(LockIcon, {}) })), children] }));
3155
+ const orientationClass = orientation === 'horizontal' ? 'horizontal' : 'vertical';
3156
+ return (jsxs(Panel, { className: cc(['react-flow__controls', orientationClass, className]), position: position, style: style, "data-testid": "rf__controls", "aria-label": ariaLabel, children: [showZoom && (jsxs(Fragment, { children: [jsx(ControlButton, { onClick: onZoomInHandler, className: "react-flow__controls-zoomin", title: "zoom in", "aria-label": "zoom in", disabled: maxZoomReached, children: jsx(PlusIcon, {}) }), jsx(ControlButton, { onClick: onZoomOutHandler, className: "react-flow__controls-zoomout", title: "zoom out", "aria-label": "zoom out", disabled: minZoomReached, children: jsx(MinusIcon, {}) })] })), showFitView && (jsx(ControlButton, { className: "react-flow__controls-fitview", onClick: onFitViewHandler, title: "fit view", "aria-label": "fit view", children: jsx(FitViewIcon, {}) })), showInteractive && (jsx(ControlButton, { className: "react-flow__controls-interactive", onClick: onToggleInteractivity, title: "toggle interactivity", "aria-label": "toggle interactivity", children: isInteractive ? jsx(UnlockIcon, {}) : jsx(LockIcon, {}) })), children] }));
3171
3157
  }
3172
3158
  ControlsComponent.displayName = 'Controls';
3173
3159
  const Controls = memo(ControlsComponent);
@@ -3234,7 +3220,9 @@ const selector$1 = (s) => {
3234
3220
  };
3235
3221
  return {
3236
3222
  viewBB,
3237
- boundingRect: s.nodes.length > 0 ? getBoundsOfRects(getNodesBounds(s.nodes, { nodeOrigin: s.nodeOrigin }), viewBB) : viewBB,
3223
+ boundingRect: s.nodeLookup.size > 0
3224
+ ? getBoundsOfRects(getInternalNodesBounds(s.nodeLookup, { nodeOrigin: s.nodeOrigin }), viewBB)
3225
+ : viewBB,
3238
3226
  rfId: s.rfId,
3239
3227
  nodeOrigin: s.nodeOrigin,
3240
3228
  panZoom: s.panZoom,
@@ -3441,12 +3429,12 @@ function NodeToolbarPortal({ children }) {
3441
3429
  return createPortal(children, wrapperRef);
3442
3430
  }
3443
3431
 
3444
- const nodeEqualityFn = (a, b) => a?.computed?.positionAbsolute?.x !== b?.computed?.positionAbsolute?.x ||
3445
- a?.computed?.positionAbsolute?.y !== b?.computed?.positionAbsolute?.y ||
3446
- a?.computed?.width !== b?.computed?.width ||
3447
- a?.computed?.height !== b?.computed?.height ||
3432
+ const nodeEqualityFn = (a, b) => a?.internals.positionAbsolute.x !== b?.internals.positionAbsolute.x ||
3433
+ a?.internals.positionAbsolute.y !== b?.internals.positionAbsolute.y ||
3434
+ a?.measured.width !== b?.measured.width ||
3435
+ a?.measured.height !== b?.measured.height ||
3448
3436
  a?.selected !== b?.selected ||
3449
- a?.[internalsSymbol]?.z !== b?.[internalsSymbol]?.z;
3437
+ a?.internals.z !== b?.internals.z;
3450
3438
  const nodesEqualityFn = (a, b) => {
3451
3439
  if (a.length !== b.length) {
3452
3440
  return false;
@@ -3482,7 +3470,7 @@ function NodeToolbar({ nodeId, children, className, style, isVisible, position =
3482
3470
  return null;
3483
3471
  }
3484
3472
  const nodeRect = getNodesBounds(nodes, { nodeOrigin });
3485
- const zIndex = Math.max(...nodes.map((node) => (node[internalsSymbol]?.z || 1) + 1));
3473
+ const zIndex = Math.max(...nodes.map((node) => (node.internals?.z || 1) + 1));
3486
3474
  const wrapperStyle = {
3487
3475
  position: 'absolute',
3488
3476
  transform: getNodeToolbarTransform(nodeRect, viewport, position, offset, align),
@@ -3492,4 +3480,4 @@ function NodeToolbar({ nodeId, children, className, style, isVisible, position =
3492
3480
  return (jsx(NodeToolbarPortal, { children: jsx("div", { style: wrapperStyle, className: cc(['react-flow__node-toolbar', className]), ...rest, "data-id": nodes.reduce((acc, node) => `${acc}${node.id} `, '').trim(), children: children }) }));
3493
3481
  }
3494
3482
 
3495
- export { Background, BackgroundVariant, BaseEdge, BezierEdge, ControlButton, Controls, EdgeLabelRenderer, EdgeText, Handle, MiniMap, NodeResizeControl, NodeResizer, NodeToolbar, Panel, index as ReactFlow, ReactFlowProvider, SimpleBezierEdge, SmoothStepEdge, StepEdge, StraightEdge, ViewportPortal, applyEdgeChanges, applyNodeChanges, getSimpleBezierPath, handleParentExpand, isEdge, isNode, useConnection, useEdges, useEdgesState, useHandleConnections, useKeyPress, useNodeId, useNodes, useNodesData, useNodesInitialized, useNodesState, useOnSelectionChange, useOnViewportChange, useReactFlow, useStore, useStoreApi, useUpdateNodeInternals, useViewport };
3483
+ export { Background, BackgroundVariant, BaseEdge, BezierEdge, ControlButton, Controls, EdgeLabelRenderer, EdgeText, Handle, MiniMap, NodeResizeControl, NodeResizer, NodeToolbar, Panel, index as ReactFlow, ReactFlowProvider, SimpleBezierEdge, SmoothStepEdge, StepEdge, StraightEdge, ViewportPortal, applyEdgeChanges, applyNodeChanges, getSimpleBezierPath, isEdge, isNode, useConnection, useEdges, useEdgesState, useHandleConnections, useInternalNode, useKeyPress, useNodeId, useNodes, useNodesData, useNodesInitialized, useNodesState, useOnSelectionChange, useOnViewportChange, useReactFlow, useStore, useStoreApi, useUpdateNodeInternals, useViewport };