@xyflow/react 12.0.0-next.9 → 12.0.1

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 (366) hide show
  1. package/dist/base.css +122 -8
  2. package/dist/esm/additional-components/Background/Background.d.ts.map +1 -1
  3. package/dist/esm/additional-components/Background/Patterns.d.ts.map +1 -1
  4. package/dist/esm/additional-components/Background/index.d.ts.map +1 -1
  5. package/dist/esm/additional-components/Background/types.d.ts.map +1 -1
  6. package/dist/esm/additional-components/Controls/ControlButton.d.ts.map +1 -1
  7. package/dist/esm/additional-components/Controls/Controls.d.ts +1 -1
  8. package/dist/esm/additional-components/Controls/Controls.d.ts.map +1 -1
  9. package/dist/esm/additional-components/Controls/Icons/FitView.d.ts.map +1 -1
  10. package/dist/esm/additional-components/Controls/Icons/Lock.d.ts.map +1 -1
  11. package/dist/esm/additional-components/Controls/Icons/Minus.d.ts.map +1 -1
  12. package/dist/esm/additional-components/Controls/Icons/Plus.d.ts.map +1 -1
  13. package/dist/esm/additional-components/Controls/Icons/Unlock.d.ts.map +1 -1
  14. package/dist/esm/additional-components/Controls/index.d.ts.map +1 -1
  15. package/dist/esm/additional-components/Controls/types.d.ts +1 -0
  16. package/dist/esm/additional-components/Controls/types.d.ts.map +1 -1
  17. package/dist/esm/additional-components/MiniMap/MiniMap.d.ts +3 -3
  18. package/dist/esm/additional-components/MiniMap/MiniMap.d.ts.map +1 -1
  19. package/dist/esm/additional-components/MiniMap/MiniMapNode.d.ts.map +1 -1
  20. package/dist/esm/additional-components/MiniMap/MiniMapNodes.d.ts +3 -3
  21. package/dist/esm/additional-components/MiniMap/MiniMapNodes.d.ts.map +1 -1
  22. package/dist/esm/additional-components/MiniMap/index.d.ts.map +1 -1
  23. package/dist/esm/additional-components/MiniMap/types.d.ts.map +1 -1
  24. package/dist/esm/additional-components/NodeResizer/NodeResizeControl.d.ts.map +1 -1
  25. package/dist/esm/additional-components/NodeResizer/NodeResizer.d.ts.map +1 -1
  26. package/dist/esm/additional-components/NodeResizer/index.d.ts.map +1 -1
  27. package/dist/esm/additional-components/NodeResizer/types.d.ts.map +1 -1
  28. package/dist/esm/additional-components/NodeToolbar/NodeToolbar.d.ts.map +1 -1
  29. package/dist/esm/additional-components/NodeToolbar/NodeToolbarPortal.d.ts.map +1 -1
  30. package/dist/esm/additional-components/NodeToolbar/index.d.ts.map +1 -1
  31. package/dist/esm/additional-components/NodeToolbar/types.d.ts.map +1 -1
  32. package/dist/esm/additional-components/index.d.ts.map +1 -1
  33. package/dist/esm/components/A11yDescriptions/index.d.ts.map +1 -1
  34. package/dist/esm/components/Attribution/index.d.ts.map +1 -1
  35. package/dist/esm/components/BatchProvider/index.d.ts +17 -0
  36. package/dist/esm/components/BatchProvider/index.d.ts.map +1 -0
  37. package/dist/esm/components/BatchProvider/types.d.ts +7 -0
  38. package/dist/esm/components/BatchProvider/types.d.ts.map +1 -0
  39. package/dist/esm/components/BatchProvider/useQueue.d.ts +11 -0
  40. package/dist/esm/components/BatchProvider/useQueue.d.ts.map +1 -0
  41. package/dist/esm/components/ConnectionLine/index.d.ts.map +1 -1
  42. package/dist/esm/components/EdgeLabelRenderer/index.d.ts.map +1 -1
  43. package/dist/esm/components/EdgeWrapper/EdgeUpdateAnchors.d.ts +9 -9
  44. package/dist/esm/components/EdgeWrapper/EdgeUpdateAnchors.d.ts.map +1 -1
  45. package/dist/esm/components/EdgeWrapper/index.d.ts +2 -2
  46. package/dist/esm/components/EdgeWrapper/index.d.ts.map +1 -1
  47. package/dist/esm/components/EdgeWrapper/utils.d.ts.map +1 -1
  48. package/dist/esm/components/Edges/BaseEdge.d.ts.map +1 -1
  49. package/dist/esm/components/Edges/BezierEdge.d.ts.map +1 -1
  50. package/dist/esm/components/Edges/EdgeAnchor.d.ts.map +1 -1
  51. package/dist/esm/components/Edges/EdgeText.d.ts.map +1 -1
  52. package/dist/esm/components/Edges/SimpleBezierEdge.d.ts.map +1 -1
  53. package/dist/esm/components/Edges/SmoothStepEdge.d.ts.map +1 -1
  54. package/dist/esm/components/Edges/StepEdge.d.ts.map +1 -1
  55. package/dist/esm/components/Edges/StraightEdge.d.ts.map +1 -1
  56. package/dist/esm/components/Edges/index.d.ts.map +1 -1
  57. package/dist/esm/components/Handle/index.d.ts +7 -5
  58. package/dist/esm/components/Handle/index.d.ts.map +1 -1
  59. package/dist/esm/components/NodeWrapper/index.d.ts +2 -2
  60. package/dist/esm/components/NodeWrapper/index.d.ts.map +1 -1
  61. package/dist/esm/components/NodeWrapper/useNodeObserver.d.ts +15 -0
  62. package/dist/esm/components/NodeWrapper/useNodeObserver.d.ts.map +1 -0
  63. package/dist/esm/components/NodeWrapper/utils.d.ts +5 -1
  64. package/dist/esm/components/NodeWrapper/utils.d.ts.map +1 -1
  65. package/dist/esm/components/Nodes/DefaultNode.d.ts +2 -2
  66. package/dist/esm/components/Nodes/DefaultNode.d.ts.map +1 -1
  67. package/dist/esm/components/Nodes/GroupNode.d.ts.map +1 -1
  68. package/dist/esm/components/Nodes/InputNode.d.ts +2 -2
  69. package/dist/esm/components/Nodes/InputNode.d.ts.map +1 -1
  70. package/dist/esm/components/Nodes/OutputNode.d.ts +2 -2
  71. package/dist/esm/components/Nodes/OutputNode.d.ts.map +1 -1
  72. package/dist/esm/components/Nodes/utils.d.ts.map +1 -1
  73. package/dist/esm/components/NodesSelection/index.d.ts +3 -3
  74. package/dist/esm/components/NodesSelection/index.d.ts.map +1 -1
  75. package/dist/esm/components/Panel/index.d.ts.map +1 -1
  76. package/dist/esm/components/ReactFlowProvider/index.d.ts +6 -3
  77. package/dist/esm/components/ReactFlowProvider/index.d.ts.map +1 -1
  78. package/dist/esm/components/SelectionListener/index.d.ts.map +1 -1
  79. package/dist/esm/components/StoreUpdater/index.d.ts +4 -4
  80. package/dist/esm/components/StoreUpdater/index.d.ts.map +1 -1
  81. package/dist/esm/components/UserSelection/index.d.ts.map +1 -1
  82. package/dist/esm/components/ViewportPortal/index.d.ts.map +1 -1
  83. package/dist/esm/container/EdgeRenderer/MarkerDefinitions.d.ts.map +1 -1
  84. package/dist/esm/container/EdgeRenderer/MarkerSymbols.d.ts.map +1 -1
  85. package/dist/esm/container/EdgeRenderer/index.d.ts +4 -3
  86. package/dist/esm/container/EdgeRenderer/index.d.ts.map +1 -1
  87. package/dist/esm/container/FlowRenderer/index.d.ts +8 -5
  88. package/dist/esm/container/FlowRenderer/index.d.ts.map +1 -1
  89. package/dist/esm/container/GraphView/index.d.ts +4 -5
  90. package/dist/esm/container/GraphView/index.d.ts.map +1 -1
  91. package/dist/esm/container/GraphView/useNodeOrEdgeTypesWarning.d.ts +6 -0
  92. package/dist/esm/container/GraphView/useNodeOrEdgeTypesWarning.d.ts.map +1 -1
  93. package/dist/esm/container/GraphView/useStylesLoadedWarning.d.ts +2 -0
  94. package/dist/esm/container/GraphView/useStylesLoadedWarning.d.ts.map +1 -0
  95. package/dist/esm/container/NodeRenderer/index.d.ts +8 -6
  96. package/dist/esm/container/NodeRenderer/index.d.ts.map +1 -1
  97. package/dist/esm/container/NodeRenderer/useResizeObserver.d.ts.map +1 -1
  98. package/dist/esm/container/Pane/index.d.ts +2 -1
  99. package/dist/esm/container/Pane/index.d.ts.map +1 -1
  100. package/dist/esm/container/ReactFlow/Wrapper.d.ts +3 -1
  101. package/dist/esm/container/ReactFlow/Wrapper.d.ts.map +1 -1
  102. package/dist/esm/container/ReactFlow/index.d.ts +3 -3
  103. package/dist/esm/container/ReactFlow/index.d.ts.map +1 -1
  104. package/dist/esm/container/ReactFlow/init-values.d.ts.map +1 -1
  105. package/dist/esm/container/Viewport/index.d.ts.map +1 -1
  106. package/dist/esm/container/ZoomPane/index.d.ts +1 -1
  107. package/dist/esm/container/ZoomPane/index.d.ts.map +1 -1
  108. package/dist/esm/contexts/NodeIdContext.d.ts.map +1 -1
  109. package/dist/esm/contexts/{RFStoreContext.d.ts → StoreContext.d.ts} +1 -1
  110. package/dist/esm/contexts/StoreContext.d.ts.map +1 -0
  111. package/dist/esm/hooks/useColorModeClass.d.ts.map +1 -1
  112. package/dist/esm/hooks/useConnection.d.ts +5 -15
  113. package/dist/esm/hooks/useConnection.d.ts.map +1 -1
  114. package/dist/esm/hooks/useDrag.d.ts.map +1 -1
  115. package/dist/esm/hooks/useEdges.d.ts +1 -1
  116. package/dist/esm/hooks/useEdges.d.ts.map +1 -1
  117. package/dist/esm/hooks/useGlobalKeyHandler.d.ts.map +1 -1
  118. package/dist/esm/hooks/useHandleConnections.d.ts.map +1 -1
  119. package/dist/esm/hooks/useInternalNode.d.ts +10 -0
  120. package/dist/esm/hooks/useInternalNode.d.ts.map +1 -0
  121. package/dist/esm/hooks/useIsomorphicLayoutEffect.d.ts +3 -0
  122. package/dist/esm/hooks/useIsomorphicLayoutEffect.d.ts.map +1 -0
  123. package/dist/esm/hooks/useKeyPress.d.ts.map +1 -1
  124. package/dist/esm/hooks/useMoveSelectedNodes.d.ts.map +1 -1
  125. package/dist/esm/hooks/useNodes.d.ts.map +1 -1
  126. package/dist/esm/hooks/useNodesData.d.ts +3 -4
  127. package/dist/esm/hooks/useNodesData.d.ts.map +1 -1
  128. package/dist/esm/hooks/useNodesEdgesState.d.ts +3 -3
  129. package/dist/esm/hooks/useNodesEdgesState.d.ts.map +1 -1
  130. package/dist/esm/hooks/useNodesInitialized.d.ts.map +1 -1
  131. package/dist/esm/hooks/useOnInitHandler.d.ts +2 -2
  132. package/dist/esm/hooks/useOnInitHandler.d.ts.map +1 -1
  133. package/dist/esm/hooks/useOnSelectionChange.d.ts.map +1 -1
  134. package/dist/esm/hooks/useOnViewportChange.d.ts.map +1 -1
  135. package/dist/esm/hooks/useReactFlow.d.ts.map +1 -1
  136. package/dist/esm/hooks/useResizeHandler.d.ts.map +1 -1
  137. package/dist/esm/hooks/useStore.d.ts +10 -11
  138. package/dist/esm/hooks/useStore.d.ts.map +1 -1
  139. package/dist/esm/hooks/useUpdateNodeInternals.d.ts.map +1 -1
  140. package/dist/esm/hooks/useViewport.d.ts.map +1 -1
  141. package/dist/esm/hooks/useViewportHelper.d.ts.map +1 -1
  142. package/dist/esm/hooks/useViewportSync.d.ts.map +1 -1
  143. package/dist/esm/hooks/useVisibleEdgeIds.d.ts.map +1 -1
  144. package/dist/esm/hooks/useVisibleNodeIds.d.ts.map +1 -1
  145. package/dist/esm/index.d.ts +5 -4
  146. package/dist/esm/index.d.ts.map +1 -1
  147. package/dist/esm/index.js +988 -819
  148. package/dist/esm/index.mjs +988 -819
  149. package/dist/esm/store/index.d.ts +8 -6
  150. package/dist/esm/store/index.d.ts.map +1 -1
  151. package/dist/esm/store/initialState.d.ts +7 -5
  152. package/dist/esm/store/initialState.d.ts.map +1 -1
  153. package/dist/esm/styles/utils.d.ts.map +1 -1
  154. package/dist/esm/types/component-props.d.ts +51 -39
  155. package/dist/esm/types/component-props.d.ts.map +1 -1
  156. package/dist/esm/types/edges.d.ts +36 -36
  157. package/dist/esm/types/edges.d.ts.map +1 -1
  158. package/dist/esm/types/general.d.ts +18 -16
  159. package/dist/esm/types/general.d.ts.map +1 -1
  160. package/dist/esm/types/index.d.ts +0 -1
  161. package/dist/esm/types/index.d.ts.map +1 -1
  162. package/dist/esm/types/instance.d.ts +63 -44
  163. package/dist/esm/types/instance.d.ts.map +1 -1
  164. package/dist/esm/types/nodes.d.ts +20 -10
  165. package/dist/esm/types/nodes.d.ts.map +1 -1
  166. package/dist/esm/types/store.d.ts +33 -31
  167. package/dist/esm/types/store.d.ts.map +1 -1
  168. package/dist/esm/utils/changes.d.ts +5 -5
  169. package/dist/esm/utils/changes.d.ts.map +1 -1
  170. package/dist/esm/utils/general.d.ts +4 -2
  171. package/dist/esm/utils/general.d.ts.map +1 -1
  172. package/dist/esm/utils/index.d.ts.map +1 -1
  173. package/dist/style.css +30 -11
  174. package/dist/umd/additional-components/Background/Background.d.ts.map +1 -1
  175. package/dist/umd/additional-components/Background/Patterns.d.ts.map +1 -1
  176. package/dist/umd/additional-components/Background/index.d.ts.map +1 -1
  177. package/dist/umd/additional-components/Background/types.d.ts.map +1 -1
  178. package/dist/umd/additional-components/Controls/ControlButton.d.ts.map +1 -1
  179. package/dist/umd/additional-components/Controls/Controls.d.ts +1 -1
  180. package/dist/umd/additional-components/Controls/Controls.d.ts.map +1 -1
  181. package/dist/umd/additional-components/Controls/Icons/FitView.d.ts.map +1 -1
  182. package/dist/umd/additional-components/Controls/Icons/Lock.d.ts.map +1 -1
  183. package/dist/umd/additional-components/Controls/Icons/Minus.d.ts.map +1 -1
  184. package/dist/umd/additional-components/Controls/Icons/Plus.d.ts.map +1 -1
  185. package/dist/umd/additional-components/Controls/Icons/Unlock.d.ts.map +1 -1
  186. package/dist/umd/additional-components/Controls/index.d.ts.map +1 -1
  187. package/dist/umd/additional-components/Controls/types.d.ts +1 -0
  188. package/dist/umd/additional-components/Controls/types.d.ts.map +1 -1
  189. package/dist/umd/additional-components/MiniMap/MiniMap.d.ts +3 -3
  190. package/dist/umd/additional-components/MiniMap/MiniMap.d.ts.map +1 -1
  191. package/dist/umd/additional-components/MiniMap/MiniMapNode.d.ts.map +1 -1
  192. package/dist/umd/additional-components/MiniMap/MiniMapNodes.d.ts +3 -3
  193. package/dist/umd/additional-components/MiniMap/MiniMapNodes.d.ts.map +1 -1
  194. package/dist/umd/additional-components/MiniMap/index.d.ts.map +1 -1
  195. package/dist/umd/additional-components/MiniMap/types.d.ts.map +1 -1
  196. package/dist/umd/additional-components/NodeResizer/NodeResizeControl.d.ts.map +1 -1
  197. package/dist/umd/additional-components/NodeResizer/NodeResizer.d.ts.map +1 -1
  198. package/dist/umd/additional-components/NodeResizer/index.d.ts.map +1 -1
  199. package/dist/umd/additional-components/NodeResizer/types.d.ts.map +1 -1
  200. package/dist/umd/additional-components/NodeToolbar/NodeToolbar.d.ts.map +1 -1
  201. package/dist/umd/additional-components/NodeToolbar/NodeToolbarPortal.d.ts.map +1 -1
  202. package/dist/umd/additional-components/NodeToolbar/index.d.ts.map +1 -1
  203. package/dist/umd/additional-components/NodeToolbar/types.d.ts.map +1 -1
  204. package/dist/umd/additional-components/index.d.ts.map +1 -1
  205. package/dist/umd/components/A11yDescriptions/index.d.ts.map +1 -1
  206. package/dist/umd/components/Attribution/index.d.ts.map +1 -1
  207. package/dist/umd/components/BatchProvider/index.d.ts +17 -0
  208. package/dist/umd/components/BatchProvider/index.d.ts.map +1 -0
  209. package/dist/umd/components/BatchProvider/types.d.ts +7 -0
  210. package/dist/umd/components/BatchProvider/types.d.ts.map +1 -0
  211. package/dist/umd/components/BatchProvider/useQueue.d.ts +11 -0
  212. package/dist/umd/components/BatchProvider/useQueue.d.ts.map +1 -0
  213. package/dist/umd/components/ConnectionLine/index.d.ts.map +1 -1
  214. package/dist/umd/components/EdgeLabelRenderer/index.d.ts.map +1 -1
  215. package/dist/umd/components/EdgeWrapper/EdgeUpdateAnchors.d.ts +9 -9
  216. package/dist/umd/components/EdgeWrapper/EdgeUpdateAnchors.d.ts.map +1 -1
  217. package/dist/umd/components/EdgeWrapper/index.d.ts +2 -2
  218. package/dist/umd/components/EdgeWrapper/index.d.ts.map +1 -1
  219. package/dist/umd/components/EdgeWrapper/utils.d.ts.map +1 -1
  220. package/dist/umd/components/Edges/BaseEdge.d.ts.map +1 -1
  221. package/dist/umd/components/Edges/BezierEdge.d.ts.map +1 -1
  222. package/dist/umd/components/Edges/EdgeAnchor.d.ts.map +1 -1
  223. package/dist/umd/components/Edges/EdgeText.d.ts.map +1 -1
  224. package/dist/umd/components/Edges/SimpleBezierEdge.d.ts.map +1 -1
  225. package/dist/umd/components/Edges/SmoothStepEdge.d.ts.map +1 -1
  226. package/dist/umd/components/Edges/StepEdge.d.ts.map +1 -1
  227. package/dist/umd/components/Edges/StraightEdge.d.ts.map +1 -1
  228. package/dist/umd/components/Edges/index.d.ts.map +1 -1
  229. package/dist/umd/components/Handle/index.d.ts +7 -5
  230. package/dist/umd/components/Handle/index.d.ts.map +1 -1
  231. package/dist/umd/components/NodeWrapper/index.d.ts +2 -2
  232. package/dist/umd/components/NodeWrapper/index.d.ts.map +1 -1
  233. package/dist/umd/components/NodeWrapper/useNodeObserver.d.ts +15 -0
  234. package/dist/umd/components/NodeWrapper/useNodeObserver.d.ts.map +1 -0
  235. package/dist/umd/components/NodeWrapper/utils.d.ts +5 -1
  236. package/dist/umd/components/NodeWrapper/utils.d.ts.map +1 -1
  237. package/dist/umd/components/Nodes/DefaultNode.d.ts +2 -2
  238. package/dist/umd/components/Nodes/DefaultNode.d.ts.map +1 -1
  239. package/dist/umd/components/Nodes/GroupNode.d.ts.map +1 -1
  240. package/dist/umd/components/Nodes/InputNode.d.ts +2 -2
  241. package/dist/umd/components/Nodes/InputNode.d.ts.map +1 -1
  242. package/dist/umd/components/Nodes/OutputNode.d.ts +2 -2
  243. package/dist/umd/components/Nodes/OutputNode.d.ts.map +1 -1
  244. package/dist/umd/components/Nodes/utils.d.ts.map +1 -1
  245. package/dist/umd/components/NodesSelection/index.d.ts +3 -3
  246. package/dist/umd/components/NodesSelection/index.d.ts.map +1 -1
  247. package/dist/umd/components/Panel/index.d.ts.map +1 -1
  248. package/dist/umd/components/ReactFlowProvider/index.d.ts +6 -3
  249. package/dist/umd/components/ReactFlowProvider/index.d.ts.map +1 -1
  250. package/dist/umd/components/SelectionListener/index.d.ts.map +1 -1
  251. package/dist/umd/components/StoreUpdater/index.d.ts +4 -4
  252. package/dist/umd/components/StoreUpdater/index.d.ts.map +1 -1
  253. package/dist/umd/components/UserSelection/index.d.ts.map +1 -1
  254. package/dist/umd/components/ViewportPortal/index.d.ts.map +1 -1
  255. package/dist/umd/container/EdgeRenderer/MarkerDefinitions.d.ts.map +1 -1
  256. package/dist/umd/container/EdgeRenderer/MarkerSymbols.d.ts.map +1 -1
  257. package/dist/umd/container/EdgeRenderer/index.d.ts +4 -3
  258. package/dist/umd/container/EdgeRenderer/index.d.ts.map +1 -1
  259. package/dist/umd/container/FlowRenderer/index.d.ts +8 -5
  260. package/dist/umd/container/FlowRenderer/index.d.ts.map +1 -1
  261. package/dist/umd/container/GraphView/index.d.ts +4 -5
  262. package/dist/umd/container/GraphView/index.d.ts.map +1 -1
  263. package/dist/umd/container/GraphView/useNodeOrEdgeTypesWarning.d.ts +6 -0
  264. package/dist/umd/container/GraphView/useNodeOrEdgeTypesWarning.d.ts.map +1 -1
  265. package/dist/umd/container/GraphView/useStylesLoadedWarning.d.ts +2 -0
  266. package/dist/umd/container/GraphView/useStylesLoadedWarning.d.ts.map +1 -0
  267. package/dist/umd/container/NodeRenderer/index.d.ts +8 -6
  268. package/dist/umd/container/NodeRenderer/index.d.ts.map +1 -1
  269. package/dist/umd/container/NodeRenderer/useResizeObserver.d.ts.map +1 -1
  270. package/dist/umd/container/Pane/index.d.ts +2 -1
  271. package/dist/umd/container/Pane/index.d.ts.map +1 -1
  272. package/dist/umd/container/ReactFlow/Wrapper.d.ts +3 -1
  273. package/dist/umd/container/ReactFlow/Wrapper.d.ts.map +1 -1
  274. package/dist/umd/container/ReactFlow/index.d.ts +3 -3
  275. package/dist/umd/container/ReactFlow/index.d.ts.map +1 -1
  276. package/dist/umd/container/ReactFlow/init-values.d.ts.map +1 -1
  277. package/dist/umd/container/Viewport/index.d.ts.map +1 -1
  278. package/dist/umd/container/ZoomPane/index.d.ts +1 -1
  279. package/dist/umd/container/ZoomPane/index.d.ts.map +1 -1
  280. package/dist/umd/contexts/NodeIdContext.d.ts.map +1 -1
  281. package/dist/umd/contexts/{RFStoreContext.d.ts → StoreContext.d.ts} +1 -1
  282. package/dist/umd/contexts/StoreContext.d.ts.map +1 -0
  283. package/dist/umd/hooks/useColorModeClass.d.ts.map +1 -1
  284. package/dist/umd/hooks/useConnection.d.ts +5 -15
  285. package/dist/umd/hooks/useConnection.d.ts.map +1 -1
  286. package/dist/umd/hooks/useDrag.d.ts.map +1 -1
  287. package/dist/umd/hooks/useEdges.d.ts +1 -1
  288. package/dist/umd/hooks/useEdges.d.ts.map +1 -1
  289. package/dist/umd/hooks/useGlobalKeyHandler.d.ts.map +1 -1
  290. package/dist/umd/hooks/useHandleConnections.d.ts.map +1 -1
  291. package/dist/umd/hooks/useInternalNode.d.ts +10 -0
  292. package/dist/umd/hooks/useInternalNode.d.ts.map +1 -0
  293. package/dist/umd/hooks/useIsomorphicLayoutEffect.d.ts +3 -0
  294. package/dist/umd/hooks/useIsomorphicLayoutEffect.d.ts.map +1 -0
  295. package/dist/umd/hooks/useKeyPress.d.ts.map +1 -1
  296. package/dist/umd/hooks/useMoveSelectedNodes.d.ts.map +1 -1
  297. package/dist/umd/hooks/useNodes.d.ts.map +1 -1
  298. package/dist/umd/hooks/useNodesData.d.ts +3 -4
  299. package/dist/umd/hooks/useNodesData.d.ts.map +1 -1
  300. package/dist/umd/hooks/useNodesEdgesState.d.ts +3 -3
  301. package/dist/umd/hooks/useNodesEdgesState.d.ts.map +1 -1
  302. package/dist/umd/hooks/useNodesInitialized.d.ts.map +1 -1
  303. package/dist/umd/hooks/useOnInitHandler.d.ts +2 -2
  304. package/dist/umd/hooks/useOnInitHandler.d.ts.map +1 -1
  305. package/dist/umd/hooks/useOnSelectionChange.d.ts.map +1 -1
  306. package/dist/umd/hooks/useOnViewportChange.d.ts.map +1 -1
  307. package/dist/umd/hooks/useReactFlow.d.ts.map +1 -1
  308. package/dist/umd/hooks/useResizeHandler.d.ts.map +1 -1
  309. package/dist/umd/hooks/useStore.d.ts +10 -11
  310. package/dist/umd/hooks/useStore.d.ts.map +1 -1
  311. package/dist/umd/hooks/useUpdateNodeInternals.d.ts.map +1 -1
  312. package/dist/umd/hooks/useViewport.d.ts.map +1 -1
  313. package/dist/umd/hooks/useViewportHelper.d.ts.map +1 -1
  314. package/dist/umd/hooks/useViewportSync.d.ts.map +1 -1
  315. package/dist/umd/hooks/useVisibleEdgeIds.d.ts.map +1 -1
  316. package/dist/umd/hooks/useVisibleNodeIds.d.ts.map +1 -1
  317. package/dist/umd/index.d.ts +5 -4
  318. package/dist/umd/index.d.ts.map +1 -1
  319. package/dist/umd/index.js +2 -2
  320. package/dist/umd/store/index.d.ts +8 -6
  321. package/dist/umd/store/index.d.ts.map +1 -1
  322. package/dist/umd/store/initialState.d.ts +7 -5
  323. package/dist/umd/store/initialState.d.ts.map +1 -1
  324. package/dist/umd/styles/utils.d.ts.map +1 -1
  325. package/dist/umd/types/component-props.d.ts +51 -39
  326. package/dist/umd/types/component-props.d.ts.map +1 -1
  327. package/dist/umd/types/edges.d.ts +36 -36
  328. package/dist/umd/types/edges.d.ts.map +1 -1
  329. package/dist/umd/types/general.d.ts +18 -16
  330. package/dist/umd/types/general.d.ts.map +1 -1
  331. package/dist/umd/types/index.d.ts +0 -1
  332. package/dist/umd/types/index.d.ts.map +1 -1
  333. package/dist/umd/types/instance.d.ts +63 -44
  334. package/dist/umd/types/instance.d.ts.map +1 -1
  335. package/dist/umd/types/nodes.d.ts +20 -10
  336. package/dist/umd/types/nodes.d.ts.map +1 -1
  337. package/dist/umd/types/store.d.ts +33 -31
  338. package/dist/umd/types/store.d.ts.map +1 -1
  339. package/dist/umd/utils/changes.d.ts +5 -5
  340. package/dist/umd/utils/changes.d.ts.map +1 -1
  341. package/dist/umd/utils/general.d.ts +4 -2
  342. package/dist/umd/utils/general.d.ts.map +1 -1
  343. package/dist/umd/utils/index.d.ts.map +1 -1
  344. package/package.json +2 -2
  345. package/dist/esm/additional-components/NodeResizer/ResizeControl.d.ts +0 -7
  346. package/dist/esm/additional-components/NodeResizer/ResizeControl.d.ts.map +0 -1
  347. package/dist/esm/additional-components/NodeResizer/utils.d.ts +0 -11
  348. package/dist/esm/additional-components/NodeResizer/utils.d.ts.map +0 -1
  349. package/dist/esm/contexts/RFStoreContext.d.ts.map +0 -1
  350. package/dist/esm/hooks/useUpdateNodePositions.d.ts +0 -12
  351. package/dist/esm/hooks/useUpdateNodePositions.d.ts.map +0 -1
  352. package/dist/esm/store/utils.d.ts +0 -12
  353. package/dist/esm/store/utils.d.ts.map +0 -1
  354. package/dist/esm/types/changes.d.ts +0 -51
  355. package/dist/esm/types/changes.d.ts.map +0 -1
  356. package/dist/umd/additional-components/NodeResizer/ResizeControl.d.ts +0 -7
  357. package/dist/umd/additional-components/NodeResizer/ResizeControl.d.ts.map +0 -1
  358. package/dist/umd/additional-components/NodeResizer/utils.d.ts +0 -11
  359. package/dist/umd/additional-components/NodeResizer/utils.d.ts.map +0 -1
  360. package/dist/umd/contexts/RFStoreContext.d.ts.map +0 -1
  361. package/dist/umd/hooks/useUpdateNodePositions.d.ts +0 -12
  362. package/dist/umd/hooks/useUpdateNodePositions.d.ts.map +0 -1
  363. package/dist/umd/store/utils.d.ts +0 -12
  364. package/dist/umd/store/utils.d.ts.map +0 -1
  365. package/dist/umd/types/changes.d.ts +0 -51
  366. package/dist/umd/types/changes.d.ts.map +0 -1
@@ -1,9 +1,9 @@
1
1
  "use client"
2
2
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
3
- import { createContext, useContext, useMemo, useEffect, useRef, useState, useCallback, useLayoutEffect, forwardRef, memo } from 'react';
4
3
  import cc from 'classcat';
5
- import { errorMessages, infiniteExtent, isInputDOMNode, fitView, getViewportForBounds, pointToRendererPoint, rendererPointToPoint, isNodeBase, isEdgeBase, getElementsToRemove, isRectObject, nodeToRect, getOverlappingArea, getDimensions, XYPanZoom, PanOnScrollMode, SelectionMode, getEventPosition, getNodesInside, XYDrag, snapPosition, calculateNodePosition, Position, isMouseEvent, XYHandle, getHostForElement, addEdge, getNodesBounds, clampPosition, internalsSymbol, getPositionWithOrigin, elementSelectionKeys, isEdgeVisible, MarkerType, createMarkerIds, isNumeric, getBezierEdgeCenter, getSmoothStepPath, getStraightPath, getBezierPath, getEdgePosition, getElevatedEdgeZIndex, getMarkerId, ConnectionMode, ConnectionLineType, updateConnectionLookup, adoptUserProvidedNodes, devWarn, updateNodeDimensions, updateAbsolutePositions, panBy, isMacOs, areConnectionMapsEqual, handleConnectionChange, getNodePositionWithOrigin, XYMinimap, getBoundsOfRects, ResizeControlVariant, XYResizer, XY_RESIZER_LINE_POSITIONS, XY_RESIZER_HANDLE_POSITIONS, getNodeToolbarTransform } from '@xyflow/system';
6
- 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, getFitViewNodes, fitView, getViewportForBounds, pointToRendererPoint, rendererPointToPoint, isNodeBase, isEdgeBase, getElementsToRemove, isRectObject, nodeToRect, getOverlappingArea, evaluateAbsolutePosition, getDimensions, XYPanZoom, PanOnScrollMode, SelectionMode, getEventPosition, getNodesInside, XYDrag, snapPosition, calculateNodePosition, Position, ConnectionMode, isMouseEvent, XYHandle, getHostForElement, addEdge, getInternalNodesBounds, isNumeric, nodeHasDimensions, getNodeDimensions, clampPosition, elementSelectionKeys, isEdgeVisible, MarkerType, createMarkerIds, getBezierEdgeCenter, getSmoothStepPath, getStraightPath, getBezierPath, getEdgePosition, getElevatedEdgeZIndex, getMarkerId, getConnectionStatus, ConnectionLineType, updateConnectionLookup, adoptUserNodes, initialConnection, devWarn, updateNodeInternals, updateAbsolutePositions, handleExpandParent, panBy, isMacOs, areConnectionMapsEqual, handleConnectionChange, shallowNodeData, 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, reconnectEdge } from '@xyflow/system';
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';
9
9
  import { createPortal } from 'react-dom';
@@ -19,6 +19,10 @@ const zustandErrorMessage = errorMessages['error001']();
19
19
  * @param selector
20
20
  * @param equalityFn
21
21
  * @returns The selected state slice
22
+ *
23
+ * @example
24
+ * const nodes = useStore((state: ReactFlowState<MyNodeType>) => state.nodes);
25
+ *
22
26
  */
23
27
  function useStore(selector, equalityFn) {
24
28
  const store = useContext(StoreContext);
@@ -27,7 +31,7 @@ function useStore(selector, equalityFn) {
27
31
  }
28
32
  return useStoreWithEqualityFn(store, selector, equalityFn);
29
33
  }
30
- const useStoreApi = () => {
34
+ function useStoreApi() {
31
35
  const store = useContext(StoreContext);
32
36
  if (store === null) {
33
37
  throw new Error(zustandErrorMessage);
@@ -36,9 +40,8 @@ const useStoreApi = () => {
36
40
  getState: store.getState,
37
41
  setState: store.setState,
38
42
  subscribe: store.subscribe,
39
- destroy: store.destroy,
40
43
  }), [store]);
41
- };
44
+ }
42
45
 
43
46
  const style = { display: 'none' };
44
47
  const ariaLiveStyle = {
@@ -55,18 +58,18 @@ const ariaLiveStyle = {
55
58
  const ARIA_NODE_DESC_KEY = 'react-flow__node-desc';
56
59
  const ARIA_EDGE_DESC_KEY = 'react-flow__edge-desc';
57
60
  const ARIA_LIVE_MESSAGE = 'react-flow__aria-live';
58
- const selector$q = (s) => s.ariaLiveMessage;
61
+ const selector$p = (s) => s.ariaLiveMessage;
59
62
  function AriaLiveMessage({ rfId }) {
60
- const ariaLiveMessage = useStore(selector$q);
63
+ const ariaLiveMessage = useStore(selector$p);
61
64
  return (jsx("div", { id: `${ARIA_LIVE_MESSAGE}-${rfId}`, "aria-live": "assertive", "aria-atomic": "true", style: ariaLiveStyle, children: ariaLiveMessage }));
62
65
  }
63
66
  function A11yDescriptions({ rfId, disableKeyboardA11y }) {
64
67
  return (jsxs(Fragment, { children: [jsxs("div", { id: `${ARIA_NODE_DESC_KEY}-${rfId}`, style: style, children: ["Press enter or space to select a node.", !disableKeyboardA11y && 'You can then use the arrow keys to move the node around.', " Press delete to remove it and escape to cancel.", ' '] }), jsx("div", { id: `${ARIA_EDGE_DESC_KEY}-${rfId}`, style: style, children: "Press enter or space to select an edge. You can then press delete to remove it or escape to cancel." }), !disableKeyboardA11y && jsx(AriaLiveMessage, { rfId: rfId })] }));
65
68
  }
66
69
 
67
- const selector$p = (s) => (s.userSelectionActive ? 'none' : 'all');
70
+ const selector$o = (s) => (s.userSelectionActive ? 'none' : 'all');
68
71
  function Panel({ position = 'top-left', children, className, style, ...rest }) {
69
- const pointerEvents = useStore(selector$p);
72
+ const pointerEvents = useStore(selector$o);
70
73
  const positionClasses = `${position}`.split('-');
71
74
  return (jsx("div", { className: cc(['react-flow__panel', className, ...positionClasses]), style: { ...style, pointerEvents }, ...rest, children: children }));
72
75
  }
@@ -78,10 +81,21 @@ function Attribution({ proOptions, position = 'bottom-right' }) {
78
81
  return (jsx(Panel, { position: position, className: "react-flow__attribution", "data-message": "Please only hide this attribution when you are subscribed to React Flow Pro: https://pro.reactflow.dev", children: jsx("a", { href: "https://reactflow.dev", target: "_blank", rel: "noopener noreferrer", "aria-label": "React Flow attribution", children: "React Flow" }) }));
79
82
  }
80
83
 
81
- const selector$o = (s) => ({
82
- selectedNodes: s.nodes.filter((n) => n.selected),
83
- selectedEdges: s.edges.filter((e) => e.selected),
84
- });
84
+ const selector$n = (s) => {
85
+ const selectedNodes = [];
86
+ const selectedEdges = [];
87
+ for (const [, node] of s.nodeLookup) {
88
+ if (node.selected) {
89
+ selectedNodes.push(node.internals.userNode);
90
+ }
91
+ }
92
+ for (const [, edge] of s.edgeLookup) {
93
+ if (edge.selected) {
94
+ selectedEdges.push(edge);
95
+ }
96
+ }
97
+ return { selectedNodes, selectedEdges };
98
+ };
85
99
  const selectId = (obj) => obj.id;
86
100
  function areEqual(a, b) {
87
101
  return (shallow(a.selectedNodes.map(selectId), b.selectedNodes.map(selectId)) &&
@@ -89,7 +103,7 @@ function areEqual(a, b) {
89
103
  }
90
104
  function SelectionListenerInner({ onSelectionChange }) {
91
105
  const store = useStoreApi();
92
- const { selectedNodes, selectedEdges } = useStore(selector$o, areEqual);
106
+ const { selectedNodes, selectedEdges } = useStore(selector$n, areEqual);
93
107
  useEffect(() => {
94
108
  const params = { nodes: selectedNodes, edges: selectedEdges };
95
109
  onSelectionChange?.(params);
@@ -129,7 +143,7 @@ const reactFlowFieldsToTrack = [
129
143
  'nodesConnectable',
130
144
  'nodesFocusable',
131
145
  'edgesFocusable',
132
- 'edgesUpdatable',
146
+ 'edgesReconnectable',
133
147
  'elevateNodesOnSelect',
134
148
  'elevateEdgesOnSelect',
135
149
  'minZoom',
@@ -168,10 +182,13 @@ const reactFlowFieldsToTrack = [
168
182
  'selectNodesOnDrag',
169
183
  'nodeDragThreshold',
170
184
  'onBeforeDelete',
185
+ 'debug',
186
+ 'autoPanSpeed',
187
+ 'paneClickDistance',
171
188
  ];
172
189
  // rfId doesn't exist in ReactFlowProps, but it's one of the fields we want to update
173
190
  const fieldsToTrack = [...reactFlowFieldsToTrack, 'rfId'];
174
- const selector$n = (s) => ({
191
+ const selector$m = (s) => ({
175
192
  setNodes: s.setNodes,
176
193
  setEdges: s.setEdges,
177
194
  setMinZoom: s.setMinZoom,
@@ -180,6 +197,7 @@ const selector$n = (s) => ({
180
197
  setNodeExtent: s.setNodeExtent,
181
198
  reset: s.reset,
182
199
  setDefaultNodesAndEdges: s.setDefaultNodesAndEdges,
200
+ setPaneClickDistance: s.setPaneClickDistance,
183
201
  });
184
202
  const initPrevValues = {
185
203
  // these are values that are also passed directly to other components
@@ -192,9 +210,10 @@ const initPrevValues = {
192
210
  elementsSelectable: true,
193
211
  noPanClassName: 'nopan',
194
212
  rfId: '1',
213
+ paneClickDistance: 0,
195
214
  };
196
215
  function StoreUpdater(props) {
197
- const { setNodes, setEdges, setMinZoom, setMaxZoom, setTranslateExtent, setNodeExtent, reset, setDefaultNodesAndEdges, } = useStore(selector$n, shallow);
216
+ const { setNodes, setEdges, setMinZoom, setMaxZoom, setTranslateExtent, setNodeExtent, reset, setDefaultNodesAndEdges, setPaneClickDistance, } = useStore(selector$m, shallow);
198
217
  const store = useStoreApi();
199
218
  useEffect(() => {
200
219
  setDefaultNodesAndEdges(props.defaultNodes, props.defaultEdges);
@@ -226,6 +245,8 @@ function StoreUpdater(props) {
226
245
  setTranslateExtent(fieldValue);
227
246
  else if (fieldName === 'nodeExtent')
228
247
  setNodeExtent(fieldValue);
248
+ else if (fieldName === 'paneClickDistance')
249
+ setPaneClickDistance(fieldValue);
229
250
  // Renamed fields
230
251
  else if (fieldName === 'fitView')
231
252
  store.setState({ fitViewOnInit: fieldValue });
@@ -351,10 +372,12 @@ keyCode = null, options = { target: defaultDoc, actInsideInputWithModifier: true
351
372
  target?.addEventListener('keydown', downHandler);
352
373
  target?.addEventListener('keyup', upHandler);
353
374
  window.addEventListener('blur', resetHandler);
375
+ window.addEventListener('contextmenu', resetHandler);
354
376
  return () => {
355
377
  target?.removeEventListener('keydown', downHandler);
356
378
  target?.removeEventListener('keyup', upHandler);
357
379
  window.removeEventListener('blur', resetHandler);
380
+ window.removeEventListener('contextmenu', resetHandler);
358
381
  };
359
382
  }
360
383
  }, [keyCode, setKeyPressed]);
@@ -375,7 +398,6 @@ function useKeyOrCode(eventCode, keysToWatch) {
375
398
  return keysToWatch.includes(eventCode) ? 'code' : 'key';
376
399
  }
377
400
 
378
- const selector$m = (s) => !!s.panZoom;
379
401
  /**
380
402
  * Hook for getting viewport helper functions.
381
403
  *
@@ -384,54 +406,74 @@ const selector$m = (s) => !!s.panZoom;
384
406
  */
385
407
  const useViewportHelper = () => {
386
408
  const store = useStoreApi();
387
- const panZoomInitialized = useStore(selector$m);
388
- const viewportHelperFunctions = useMemo(() => {
409
+ return useMemo(() => {
389
410
  return {
390
- zoomIn: (options) => store.getState().panZoom?.scaleBy(1.2, { duration: options?.duration }),
391
- zoomOut: (options) => store.getState().panZoom?.scaleBy(1 / 1.2, { duration: options?.duration }),
392
- zoomTo: (zoomLevel, options) => store.getState().panZoom?.scaleTo(zoomLevel, { duration: options?.duration }),
411
+ zoomIn: (options) => {
412
+ const { panZoom } = store.getState();
413
+ return panZoom ? panZoom.scaleBy(1.2, { duration: options?.duration }) : Promise.resolve(false);
414
+ },
415
+ zoomOut: (options) => {
416
+ const { panZoom } = store.getState();
417
+ return panZoom ? panZoom.scaleBy(1 / 1.2, { duration: options?.duration }) : Promise.resolve(false);
418
+ },
419
+ zoomTo: (zoomLevel, options) => {
420
+ const { panZoom } = store.getState();
421
+ return panZoom ? panZoom.scaleTo(zoomLevel, { duration: options?.duration }) : Promise.resolve(false);
422
+ },
393
423
  getZoom: () => store.getState().transform[2],
394
- setViewport: (viewport, options) => {
424
+ setViewport: async (viewport, options) => {
395
425
  const { transform: [tX, tY, tZoom], panZoom, } = store.getState();
396
- panZoom?.setViewport({
426
+ if (!panZoom) {
427
+ return Promise.resolve(false);
428
+ }
429
+ await panZoom.setViewport({
397
430
  x: viewport.x ?? tX,
398
431
  y: viewport.y ?? tY,
399
432
  zoom: viewport.zoom ?? tZoom,
400
433
  }, { duration: options?.duration });
434
+ return Promise.resolve(true);
401
435
  },
402
436
  getViewport: () => {
403
437
  const [x, y, zoom] = store.getState().transform;
404
438
  return { x, y, zoom };
405
439
  },
406
440
  fitView: (options) => {
407
- const { nodes, width, height, nodeOrigin, minZoom, maxZoom, panZoom } = store.getState();
441
+ const { nodeLookup, width, height, minZoom, maxZoom, panZoom } = store.getState();
442
+ const fitViewNodes = getFitViewNodes(nodeLookup, options);
408
443
  return panZoom
409
444
  ? fitView({
410
- nodes,
445
+ nodes: fitViewNodes,
411
446
  width,
412
447
  height,
413
- nodeOrigin,
414
448
  minZoom,
415
449
  maxZoom,
416
450
  panZoom,
417
451
  }, options)
418
- : false;
452
+ : Promise.resolve(false);
419
453
  },
420
- setCenter: (x, y, options) => {
454
+ setCenter: async (x, y, options) => {
421
455
  const { width, height, maxZoom, panZoom } = store.getState();
422
456
  const nextZoom = typeof options?.zoom !== 'undefined' ? options.zoom : maxZoom;
423
457
  const centerX = width / 2 - x * nextZoom;
424
458
  const centerY = height / 2 - y * nextZoom;
425
- panZoom?.setViewport({
459
+ if (!panZoom) {
460
+ return Promise.resolve(false);
461
+ }
462
+ await panZoom.setViewport({
426
463
  x: centerX,
427
464
  y: centerY,
428
465
  zoom: nextZoom,
429
466
  }, { duration: options?.duration });
467
+ return Promise.resolve(true);
430
468
  },
431
- fitBounds: (bounds, options) => {
469
+ fitBounds: async (bounds, options) => {
432
470
  const { width, height, minZoom, maxZoom, panZoom } = store.getState();
433
471
  const viewport = getViewportForBounds(bounds, width, height, minZoom, maxZoom, options?.padding ?? 0.1);
434
- panZoom?.setViewport(viewport, { duration: options?.duration });
472
+ if (!panZoom) {
473
+ return Promise.resolve(false);
474
+ }
475
+ await panZoom.setViewport(viewport, { duration: options?.duration });
476
+ return Promise.resolve(true);
435
477
  },
436
478
  screenToFlowPosition: (clientPosition, options = { snapToGrid: true }) => {
437
479
  const { transform, snapGrid, domNode } = store.getState();
@@ -457,48 +499,10 @@ const useViewportHelper = () => {
457
499
  y: rendererPosition.y + domY,
458
500
  };
459
501
  },
460
- viewportInitialized: panZoomInitialized,
461
502
  };
462
- }, [panZoomInitialized]);
463
- return viewportHelperFunctions;
503
+ }, []);
464
504
  };
465
505
 
466
- function handleParentExpand(updatedElements, updateItem) {
467
- for (const [index, item] of updatedElements.entries()) {
468
- if (item.id === updateItem.parentNode) {
469
- const parent = { ...item };
470
- parent.computed ??= {};
471
- const extendWidth = updateItem.position.x + updateItem.computed.width - parent.computed.width;
472
- const extendHeight = updateItem.position.y + updateItem.computed.height - parent.computed.height;
473
- if (extendWidth > 0 || extendHeight > 0 || updateItem.position.x < 0 || updateItem.position.y < 0) {
474
- parent.width = parent.width ?? parent.computed.width;
475
- parent.height = parent.height ?? parent.computed.height;
476
- if (extendWidth > 0) {
477
- parent.width += extendWidth;
478
- }
479
- if (extendHeight > 0) {
480
- parent.height += extendHeight;
481
- }
482
- if (updateItem.position.x < 0) {
483
- const xDiff = Math.abs(updateItem.position.x);
484
- parent.position.x = parent.position.x - xDiff;
485
- parent.width += xDiff;
486
- updateItem.position.x = 0;
487
- }
488
- if (updateItem.position.y < 0) {
489
- const yDiff = Math.abs(updateItem.position.y);
490
- parent.position.y = parent.position.y - yDiff;
491
- parent.height += yDiff;
492
- updateItem.position.y = 0;
493
- }
494
- parent.computed.width = parent.width;
495
- parent.computed.height = parent.height;
496
- updatedElements[index] = parent;
497
- }
498
- break;
499
- }
500
- }
501
- }
502
506
  // This function applies changes to nodes or edges that are triggered by React Flow internally.
503
507
  // When you drag a node for example, React Flow will send a position change update.
504
508
  // This function then applies the changes and returns the updated elements.
@@ -550,14 +554,14 @@ function applyChanges(changes, elements) {
550
554
  /// each _mutate_ this object, so there's only ever one copy.
551
555
  const updatedElement = { ...element };
552
556
  for (const change of changes) {
553
- applyChange(change, updatedElement, updatedElements);
557
+ applyChange(change, updatedElement);
554
558
  }
555
559
  updatedElements.push(updatedElement);
556
560
  }
557
561
  return updatedElements;
558
562
  }
559
563
  // Applies a single change to an element. This is a *mutable* update.
560
- function applyChange(change, element, elements = []) {
564
+ function applyChange(change, element) {
561
565
  switch (change.type) {
562
566
  case 'select': {
563
567
  element.selected = change.selected;
@@ -567,24 +571,17 @@ function applyChange(change, element, elements = []) {
567
571
  if (typeof change.position !== 'undefined') {
568
572
  element.position = change.position;
569
573
  }
570
- if (typeof change.positionAbsolute !== 'undefined') {
571
- element.computed ??= {};
572
- element.computed.positionAbsolute = change.positionAbsolute;
573
- }
574
574
  if (typeof change.dragging !== 'undefined') {
575
575
  element.dragging = change.dragging;
576
576
  }
577
- if (element.expandParent) {
578
- handleParentExpand(elements, element);
579
- }
580
577
  break;
581
578
  }
582
579
  case 'dimensions': {
583
580
  if (typeof change.dimensions !== 'undefined') {
584
- element.computed ??= {};
585
- element.computed.width = change.dimensions.width;
586
- element.computed.height = change.dimensions.height;
587
- if (change.resizing) {
581
+ element.measured ??= {};
582
+ element.measured.width = change.dimensions.width;
583
+ element.measured.height = change.dimensions.height;
584
+ if (change.setAttributes) {
588
585
  element.width = change.dimensions.width;
589
586
  element.height = change.dimensions.height;
590
587
  }
@@ -592,9 +589,6 @@ function applyChange(change, element, elements = []) {
592
589
  if (typeof change.resizing === 'boolean') {
593
590
  element.resizing = change.resizing;
594
591
  }
595
- if (element.expandParent) {
596
- handleParentExpand(elements, element);
597
- }
598
592
  break;
599
593
  }
600
594
  }
@@ -654,8 +648,8 @@ function createSelectionChange(id, selected) {
654
648
  }
655
649
  function getSelectionChanges(items, selectedIds = new Set(), mutateItem = false) {
656
650
  const changes = [];
657
- for (const item of items) {
658
- const willBeSelected = selectedIds.has(item.id);
651
+ for (const [id, item] of items) {
652
+ const willBeSelected = selectedIds.has(id);
659
653
  // we don't want to set all items to selected=false on the first selection
660
654
  if (!(item.selected === undefined && !willBeSelected) && item.selected !== willBeSelected) {
661
655
  if (mutateItem) {
@@ -673,7 +667,8 @@ function getElementsDiffChanges({ items = [], lookup, }) {
673
667
  const changes = [];
674
668
  const itemsLookup = new Map(items.map((item) => [item.id, item]));
675
669
  for (const item of items) {
676
- const storeItem = lookup.get(item.id);
670
+ const lookupItem = lookup.get(item.id);
671
+ const storeItem = lookupItem?.internals?.userNode ?? lookupItem;
677
672
  if (storeItem !== undefined && storeItem !== item) {
678
673
  changes.push({ id: item.id, item: item, type: 'replace' });
679
674
  }
@@ -689,6 +684,12 @@ function getElementsDiffChanges({ items = [], lookup, }) {
689
684
  }
690
685
  return changes;
691
686
  }
687
+ function elementToRemoveChange(item) {
688
+ return {
689
+ id: item.id,
690
+ type: 'remove',
691
+ };
692
+ }
692
693
 
693
694
  /**
694
695
  * Test whether an object is useable as a Node
@@ -706,246 +707,293 @@ const isNode = (element) => isNodeBase(element);
706
707
  * @returns A boolean indicating whether the element is an Edge
707
708
  */
708
709
  const isEdge = (element) => isEdgeBase(element);
710
+ // eslint-disable-next-line @typescript-eslint/ban-types
711
+ function fixedForwardRef(render) {
712
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
713
+ return forwardRef(render);
714
+ }
715
+
716
+ // we need this hook to prevent a warning when using react-flow in SSR
717
+ const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
709
718
 
710
719
  /**
711
- * Hook for accessing the ReactFlow instance.
720
+ * This hook returns a queue that can be used to batch updates.
712
721
  *
713
- * @public
714
- * @returns ReactFlowInstance
722
+ * @param runQueue - a function that gets called when the queue is flushed
723
+ * @internal
724
+ *
725
+ * @returns a Queue object
715
726
  */
716
- function useReactFlow() {
717
- const viewportHelper = useViewportHelper();
718
- const store = useStoreApi();
719
- const getNodes = useCallback(() => {
720
- return store.getState().nodes.map((n) => ({ ...n }));
721
- }, []);
722
- const getNode = useCallback((id) => {
723
- return store.getState().nodeLookup.get(id);
724
- }, []);
725
- const getEdges = useCallback(() => {
726
- const { edges = [] } = store.getState();
727
- return edges.map((e) => ({ ...e }));
728
- }, []);
729
- const getEdge = useCallback((id) => {
730
- const { edges = [] } = store.getState();
731
- return edges.find((e) => e.id === id);
732
- }, []);
733
- // A reference of all the batched updates to process before the next render. We
734
- // want a mutable reference here so multiple synchronous calls to `setNodes` etc
735
- // can be batched together.
736
- const setElementsQueue = useRef({ nodes: [], edges: [] });
727
+ function useQueue(runQueue) {
737
728
  // Because we're using a ref above, we need some way to let React know when to
738
729
  // actually process the queue. We flip this bit of state to `true` any time we
739
730
  // mutate the queue and then flip it back to `false` after flushing the queue.
740
- const [shouldFlushQueue, setShouldFlushQueue] = useState(false);
731
+ const [shouldFlush, setShouldFlush] = useState(false);
732
+ // A reference of all the batched updates to process before the next render. We
733
+ // want a reference here so multiple synchronous calls to `setNodes` etc can be
734
+ // batched together.
735
+ const [queue] = useState(() => createQueue(() => setShouldFlush(true)));
741
736
  // Layout effects are guaranteed to run before the next render which means we
742
737
  // shouldn't run into any issues with stale state or weird issues that come from
743
738
  // rendering things one frame later than expected (we used to use `setTimeout`).
744
- useLayoutEffect(() => {
739
+ useIsomorphicLayoutEffect(() => {
745
740
  // Because we need to flip the state back to false after flushing, this should
746
741
  // trigger the hook again (!). If the hook is being run again we know that any
747
742
  // updates should have been processed by now and we can safely clear the queue
748
743
  // and bail early.
749
- if (!shouldFlushQueue) {
750
- setElementsQueue.current = { nodes: [], edges: [] };
744
+ if (!shouldFlush) {
745
+ queue.reset();
751
746
  return;
752
747
  }
753
- if (setElementsQueue.current.nodes.length) {
754
- const { nodes = [], setNodes, hasDefaultNodes, onNodesChange, nodeLookup } = store.getState();
755
- // This is essentially an `Array.reduce` in imperative clothing. Processing
756
- // this queue is a relatively hot path so we'd like to avoid the overhead of
757
- // array methods where we can.
758
- let next = nodes;
759
- for (const payload of setElementsQueue.current.nodes) {
760
- next = typeof payload === 'function' ? payload(next) : payload;
761
- }
762
- if (hasDefaultNodes) {
763
- setNodes(next);
764
- }
765
- else if (onNodesChange) {
766
- onNodesChange(getElementsDiffChanges({
767
- items: next,
768
- lookup: nodeLookup,
769
- }));
770
- }
771
- setElementsQueue.current.nodes = [];
772
- }
773
- if (setElementsQueue.current.edges.length) {
774
- const { edges = [], setEdges, hasDefaultEdges, onEdgesChange, edgeLookup } = store.getState();
775
- let next = edges;
776
- for (const payload of setElementsQueue.current.edges) {
777
- next = typeof payload === 'function' ? payload(next) : payload;
778
- }
779
- if (hasDefaultEdges) {
780
- setEdges(next);
781
- }
782
- else if (onEdgesChange) {
783
- onEdgesChange(getElementsDiffChanges({
784
- items: next,
785
- lookup: edgeLookup,
786
- }));
787
- }
788
- setElementsQueue.current.edges = [];
748
+ const queueItems = queue.get();
749
+ if (queueItems.length) {
750
+ runQueue(queueItems);
751
+ queue.reset();
789
752
  }
790
753
  // Beacuse we're using reactive state to trigger this effect, we need to flip
791
754
  // it back to false.
792
- setShouldFlushQueue(false);
793
- }, [shouldFlushQueue]);
794
- const setNodes = useCallback((payload) => {
795
- setElementsQueue.current.nodes.push(payload);
796
- setShouldFlushQueue(true);
797
- }, []);
798
- const setEdges = useCallback((payload) => {
799
- setElementsQueue.current.edges.push(payload);
800
- setShouldFlushQueue(true);
801
- }, []);
802
- const addNodes = useCallback((payload) => {
803
- const newNodes = Array.isArray(payload) ? payload : [payload];
804
- // Queueing a functional update means that we won't worry about other calls
805
- // to `setNodes` that might happen elsewhere.
806
- setElementsQueue.current.nodes.push((nodes) => [...nodes, ...newNodes]);
807
- setShouldFlushQueue(true);
808
- }, []);
809
- const addEdges = useCallback((payload) => {
810
- const newEdges = Array.isArray(payload) ? payload : [payload];
811
- setElementsQueue.current.edges.push((edges) => [...edges, ...newEdges]);
812
- setShouldFlushQueue(true);
813
- }, []);
814
- const toObject = useCallback(() => {
815
- const { nodes = [], edges = [], transform } = store.getState();
816
- const [x, y, zoom] = transform;
817
- return {
818
- nodes: nodes.map((n) => ({ ...n })),
819
- edges: edges.map((e) => ({ ...e })),
820
- viewport: {
821
- x,
822
- y,
823
- zoom,
824
- },
825
- };
826
- }, []);
827
- const deleteElements = useCallback(async ({ nodes: nodesToRemove = [], edges: edgesToRemove = [] }) => {
828
- const { nodes, edges, hasDefaultNodes, hasDefaultEdges, onNodesDelete, onEdgesDelete, onNodesChange, onEdgesChange, onDelete, onBeforeDelete, } = store.getState();
829
- const { nodes: matchingNodes, edges: matchingEdges } = await getElementsToRemove({
830
- nodesToRemove,
831
- edgesToRemove,
832
- nodes,
833
- edges,
834
- onBeforeDelete,
835
- });
836
- const hasMatchingEdges = matchingEdges.length > 0;
837
- const hasMatchingNodes = matchingNodes.length > 0;
838
- if (hasMatchingEdges) {
839
- if (hasDefaultEdges) {
840
- const nextEdges = edges.filter((e) => !matchingEdges.some((mE) => mE.id === e.id));
841
- store.getState().setEdges(nextEdges);
842
- }
843
- onEdgesDelete?.(matchingEdges);
844
- onEdgesChange?.(matchingEdges.map((edge) => ({
845
- id: edge.id,
846
- type: 'remove',
847
- })));
848
- }
849
- if (hasMatchingNodes) {
850
- if (hasDefaultNodes) {
851
- const nextNodes = nodes.filter((n) => !matchingNodes.some((mN) => mN.id === n.id));
852
- store.getState().setNodes(nextNodes);
853
- }
854
- onNodesDelete?.(matchingNodes);
855
- onNodesChange?.(matchingNodes.map((node) => ({ id: node.id, type: 'remove' })));
856
- }
857
- if (hasMatchingNodes || hasMatchingEdges) {
858
- onDelete?.({ nodes: matchingNodes, edges: matchingEdges });
755
+ setShouldFlush(false);
756
+ }, [shouldFlush]);
757
+ return queue;
758
+ }
759
+ function createQueue(cb) {
760
+ let queue = [];
761
+ return {
762
+ get: () => queue,
763
+ reset: () => {
764
+ queue = [];
765
+ },
766
+ push: (item) => {
767
+ queue.push(item);
768
+ cb();
769
+ },
770
+ };
771
+ }
772
+
773
+ const BatchContext = createContext(null);
774
+ /**
775
+ * This is a context provider that holds and processes the node and edge update queues
776
+ * that are needed to handle setNodes, addNodes, setEdges and addEdges.
777
+ *
778
+ * @internal
779
+ */
780
+ function BatchProvider({ children, }) {
781
+ const store = useStoreApi();
782
+ const nodeQueueHandler = useCallback((queueItems) => {
783
+ const { nodes = [], setNodes, hasDefaultNodes, onNodesChange, nodeLookup } = store.getState();
784
+ // This is essentially an `Array.reduce` in imperative clothing. Processing
785
+ // this queue is a relatively hot path so we'd like to avoid the overhead of
786
+ // array methods where we can.
787
+ let next = nodes;
788
+ for (const payload of queueItems) {
789
+ next = typeof payload === 'function' ? payload(next) : payload;
790
+ }
791
+ if (hasDefaultNodes) {
792
+ setNodes(next);
793
+ }
794
+ else if (onNodesChange) {
795
+ onNodesChange(getElementsDiffChanges({
796
+ items: next,
797
+ lookup: nodeLookup,
798
+ }));
859
799
  }
860
- return { deletedNodes: matchingNodes, deletedEdges: matchingEdges };
861
- }, []);
862
- const getNodeRect = useCallback((nodeOrRect) => {
863
- const isRect = isRectObject(nodeOrRect);
864
- const node = isRect ? null : store.getState().nodeLookup.get(nodeOrRect.id);
865
- if (!isRect && !node) {
866
- return [null, null, isRect];
867
- }
868
- const nodeRect = isRect ? nodeOrRect : nodeToRect(node);
869
- return [nodeRect, node, isRect];
870
800
  }, []);
871
- const getIntersectingNodes = useCallback((nodeOrRect, partially = true, nodes) => {
872
- const [nodeRect, node, isRect] = getNodeRect(nodeOrRect);
873
- if (!nodeRect) {
874
- return [];
801
+ const nodeQueue = useQueue(nodeQueueHandler);
802
+ const edgeQueueHandler = useCallback((queueItems) => {
803
+ const { edges = [], setEdges, hasDefaultEdges, onEdgesChange, edgeLookup } = store.getState();
804
+ let next = edges;
805
+ for (const payload of queueItems) {
806
+ next = typeof payload === 'function' ? payload(next) : payload;
875
807
  }
876
- return (nodes || store.getState().nodes).filter((n) => {
877
- if (!isRect && (n.id === node.id || !n.computed?.positionAbsolute)) {
878
- return false;
879
- }
880
- const currNodeRect = nodeToRect(n);
881
- const overlappingArea = getOverlappingArea(currNodeRect, nodeRect);
882
- const partiallyVisible = partially && overlappingArea > 0;
883
- return partiallyVisible || overlappingArea >= nodeRect.width * nodeRect.height;
884
- });
885
- }, []);
886
- const isNodeIntersecting = useCallback((nodeOrRect, area, partially = true) => {
887
- const [nodeRect] = getNodeRect(nodeOrRect);
888
- if (!nodeRect) {
889
- return false;
808
+ if (hasDefaultEdges) {
809
+ setEdges(next);
810
+ }
811
+ else if (onEdgesChange) {
812
+ onEdgesChange(getElementsDiffChanges({
813
+ items: next,
814
+ lookup: edgeLookup,
815
+ }));
890
816
  }
891
- const overlappingArea = getOverlappingArea(nodeRect, area);
892
- const partiallyVisible = partially && overlappingArea > 0;
893
- return partiallyVisible || overlappingArea >= nodeRect.width * nodeRect.height;
894
817
  }, []);
895
- const updateNode = useCallback((id, nodeUpdate, options = { replace: true }) => {
896
- setNodes((prevNodes) => prevNodes.map((node) => {
897
- if (node.id === id) {
898
- const nextNode = typeof nodeUpdate === 'function' ? nodeUpdate(node) : nodeUpdate;
899
- return options.replace && isNode(nextNode) ? nextNode : { ...node, ...nextNode };
900
- }
901
- return node;
902
- }));
903
- }, [setNodes]);
904
- const updateNodeData = useCallback((id, dataUpdate, options = { replace: false }) => {
905
- updateNode(id, (node) => {
906
- const nextData = typeof dataUpdate === 'function' ? dataUpdate(node) : dataUpdate;
907
- return options.replace ? { ...node, data: nextData } : { ...node, data: { ...node.data, ...nextData } };
908
- }, options);
909
- }, [updateNode]);
910
- return useMemo(() => {
818
+ const edgeQueue = useQueue(edgeQueueHandler);
819
+ const value = useMemo(() => ({ nodeQueue, edgeQueue }), []);
820
+ return jsx(BatchContext.Provider, { value: value, children: children });
821
+ }
822
+ function useBatchContext() {
823
+ const batchContext = useContext(BatchContext);
824
+ if (!batchContext) {
825
+ throw new Error('useBatchContext must be used within a BatchProvider');
826
+ }
827
+ return batchContext;
828
+ }
829
+
830
+ const selector$l = (s) => !!s.panZoom;
831
+ /**
832
+ * Hook for accessing the ReactFlow instance.
833
+ *
834
+ * @public
835
+ * @returns ReactFlowInstance
836
+ */
837
+ function useReactFlow() {
838
+ const viewportHelper = useViewportHelper();
839
+ const store = useStoreApi();
840
+ const batchContext = useBatchContext();
841
+ const viewportInitialized = useStore(selector$l);
842
+ const generalHelper = useMemo(() => {
843
+ const getInternalNode = (id) => store.getState().nodeLookup.get(id);
844
+ const setNodes = (payload) => {
845
+ batchContext.nodeQueue.push(payload);
846
+ };
847
+ const setEdges = (payload) => {
848
+ batchContext.edgeQueue.push(payload);
849
+ };
850
+ const getNodeRect = (node) => {
851
+ const { nodeLookup, nodeOrigin } = store.getState();
852
+ const nodeToUse = isNode(node) ? node : nodeLookup.get(node.id);
853
+ const position = nodeToUse.parentId
854
+ ? evaluateAbsolutePosition(nodeToUse.position, nodeToUse.measured, nodeToUse.parentId, nodeLookup, nodeOrigin)
855
+ : nodeToUse.position;
856
+ const nodeWithPosition = {
857
+ id: nodeToUse.id,
858
+ position,
859
+ width: nodeToUse.measured?.width ?? nodeToUse.width,
860
+ height: nodeToUse.measured?.height ?? nodeToUse.height,
861
+ data: nodeToUse.data,
862
+ };
863
+ return nodeToRect(nodeWithPosition);
864
+ };
865
+ const updateNode = (id, nodeUpdate, options = { replace: false }) => {
866
+ setNodes((prevNodes) => prevNodes.map((node) => {
867
+ if (node.id === id) {
868
+ const nextNode = typeof nodeUpdate === 'function' ? nodeUpdate(node) : nodeUpdate;
869
+ return options.replace && isNode(nextNode) ? nextNode : { ...node, ...nextNode };
870
+ }
871
+ return node;
872
+ }));
873
+ };
874
+ const updateEdge = (id, edgeUpdate, options = { replace: false }) => {
875
+ setEdges((prevEdges) => prevEdges.map((edge) => {
876
+ if (edge.id === id) {
877
+ const nextEdge = typeof edgeUpdate === 'function' ? edgeUpdate(edge) : edgeUpdate;
878
+ return options.replace && isEdge(nextEdge) ? nextEdge : { ...edge, ...nextEdge };
879
+ }
880
+ return edge;
881
+ }));
882
+ };
911
883
  return {
912
- ...viewportHelper,
913
- getNodes,
914
- getNode,
915
- getEdges,
916
- getEdge,
884
+ getNodes: () => store.getState().nodes.map((n) => ({ ...n })),
885
+ getNode: (id) => getInternalNode(id)?.internals.userNode,
886
+ getInternalNode,
887
+ getEdges: () => {
888
+ const { edges = [] } = store.getState();
889
+ return edges.map((e) => ({ ...e }));
890
+ },
891
+ getEdge: (id) => store.getState().edgeLookup.get(id),
917
892
  setNodes,
918
893
  setEdges,
919
- addNodes,
920
- addEdges,
921
- toObject,
922
- deleteElements,
923
- getIntersectingNodes,
924
- isNodeIntersecting,
894
+ addNodes: (payload) => {
895
+ const newNodes = Array.isArray(payload) ? payload : [payload];
896
+ batchContext.nodeQueue.push((nodes) => [...nodes, ...newNodes]);
897
+ },
898
+ addEdges: (payload) => {
899
+ const newEdges = Array.isArray(payload) ? payload : [payload];
900
+ batchContext.edgeQueue.push((edges) => [...edges, ...newEdges]);
901
+ },
902
+ toObject: () => {
903
+ const { nodes = [], edges = [], transform } = store.getState();
904
+ const [x, y, zoom] = transform;
905
+ return {
906
+ nodes: nodes.map((n) => ({ ...n })),
907
+ edges: edges.map((e) => ({ ...e })),
908
+ viewport: {
909
+ x,
910
+ y,
911
+ zoom,
912
+ },
913
+ };
914
+ },
915
+ deleteElements: async ({ nodes: nodesToRemove = [], edges: edgesToRemove = [] }) => {
916
+ const { nodes, edges, onNodesDelete, onEdgesDelete, triggerNodeChanges, triggerEdgeChanges, onDelete, onBeforeDelete, } = store.getState();
917
+ const { nodes: matchingNodes, edges: matchingEdges } = await getElementsToRemove({
918
+ nodesToRemove,
919
+ edgesToRemove,
920
+ nodes,
921
+ edges,
922
+ onBeforeDelete,
923
+ });
924
+ const hasMatchingEdges = matchingEdges.length > 0;
925
+ const hasMatchingNodes = matchingNodes.length > 0;
926
+ if (hasMatchingEdges) {
927
+ const edgeChanges = matchingEdges.map(elementToRemoveChange);
928
+ onEdgesDelete?.(matchingEdges);
929
+ triggerEdgeChanges(edgeChanges);
930
+ }
931
+ if (hasMatchingNodes) {
932
+ const nodeChanges = matchingNodes.map(elementToRemoveChange);
933
+ onNodesDelete?.(matchingNodes);
934
+ triggerNodeChanges(nodeChanges);
935
+ }
936
+ if (hasMatchingNodes || hasMatchingEdges) {
937
+ onDelete?.({ nodes: matchingNodes, edges: matchingEdges });
938
+ }
939
+ return { deletedNodes: matchingNodes, deletedEdges: matchingEdges };
940
+ },
941
+ getIntersectingNodes: (nodeOrRect, partially = true, nodes) => {
942
+ const isRect = isRectObject(nodeOrRect);
943
+ const nodeRect = isRect ? nodeOrRect : getNodeRect(nodeOrRect);
944
+ const hasNodesOption = nodes !== undefined;
945
+ if (!nodeRect) {
946
+ return [];
947
+ }
948
+ return (nodes || store.getState().nodes).filter((n) => {
949
+ const internalNode = store.getState().nodeLookup.get(n.id);
950
+ if (internalNode && !isRect && (n.id === nodeOrRect.id || !internalNode.internals.positionAbsolute)) {
951
+ return false;
952
+ }
953
+ const currNodeRect = nodeToRect(hasNodesOption ? n : internalNode);
954
+ const overlappingArea = getOverlappingArea(currNodeRect, nodeRect);
955
+ const partiallyVisible = partially && overlappingArea > 0;
956
+ return partiallyVisible || overlappingArea >= nodeRect.width * nodeRect.height;
957
+ });
958
+ },
959
+ isNodeIntersecting: (nodeOrRect, area, partially = true) => {
960
+ const isRect = isRectObject(nodeOrRect);
961
+ const nodeRect = isRect ? nodeOrRect : getNodeRect(nodeOrRect);
962
+ if (!nodeRect) {
963
+ return false;
964
+ }
965
+ const overlappingArea = getOverlappingArea(nodeRect, area);
966
+ const partiallyVisible = partially && overlappingArea > 0;
967
+ return partiallyVisible || overlappingArea >= nodeRect.width * nodeRect.height;
968
+ },
925
969
  updateNode,
926
- updateNodeData,
970
+ updateNodeData: (id, dataUpdate, options = { replace: false }) => {
971
+ updateNode(id, (node) => {
972
+ const nextData = typeof dataUpdate === 'function' ? dataUpdate(node) : dataUpdate;
973
+ return options.replace ? { ...node, data: nextData } : { ...node, data: { ...node.data, ...nextData } };
974
+ }, options);
975
+ },
976
+ updateEdge,
977
+ updateEdgeData: (id, dataUpdate, options = { replace: false }) => {
978
+ updateEdge(id, (edge) => {
979
+ const nextData = typeof dataUpdate === 'function' ? dataUpdate(edge) : dataUpdate;
980
+ return options.replace ? { ...edge, data: nextData } : { ...edge, data: { ...edge.data, ...nextData } };
981
+ }, options);
982
+ },
927
983
  };
928
- }, [
929
- viewportHelper,
930
- getNodes,
931
- getNode,
932
- getEdges,
933
- getEdge,
934
- setNodes,
935
- setEdges,
936
- addNodes,
937
- addEdges,
938
- toObject,
939
- deleteElements,
940
- getIntersectingNodes,
941
- isNodeIntersecting,
942
- updateNode,
943
- updateNodeData,
944
- ]);
984
+ }, []);
985
+ return useMemo(() => {
986
+ return {
987
+ ...generalHelper,
988
+ ...viewportHelper,
989
+ viewportInitialized,
990
+ };
991
+ }, [viewportInitialized]);
945
992
  }
946
993
 
947
994
  const selected = (item) => item.selected;
948
995
  const deleteKeyOptions = { actInsideInputWithModifier: false };
996
+ const win$1 = typeof window !== 'undefined' ? window : undefined;
949
997
  /**
950
998
  * Hook for handling global key events.
951
999
  *
@@ -955,7 +1003,7 @@ function useGlobalKeyHandler({ deleteKeyCode, multiSelectionKeyCode, }) {
955
1003
  const store = useStoreApi();
956
1004
  const { deleteElements } = useReactFlow();
957
1005
  const deleteKeyPressed = useKeyPress(deleteKeyCode, deleteKeyOptions);
958
- const multiSelectionKeyPressed = useKeyPress(multiSelectionKeyCode);
1006
+ const multiSelectionKeyPressed = useKeyPress(multiSelectionKeyCode, { target: win$1 });
959
1007
  useEffect(() => {
960
1008
  if (deleteKeyPressed) {
961
1009
  const { edges, nodes } = store.getState();
@@ -1009,14 +1057,14 @@ const containerStyle = {
1009
1057
  left: 0,
1010
1058
  };
1011
1059
 
1012
- const selector$l = (s) => ({
1060
+ const selector$k = (s) => ({
1013
1061
  userSelectionActive: s.userSelectionActive,
1014
1062
  lib: s.lib,
1015
1063
  });
1016
- function ZoomPane({ onPaneContextMenu, zoomOnScroll = true, zoomOnPinch = true, panOnScroll = false, panOnScrollSpeed = 0.5, panOnScrollMode = PanOnScrollMode.Free, zoomOnDoubleClick = true, panOnDrag = true, defaultViewport, translateExtent, minZoom, maxZoom, zoomActivationKeyCode, preventScrolling = true, children, noWheelClassName, noPanClassName, onViewportChange, isControlledViewport, }) {
1064
+ function ZoomPane({ onPaneContextMenu, zoomOnScroll = true, zoomOnPinch = true, panOnScroll = false, panOnScrollSpeed = 0.5, panOnScrollMode = PanOnScrollMode.Free, zoomOnDoubleClick = true, panOnDrag = true, defaultViewport, translateExtent, minZoom, maxZoom, zoomActivationKeyCode, preventScrolling = true, children, noWheelClassName, noPanClassName, onViewportChange, isControlledViewport, paneClickDistance, }) {
1017
1065
  const store = useStoreApi();
1018
1066
  const zoomPane = useRef(null);
1019
- const { userSelectionActive, lib } = useStore(selector$l, shallow);
1067
+ const { userSelectionActive, lib } = useStore(selector$k, shallow);
1020
1068
  const zoomActivationKeyPressed = useKeyPress(zoomActivationKeyCode);
1021
1069
  const panZoom = useRef();
1022
1070
  useResizeHandler(zoomPane);
@@ -1028,6 +1076,7 @@ function ZoomPane({ onPaneContextMenu, zoomOnScroll = true, zoomOnPinch = true,
1028
1076
  maxZoom,
1029
1077
  translateExtent,
1030
1078
  viewport: defaultViewport,
1079
+ paneClickDistance,
1031
1080
  onTransformChange: (transform) => {
1032
1081
  onViewportChange?.({ x: transform[0], y: transform[1], zoom: transform[2] });
1033
1082
  if (!isControlledViewport) {
@@ -1098,12 +1147,12 @@ function ZoomPane({ onPaneContextMenu, zoomOnScroll = true, zoomOnPinch = true,
1098
1147
  return (jsx("div", { className: "react-flow__renderer", ref: zoomPane, style: containerStyle, children: children }));
1099
1148
  }
1100
1149
 
1101
- const selector$k = (s) => ({
1150
+ const selector$j = (s) => ({
1102
1151
  userSelectionActive: s.userSelectionActive,
1103
1152
  userSelectionRect: s.userSelectionRect,
1104
1153
  });
1105
1154
  function UserSelection() {
1106
- const { userSelectionActive, userSelectionRect } = useStore(selector$k, shallow);
1155
+ const { userSelectionActive, userSelectionRect } = useStore(selector$j, shallow);
1107
1156
  const isActive = userSelectionActive && userSelectionRect;
1108
1157
  if (!isActive) {
1109
1158
  return null;
@@ -1123,24 +1172,33 @@ const wrapHandler = (handler, containerRef) => {
1123
1172
  handler?.(event);
1124
1173
  };
1125
1174
  };
1126
- const selector$j = (s) => ({
1175
+ const selector$i = (s) => ({
1127
1176
  userSelectionActive: s.userSelectionActive,
1128
1177
  elementsSelectable: s.elementsSelectable,
1129
1178
  dragging: s.paneDragging,
1130
1179
  });
1131
- function Pane({ isSelecting, selectionMode = SelectionMode.Full, panOnDrag, onSelectionStart, onSelectionEnd, onPaneClick, onPaneContextMenu, onPaneScroll, onPaneMouseEnter, onPaneMouseMove, onPaneMouseLeave, children, }) {
1180
+ function Pane({ isSelecting, selectionKeyPressed, selectionMode = SelectionMode.Full, panOnDrag, onSelectionStart, onSelectionEnd, onPaneClick, onPaneContextMenu, onPaneScroll, onPaneMouseEnter, onPaneMouseMove, onPaneMouseLeave, children, }) {
1132
1181
  const container = useRef(null);
1133
1182
  const store = useStoreApi();
1134
1183
  const prevSelectedNodesCount = useRef(0);
1135
1184
  const prevSelectedEdgesCount = useRef(0);
1136
1185
  const containerBounds = useRef();
1137
- const { userSelectionActive, elementsSelectable, dragging } = useStore(selector$j, shallow);
1186
+ const edgeIdLookup = useRef(new Map());
1187
+ const { userSelectionActive, elementsSelectable, dragging } = useStore(selector$i, shallow);
1188
+ const hasActiveSelection = elementsSelectable && (isSelecting || userSelectionActive);
1189
+ // Used to prevent click events when the user lets go of the selectionKey during a selection
1190
+ const selectionInProgress = useRef(false);
1138
1191
  const resetUserSelection = () => {
1139
1192
  store.setState({ userSelectionActive: false, userSelectionRect: null });
1140
1193
  prevSelectedNodesCount.current = 0;
1141
1194
  prevSelectedEdgesCount.current = 0;
1142
1195
  };
1143
1196
  const onClick = (event) => {
1197
+ // We prevent click events when the user let go of the selectionKey during a selection
1198
+ if (selectionInProgress.current) {
1199
+ selectionInProgress.current = false;
1200
+ return;
1201
+ }
1144
1202
  onPaneClick?.(event);
1145
1203
  store.getState().resetSelectedElements();
1146
1204
  store.setState({ nodesSelectionActive: false });
@@ -1153,9 +1211,10 @@ function Pane({ isSelecting, selectionMode = SelectionMode.Full, panOnDrag, onSe
1153
1211
  onPaneContextMenu?.(event);
1154
1212
  };
1155
1213
  const onWheel = onPaneScroll ? (event) => onPaneScroll(event) : undefined;
1156
- const onMouseDown = (event) => {
1157
- const { resetSelectedElements, domNode } = store.getState();
1214
+ const onPointerDown = (event) => {
1215
+ const { resetSelectedElements, domNode, edgeLookup } = store.getState();
1158
1216
  containerBounds.current = domNode?.getBoundingClientRect();
1217
+ event.target?.setPointerCapture?.(event.pointerId);
1159
1218
  if (!elementsSelectable ||
1160
1219
  !isSelecting ||
1161
1220
  event.button !== 0 ||
@@ -1163,6 +1222,11 @@ function Pane({ isSelecting, selectionMode = SelectionMode.Full, panOnDrag, onSe
1163
1222
  !containerBounds.current) {
1164
1223
  return;
1165
1224
  }
1225
+ edgeIdLookup.current = new Map();
1226
+ for (const [id, edge] of edgeLookup) {
1227
+ edgeIdLookup.current.set(edge.source, edgeIdLookup.current.get(edge.source)?.add(id) || new Set([id]));
1228
+ edgeIdLookup.current.set(edge.target, edgeIdLookup.current.get(edge.target)?.add(id) || new Set([id]));
1229
+ }
1166
1230
  const { x, y } = getEventPosition(event.nativeEvent, containerBounds.current);
1167
1231
  resetSelectedElements();
1168
1232
  store.setState({
@@ -1177,74 +1241,73 @@ function Pane({ isSelecting, selectionMode = SelectionMode.Full, panOnDrag, onSe
1177
1241
  });
1178
1242
  onSelectionStart?.(event);
1179
1243
  };
1180
- const onMouseMove = (event) => {
1181
- const { userSelectionRect, edges, transform, nodeOrigin, nodes, onNodesChange, onEdgesChange } = store.getState();
1182
- if (!isSelecting || !containerBounds.current || !userSelectionRect) {
1244
+ const onPointerMove = (event) => {
1245
+ const { userSelectionRect, edgeLookup, transform, nodeLookup, triggerNodeChanges, triggerEdgeChanges } = store.getState();
1246
+ if (!containerBounds.current || !userSelectionRect) {
1183
1247
  return;
1184
1248
  }
1185
- store.setState({ userSelectionActive: true, nodesSelectionActive: false });
1186
- const mousePos = getEventPosition(event.nativeEvent, containerBounds.current);
1187
- const startX = userSelectionRect.startX ?? 0;
1188
- const startY = userSelectionRect.startY ?? 0;
1249
+ selectionInProgress.current = true;
1250
+ const { x: mouseX, y: mouseY } = getEventPosition(event.nativeEvent, containerBounds.current);
1251
+ const { startX, startY } = userSelectionRect;
1189
1252
  const nextUserSelectRect = {
1190
- ...userSelectionRect,
1191
- x: mousePos.x < startX ? mousePos.x : startX,
1192
- y: mousePos.y < startY ? mousePos.y : startY,
1193
- width: Math.abs(mousePos.x - startX),
1194
- height: Math.abs(mousePos.y - startY),
1253
+ startX,
1254
+ startY,
1255
+ x: mouseX < startX ? mouseX : startX,
1256
+ y: mouseY < startY ? mouseY : startY,
1257
+ width: Math.abs(mouseX - startX),
1258
+ height: Math.abs(mouseY - startY),
1195
1259
  };
1196
- const selectedNodes = getNodesInside(nodes, nextUserSelectRect, transform, selectionMode === SelectionMode.Partial, true, nodeOrigin);
1260
+ const selectedNodes = getNodesInside(nodeLookup, nextUserSelectRect, transform, selectionMode === SelectionMode.Partial, true);
1197
1261
  const selectedEdgeIds = new Set();
1198
1262
  const selectedNodeIds = new Set();
1199
1263
  for (const selectedNode of selectedNodes) {
1200
1264
  selectedNodeIds.add(selectedNode.id);
1201
- for (const edge of edges) {
1202
- if (edge.source === selectedNode.id || edge.target === selectedNode.id) {
1203
- selectedEdgeIds.add(edge.id);
1265
+ const edgeIds = edgeIdLookup.current.get(selectedNode.id);
1266
+ if (edgeIds) {
1267
+ for (const edgeId of edgeIds) {
1268
+ selectedEdgeIds.add(edgeId);
1204
1269
  }
1205
1270
  }
1206
1271
  }
1207
1272
  if (prevSelectedNodesCount.current !== selectedNodeIds.size) {
1208
1273
  prevSelectedNodesCount.current = selectedNodeIds.size;
1209
- const changes = getSelectionChanges(nodes, selectedNodeIds, true);
1210
- if (changes.length) {
1211
- onNodesChange?.(changes);
1212
- }
1274
+ const changes = getSelectionChanges(nodeLookup, selectedNodeIds, true);
1275
+ triggerNodeChanges(changes);
1213
1276
  }
1214
1277
  if (prevSelectedEdgesCount.current !== selectedEdgeIds.size) {
1215
1278
  prevSelectedEdgesCount.current = selectedEdgeIds.size;
1216
- const changes = getSelectionChanges(edges, selectedEdgeIds);
1217
- if (changes.length) {
1218
- onEdgesChange?.(changes);
1219
- }
1279
+ const changes = getSelectionChanges(edgeLookup, selectedEdgeIds);
1280
+ triggerEdgeChanges(changes);
1220
1281
  }
1221
1282
  store.setState({
1222
1283
  userSelectionRect: nextUserSelectRect,
1284
+ userSelectionActive: true,
1285
+ nodesSelectionActive: false,
1223
1286
  });
1224
1287
  };
1225
- const onMouseUp = (event) => {
1288
+ const onPointerUp = (event) => {
1226
1289
  if (event.button !== 0) {
1227
1290
  return;
1228
1291
  }
1292
+ event.target?.releasePointerCapture?.(event.pointerId);
1229
1293
  const { userSelectionRect } = store.getState();
1230
1294
  // We only want to trigger click functions when in selection mode if
1231
1295
  // the user did not move the mouse.
1232
1296
  if (!userSelectionActive && userSelectionRect && event.target === container.current) {
1233
1297
  onClick?.(event);
1234
1298
  }
1235
- store.setState({ nodesSelectionActive: prevSelectedNodesCount.current > 0 });
1299
+ if (prevSelectedNodesCount.current > 0) {
1300
+ store.setState({ nodesSelectionActive: true });
1301
+ }
1236
1302
  resetUserSelection();
1237
1303
  onSelectionEnd?.(event);
1238
- };
1239
- const onMouseLeave = (event) => {
1240
- if (userSelectionActive) {
1241
- store.setState({ nodesSelectionActive: prevSelectedNodesCount.current > 0 });
1242
- onSelectionEnd?.(event);
1304
+ // If the user kept holding the selectionKey during the selection,
1305
+ // we need to reset the selectionInProgress, so the next click event is not prevented
1306
+ if (selectionKeyPressed) {
1307
+ selectionInProgress.current = false;
1243
1308
  }
1244
- resetUserSelection();
1245
1309
  };
1246
- const hasActiveSelection = elementsSelectable && (isSelecting || userSelectionActive);
1247
- return (jsxs("div", { className: cc(['react-flow__pane', { dragging, selection: isSelecting }]), onClick: hasActiveSelection ? undefined : wrapHandler(onClick, container), onContextMenu: wrapHandler(onContextMenu, container), onWheel: wrapHandler(onWheel, container), onMouseEnter: hasActiveSelection ? undefined : onPaneMouseEnter, onMouseDown: hasActiveSelection ? onMouseDown : undefined, onMouseMove: hasActiveSelection ? onMouseMove : onPaneMouseMove, onMouseUp: hasActiveSelection ? onMouseUp : undefined, onMouseLeave: hasActiveSelection ? onMouseLeave : onPaneMouseLeave, ref: container, style: containerStyle, children: [children, jsx(UserSelection, {})] }));
1310
+ return (jsxs("div", { className: cc(['react-flow__pane', { draggable: panOnDrag, dragging, selection: isSelecting }]), onClick: hasActiveSelection ? undefined : wrapHandler(onClick, container), onContextMenu: wrapHandler(onContextMenu, container), onWheel: wrapHandler(onWheel, container), onPointerEnter: hasActiveSelection ? undefined : onPaneMouseEnter, onPointerDown: hasActiveSelection ? onPointerDown : onPaneMouseMove, onPointerMove: hasActiveSelection ? onPointerMove : onPaneMouseMove, onPointerUp: hasActiveSelection ? onPointerUp : undefined, onPointerLeave: onPaneMouseLeave, ref: container, style: containerStyle, children: [children, jsx(UserSelection, {})] }));
1248
1311
  }
1249
1312
 
1250
1313
  // this handler is called by
@@ -1278,31 +1341,28 @@ function useDrag({ nodeRef, disabled = false, noDragClassName, handleSelector, n
1278
1341
  const [dragging, setDragging] = useState(false);
1279
1342
  const xyDrag = useRef();
1280
1343
  useEffect(() => {
1281
- if (nodeRef?.current) {
1282
- xyDrag.current = XYDrag({
1283
- domNode: nodeRef.current,
1284
- getStoreItems: () => store.getState(),
1285
- onNodeMouseDown: (id) => {
1286
- handleNodeClick({
1287
- id,
1288
- store,
1289
- nodeRef,
1290
- });
1291
- },
1292
- onDragStart: () => {
1293
- setDragging(true);
1294
- },
1295
- onDragStop: () => {
1296
- setDragging(false);
1297
- },
1298
- });
1299
- }
1344
+ xyDrag.current = XYDrag({
1345
+ getStoreItems: () => store.getState(),
1346
+ onNodeMouseDown: (id) => {
1347
+ handleNodeClick({
1348
+ id,
1349
+ store,
1350
+ nodeRef,
1351
+ });
1352
+ },
1353
+ onDragStart: () => {
1354
+ setDragging(true);
1355
+ },
1356
+ onDragStop: () => {
1357
+ setDragging(false);
1358
+ },
1359
+ });
1300
1360
  }, []);
1301
1361
  useEffect(() => {
1302
1362
  if (disabled) {
1303
1363
  xyDrag.current?.destroy();
1304
1364
  }
1305
- else {
1365
+ else if (nodeRef.current) {
1306
1366
  xyDrag.current?.update({
1307
1367
  noDragClassName,
1308
1368
  handleSelector,
@@ -1328,36 +1388,38 @@ const selectedAndDraggable = (nodesDraggable) => (n) => n.selected && (n.draggab
1328
1388
  function useMoveSelectedNodes() {
1329
1389
  const store = useStoreApi();
1330
1390
  const moveSelectedNodes = useCallback((params) => {
1331
- const { nodeExtent, nodes, snapToGrid, snapGrid, nodesDraggable, onError, updateNodePositions, nodeLookup, nodeOrigin, } = store.getState();
1332
- const selectedNodes = nodes.filter(selectedAndDraggable(nodesDraggable));
1391
+ const { nodeExtent, snapToGrid, snapGrid, nodesDraggable, onError, updateNodePositions, nodeLookup, nodeOrigin } = store.getState();
1392
+ const nodeUpdates = new Map();
1393
+ const isSelected = selectedAndDraggable(nodesDraggable);
1333
1394
  // by default a node moves 5px on each key press
1334
1395
  // if snap grid is enabled, we use that for the velocity
1335
1396
  const xVelo = snapToGrid ? snapGrid[0] : 5;
1336
1397
  const yVelo = snapToGrid ? snapGrid[1] : 5;
1337
1398
  const xDiff = params.direction.x * xVelo * params.factor;
1338
1399
  const yDiff = params.direction.y * yVelo * params.factor;
1339
- const nodeUpdates = selectedNodes.map((node) => {
1340
- if (node.computed?.positionAbsolute) {
1341
- let nextPosition = {
1342
- x: node.computed.positionAbsolute.x + xDiff,
1343
- y: node.computed.positionAbsolute.y + yDiff,
1344
- };
1345
- if (snapToGrid) {
1346
- nextPosition = snapPosition(nextPosition, snapGrid);
1347
- }
1348
- const { position, positionAbsolute } = calculateNodePosition({
1349
- nodeId: node.id,
1350
- nextPosition,
1351
- nodeLookup,
1352
- nodeExtent,
1353
- nodeOrigin,
1354
- onError,
1355
- });
1356
- node.position = position;
1357
- node.computed.positionAbsolute = positionAbsolute;
1400
+ for (const [, node] of nodeLookup) {
1401
+ if (!isSelected(node)) {
1402
+ continue;
1358
1403
  }
1359
- return node;
1360
- });
1404
+ let nextPosition = {
1405
+ x: node.internals.positionAbsolute.x + xDiff,
1406
+ y: node.internals.positionAbsolute.y + yDiff,
1407
+ };
1408
+ if (snapToGrid) {
1409
+ nextPosition = snapPosition(nextPosition, snapGrid);
1410
+ }
1411
+ const { position, positionAbsolute } = calculateNodePosition({
1412
+ nodeId: node.id,
1413
+ nextPosition,
1414
+ nodeLookup,
1415
+ nodeExtent,
1416
+ nodeOrigin,
1417
+ onError,
1418
+ });
1419
+ node.position = position;
1420
+ node.internals.positionAbsolute = positionAbsolute;
1421
+ nodeUpdates.set(node.id, node);
1422
+ }
1361
1423
  updateNodePositions(nodeUpdates);
1362
1424
  }, []);
1363
1425
  return moveSelectedNodes;
@@ -1371,26 +1433,33 @@ const useNodeId = () => {
1371
1433
  return nodeId;
1372
1434
  };
1373
1435
 
1374
- const selector$i = (s) => ({
1436
+ const selector$h = (s) => ({
1375
1437
  connectOnClick: s.connectOnClick,
1376
1438
  noPanClassName: s.noPanClassName,
1377
1439
  rfId: s.rfId,
1378
1440
  });
1379
1441
  const connectingSelector = (nodeId, handleId, type) => (state) => {
1380
- const { connectionStartHandle: startHandle, connectionEndHandle: endHandle, connectionClickStartHandle: clickHandle, } = state;
1442
+ const { connectionClickStartHandle: clickHandle, connectionMode, connection } = state;
1443
+ const { fromHandle, toHandle, isValid } = connection;
1444
+ const connectingTo = toHandle?.nodeId === nodeId && toHandle?.id === handleId && toHandle?.type === type;
1381
1445
  return {
1382
- connecting: (startHandle?.nodeId === nodeId && startHandle?.handleId === handleId && startHandle?.type === type) ||
1383
- (endHandle?.nodeId === nodeId && endHandle?.handleId === handleId && endHandle?.type === type),
1384
- clickConnecting: clickHandle?.nodeId === nodeId && clickHandle?.handleId === handleId && clickHandle?.type === type,
1446
+ connectingFrom: fromHandle?.nodeId === nodeId && fromHandle?.id === handleId && fromHandle?.type === type,
1447
+ connectingTo,
1448
+ clickConnecting: clickHandle?.nodeId === nodeId && clickHandle?.id === handleId && clickHandle?.type === type,
1449
+ isPossibleEndHandle: connectionMode === ConnectionMode.Strict
1450
+ ? fromHandle?.type !== type
1451
+ : nodeId !== fromHandle?.nodeId || handleId !== fromHandle?.id,
1452
+ connectionInProcess: !!fromHandle,
1453
+ valid: connectingTo && isValid,
1385
1454
  };
1386
1455
  };
1387
- const HandleComponent = forwardRef(({ type = 'source', position = Position.Top, isValidConnection, isConnectable = true, isConnectableStart = true, isConnectableEnd = true, id, onConnect, children, className, onMouseDown, onTouchStart, ...rest }, ref) => {
1456
+ function HandleComponent({ type = 'source', position = Position.Top, isValidConnection, isConnectable = true, isConnectableStart = true, isConnectableEnd = true, id, onConnect, children, className, onMouseDown, onTouchStart, ...rest }, ref) {
1388
1457
  const handleId = id || null;
1389
1458
  const isTarget = type === 'target';
1390
1459
  const store = useStoreApi();
1391
1460
  const nodeId = useNodeId();
1392
- const { connectOnClick, noPanClassName, rfId } = useStore(selector$i, shallow);
1393
- const { connecting, clickConnecting } = useStore(connectingSelector(nodeId, handleId, type), shallow);
1461
+ const { connectOnClick, noPanClassName, rfId } = useStore(selector$h, shallow);
1462
+ const { connectingFrom, connectingTo, clickConnecting, isPossibleEndHandle, connectionInProcess, valid } = useStore(connectingSelector(nodeId, handleId, type), shallow);
1394
1463
  if (!nodeId) {
1395
1464
  store.getState().onError?.('010', errorMessages['error010']());
1396
1465
  }
@@ -1420,7 +1489,7 @@ const HandleComponent = forwardRef(({ type = 'source', position = Position.Top,
1420
1489
  connectionMode: currentStore.connectionMode,
1421
1490
  connectionRadius: currentStore.connectionRadius,
1422
1491
  domNode: currentStore.domNode,
1423
- nodes: currentStore.nodes,
1492
+ nodeLookup: currentStore.nodeLookup,
1424
1493
  lib: currentStore.lib,
1425
1494
  isTarget,
1426
1495
  handleId,
@@ -1434,6 +1503,8 @@ const HandleComponent = forwardRef(({ type = 'source', position = Position.Top,
1434
1503
  onConnect: onConnectExtended,
1435
1504
  isValidConnection: isValidConnection || currentStore.isValidConnection,
1436
1505
  getTransform: () => store.getState().transform,
1506
+ getFromHandle: () => store.getState().connection.fromHandle,
1507
+ autoPanSpeed: currentStore.autoPanSpeed,
1437
1508
  });
1438
1509
  }
1439
1510
  if (isMouseTriggered) {
@@ -1450,7 +1521,7 @@ const HandleComponent = forwardRef(({ type = 'source', position = Position.Top,
1450
1521
  }
1451
1522
  if (!connectionClickStartHandle) {
1452
1523
  onClickConnectStart?.(event.nativeEvent, { nodeId, handleId, handleType: type });
1453
- store.setState({ connectionClickStartHandle: { nodeId, type, handleId } });
1524
+ store.setState({ connectionClickStartHandle: { nodeId, type, id: handleId } });
1454
1525
  return;
1455
1526
  }
1456
1527
  const doc = getHostForElement(event.target);
@@ -1463,7 +1534,7 @@ const HandleComponent = forwardRef(({ type = 'source', position = Position.Top,
1463
1534
  },
1464
1535
  connectionMode,
1465
1536
  fromNodeId: connectionClickStartHandle.nodeId,
1466
- fromHandleId: connectionClickStartHandle.handleId || null,
1537
+ fromHandleId: connectionClickStartHandle.id || null,
1467
1538
  fromType: connectionClickStartHandle.type,
1468
1539
  isValidConnection: isValidConnectionHandler,
1469
1540
  flowId,
@@ -1488,17 +1559,22 @@ const HandleComponent = forwardRef(({ type = 'source', position = Position.Top,
1488
1559
  connectable: isConnectable,
1489
1560
  connectablestart: isConnectableStart,
1490
1561
  connectableend: isConnectableEnd,
1491
- connecting: clickConnecting,
1492
- // this class is used to style the handle when the user is connecting
1493
- connectionindicator: isConnectable && ((isConnectableStart && !connecting) || (isConnectableEnd && connecting)),
1562
+ clickconnecting: clickConnecting,
1563
+ connectingfrom: connectingFrom,
1564
+ connectingto: connectingTo,
1565
+ valid,
1566
+ // shows where you can start a connection from
1567
+ // and where you can end it while connecting
1568
+ connectionindicator: isConnectable &&
1569
+ (!connectionInProcess || isPossibleEndHandle) &&
1570
+ (connectionInProcess ? isConnectableEnd : isConnectableStart),
1494
1571
  },
1495
1572
  ]), onMouseDown: onPointerDown, onTouchStart: onPointerDown, onClick: connectOnClick ? onClick : undefined, ref: ref, ...rest, children: children }));
1496
- });
1497
- HandleComponent.displayName = 'Handle';
1573
+ }
1498
1574
  /**
1499
- * The Handle component is the part of a node that can be used to connect nodes.
1575
+ * The Handle component is a UI element that is used to connect nodes.
1500
1576
  */
1501
- const Handle = memo(HandleComponent);
1577
+ const Handle = memo(fixedForwardRef(HandleComponent));
1502
1578
 
1503
1579
  function InputNode({ data, isConnectable, sourcePosition = Position.Bottom }) {
1504
1580
  return (jsxs(Fragment, { children: [data?.label, jsx(Handle, { type: "source", position: sourcePosition, isConnectable: isConnectable })] }));
@@ -1528,20 +1604,33 @@ const builtinNodeTypes = {
1528
1604
  output: OutputNode,
1529
1605
  group: GroupNode,
1530
1606
  };
1607
+ function getNodeInlineStyleDimensions(node) {
1608
+ if (node.internals.handleBounds === undefined) {
1609
+ return {
1610
+ width: node.width ?? node.initialWidth ?? node.style?.width,
1611
+ height: node.height ?? node.initialHeight ?? node.style?.height,
1612
+ };
1613
+ }
1614
+ return {
1615
+ width: node.width ?? node.style?.width,
1616
+ height: node.height ?? node.style?.height,
1617
+ };
1618
+ }
1531
1619
 
1532
- const selector$h = (s) => {
1533
- const selectedNodes = s.nodes.filter((n) => n.selected);
1534
- const { width, height, x, y } = getNodesBounds(selectedNodes, { nodeOrigin: s.nodeOrigin });
1620
+ const selector$g = (s) => {
1621
+ const { width, height, x, y } = getInternalNodesBounds(s.nodeLookup, {
1622
+ filter: (node) => !!node.selected,
1623
+ });
1535
1624
  return {
1536
- width,
1537
- height,
1625
+ width: isNumeric(width) ? width : null,
1626
+ height: isNumeric(height) ? height : null,
1538
1627
  userSelectionActive: s.userSelectionActive,
1539
1628
  transformString: `translate(${s.transform[0]}px,${s.transform[1]}px) scale(${s.transform[2]}) translate(${x}px,${y}px)`,
1540
1629
  };
1541
1630
  };
1542
- function NodesSelection({ onSelectionContextMenu, noPanClassName, disableKeyboardA11y }) {
1631
+ function NodesSelection({ onSelectionContextMenu, noPanClassName, disableKeyboardA11y, }) {
1543
1632
  const store = useStoreApi();
1544
- const { width, height, transformString, userSelectionActive } = useStore(selector$h, shallow);
1633
+ const { width, height, transformString, userSelectionActive } = useStore(selector$g, shallow);
1545
1634
  const moveSelectedNodes = useMoveSelectedNodes();
1546
1635
  const nodeRef = useRef(null);
1547
1636
  useEffect(() => {
@@ -1579,25 +1668,26 @@ function NodesSelection({ onSelectionContextMenu, noPanClassName, disableKeyboar
1579
1668
  } }) }));
1580
1669
  }
1581
1670
 
1582
- const selector$g = (s) => {
1671
+ const win = typeof window !== 'undefined' ? window : undefined;
1672
+ const selector$f = (s) => {
1583
1673
  return { nodesSelectionActive: s.nodesSelectionActive, userSelectionActive: s.userSelectionActive };
1584
1674
  };
1585
- const FlowRendererComponent = ({ children, onPaneClick, onPaneMouseEnter, onPaneMouseMove, onPaneMouseLeave, onPaneContextMenu, onPaneScroll, deleteKeyCode, selectionKeyCode, selectionOnDrag, selectionMode, onSelectionStart, onSelectionEnd, multiSelectionKeyCode, panActivationKeyCode, zoomActivationKeyCode, elementsSelectable, zoomOnScroll, zoomOnPinch, panOnScroll: _panOnScroll, panOnScrollSpeed, panOnScrollMode, zoomOnDoubleClick, panOnDrag: _panOnDrag, defaultViewport, translateExtent, minZoom, maxZoom, preventScrolling, onSelectionContextMenu, noWheelClassName, noPanClassName, disableKeyboardA11y, onViewportChange, isControlledViewport, }) => {
1586
- const { nodesSelectionActive, userSelectionActive } = useStore(selector$g);
1587
- const selectionKeyPressed = useKeyPress(selectionKeyCode);
1588
- const panActivationKeyPressed = useKeyPress(panActivationKeyCode);
1675
+ function FlowRendererComponent({ children, onPaneClick, onPaneMouseEnter, onPaneMouseMove, onPaneMouseLeave, onPaneContextMenu, onPaneScroll, paneClickDistance, deleteKeyCode, selectionKeyCode, selectionOnDrag, selectionMode, onSelectionStart, onSelectionEnd, multiSelectionKeyCode, panActivationKeyCode, zoomActivationKeyCode, elementsSelectable, zoomOnScroll, zoomOnPinch, panOnScroll: _panOnScroll, panOnScrollSpeed, panOnScrollMode, zoomOnDoubleClick, panOnDrag: _panOnDrag, defaultViewport, translateExtent, minZoom, maxZoom, preventScrolling, onSelectionContextMenu, noWheelClassName, noPanClassName, disableKeyboardA11y, onViewportChange, isControlledViewport, }) {
1676
+ const { nodesSelectionActive, userSelectionActive } = useStore(selector$f);
1677
+ const selectionKeyPressed = useKeyPress(selectionKeyCode, { target: win });
1678
+ const panActivationKeyPressed = useKeyPress(panActivationKeyCode, { target: win });
1589
1679
  const panOnDrag = panActivationKeyPressed || _panOnDrag;
1590
1680
  const panOnScroll = panActivationKeyPressed || _panOnScroll;
1591
1681
  const isSelecting = selectionKeyPressed || userSelectionActive || (selectionOnDrag && panOnDrag !== true);
1592
1682
  useGlobalKeyHandler({ deleteKeyCode, multiSelectionKeyCode });
1593
- return (jsx(ZoomPane, { onPaneContextMenu: onPaneContextMenu, elementsSelectable: elementsSelectable, zoomOnScroll: zoomOnScroll, zoomOnPinch: zoomOnPinch, panOnScroll: panOnScroll, panOnScrollSpeed: panOnScrollSpeed, panOnScrollMode: panOnScrollMode, zoomOnDoubleClick: zoomOnDoubleClick, panOnDrag: !selectionKeyPressed && panOnDrag, defaultViewport: defaultViewport, translateExtent: translateExtent, minZoom: minZoom, maxZoom: maxZoom, zoomActivationKeyCode: zoomActivationKeyCode, preventScrolling: preventScrolling, noWheelClassName: noWheelClassName, noPanClassName: noPanClassName, onViewportChange: onViewportChange, isControlledViewport: isControlledViewport, children: jsxs(Pane, { onSelectionStart: onSelectionStart, onSelectionEnd: onSelectionEnd, onPaneClick: onPaneClick, onPaneMouseEnter: onPaneMouseEnter, onPaneMouseMove: onPaneMouseMove, onPaneMouseLeave: onPaneMouseLeave, onPaneContextMenu: onPaneContextMenu, onPaneScroll: onPaneScroll, panOnDrag: panOnDrag, isSelecting: !!isSelecting, selectionMode: selectionMode, children: [children, nodesSelectionActive && (jsx(NodesSelection, { onSelectionContextMenu: onSelectionContextMenu, noPanClassName: noPanClassName, disableKeyboardA11y: disableKeyboardA11y }))] }) }));
1594
- };
1683
+ return (jsx(ZoomPane, { onPaneContextMenu: onPaneContextMenu, elementsSelectable: elementsSelectable, zoomOnScroll: zoomOnScroll, zoomOnPinch: zoomOnPinch, panOnScroll: panOnScroll, panOnScrollSpeed: panOnScrollSpeed, panOnScrollMode: panOnScrollMode, zoomOnDoubleClick: zoomOnDoubleClick, panOnDrag: !selectionKeyPressed && panOnDrag, defaultViewport: defaultViewport, translateExtent: translateExtent, minZoom: minZoom, maxZoom: maxZoom, zoomActivationKeyCode: zoomActivationKeyCode, preventScrolling: preventScrolling, noWheelClassName: noWheelClassName, noPanClassName: noPanClassName, onViewportChange: onViewportChange, isControlledViewport: isControlledViewport, paneClickDistance: paneClickDistance, children: jsxs(Pane, { onSelectionStart: onSelectionStart, onSelectionEnd: onSelectionEnd, onPaneClick: onPaneClick, onPaneMouseEnter: onPaneMouseEnter, onPaneMouseMove: onPaneMouseMove, onPaneMouseLeave: onPaneMouseLeave, onPaneContextMenu: onPaneContextMenu, onPaneScroll: onPaneScroll, panOnDrag: panOnDrag, isSelecting: !!isSelecting, selectionMode: selectionMode, selectionKeyPressed: selectionKeyPressed, children: [children, nodesSelectionActive && (jsx(NodesSelection, { onSelectionContextMenu: onSelectionContextMenu, noPanClassName: noPanClassName, disableKeyboardA11y: disableKeyboardA11y }))] }) }));
1684
+ }
1595
1685
  FlowRendererComponent.displayName = 'FlowRenderer';
1596
1686
  const FlowRenderer = memo(FlowRendererComponent);
1597
1687
 
1598
- const selector$f = (onlyRenderVisible) => (s) => {
1688
+ const selector$e = (onlyRenderVisible) => (s) => {
1599
1689
  return onlyRenderVisible
1600
- ? getNodesInside(s.nodes, { x: 0, y: 0, width: s.width, height: s.height }, s.transform, true).map((node) => node.id)
1690
+ ? getNodesInside(s.nodeLookup, { x: 0, y: 0, width: s.width, height: s.height }, s.transform, true).map((node) => node.id)
1601
1691
  : Array.from(s.nodeLookup.keys());
1602
1692
  };
1603
1693
  /**
@@ -1608,55 +1698,97 @@ const selector$f = (onlyRenderVisible) => (s) => {
1608
1698
  * @returns array with visible node ids
1609
1699
  */
1610
1700
  function useVisibleNodeIds(onlyRenderVisible) {
1611
- const nodeIds = useStore(useCallback(selector$f(onlyRenderVisible), [onlyRenderVisible]), shallow);
1701
+ const nodeIds = useStore(useCallback(selector$e(onlyRenderVisible), [onlyRenderVisible]), shallow);
1612
1702
  return nodeIds;
1613
1703
  }
1614
1704
 
1615
- const selector$e = (s) => s.updateNodeDimensions;
1705
+ const selector$d = (s) => s.updateNodeInternals;
1616
1706
  function useResizeObserver() {
1617
- const updateNodeDimensions = useStore(selector$e);
1618
- const resizeObserverRef = useRef();
1619
- const resizeObserver = useMemo(() => {
1707
+ const updateNodeInternals = useStore(selector$d);
1708
+ const [resizeObserver] = useState(() => {
1620
1709
  if (typeof ResizeObserver === 'undefined') {
1621
1710
  return null;
1622
1711
  }
1623
- const observer = new ResizeObserver((entries) => {
1712
+ return new ResizeObserver((entries) => {
1624
1713
  const updates = new Map();
1625
1714
  entries.forEach((entry) => {
1626
1715
  const id = entry.target.getAttribute('data-id');
1627
1716
  updates.set(id, {
1628
1717
  id,
1629
1718
  nodeElement: entry.target,
1630
- forceUpdate: true,
1719
+ force: true,
1631
1720
  });
1632
1721
  });
1633
- updateNodeDimensions(updates);
1722
+ updateNodeInternals(updates);
1634
1723
  });
1635
- resizeObserverRef.current = observer;
1636
- return observer;
1637
- }, []);
1724
+ });
1638
1725
  useEffect(() => {
1639
1726
  return () => {
1640
- resizeObserverRef?.current?.disconnect();
1727
+ resizeObserver?.disconnect();
1641
1728
  };
1642
- }, []);
1729
+ }, [resizeObserver]);
1643
1730
  return resizeObserver;
1644
1731
  }
1645
1732
 
1646
- function NodeWrapper({ id, onClick, onMouseEnter, onMouseMove, onMouseLeave, onContextMenu, onDoubleClick, nodesDraggable, elementsSelectable, nodesConnectable, nodesFocusable, resizeObserver, noDragClassName, noPanClassName, disableKeyboardA11y, rfId, nodeTypes, nodeExtent, nodeOrigin, onError, }) {
1647
- const { node, positionAbsoluteX, positionAbsoluteY, zIndex, isParent } = useStore((s) => {
1733
+ /**
1734
+ * Hook to handle the resize observation + internal updates for the passed node.
1735
+ *
1736
+ * @internal
1737
+ * @returns nodeRef - reference to the node element
1738
+ */
1739
+ function useNodeObserver({ node, nodeType, hasDimensions, resizeObserver, }) {
1740
+ const store = useStoreApi();
1741
+ const nodeRef = useRef(null);
1742
+ const observedNode = useRef(null);
1743
+ const prevSourcePosition = useRef(node.sourcePosition);
1744
+ const prevTargetPosition = useRef(node.targetPosition);
1745
+ const prevType = useRef(nodeType);
1746
+ const isInitialized = hasDimensions && !!node.internals.handleBounds;
1747
+ useEffect(() => {
1748
+ if (nodeRef.current && !node.hidden && (!isInitialized || observedNode.current !== nodeRef.current)) {
1749
+ if (observedNode.current) {
1750
+ resizeObserver?.unobserve(observedNode.current);
1751
+ }
1752
+ resizeObserver?.observe(nodeRef.current);
1753
+ observedNode.current = nodeRef.current;
1754
+ }
1755
+ }, [isInitialized, node.hidden]);
1756
+ useEffect(() => {
1757
+ return () => {
1758
+ if (observedNode.current) {
1759
+ resizeObserver?.unobserve(observedNode.current);
1760
+ observedNode.current = null;
1761
+ }
1762
+ };
1763
+ }, []);
1764
+ useEffect(() => {
1765
+ if (nodeRef.current) {
1766
+ // when the user programmatically changes the source or handle position, we need to update the internals
1767
+ // to make sure the edges are updated correctly
1768
+ const typeChanged = prevType.current !== nodeType;
1769
+ const sourcePosChanged = prevSourcePosition.current !== node.sourcePosition;
1770
+ const targetPosChanged = prevTargetPosition.current !== node.targetPosition;
1771
+ if (typeChanged || sourcePosChanged || targetPosChanged) {
1772
+ prevType.current = nodeType;
1773
+ prevSourcePosition.current = node.sourcePosition;
1774
+ prevTargetPosition.current = node.targetPosition;
1775
+ store
1776
+ .getState()
1777
+ .updateNodeInternals(new Map([[node.id, { id: node.id, nodeElement: nodeRef.current, force: true }]]));
1778
+ }
1779
+ }
1780
+ }, [node.id, nodeType, node.sourcePosition, node.targetPosition]);
1781
+ return nodeRef;
1782
+ }
1783
+
1784
+ function NodeWrapper({ id, onClick, onMouseEnter, onMouseMove, onMouseLeave, onContextMenu, onDoubleClick, nodesDraggable, elementsSelectable, nodesConnectable, nodesFocusable, resizeObserver, noDragClassName, noPanClassName, disableKeyboardA11y, rfId, nodeTypes, nodeExtent, onError, }) {
1785
+ const { node, internals, isParent } = useStore((s) => {
1648
1786
  const node = s.nodeLookup.get(id);
1649
- const positionAbsolute = nodeExtent
1650
- ? clampPosition(node.computed?.positionAbsolute, nodeExtent)
1651
- : node.computed?.positionAbsolute || { x: 0, y: 0 };
1787
+ const isParent = s.parentLookup.has(id);
1652
1788
  return {
1653
1789
  node,
1654
- // we are mutating positionAbsolute, z and isParent attributes for sub flows
1655
- // so we we need to force a re-render when some change
1656
- positionAbsoluteX: positionAbsolute.x,
1657
- positionAbsoluteY: positionAbsolute.y,
1658
- zIndex: node[internalsSymbol]?.z ?? 0,
1659
- isParent: !!node[internalsSymbol]?.isParent,
1790
+ internals: node.internals,
1791
+ isParent,
1660
1792
  };
1661
1793
  }, shallow);
1662
1794
  let nodeType = node.type || 'default';
@@ -1671,51 +1803,8 @@ function NodeWrapper({ id, onClick, onMouseEnter, onMouseMove, onMouseLeave, onC
1671
1803
  const isConnectable = !!(node.connectable || (nodesConnectable && typeof node.connectable === 'undefined'));
1672
1804
  const isFocusable = !!(node.focusable || (nodesFocusable && typeof node.focusable === 'undefined'));
1673
1805
  const store = useStoreApi();
1674
- const nodeRef = useRef(null);
1675
- const prevSourcePosition = useRef(node.sourcePosition);
1676
- const prevTargetPosition = useRef(node.targetPosition);
1677
- const prevType = useRef(nodeType);
1678
- const width = node.width ?? undefined;
1679
- const height = node.height ?? undefined;
1680
- const computedWidth = node.computed?.width;
1681
- const computedHeight = node.computed?.height;
1682
- const initialized = (!!computedWidth && !!computedHeight) || (!!width && !!height);
1683
- const hasHandleBounds = !!node[internalsSymbol]?.handleBounds;
1684
- const moveSelectedNodes = useMoveSelectedNodes();
1685
- useEffect(() => {
1686
- return () => {
1687
- if (nodeRef.current) {
1688
- resizeObserver?.unobserve(nodeRef.current);
1689
- }
1690
- };
1691
- }, []);
1692
- useEffect(() => {
1693
- if (nodeRef.current && !node.hidden) {
1694
- const currNode = nodeRef.current;
1695
- if (!initialized || !hasHandleBounds) {
1696
- resizeObserver?.unobserve(currNode);
1697
- resizeObserver?.observe(currNode);
1698
- }
1699
- }
1700
- }, [node.hidden, initialized, hasHandleBounds]);
1701
- useEffect(() => {
1702
- // when the user programmatically changes the source or handle position, we re-initialize the node
1703
- const typeChanged = prevType.current !== nodeType;
1704
- const sourcePosChanged = prevSourcePosition.current !== node.sourcePosition;
1705
- const targetPosChanged = prevTargetPosition.current !== node.targetPosition;
1706
- if (nodeRef.current && (typeChanged || sourcePosChanged || targetPosChanged)) {
1707
- if (typeChanged) {
1708
- prevType.current = nodeType;
1709
- }
1710
- if (sourcePosChanged) {
1711
- prevSourcePosition.current = node.sourcePosition;
1712
- }
1713
- if (targetPosChanged) {
1714
- prevTargetPosition.current = node.targetPosition;
1715
- }
1716
- store.getState().updateNodeDimensions(new Map([[id, { id, nodeElement: nodeRef.current, forceUpdate: true }]]));
1717
- }
1718
- }, [id, nodeType, node.sourcePosition, node.targetPosition]);
1806
+ const hasDimensions = nodeHasDimensions(node);
1807
+ const nodeRef = useNodeObserver({ node, nodeType, hasDimensions, resizeObserver });
1719
1808
  const dragging = useDrag({
1720
1809
  nodeRef,
1721
1810
  disabled: node.hidden || !isDraggable,
@@ -1724,22 +1813,32 @@ function NodeWrapper({ id, onClick, onMouseEnter, onMouseMove, onMouseLeave, onC
1724
1813
  nodeId: id,
1725
1814
  isSelectable,
1726
1815
  });
1816
+ const moveSelectedNodes = useMoveSelectedNodes();
1727
1817
  if (node.hidden) {
1728
1818
  return null;
1729
1819
  }
1730
- const positionAbsoluteOrigin = getPositionWithOrigin({
1731
- x: positionAbsoluteX,
1732
- y: positionAbsoluteY,
1733
- width: computedWidth ?? width ?? 0,
1734
- height: computedHeight ?? height ?? 0,
1735
- origin: node.origin || nodeOrigin,
1736
- });
1820
+ const nodeDimensions = getNodeDimensions(node);
1821
+ const inlineDimensions = getNodeInlineStyleDimensions(node);
1822
+ // TODO: clamping should happen earlier
1823
+ const clampedPosition = nodeExtent
1824
+ ? clampPosition(internals.positionAbsolute, nodeExtent)
1825
+ : internals.positionAbsolute;
1737
1826
  const hasPointerEvents = isSelectable || isDraggable || onClick || onMouseEnter || onMouseMove || onMouseLeave;
1738
- const onMouseEnterHandler = onMouseEnter ? (event) => onMouseEnter(event, { ...node }) : undefined;
1739
- const onMouseMoveHandler = onMouseMove ? (event) => onMouseMove(event, { ...node }) : undefined;
1740
- const onMouseLeaveHandler = onMouseLeave ? (event) => onMouseLeave(event, { ...node }) : undefined;
1741
- const onContextMenuHandler = onContextMenu ? (event) => onContextMenu(event, { ...node }) : undefined;
1742
- const onDoubleClickHandler = onDoubleClick ? (event) => onDoubleClick(event, { ...node }) : undefined;
1827
+ const onMouseEnterHandler = onMouseEnter
1828
+ ? (event) => onMouseEnter(event, { ...internals.userNode })
1829
+ : undefined;
1830
+ const onMouseMoveHandler = onMouseMove
1831
+ ? (event) => onMouseMove(event, { ...internals.userNode })
1832
+ : undefined;
1833
+ const onMouseLeaveHandler = onMouseLeave
1834
+ ? (event) => onMouseLeave(event, { ...internals.userNode })
1835
+ : undefined;
1836
+ const onContextMenuHandler = onContextMenu
1837
+ ? (event) => onContextMenu(event, { ...internals.userNode })
1838
+ : undefined;
1839
+ const onDoubleClickHandler = onDoubleClick
1840
+ ? (event) => onDoubleClick(event, { ...internals.userNode })
1841
+ : undefined;
1743
1842
  const onSelectNodeHandler = (event) => {
1744
1843
  const { selectNodesOnDrag, nodeDragThreshold } = store.getState();
1745
1844
  if (isSelectable && (!selectNodesOnDrag || !isDraggable || nodeDragThreshold > 0)) {
@@ -1752,11 +1851,11 @@ function NodeWrapper({ id, onClick, onMouseEnter, onMouseMove, onMouseLeave, onC
1752
1851
  });
1753
1852
  }
1754
1853
  if (onClick) {
1755
- onClick(event, { ...node });
1854
+ onClick(event, { ...internals.userNode });
1756
1855
  }
1757
1856
  };
1758
1857
  const onKeyDown = (event) => {
1759
- if (isInputDOMNode(event.nativeEvent)) {
1858
+ if (isInputDOMNode(event.nativeEvent) || disableKeyboardA11y) {
1760
1859
  return;
1761
1860
  }
1762
1861
  if (elementSelectionKeys.includes(event.key) && isSelectable) {
@@ -1768,14 +1867,11 @@ function NodeWrapper({ id, onClick, onMouseEnter, onMouseMove, onMouseLeave, onC
1768
1867
  nodeRef,
1769
1868
  });
1770
1869
  }
1771
- else if (!disableKeyboardA11y &&
1772
- isDraggable &&
1773
- node.selected &&
1774
- Object.prototype.hasOwnProperty.call(arrowKeyDiffs, event.key)) {
1870
+ else if (isDraggable && node.selected && Object.prototype.hasOwnProperty.call(arrowKeyDiffs, event.key)) {
1775
1871
  store.setState({
1776
1872
  ariaLiveMessage: `Moved selected node ${event.key
1777
1873
  .replace('Arrow', '')
1778
- .toLowerCase()}. New position, x: ${~~positionAbsoluteX}, y: ${~~positionAbsoluteY}`,
1874
+ .toLowerCase()}. New position, x: ${~~clampedPosition.x}, y: ${~~clampedPosition.y}`,
1779
1875
  });
1780
1876
  moveSelectedNodes({
1781
1877
  direction: arrowKeyDiffs[event.key],
@@ -1795,28 +1891,28 @@ function NodeWrapper({ id, onClick, onMouseEnter, onMouseMove, onMouseLeave, onC
1795
1891
  selected: node.selected,
1796
1892
  selectable: isSelectable,
1797
1893
  parent: isParent,
1894
+ draggable: isDraggable,
1798
1895
  dragging,
1799
1896
  },
1800
1897
  ]), ref: nodeRef, style: {
1801
- zIndex,
1802
- transform: `translate(${positionAbsoluteOrigin.x}px,${positionAbsoluteOrigin.y}px)`,
1898
+ zIndex: internals.z,
1899
+ transform: `translate(${clampedPosition.x}px,${clampedPosition.y}px)`,
1803
1900
  pointerEvents: hasPointerEvents ? 'all' : 'none',
1804
- visibility: initialized ? 'visible' : 'hidden',
1901
+ visibility: hasDimensions ? 'visible' : 'hidden',
1805
1902
  ...node.style,
1806
- width: width ?? node.style?.width,
1807
- height: height ?? node.style?.height,
1808
- }, "data-id": id, "data-testid": `rf__node-${id}`, onMouseEnter: onMouseEnterHandler, onMouseMove: onMouseMoveHandler, onMouseLeave: onMouseLeaveHandler, onContextMenu: onContextMenuHandler, onClick: onSelectNodeHandler, onDoubleClick: onDoubleClickHandler, onKeyDown: isFocusable ? onKeyDown : undefined, tabIndex: isFocusable ? 0 : undefined, role: isFocusable ? 'button' : undefined, "aria-describedby": disableKeyboardA11y ? undefined : `${ARIA_NODE_DESC_KEY}-${rfId}`, "aria-label": node.ariaLabel, children: jsx(Provider, { value: id, children: jsx(NodeComponent, { id: id, data: node.data, type: nodeType, width: computedWidth, height: computedHeight, positionAbsoluteX: positionAbsoluteX, positionAbsoluteY: positionAbsoluteY, selected: node.selected, isConnectable: isConnectable, sourcePosition: node.sourcePosition, targetPosition: node.targetPosition, dragging: dragging, dragHandle: node.dragHandle, zIndex: zIndex }) }) }));
1903
+ ...inlineDimensions,
1904
+ }, "data-id": id, "data-testid": `rf__node-${id}`, onMouseEnter: onMouseEnterHandler, onMouseMove: onMouseMoveHandler, onMouseLeave: onMouseLeaveHandler, onContextMenu: onContextMenuHandler, onClick: onSelectNodeHandler, onDoubleClick: onDoubleClickHandler, onKeyDown: isFocusable ? onKeyDown : undefined, tabIndex: isFocusable ? 0 : undefined, role: isFocusable ? 'button' : undefined, "aria-describedby": disableKeyboardA11y ? undefined : `${ARIA_NODE_DESC_KEY}-${rfId}`, "aria-label": node.ariaLabel, children: jsx(Provider, { value: id, children: jsx(NodeComponent, { id: id, data: node.data, type: nodeType, positionAbsoluteX: clampedPosition.x, positionAbsoluteY: clampedPosition.y, selected: node.selected, selectable: isSelectable, draggable: isDraggable, deletable: node.deletable ?? true, isConnectable: isConnectable, sourcePosition: node.sourcePosition, targetPosition: node.targetPosition, dragging: dragging, dragHandle: node.dragHandle, zIndex: internals.z, parentId: node.parentId, ...nodeDimensions }) }) }));
1809
1905
  }
1810
1906
 
1811
- const selector$d = (s) => ({
1907
+ const selector$c = (s) => ({
1812
1908
  nodesDraggable: s.nodesDraggable,
1813
1909
  nodesConnectable: s.nodesConnectable,
1814
1910
  nodesFocusable: s.nodesFocusable,
1815
1911
  elementsSelectable: s.elementsSelectable,
1816
1912
  onError: s.onError,
1817
1913
  });
1818
- const NodeRendererComponent = (props) => {
1819
- const { nodesDraggable, nodesConnectable, nodesFocusable, elementsSelectable, onError } = useStore(selector$d, shallow);
1914
+ function NodeRendererComponent(props) {
1915
+ const { nodesDraggable, nodesConnectable, nodesFocusable, elementsSelectable, onError } = useStore(selector$c, shallow);
1820
1916
  const nodeIds = useVisibleNodeIds(props.onlyRenderVisibleElements);
1821
1917
  const resizeObserver = useResizeObserver();
1822
1918
  return (jsx("div", { className: "react-flow__nodes", style: containerStyle, children: nodeIds.map((nodeId) => {
@@ -1844,9 +1940,9 @@ const NodeRendererComponent = (props) => {
1844
1940
  // moved into `NodeComponentWrapper`. This ensures they are
1845
1941
  // memorized – so if `NodeRenderer` *has* to rerender, it only
1846
1942
  // needs to regenerate the list of nodes, nothing else.
1847
- jsx(NodeWrapper, { id: nodeId, nodeTypes: props.nodeTypes, nodeExtent: props.nodeExtent, nodeOrigin: props.nodeOrigin, onClick: props.onNodeClick, onMouseEnter: props.onNodeMouseEnter, onMouseMove: props.onNodeMouseMove, onMouseLeave: props.onNodeMouseLeave, onContextMenu: props.onNodeContextMenu, onDoubleClick: props.onNodeDoubleClick, noDragClassName: props.noDragClassName, noPanClassName: props.noPanClassName, rfId: props.rfId, disableKeyboardA11y: props.disableKeyboardA11y, resizeObserver: resizeObserver, nodesDraggable: nodesDraggable, nodesConnectable: nodesConnectable, nodesFocusable: nodesFocusable, elementsSelectable: elementsSelectable, onError: onError }, nodeId));
1943
+ jsx(NodeWrapper, { id: nodeId, nodeTypes: props.nodeTypes, nodeExtent: props.nodeExtent, onClick: props.onNodeClick, onMouseEnter: props.onNodeMouseEnter, onMouseMove: props.onNodeMouseMove, onMouseLeave: props.onNodeMouseLeave, onContextMenu: props.onNodeContextMenu, onDoubleClick: props.onNodeDoubleClick, noDragClassName: props.noDragClassName, noPanClassName: props.noPanClassName, rfId: props.rfId, disableKeyboardA11y: props.disableKeyboardA11y, resizeObserver: resizeObserver, nodesDraggable: nodesDraggable, nodesConnectable: nodesConnectable, nodesFocusable: nodesFocusable, elementsSelectable: elementsSelectable, onError: onError }, nodeId));
1848
1944
  }) }));
1849
- };
1945
+ }
1850
1946
  NodeRendererComponent.displayName = 'NodeRenderer';
1851
1947
  const NodeRenderer = memo(NodeRendererComponent);
1852
1948
 
@@ -1948,21 +2044,22 @@ var MarkerDefinitions$1 = memo(MarkerDefinitions);
1948
2044
  function EdgeTextComponent({ x, y, label, labelStyle = {}, labelShowBg = true, labelBgStyle = {}, labelBgPadding = [2, 4], labelBgBorderRadius = 2, children, className, ...rest }) {
1949
2045
  const [edgeTextBbox, setEdgeTextBbox] = useState({ x: 1, y: 0, width: 0, height: 0 });
1950
2046
  const edgeTextClasses = cc(['react-flow__edge-textwrapper', className]);
1951
- const onEdgeTextRefChange = useCallback((edgeRef) => {
1952
- if (edgeRef === null)
1953
- return;
1954
- const textBbox = edgeRef.getBBox();
1955
- setEdgeTextBbox({
1956
- x: textBbox.x,
1957
- y: textBbox.y,
1958
- width: textBbox.width,
1959
- height: textBbox.height,
1960
- });
1961
- }, []);
2047
+ const edgeTextRef = useRef(null);
2048
+ useEffect(() => {
2049
+ if (edgeTextRef.current) {
2050
+ const textBbox = edgeTextRef.current.getBBox();
2051
+ setEdgeTextBbox({
2052
+ x: textBbox.x,
2053
+ y: textBbox.y,
2054
+ width: textBbox.width,
2055
+ height: textBbox.height,
2056
+ });
2057
+ }
2058
+ }, [label]);
1962
2059
  if (typeof label === 'undefined' || !label) {
1963
2060
  return null;
1964
2061
  }
1965
- return (jsxs("g", { transform: `translate(${x - edgeTextBbox.width / 2} ${y - edgeTextBbox.height / 2})`, className: edgeTextClasses, visibility: edgeTextBbox.width ? 'visible' : 'hidden', ...rest, children: [labelShowBg && (jsx("rect", { width: edgeTextBbox.width + 2 * labelBgPadding[0], x: -labelBgPadding[0], y: -labelBgPadding[1], height: edgeTextBbox.height + 2 * labelBgPadding[1], className: "react-flow__edge-textbg", style: labelBgStyle, rx: labelBgBorderRadius, ry: labelBgBorderRadius })), jsx("text", { className: "react-flow__edge-text", y: edgeTextBbox.height / 2, dy: "0.3em", ref: onEdgeTextRefChange, style: labelStyle, children: label }), children] }));
2062
+ return (jsxs("g", { transform: `translate(${x - edgeTextBbox.width / 2} ${y - edgeTextBbox.height / 2})`, className: edgeTextClasses, visibility: edgeTextBbox.width ? 'visible' : 'hidden', ...rest, children: [labelShowBg && (jsx("rect", { width: edgeTextBbox.width + 2 * labelBgPadding[0], x: -labelBgPadding[0], y: -labelBgPadding[1], height: edgeTextBbox.height + 2 * labelBgPadding[1], className: "react-flow__edge-textbg", style: labelBgStyle, rx: labelBgBorderRadius, ry: labelBgBorderRadius })), jsx("text", { className: "react-flow__edge-text", y: edgeTextBbox.height / 2, dy: "0.3em", ref: edgeTextRef, style: labelStyle, children: label }), children] }));
1966
2063
  }
1967
2064
  EdgeTextComponent.displayName = 'EdgeText';
1968
2065
  const EdgeText = memo(EdgeTextComponent);
@@ -2133,25 +2230,25 @@ function EdgeAnchor({ position, centerX, centerY, radius = 10, onMouseDown, onMo
2133
2230
  return (jsx("circle", { onMouseDown: onMouseDown, onMouseEnter: onMouseEnter, onMouseOut: onMouseOut, className: cc([EdgeUpdaterClassName, `${EdgeUpdaterClassName}-${type}`]), cx: shiftX(centerX, radius, position), cy: shiftY(centerY, radius, position), r: radius, stroke: "transparent", fill: "transparent" }));
2134
2231
  }
2135
2232
 
2136
- function EdgeUpdateAnchors({ isUpdatable, edgeUpdaterRadius, edge, targetHandleId, sourceHandleId, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, onEdgeUpdate, onEdgeUpdateStart, onEdgeUpdateEnd, setUpdating, setUpdateHover, }) {
2233
+ function EdgeUpdateAnchors({ isReconnectable, reconnectRadius, edge, targetHandleId, sourceHandleId, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, onReconnect, onReconnectStart, onReconnectEnd, setReconnecting, setUpdateHover, }) {
2137
2234
  const store = useStoreApi();
2138
2235
  const handleEdgeUpdater = (event, isSourceHandle) => {
2139
2236
  // avoid triggering edge updater if mouse btn is not left
2140
2237
  if (event.button !== 0) {
2141
2238
  return;
2142
2239
  }
2143
- const { autoPanOnConnect, domNode, isValidConnection, connectionMode, connectionRadius, lib, onConnectStart, onConnectEnd, cancelConnection, nodes, rfId: flowId, panBy, updateConnection, } = store.getState();
2240
+ const { autoPanOnConnect, domNode, isValidConnection, connectionMode, connectionRadius, lib, onConnectStart, onConnectEnd, cancelConnection, nodeLookup, rfId: flowId, panBy, updateConnection, } = store.getState();
2144
2241
  const nodeId = isSourceHandle ? edge.target : edge.source;
2145
2242
  const handleId = (isSourceHandle ? targetHandleId : sourceHandleId) || null;
2146
2243
  const handleType = isSourceHandle ? 'target' : 'source';
2147
2244
  const isTarget = isSourceHandle;
2148
- setUpdating(true);
2149
- onEdgeUpdateStart?.(event, edge, handleType);
2150
- const _onEdgeUpdateEnd = (evt) => {
2151
- setUpdating(false);
2152
- onEdgeUpdateEnd?.(evt, edge, handleType);
2245
+ setReconnecting(true);
2246
+ onReconnectStart?.(event, edge, handleType);
2247
+ const _onReconnectEnd = (evt) => {
2248
+ setReconnecting(false);
2249
+ onReconnectEnd?.(evt, edge, handleType);
2153
2250
  };
2154
- const onConnectEdge = (connection) => onEdgeUpdate?.(edge, connection);
2251
+ const onConnectEdge = (connection) => onReconnect?.(edge, connection);
2155
2252
  XYHandle.onPointerDown(event.nativeEvent, {
2156
2253
  autoPanOnConnect,
2157
2254
  connectionMode,
@@ -2159,7 +2256,7 @@ function EdgeUpdateAnchors({ isUpdatable, edgeUpdaterRadius, edge, targetHandleI
2159
2256
  domNode,
2160
2257
  handleId,
2161
2258
  nodeId,
2162
- nodes,
2259
+ nodeLookup,
2163
2260
  isTarget,
2164
2261
  edgeUpdaterType: handleType,
2165
2262
  lib,
@@ -2170,19 +2267,20 @@ function EdgeUpdateAnchors({ isUpdatable, edgeUpdaterRadius, edge, targetHandleI
2170
2267
  onConnect: onConnectEdge,
2171
2268
  onConnectStart,
2172
2269
  onConnectEnd,
2173
- onEdgeUpdateEnd: _onEdgeUpdateEnd,
2270
+ onReconnectEnd: _onReconnectEnd,
2174
2271
  updateConnection,
2175
2272
  getTransform: () => store.getState().transform,
2273
+ getFromHandle: () => store.getState().connection.fromHandle,
2176
2274
  });
2177
2275
  };
2178
- const onEdgeUpdaterSourceMouseDown = (event) => handleEdgeUpdater(event, true);
2179
- const onEdgeUpdaterTargetMouseDown = (event) => handleEdgeUpdater(event, false);
2180
- const onEdgeUpdaterMouseEnter = () => setUpdateHover(true);
2181
- const onEdgeUpdaterMouseOut = () => setUpdateHover(false);
2182
- return (jsxs(Fragment, { children: [(isUpdatable === 'source' || isUpdatable === true) && (jsx(EdgeAnchor, { position: sourcePosition, centerX: sourceX, centerY: sourceY, radius: edgeUpdaterRadius, onMouseDown: onEdgeUpdaterSourceMouseDown, onMouseEnter: onEdgeUpdaterMouseEnter, onMouseOut: onEdgeUpdaterMouseOut, type: "source" })), (isUpdatable === 'target' || isUpdatable === true) && (jsx(EdgeAnchor, { position: targetPosition, centerX: targetX, centerY: targetY, radius: edgeUpdaterRadius, onMouseDown: onEdgeUpdaterTargetMouseDown, onMouseEnter: onEdgeUpdaterMouseEnter, onMouseOut: onEdgeUpdaterMouseOut, type: "target" }))] }));
2276
+ const onReconnectSourceMouseDown = (event) => handleEdgeUpdater(event, true);
2277
+ const onReconnectTargetMouseDown = (event) => handleEdgeUpdater(event, false);
2278
+ const onReconnectMouseEnter = () => setUpdateHover(true);
2279
+ const onReconnectMouseOut = () => setUpdateHover(false);
2280
+ return (jsxs(Fragment, { children: [(isReconnectable === 'source' || isReconnectable === true) && (jsx(EdgeAnchor, { position: sourcePosition, centerX: sourceX, centerY: sourceY, radius: reconnectRadius, onMouseDown: onReconnectSourceMouseDown, onMouseEnter: onReconnectMouseEnter, onMouseOut: onReconnectMouseOut, type: "source" })), (isReconnectable === 'target' || isReconnectable === true) && (jsx(EdgeAnchor, { position: targetPosition, centerX: targetX, centerY: targetY, radius: reconnectRadius, onMouseDown: onReconnectTargetMouseDown, onMouseEnter: onReconnectMouseEnter, onMouseOut: onReconnectMouseOut, type: "target" }))] }));
2183
2281
  }
2184
2282
 
2185
- function EdgeWrapper({ id, edgesFocusable, edgesUpdatable, elementsSelectable, onClick, onDoubleClick, onContextMenu, onMouseEnter, onMouseMove, onMouseLeave, edgeUpdaterRadius, onEdgeUpdate, onEdgeUpdateStart, onEdgeUpdateEnd, rfId, edgeTypes, noPanClassName, onError, }) {
2283
+ function EdgeWrapper({ id, edgesFocusable, edgesReconnectable, elementsSelectable, onClick, onDoubleClick, onContextMenu, onMouseEnter, onMouseMove, onMouseLeave, reconnectRadius, onReconnect, onReconnectStart, onReconnectEnd, rfId, edgeTypes, noPanClassName, onError, disableKeyboardA11y, }) {
2186
2284
  let edge = useStore((s) => s.edgeLookup.get(id));
2187
2285
  const defaultEdgeOptions = useStore((s) => s.defaultEdgeOptions);
2188
2286
  edge = defaultEdgeOptions ? { ...defaultEdgeOptions, ...edge } : edge;
@@ -2194,12 +2292,12 @@ function EdgeWrapper({ id, edgesFocusable, edgesUpdatable, elementsSelectable, o
2194
2292
  EdgeComponent = builtinEdgeTypes.default;
2195
2293
  }
2196
2294
  const isFocusable = !!(edge.focusable || (edgesFocusable && typeof edge.focusable === 'undefined'));
2197
- const isUpdatable = typeof onEdgeUpdate !== 'undefined' &&
2198
- (edge.updatable || (edgesUpdatable && typeof edge.updatable === 'undefined'));
2295
+ const isReconnectable = typeof onReconnect !== 'undefined' &&
2296
+ (edge.reconnectable || (edgesReconnectable && typeof edge.reconnectable === 'undefined'));
2199
2297
  const isSelectable = !!(edge.selectable || (elementsSelectable && typeof edge.selectable === 'undefined'));
2200
2298
  const edgeRef = useRef(null);
2201
2299
  const [updateHover, setUpdateHover] = useState(false);
2202
- const [updating, setUpdating] = useState(false);
2300
+ const [reconnecting, setReconnecting] = useState(false);
2203
2301
  const store = useStoreApi();
2204
2302
  const { zIndex, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition } = useStore(useCallback((store) => {
2205
2303
  const sourceNode = store.nodeLookup.get(edge.source);
@@ -2233,7 +2331,7 @@ function EdgeWrapper({ id, edgesFocusable, edgesUpdatable, elementsSelectable, o
2233
2331
  }, [edge.source, edge.target, edge.sourceHandle, edge.targetHandle, edge.selected, edge.zIndex]), shallow);
2234
2332
  const markerStartUrl = useMemo(() => (edge.markerStart ? `url('#${getMarkerId(edge.markerStart, rfId)}')` : undefined), [edge.markerStart, rfId]);
2235
2333
  const markerEndUrl = useMemo(() => (edge.markerEnd ? `url('#${getMarkerId(edge.markerEnd, rfId)}')` : undefined), [edge.markerEnd, rfId]);
2236
- if (edge.hidden || !sourceX || !sourceY || !targetX || !targetY) {
2334
+ if (edge.hidden || sourceX === null || sourceY === null || targetX === null || targetY === null) {
2237
2335
  return null;
2238
2336
  }
2239
2337
  const onEdgeClick = (event) => {
@@ -2278,7 +2376,7 @@ function EdgeWrapper({ id, edgesFocusable, edgesUpdatable, elementsSelectable, o
2278
2376
  }
2279
2377
  : undefined;
2280
2378
  const onKeyDown = (event) => {
2281
- if (elementSelectionKeys.includes(event.key) && isSelectable) {
2379
+ if (!disableKeyboardA11y && elementSelectionKeys.includes(event.key) && isSelectable) {
2282
2380
  const { unselectNodesAndEdges, addSelectedEdges } = store.getState();
2283
2381
  const unselect = event.key === 'Escape';
2284
2382
  if (unselect) {
@@ -2302,31 +2400,31 @@ function EdgeWrapper({ id, edgesFocusable, edgesUpdatable, elementsSelectable, o
2302
2400
  updating: updateHover,
2303
2401
  selectable: isSelectable,
2304
2402
  },
2305
- ]), onClick: onEdgeClick, onDoubleClick: onEdgeDoubleClick, onContextMenu: onEdgeContextMenu, onMouseEnter: onEdgeMouseEnter, onMouseMove: onEdgeMouseMove, onMouseLeave: onEdgeMouseLeave, onKeyDown: isFocusable ? onKeyDown : undefined, tabIndex: isFocusable ? 0 : undefined, role: isFocusable ? 'button' : 'img', "data-id": id, "data-testid": `rf__edge-${id}`, "aria-label": edge.ariaLabel === null ? undefined : edge.ariaLabel || `Edge from ${edge.source} to ${edge.target}`, "aria-describedby": isFocusable ? `${ARIA_EDGE_DESC_KEY}-${rfId}` : undefined, ref: edgeRef, children: [!updating && (jsx(EdgeComponent, { id: id, source: edge.source, target: edge.target, selected: edge.selected, animated: edge.animated, label: edge.label, labelStyle: edge.labelStyle, labelShowBg: edge.labelShowBg, labelBgStyle: edge.labelBgStyle, labelBgPadding: edge.labelBgPadding, labelBgBorderRadius: edge.labelBgBorderRadius, sourceX: sourceX, sourceY: sourceY, targetX: targetX, targetY: targetY, sourcePosition: sourcePosition, targetPosition: targetPosition, data: edge.data, style: edge.style, sourceHandleId: edge.sourceHandle, targetHandleId: edge.targetHandle, markerStart: markerStartUrl, markerEnd: markerEndUrl, pathOptions: 'pathOptions' in edge ? edge.pathOptions : undefined, interactionWidth: edge.interactionWidth })), isUpdatable && (jsx(EdgeUpdateAnchors, { edge: edge, isUpdatable: isUpdatable, edgeUpdaterRadius: edgeUpdaterRadius, onEdgeUpdate: onEdgeUpdate, onEdgeUpdateStart: onEdgeUpdateStart, onEdgeUpdateEnd: onEdgeUpdateEnd, sourceX: sourceX, sourceY: sourceY, targetX: targetX, targetY: targetY, sourcePosition: sourcePosition, targetPosition: targetPosition, setUpdateHover: setUpdateHover, setUpdating: setUpdating, sourceHandleId: edge.sourceHandle, targetHandleId: edge.targetHandle }))] }) }));
2403
+ ]), onClick: onEdgeClick, onDoubleClick: onEdgeDoubleClick, onContextMenu: onEdgeContextMenu, onMouseEnter: onEdgeMouseEnter, onMouseMove: onEdgeMouseMove, onMouseLeave: onEdgeMouseLeave, onKeyDown: isFocusable ? onKeyDown : undefined, tabIndex: isFocusable ? 0 : undefined, role: isFocusable ? 'button' : 'img', "data-id": id, "data-testid": `rf__edge-${id}`, "aria-label": edge.ariaLabel === null ? undefined : edge.ariaLabel || `Edge from ${edge.source} to ${edge.target}`, "aria-describedby": isFocusable ? `${ARIA_EDGE_DESC_KEY}-${rfId}` : undefined, ref: edgeRef, children: [!reconnecting && (jsx(EdgeComponent, { id: id, source: edge.source, target: edge.target, type: edge.type, selected: edge.selected, animated: edge.animated, selectable: isSelectable, deletable: edge.deletable ?? true, label: edge.label, labelStyle: edge.labelStyle, labelShowBg: edge.labelShowBg, labelBgStyle: edge.labelBgStyle, labelBgPadding: edge.labelBgPadding, labelBgBorderRadius: edge.labelBgBorderRadius, sourceX: sourceX, sourceY: sourceY, targetX: targetX, targetY: targetY, sourcePosition: sourcePosition, targetPosition: targetPosition, data: edge.data, style: edge.style, sourceHandleId: edge.sourceHandle, targetHandleId: edge.targetHandle, markerStart: markerStartUrl, markerEnd: markerEndUrl, pathOptions: 'pathOptions' in edge ? edge.pathOptions : undefined, interactionWidth: edge.interactionWidth })), isReconnectable && (jsx(EdgeUpdateAnchors, { edge: edge, isReconnectable: isReconnectable, reconnectRadius: reconnectRadius, onReconnect: onReconnect, onReconnectStart: onReconnectStart, onReconnectEnd: onReconnectEnd, sourceX: sourceX, sourceY: sourceY, targetX: targetX, targetY: targetY, sourcePosition: sourcePosition, targetPosition: targetPosition, setUpdateHover: setUpdateHover, setReconnecting: setReconnecting, sourceHandleId: edge.sourceHandle, targetHandleId: edge.targetHandle }))] }) }));
2306
2404
  }
2307
2405
 
2308
- const selector$c = (s) => ({
2406
+ const selector$b = (s) => ({
2309
2407
  width: s.width,
2310
2408
  height: s.height,
2311
2409
  edgesFocusable: s.edgesFocusable,
2312
- edgesUpdatable: s.edgesUpdatable,
2410
+ edgesReconnectable: s.edgesReconnectable,
2313
2411
  elementsSelectable: s.elementsSelectable,
2314
2412
  connectionMode: s.connectionMode,
2315
2413
  onError: s.onError,
2316
2414
  });
2317
- function EdgeRendererComponent({ defaultMarkerColor, onlyRenderVisibleElements, rfId, edgeTypes, noPanClassName, onEdgeUpdate, onEdgeContextMenu, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, onEdgeClick, edgeUpdaterRadius, onEdgeDoubleClick, onEdgeUpdateStart, onEdgeUpdateEnd, }) {
2318
- const { edgesFocusable, edgesUpdatable, elementsSelectable, onError } = useStore(selector$c, shallow);
2415
+ function EdgeRendererComponent({ defaultMarkerColor, onlyRenderVisibleElements, rfId, edgeTypes, noPanClassName, onReconnect, onEdgeContextMenu, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, onEdgeClick, reconnectRadius, onEdgeDoubleClick, onReconnectStart, onReconnectEnd, disableKeyboardA11y, }) {
2416
+ const { edgesFocusable, edgesReconnectable, elementsSelectable, onError } = useStore(selector$b, shallow);
2319
2417
  const edgeIds = useVisibleEdgeIds(onlyRenderVisibleElements);
2320
2418
  return (jsxs("div", { className: "react-flow__edges", children: [jsx(MarkerDefinitions$1, { defaultColor: defaultMarkerColor, rfId: rfId }), edgeIds.map((id) => {
2321
- return (jsx(EdgeWrapper, { id: id, edgesFocusable: edgesFocusable, edgesUpdatable: edgesUpdatable, elementsSelectable: elementsSelectable, noPanClassName: noPanClassName, onEdgeUpdate: onEdgeUpdate, onContextMenu: onEdgeContextMenu, onMouseEnter: onEdgeMouseEnter, onMouseMove: onEdgeMouseMove, onMouseLeave: onEdgeMouseLeave, onClick: onEdgeClick, edgeUpdaterRadius: edgeUpdaterRadius, onDoubleClick: onEdgeDoubleClick, onEdgeUpdateStart: onEdgeUpdateStart, onEdgeUpdateEnd: onEdgeUpdateEnd, rfId: rfId, onError: onError, edgeTypes: edgeTypes }, id));
2419
+ return (jsx(EdgeWrapper, { id: id, edgesFocusable: edgesFocusable, edgesReconnectable: edgesReconnectable, elementsSelectable: elementsSelectable, noPanClassName: noPanClassName, onReconnect: onReconnect, onContextMenu: onEdgeContextMenu, onMouseEnter: onEdgeMouseEnter, onMouseMove: onEdgeMouseMove, onMouseLeave: onEdgeMouseLeave, onClick: onEdgeClick, reconnectRadius: reconnectRadius, onDoubleClick: onEdgeDoubleClick, onReconnectStart: onReconnectStart, onReconnectEnd: onReconnectEnd, rfId: rfId, onError: onError, edgeTypes: edgeTypes, disableKeyboardA11y: disableKeyboardA11y }, id));
2322
2420
  })] }));
2323
2421
  }
2324
2422
  EdgeRendererComponent.displayName = 'EdgeRenderer';
2325
2423
  const EdgeRenderer = memo(EdgeRendererComponent);
2326
2424
 
2327
- const selector$b = (s) => `translate(${s.transform[0]}px,${s.transform[1]}px) scale(${s.transform[2]})`;
2425
+ const selector$a = (s) => `translate(${s.transform[0]}px,${s.transform[1]}px) scale(${s.transform[2]})`;
2328
2426
  function Viewport({ children }) {
2329
- const transform = useStore(selector$b);
2427
+ const transform = useStore(selector$a);
2330
2428
  return (jsx("div", { className: "react-flow__viewport xyflow__viewport react-flow__container", style: { transform }, children: children }));
2331
2429
  }
2332
2430
 
@@ -2346,7 +2444,7 @@ function useOnInitHandler(onInit) {
2346
2444
  }, [onInit, rfInstance.viewportInitialized]);
2347
2445
  }
2348
2446
 
2349
- const selector$a = (state) => state.panZoom?.syncViewport;
2447
+ const selector$9 = (state) => state.panZoom?.syncViewport;
2350
2448
  /**
2351
2449
  * Hook for syncing the viewport with the panzoom instance.
2352
2450
  *
@@ -2354,7 +2452,7 @@ const selector$a = (state) => state.panZoom?.syncViewport;
2354
2452
  * @param viewport
2355
2453
  */
2356
2454
  function useViewportSync(viewport) {
2357
- const syncViewport = useStore(selector$a);
2455
+ const syncViewport = useStore(selector$9);
2358
2456
  const store = useStoreApi();
2359
2457
  useEffect(() => {
2360
2458
  if (viewport) {
@@ -2365,130 +2463,140 @@ function useViewportSync(viewport) {
2365
2463
  return null;
2366
2464
  }
2367
2465
 
2368
- const oppositePosition = {
2369
- [Position.Left]: Position.Right,
2370
- [Position.Right]: Position.Left,
2371
- [Position.Top]: Position.Bottom,
2372
- [Position.Bottom]: Position.Top,
2466
+ const selector$8 = (s) => {
2467
+ return s.connection.inProgress
2468
+ ? { ...s.connection, to: pointToRendererPoint(s.connection.to, s.transform) }
2469
+ : { ...s.connection };
2373
2470
  };
2374
- const ConnectionLine = ({ nodeId, handleType, style, type = ConnectionLineType.Bezier, CustomComponent, connectionStatus, }) => {
2375
- const { fromNode, handleId, toX, toY, connectionMode } = useStore(useCallback((s) => ({
2376
- fromNode: s.nodeLookup.get(nodeId),
2377
- handleId: s.connectionStartHandle?.handleId,
2378
- toX: (s.connectionPosition.x - s.transform[0]) / s.transform[2],
2379
- toY: (s.connectionPosition.y - s.transform[1]) / s.transform[2],
2380
- connectionMode: s.connectionMode,
2381
- }), [nodeId]), shallow);
2382
- const fromHandleBounds = fromNode?.[internalsSymbol]?.handleBounds;
2383
- let handleBounds = fromHandleBounds?.[handleType];
2384
- if (connectionMode === ConnectionMode.Loose) {
2385
- handleBounds = handleBounds ? handleBounds : fromHandleBounds?.[handleType === 'source' ? 'target' : 'source'];
2386
- }
2387
- if (!fromNode || !handleBounds) {
2471
+ /**
2472
+ * Hook for accessing the connection state.
2473
+ *
2474
+ * @public
2475
+ * @returns ConnectionState
2476
+ */
2477
+ function useConnection() {
2478
+ return useStore(selector$8, shallow);
2479
+ }
2480
+
2481
+ const selector$7 = (s) => ({
2482
+ nodesConnectable: s.nodesConnectable,
2483
+ isValid: s.connection.isValid,
2484
+ inProgress: s.connection.inProgress,
2485
+ width: s.width,
2486
+ height: s.height,
2487
+ });
2488
+ function ConnectionLineWrapper({ containerStyle, style, type, component }) {
2489
+ const { nodesConnectable, width, height, isValid, inProgress } = useStore(selector$7, shallow);
2490
+ const renderConnection = !!(width && nodesConnectable && inProgress);
2491
+ if (!renderConnection) {
2388
2492
  return null;
2389
2493
  }
2390
- const fromHandle = handleId ? handleBounds.find((d) => d.id === handleId) : handleBounds[0];
2391
- const fromHandleX = fromHandle ? fromHandle.x + fromHandle.width / 2 : (fromNode.computed?.width ?? 0) / 2;
2392
- const fromHandleY = fromHandle ? fromHandle.y + fromHandle.height / 2 : fromNode.computed?.height ?? 0;
2393
- const fromX = (fromNode.computed?.positionAbsolute?.x ?? 0) + fromHandleX;
2394
- const fromY = (fromNode.computed?.positionAbsolute?.y ?? 0) + fromHandleY;
2395
- const fromPosition = fromHandle?.position;
2396
- const toPosition = fromPosition ? oppositePosition[fromPosition] : null;
2397
- if (!fromPosition || !toPosition) {
2398
- return null;
2494
+ return (jsx("svg", { style: containerStyle, width: width, height: height, className: "react-flow__connectionline react-flow__container", children: jsx("g", { className: cc(['react-flow__connection', getConnectionStatus(isValid)]), children: jsx(ConnectionLine, { style: style, type: type, CustomComponent: component, isValid: isValid }) }) }));
2495
+ }
2496
+ const ConnectionLine = ({ style, type = ConnectionLineType.Bezier, CustomComponent, isValid }) => {
2497
+ const { inProgress, from, fromNode, fromHandle, fromPosition, to, toNode, toHandle, toPosition } = useConnection();
2498
+ if (!inProgress) {
2499
+ return;
2399
2500
  }
2400
2501
  if (CustomComponent) {
2401
- return (jsx(CustomComponent, { connectionLineType: type, connectionLineStyle: style, fromNode: fromNode, fromHandle: fromHandle, fromX: fromX, fromY: fromY, toX: toX, toY: toY, fromPosition: fromPosition, toPosition: toPosition, connectionStatus: connectionStatus }));
2502
+ return (jsx(CustomComponent, { connectionLineType: type, connectionLineStyle: style, fromNode: fromNode, fromHandle: fromHandle, fromX: from.x, fromY: from.y, toX: to.x, toY: to.y, fromPosition: fromPosition, toPosition: toPosition, connectionStatus: getConnectionStatus(isValid), toNode: toNode, toHandle: toHandle }));
2402
2503
  }
2403
- let dAttr = '';
2504
+ let path = '';
2404
2505
  const pathParams = {
2405
- sourceX: fromX,
2406
- sourceY: fromY,
2506
+ sourceX: from.x,
2507
+ sourceY: from.y,
2407
2508
  sourcePosition: fromPosition,
2408
- targetX: toX,
2409
- targetY: toY,
2509
+ targetX: to.x,
2510
+ targetY: to.y,
2410
2511
  targetPosition: toPosition,
2411
2512
  };
2412
- if (type === ConnectionLineType.Bezier) {
2413
- // we assume the destination position is opposite to the source position
2414
- [dAttr] = getBezierPath(pathParams);
2415
- }
2416
- else if (type === ConnectionLineType.Step) {
2417
- [dAttr] = getSmoothStepPath({
2418
- ...pathParams,
2419
- borderRadius: 0,
2420
- });
2421
- }
2422
- else if (type === ConnectionLineType.SmoothStep) {
2423
- [dAttr] = getSmoothStepPath(pathParams);
2424
- }
2425
- else if (type === ConnectionLineType.SimpleBezier) {
2426
- [dAttr] = getSimpleBezierPath(pathParams);
2427
- }
2428
- else {
2429
- dAttr = `M${fromX},${fromY} ${toX},${toY}`;
2513
+ switch (type) {
2514
+ case ConnectionLineType.Bezier:
2515
+ [path] = getBezierPath(pathParams);
2516
+ break;
2517
+ case ConnectionLineType.SimpleBezier:
2518
+ [path] = getSimpleBezierPath(pathParams);
2519
+ break;
2520
+ case ConnectionLineType.Step:
2521
+ [path] = getSmoothStepPath({
2522
+ ...pathParams,
2523
+ borderRadius: 0,
2524
+ });
2525
+ break;
2526
+ case ConnectionLineType.SmoothStep:
2527
+ [path] = getSmoothStepPath(pathParams);
2528
+ break;
2529
+ default:
2530
+ [path] = getStraightPath(pathParams);
2430
2531
  }
2431
- return jsx("path", { d: dAttr, fill: "none", className: "react-flow__connection-path", style: style });
2532
+ return jsx("path", { d: path, fill: "none", className: "react-flow__connection-path", style: style });
2432
2533
  };
2433
2534
  ConnectionLine.displayName = 'ConnectionLine';
2434
- const selector$9 = (s) => ({
2435
- nodeId: s.connectionStartHandle?.nodeId,
2436
- handleType: s.connectionStartHandle?.type,
2437
- nodesConnectable: s.nodesConnectable,
2438
- connectionStatus: s.connectionStatus,
2439
- width: s.width,
2440
- height: s.height,
2441
- });
2442
- function ConnectionLineWrapper({ containerStyle, style, type, component }) {
2443
- const { nodeId, handleType, nodesConnectable, width, height, connectionStatus } = useStore(selector$9, shallow);
2444
- const isValid = !!(nodeId && handleType && width && nodesConnectable);
2445
- if (!isValid) {
2446
- return null;
2447
- }
2448
- return (jsx("svg", { style: containerStyle, width: width, height: height, className: "react-flow__connectionline react-flow__container", children: jsx("g", { className: cc(['react-flow__connection', connectionStatus]), children: jsx(ConnectionLine, { nodeId: nodeId, handleType: handleType, style: style, type: type, CustomComponent: component, connectionStatus: connectionStatus }) }) }));
2449
- }
2450
2535
 
2451
2536
  const emptyTypes = {};
2452
2537
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
2453
2538
  function useNodeOrEdgeTypesWarning(nodeOrEdgeTypes = emptyTypes) {
2454
- const updateCount = useRef(0);
2539
+ const typesRef = useRef(nodeOrEdgeTypes);
2455
2540
  const store = useStoreApi();
2456
2541
  useEffect(() => {
2457
2542
  if (process.env.NODE_ENV === 'development') {
2458
- if (updateCount.current > 1) {
2459
- store.getState().onError?.('002', errorMessages['error002']());
2543
+ const usedKeys = new Set([...Object.keys(typesRef.current), ...Object.keys(nodeOrEdgeTypes)]);
2544
+ for (const key of usedKeys) {
2545
+ if (typesRef.current[key] !== nodeOrEdgeTypes[key]) {
2546
+ store.getState().onError?.('002', errorMessages['error002']());
2547
+ break;
2548
+ }
2460
2549
  }
2461
- updateCount.current += 1;
2550
+ typesRef.current = nodeOrEdgeTypes;
2462
2551
  }
2463
2552
  }, [nodeOrEdgeTypes]);
2464
2553
  }
2465
2554
 
2466
- function GraphViewComponent({ nodeTypes, edgeTypes, onInit, onNodeClick, onEdgeClick, onNodeDoubleClick, onEdgeDoubleClick, onNodeMouseEnter, onNodeMouseMove, onNodeMouseLeave, onNodeContextMenu, onSelectionContextMenu, onSelectionStart, onSelectionEnd, connectionLineType, connectionLineStyle, connectionLineComponent, connectionLineContainerStyle, selectionKeyCode, selectionOnDrag, selectionMode, multiSelectionKeyCode, panActivationKeyCode, zoomActivationKeyCode, deleteKeyCode, onlyRenderVisibleElements, elementsSelectable, defaultViewport, translateExtent, minZoom, maxZoom, preventScrolling, defaultMarkerColor, zoomOnScroll, zoomOnPinch, panOnScroll, panOnScrollSpeed, panOnScrollMode, zoomOnDoubleClick, panOnDrag, onPaneClick, onPaneMouseEnter, onPaneMouseMove, onPaneMouseLeave, onPaneScroll, onPaneContextMenu, onEdgeUpdate, onEdgeContextMenu, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, edgeUpdaterRadius, onEdgeUpdateStart, onEdgeUpdateEnd, noDragClassName, noWheelClassName, noPanClassName, disableKeyboardA11y, nodeOrigin, nodeExtent, rfId, viewport, onViewportChange, }) {
2555
+ function useStylesLoadedWarning() {
2556
+ const store = useStoreApi();
2557
+ const checked = useRef(false);
2558
+ useEffect(() => {
2559
+ if (process.env.NODE_ENV === 'development') {
2560
+ if (!checked.current) {
2561
+ const pane = document.querySelector('.react-flow__pane');
2562
+ if (pane && !(window.getComputedStyle(pane).zIndex === '1')) {
2563
+ store.getState().onError?.('013', errorMessages['error013']('react'));
2564
+ }
2565
+ checked.current = true;
2566
+ }
2567
+ }
2568
+ }, []);
2569
+ }
2570
+
2571
+ function GraphViewComponent({ nodeTypes, edgeTypes, onInit, onNodeClick, onEdgeClick, onNodeDoubleClick, onEdgeDoubleClick, onNodeMouseEnter, onNodeMouseMove, onNodeMouseLeave, onNodeContextMenu, onSelectionContextMenu, onSelectionStart, onSelectionEnd, connectionLineType, connectionLineStyle, connectionLineComponent, connectionLineContainerStyle, selectionKeyCode, selectionOnDrag, selectionMode, multiSelectionKeyCode, panActivationKeyCode, zoomActivationKeyCode, deleteKeyCode, onlyRenderVisibleElements, elementsSelectable, defaultViewport, translateExtent, minZoom, maxZoom, preventScrolling, defaultMarkerColor, zoomOnScroll, zoomOnPinch, panOnScroll, panOnScrollSpeed, panOnScrollMode, zoomOnDoubleClick, panOnDrag, onPaneClick, onPaneMouseEnter, onPaneMouseMove, onPaneMouseLeave, onPaneScroll, onPaneContextMenu, paneClickDistance, onEdgeContextMenu, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, reconnectRadius, onReconnect, onReconnectStart, onReconnectEnd, noDragClassName, noWheelClassName, noPanClassName, disableKeyboardA11y, nodeExtent, rfId, viewport, onViewportChange, }) {
2467
2572
  useNodeOrEdgeTypesWarning(nodeTypes);
2468
2573
  useNodeOrEdgeTypesWarning(edgeTypes);
2574
+ useStylesLoadedWarning();
2469
2575
  useOnInitHandler(onInit);
2470
2576
  useViewportSync(viewport);
2471
- return (jsx(FlowRenderer, { onPaneClick: onPaneClick, onPaneMouseEnter: onPaneMouseEnter, onPaneMouseMove: onPaneMouseMove, onPaneMouseLeave: onPaneMouseLeave, onPaneContextMenu: onPaneContextMenu, onPaneScroll: onPaneScroll, deleteKeyCode: deleteKeyCode, selectionKeyCode: selectionKeyCode, selectionOnDrag: selectionOnDrag, selectionMode: selectionMode, onSelectionStart: onSelectionStart, onSelectionEnd: onSelectionEnd, multiSelectionKeyCode: multiSelectionKeyCode, panActivationKeyCode: panActivationKeyCode, zoomActivationKeyCode: zoomActivationKeyCode, elementsSelectable: elementsSelectable, zoomOnScroll: zoomOnScroll, zoomOnPinch: zoomOnPinch, zoomOnDoubleClick: zoomOnDoubleClick, panOnScroll: panOnScroll, panOnScrollSpeed: panOnScrollSpeed, panOnScrollMode: panOnScrollMode, panOnDrag: panOnDrag, defaultViewport: defaultViewport, translateExtent: translateExtent, minZoom: minZoom, maxZoom: maxZoom, onSelectionContextMenu: onSelectionContextMenu, preventScrolling: preventScrolling, noDragClassName: noDragClassName, noWheelClassName: noWheelClassName, noPanClassName: noPanClassName, disableKeyboardA11y: disableKeyboardA11y, onViewportChange: onViewportChange, isControlledViewport: !!viewport, children: jsxs(Viewport, { children: [jsx(EdgeRenderer, { edgeTypes: edgeTypes, onEdgeClick: onEdgeClick, onEdgeDoubleClick: onEdgeDoubleClick, onEdgeUpdate: onEdgeUpdate, onlyRenderVisibleElements: onlyRenderVisibleElements, onEdgeContextMenu: onEdgeContextMenu, onEdgeMouseEnter: onEdgeMouseEnter, onEdgeMouseMove: onEdgeMouseMove, onEdgeMouseLeave: onEdgeMouseLeave, onEdgeUpdateStart: onEdgeUpdateStart, onEdgeUpdateEnd: onEdgeUpdateEnd, edgeUpdaterRadius: edgeUpdaterRadius, defaultMarkerColor: defaultMarkerColor, noPanClassName: noPanClassName, disableKeyboardA11y: disableKeyboardA11y, rfId: rfId }), jsx(ConnectionLineWrapper, { style: connectionLineStyle, type: connectionLineType, component: connectionLineComponent, containerStyle: connectionLineContainerStyle }), jsx("div", { className: "react-flow__edgelabel-renderer" }), jsx("div", { className: "react-flow__viewport-portal" }), jsx(NodeRenderer, { nodeTypes: nodeTypes, onNodeClick: onNodeClick, onNodeDoubleClick: onNodeDoubleClick, onNodeMouseEnter: onNodeMouseEnter, onNodeMouseMove: onNodeMouseMove, onNodeMouseLeave: onNodeMouseLeave, onNodeContextMenu: onNodeContextMenu, onlyRenderVisibleElements: onlyRenderVisibleElements, noPanClassName: noPanClassName, noDragClassName: noDragClassName, disableKeyboardA11y: disableKeyboardA11y, nodeOrigin: nodeOrigin, nodeExtent: nodeExtent, rfId: rfId })] }) }));
2577
+ return (jsx(FlowRenderer, { onPaneClick: onPaneClick, onPaneMouseEnter: onPaneMouseEnter, onPaneMouseMove: onPaneMouseMove, onPaneMouseLeave: onPaneMouseLeave, onPaneContextMenu: onPaneContextMenu, onPaneScroll: onPaneScroll, paneClickDistance: paneClickDistance, deleteKeyCode: deleteKeyCode, selectionKeyCode: selectionKeyCode, selectionOnDrag: selectionOnDrag, selectionMode: selectionMode, onSelectionStart: onSelectionStart, onSelectionEnd: onSelectionEnd, multiSelectionKeyCode: multiSelectionKeyCode, panActivationKeyCode: panActivationKeyCode, zoomActivationKeyCode: zoomActivationKeyCode, elementsSelectable: elementsSelectable, zoomOnScroll: zoomOnScroll, zoomOnPinch: zoomOnPinch, zoomOnDoubleClick: zoomOnDoubleClick, panOnScroll: panOnScroll, panOnScrollSpeed: panOnScrollSpeed, panOnScrollMode: panOnScrollMode, panOnDrag: panOnDrag, defaultViewport: defaultViewport, translateExtent: translateExtent, minZoom: minZoom, maxZoom: maxZoom, onSelectionContextMenu: onSelectionContextMenu, preventScrolling: preventScrolling, noDragClassName: noDragClassName, noWheelClassName: noWheelClassName, noPanClassName: noPanClassName, disableKeyboardA11y: disableKeyboardA11y, onViewportChange: onViewportChange, isControlledViewport: !!viewport, children: jsxs(Viewport, { children: [jsx(EdgeRenderer, { edgeTypes: edgeTypes, onEdgeClick: onEdgeClick, onEdgeDoubleClick: onEdgeDoubleClick, onReconnect: onReconnect, onReconnectStart: onReconnectStart, onReconnectEnd: onReconnectEnd, onlyRenderVisibleElements: onlyRenderVisibleElements, onEdgeContextMenu: onEdgeContextMenu, onEdgeMouseEnter: onEdgeMouseEnter, onEdgeMouseMove: onEdgeMouseMove, onEdgeMouseLeave: onEdgeMouseLeave, reconnectRadius: reconnectRadius, defaultMarkerColor: defaultMarkerColor, noPanClassName: noPanClassName, disableKeyboardA11y: disableKeyboardA11y, rfId: rfId }), jsx(ConnectionLineWrapper, { style: connectionLineStyle, type: connectionLineType, component: connectionLineComponent, containerStyle: connectionLineContainerStyle }), jsx("div", { className: "react-flow__edgelabel-renderer" }), jsx(NodeRenderer, { nodeTypes: nodeTypes, onNodeClick: onNodeClick, onNodeDoubleClick: onNodeDoubleClick, onNodeMouseEnter: onNodeMouseEnter, onNodeMouseMove: onNodeMouseMove, onNodeMouseLeave: onNodeMouseLeave, onNodeContextMenu: onNodeContextMenu, onlyRenderVisibleElements: onlyRenderVisibleElements, noPanClassName: noPanClassName, noDragClassName: noDragClassName, disableKeyboardA11y: disableKeyboardA11y, nodeExtent: nodeExtent, rfId: rfId }), jsx("div", { className: "react-flow__viewport-portal" })] }) }));
2472
2578
  }
2473
2579
  GraphViewComponent.displayName = 'GraphView';
2474
2580
  const GraphView = memo(GraphViewComponent);
2475
2581
 
2476
- const getInitialState = ({ nodes, edges, defaultNodes, defaultEdges, width, height, fitView, } = {}) => {
2582
+ const getInitialState = ({ nodes, edges, defaultNodes, defaultEdges, width, height, fitView, nodeOrigin, } = {}) => {
2477
2583
  const nodeLookup = new Map();
2584
+ const parentLookup = new Map();
2478
2585
  const connectionLookup = new Map();
2479
2586
  const edgeLookup = new Map();
2480
2587
  const storeEdges = defaultEdges ?? edges ?? [];
2481
2588
  const storeNodes = defaultNodes ?? nodes ?? [];
2589
+ const storeNodeOrigin = nodeOrigin ?? [0, 0];
2482
2590
  updateConnectionLookup(connectionLookup, edgeLookup, storeEdges);
2483
- const nextNodes = adoptUserProvidedNodes(storeNodes, nodeLookup, {
2484
- nodeOrigin: [0, 0],
2591
+ adoptUserNodes(storeNodes, nodeLookup, parentLookup, {
2592
+ nodeOrigin: storeNodeOrigin,
2485
2593
  elevateNodesOnSelect: false,
2486
2594
  });
2487
2595
  let transform = [0, 0, 1];
2488
2596
  if (fitView && width && height) {
2489
- const nodesWithDimensions = nextNodes.filter((node) => node.width && node.height);
2490
- // @todo users nodeOrigin should be used here
2491
- const bounds = getNodesBounds(nodesWithDimensions, { nodeOrigin: [0, 0] });
2597
+ const bounds = getInternalNodesBounds(nodeLookup, {
2598
+ filter: (node) => !!((node.width || node.initialWidth) && (node.height || node.initialHeight)),
2599
+ });
2492
2600
  const { x, y, zoom } = getViewportForBounds(bounds, width, height, 0.5, 2, 0.1);
2493
2601
  transform = [x, y, zoom];
2494
2602
  }
@@ -2497,8 +2605,9 @@ const getInitialState = ({ nodes, edges, defaultNodes, defaultEdges, width, heig
2497
2605
  width: 0,
2498
2606
  height: 0,
2499
2607
  transform,
2500
- nodes: nextNodes,
2608
+ nodes: storeNodes,
2501
2609
  nodeLookup,
2610
+ parentLookup,
2502
2611
  edges: storeEdges,
2503
2612
  edgeLookup,
2504
2613
  connectionLookup,
@@ -2514,13 +2623,11 @@ const getInitialState = ({ nodes, edges, defaultNodes, defaultEdges, width, heig
2514
2623
  nodesSelectionActive: false,
2515
2624
  userSelectionActive: false,
2516
2625
  userSelectionRect: null,
2517
- connectionPosition: { x: 0, y: 0 },
2518
- connectionStatus: null,
2519
2626
  connectionMode: ConnectionMode.Strict,
2520
2627
  domNode: null,
2521
2628
  paneDragging: false,
2522
2629
  noPanClassName: 'nopan',
2523
- nodeOrigin: [0, 0],
2630
+ nodeOrigin: storeNodeOrigin,
2524
2631
  nodeDragThreshold: 1,
2525
2632
  snapGrid: [15, 15],
2526
2633
  snapToGrid: false,
@@ -2528,7 +2635,7 @@ const getInitialState = ({ nodes, edges, defaultNodes, defaultEdges, width, heig
2528
2635
  nodesConnectable: true,
2529
2636
  nodesFocusable: true,
2530
2637
  edgesFocusable: true,
2531
- edgesUpdatable: true,
2638
+ edgesReconnectable: true,
2532
2639
  elementsSelectable: true,
2533
2640
  elevateNodesOnSelect: true,
2534
2641
  elevateEdgesOnSelect: false,
@@ -2537,33 +2644,34 @@ const getInitialState = ({ nodes, edges, defaultNodes, defaultEdges, width, heig
2537
2644
  fitViewOnInitOptions: undefined,
2538
2645
  selectNodesOnDrag: true,
2539
2646
  multiSelectionActive: false,
2540
- connectionStartHandle: null,
2541
- connectionEndHandle: null,
2647
+ connection: { ...initialConnection },
2542
2648
  connectionClickStartHandle: null,
2543
2649
  connectOnClick: true,
2544
2650
  ariaLiveMessage: '',
2545
2651
  autoPanOnConnect: true,
2546
2652
  autoPanOnNodeDrag: true,
2653
+ autoPanSpeed: 15,
2547
2654
  connectionRadius: 20,
2548
2655
  onError: devWarn,
2549
2656
  isValidConnection: undefined,
2550
2657
  onSelectionChangeHandlers: [],
2551
2658
  lib: 'react',
2659
+ debug: false,
2552
2660
  };
2553
2661
  };
2554
2662
 
2555
- const createRFStore = ({ nodes, edges, defaultNodes, defaultEdges, width, height, fitView: fitView$1, }) => createWithEqualityFn((set, get) => ({
2556
- ...getInitialState({ nodes, edges, width, height, fitView: fitView$1, defaultNodes, defaultEdges }),
2663
+ const createStore = ({ nodes, edges, defaultNodes, defaultEdges, width, height, fitView: fitView$1, nodeOrigin, }) => createWithEqualityFn((set, get) => ({
2664
+ ...getInitialState({ nodes, edges, width, height, fitView: fitView$1, nodeOrigin, defaultNodes, defaultEdges }),
2557
2665
  setNodes: (nodes) => {
2558
- const { nodeLookup, nodeOrigin, elevateNodesOnSelect } = get();
2666
+ const { nodeLookup, parentLookup, nodeOrigin, elevateNodesOnSelect } = get();
2559
2667
  // setNodes() is called exclusively in response to user actions:
2560
2668
  // - either when the `<ReactFlow nodes>` prop is updated in the controlled ReactFlow setup,
2561
2669
  // - or when the user calls something like `reactFlowInstance.setNodes()` in an uncontrolled ReactFlow setup.
2562
2670
  //
2563
2671
  // When this happens, we take the note objects passed by the user and extend them with fields
2564
2672
  // relevant for internal React Flow operations.
2565
- const nodesWithInternalData = adoptUserProvidedNodes(nodes, nodeLookup, { nodeOrigin, elevateNodesOnSelect });
2566
- set({ nodes: nodesWithInternalData });
2673
+ adoptUserNodes(nodes, nodeLookup, parentLookup, { nodeOrigin, elevateNodesOnSelect, checkEquality: true });
2674
+ set({ nodes });
2567
2675
  },
2568
2676
  setEdges: (edges) => {
2569
2677
  const { connectionLookup, edgeLookup } = get();
@@ -2585,26 +2693,19 @@ const createRFStore = ({ nodes, edges, defaultNodes, defaultEdges, width, height
2585
2693
  // Every node gets registerd at a ResizeObserver. Whenever a node
2586
2694
  // changes its dimensions, this function is called to measure the
2587
2695
  // new dimensions and update the nodes.
2588
- updateNodeDimensions: (updates) => {
2589
- const { onNodesChange, fitView, nodes, nodeLookup, fitViewOnInit, fitViewDone, fitViewOnInitOptions, domNode, nodeOrigin, } = get();
2590
- const changes = [];
2591
- const updatedNodes = updateNodeDimensions(updates, nodes, nodeLookup, domNode, nodeOrigin, (id, dimensions) => {
2592
- changes.push({
2593
- id: id,
2594
- type: 'dimensions',
2595
- dimensions,
2596
- });
2597
- });
2598
- if (!updatedNodes) {
2696
+ updateNodeInternals: (updates) => {
2697
+ const { triggerNodeChanges, nodeLookup, parentLookup, fitViewOnInit, fitViewDone, fitViewOnInitOptions, domNode, nodeOrigin, debug, fitViewSync, } = get();
2698
+ const { changes, updatedInternals } = updateNodeInternals(updates, nodeLookup, parentLookup, domNode, nodeOrigin);
2699
+ if (!updatedInternals) {
2599
2700
  return;
2600
2701
  }
2601
- const nextNodes = updateAbsolutePositions(updatedNodes, nodeLookup, nodeOrigin);
2702
+ updateAbsolutePositions(nodeLookup, parentLookup, { nodeOrigin });
2602
2703
  // we call fitView once initially after all dimensions are set
2603
2704
  let nextFitViewDone = fitViewDone;
2604
2705
  if (!fitViewDone && fitViewOnInit) {
2605
- nextFitViewDone = fitView(nextNodes, {
2706
+ nextFitViewDone = fitViewSync({
2606
2707
  ...fitViewOnInitOptions,
2607
- nodes: fitViewOnInitOptions?.nodes || nextNodes,
2708
+ nodes: fitViewOnInitOptions?.nodes,
2608
2709
  });
2609
2710
  }
2610
2711
  // here we are cirmumventing the onNodesChange handler
@@ -2612,63 +2713,91 @@ const createRFStore = ({ nodes, edges, defaultNodes, defaultEdges, width, height
2612
2713
  // has not provided an onNodesChange handler.
2613
2714
  // Nodes are only rendered if they have a width and height
2614
2715
  // attribute which they get from this handler.
2615
- set({ nodes: nextNodes, fitViewDone: nextFitViewDone });
2716
+ set({ fitViewDone: nextFitViewDone });
2616
2717
  if (changes?.length > 0) {
2617
- onNodesChange?.(changes);
2718
+ if (debug) {
2719
+ console.log('React Flow: trigger node changes', changes);
2720
+ }
2721
+ triggerNodeChanges?.(changes);
2618
2722
  }
2619
2723
  },
2620
2724
  updateNodePositions: (nodeDragItems, dragging = false) => {
2621
- const changes = nodeDragItems.map((node) => {
2725
+ const parentExpandChildren = [];
2726
+ const changes = [];
2727
+ for (const [id, dragItem] of nodeDragItems) {
2622
2728
  const change = {
2623
- id: node.id,
2729
+ id,
2624
2730
  type: 'position',
2625
- position: node.position,
2626
- positionAbsolute: node.computed?.positionAbsolute,
2731
+ position: dragItem.position,
2627
2732
  dragging,
2628
2733
  };
2629
- return change;
2630
- });
2734
+ if (dragItem?.expandParent && dragItem?.parentId && change.position) {
2735
+ parentExpandChildren.push({
2736
+ id,
2737
+ parentId: dragItem.parentId,
2738
+ rect: {
2739
+ ...dragItem.internals.positionAbsolute,
2740
+ width: dragItem.measured.width,
2741
+ height: dragItem.measured.height,
2742
+ },
2743
+ });
2744
+ change.position.x = Math.max(0, change.position.x);
2745
+ change.position.y = Math.max(0, change.position.y);
2746
+ }
2747
+ changes.push(change);
2748
+ }
2749
+ if (parentExpandChildren.length > 0) {
2750
+ const { nodeLookup, parentLookup, nodeOrigin } = get();
2751
+ const parentExpandChanges = handleExpandParent(parentExpandChildren, nodeLookup, parentLookup, nodeOrigin);
2752
+ changes.push(...parentExpandChanges);
2753
+ }
2631
2754
  get().triggerNodeChanges(changes);
2632
2755
  },
2633
2756
  triggerNodeChanges: (changes) => {
2634
- const { onNodesChange, setNodes, nodes, hasDefaultNodes } = get();
2757
+ const { onNodesChange, setNodes, nodes, hasDefaultNodes, debug } = get();
2635
2758
  if (changes?.length) {
2636
2759
  if (hasDefaultNodes) {
2637
2760
  const updatedNodes = applyNodeChanges(changes, nodes);
2638
2761
  setNodes(updatedNodes);
2639
2762
  }
2763
+ if (debug) {
2764
+ console.log('React Flow: trigger node changes', changes);
2765
+ }
2640
2766
  onNodesChange?.(changes);
2641
2767
  }
2642
2768
  },
2643
2769
  triggerEdgeChanges: (changes) => {
2644
- const { onEdgesChange, setEdges, edges, hasDefaultEdges } = get();
2770
+ const { onEdgesChange, setEdges, edges, hasDefaultEdges, debug } = get();
2645
2771
  if (changes?.length) {
2646
2772
  if (hasDefaultEdges) {
2647
2773
  const updatedEdges = applyEdgeChanges(changes, edges);
2648
2774
  setEdges(updatedEdges);
2649
2775
  }
2776
+ if (debug) {
2777
+ console.log('React Flow: trigger edge changes', changes);
2778
+ }
2650
2779
  onEdgesChange?.(changes);
2651
2780
  }
2652
2781
  },
2653
2782
  addSelectedNodes: (selectedNodeIds) => {
2654
- const { multiSelectionActive, edges, nodes, triggerNodeChanges, triggerEdgeChanges } = get();
2783
+ const { multiSelectionActive, edgeLookup, nodeLookup, triggerNodeChanges, triggerEdgeChanges } = get();
2655
2784
  if (multiSelectionActive) {
2656
2785
  const nodeChanges = selectedNodeIds.map((nodeId) => createSelectionChange(nodeId, true));
2657
2786
  triggerNodeChanges(nodeChanges);
2658
2787
  return;
2659
2788
  }
2660
- triggerNodeChanges(getSelectionChanges(nodes, new Set([...selectedNodeIds]), true));
2661
- triggerEdgeChanges(getSelectionChanges(edges));
2789
+ triggerNodeChanges(getSelectionChanges(nodeLookup, new Set([...selectedNodeIds]), true));
2790
+ triggerEdgeChanges(getSelectionChanges(edgeLookup));
2662
2791
  },
2663
2792
  addSelectedEdges: (selectedEdgeIds) => {
2664
- const { multiSelectionActive, edges, nodes, triggerNodeChanges, triggerEdgeChanges } = get();
2793
+ const { multiSelectionActive, edgeLookup, nodeLookup, triggerNodeChanges, triggerEdgeChanges } = get();
2665
2794
  if (multiSelectionActive) {
2666
2795
  const changedEdges = selectedEdgeIds.map((edgeId) => createSelectionChange(edgeId, true));
2667
2796
  triggerEdgeChanges(changedEdges);
2668
2797
  return;
2669
2798
  }
2670
- triggerEdgeChanges(getSelectionChanges(edges, new Set([...selectedEdgeIds])));
2671
- triggerNodeChanges(getSelectionChanges(nodes, new Set(), true));
2799
+ triggerEdgeChanges(getSelectionChanges(edgeLookup, new Set([...selectedEdgeIds])));
2800
+ triggerNodeChanges(getSelectionChanges(nodeLookup, new Set(), true));
2672
2801
  },
2673
2802
  unselectNodesAndEdges: ({ nodes, edges } = {}) => {
2674
2803
  const { edges: storeEdges, nodes: storeNodes, triggerNodeChanges, triggerEdgeChanges } = get();
@@ -2696,6 +2825,9 @@ const createRFStore = ({ nodes, edges, defaultNodes, defaultEdges, width, height
2696
2825
  get().panZoom?.setTranslateExtent(translateExtent);
2697
2826
  set({ translateExtent });
2698
2827
  },
2828
+ setPaneClickDistance: (clickDistance) => {
2829
+ get().panZoom?.setClickDistance(clickDistance);
2830
+ },
2699
2831
  resetSelectedElements: () => {
2700
2832
  const { edges, nodes, triggerNodeChanges, triggerEdgeChanges } = get();
2701
2833
  const nodeChanges = nodes.reduce((res, node) => (node.selected ? [...res, createSelectionChange(node.id, false)] : res), []);
@@ -2704,82 +2836,91 @@ const createRFStore = ({ nodes, edges, defaultNodes, defaultEdges, width, height
2704
2836
  triggerEdgeChanges(edgeChanges);
2705
2837
  },
2706
2838
  setNodeExtent: (nodeExtent) => {
2707
- const { nodes } = get();
2839
+ const { nodeLookup } = get();
2840
+ for (const [, node] of nodeLookup) {
2841
+ const positionAbsolute = clampPosition(node.position, nodeExtent);
2842
+ nodeLookup.set(node.id, {
2843
+ ...node,
2844
+ internals: {
2845
+ ...node.internals,
2846
+ positionAbsolute,
2847
+ },
2848
+ });
2849
+ }
2708
2850
  set({
2709
2851
  nodeExtent,
2710
- nodes: nodes.map((node) => {
2711
- const positionAbsolute = clampPosition(node.position, nodeExtent);
2712
- return {
2713
- ...node,
2714
- computed: {
2715
- ...node.computed,
2716
- positionAbsolute,
2717
- },
2718
- };
2719
- }),
2720
2852
  });
2721
2853
  },
2722
2854
  panBy: (delta) => {
2723
2855
  const { transform, width, height, panZoom, translateExtent } = get();
2724
2856
  return panBy({ delta, panZoom, transform, translateExtent, width, height });
2725
2857
  },
2726
- fitView: (nodes, options) => {
2727
- const { panZoom, width, height, minZoom, maxZoom, nodeOrigin } = get();
2858
+ fitView: (options) => {
2859
+ const { panZoom, width, height, minZoom, maxZoom, nodeLookup } = get();
2728
2860
  if (!panZoom) {
2729
- return false;
2861
+ return Promise.resolve(false);
2730
2862
  }
2863
+ const fitViewNodes = getFitViewNodes(nodeLookup, options);
2731
2864
  return fitView({
2732
- nodes,
2865
+ nodes: fitViewNodes,
2733
2866
  width,
2734
2867
  height,
2735
2868
  panZoom,
2736
2869
  minZoom,
2737
2870
  maxZoom,
2738
- nodeOrigin,
2739
2871
  }, options);
2740
2872
  },
2741
- cancelConnection: () => set({
2742
- connectionStatus: null,
2743
- connectionStartHandle: null,
2744
- connectionEndHandle: null,
2745
- }),
2746
- updateConnection: (params) => {
2747
- const { connectionStatus, connectionStartHandle, connectionEndHandle, connectionPosition } = get();
2748
- const currentConnection = {
2749
- connectionPosition: params.connectionPosition ?? connectionPosition,
2750
- connectionStatus: params.connectionStatus ?? connectionStatus,
2751
- connectionStartHandle: params.connectionStartHandle ?? connectionStartHandle,
2752
- connectionEndHandle: params.connectionEndHandle ?? connectionEndHandle,
2753
- };
2754
- set(currentConnection);
2873
+ // we can't call an asnychronous function in updateNodeInternals
2874
+ // for that we created this sync version of fitView
2875
+ fitViewSync: (options) => {
2876
+ const { panZoom, width, height, minZoom, maxZoom, nodeLookup } = get();
2877
+ if (!panZoom) {
2878
+ return false;
2879
+ }
2880
+ const fitViewNodes = getFitViewNodes(nodeLookup, options);
2881
+ fitView({
2882
+ nodes: fitViewNodes,
2883
+ width,
2884
+ height,
2885
+ panZoom,
2886
+ minZoom,
2887
+ maxZoom,
2888
+ }, options);
2889
+ return fitViewNodes.size > 0;
2890
+ },
2891
+ cancelConnection: () => {
2892
+ set({
2893
+ connection: { ...initialConnection },
2894
+ });
2895
+ },
2896
+ updateConnection: (connection) => {
2897
+ set({ connection });
2755
2898
  },
2756
2899
  reset: () => set({ ...getInitialState() }),
2757
2900
  }), Object.is);
2758
2901
 
2759
- function ReactFlowProvider({ children, initialNodes, initialEdges, defaultNodes, defaultEdges, initialWidth, initialHeight, fitView, }) {
2760
- const storeRef = useRef(null);
2761
- if (!storeRef.current) {
2762
- storeRef.current = createRFStore({
2763
- nodes: initialNodes,
2764
- edges: initialEdges,
2765
- defaultNodes,
2766
- defaultEdges,
2767
- width: initialWidth,
2768
- height: initialHeight,
2769
- fitView,
2770
- });
2771
- }
2772
- return jsx(Provider$1, { value: storeRef.current, children: children });
2902
+ function ReactFlowProvider({ initialNodes: nodes, initialEdges: edges, defaultNodes, defaultEdges, initialWidth: width, initialHeight: height, fitView, nodeOrigin, children, }) {
2903
+ const [store] = useState(() => createStore({
2904
+ nodes,
2905
+ edges,
2906
+ defaultNodes,
2907
+ defaultEdges,
2908
+ width,
2909
+ height,
2910
+ fitView,
2911
+ nodeOrigin,
2912
+ }));
2913
+ return (jsx(Provider$1, { value: store, children: jsx(BatchProvider, { children: children }) }));
2773
2914
  }
2774
2915
 
2775
- function Wrapper({ children, nodes, edges, defaultNodes, defaultEdges, width, height, fitView, }) {
2916
+ function Wrapper({ children, nodes, edges, defaultNodes, defaultEdges, width, height, fitView, nodeOrigin, }) {
2776
2917
  const isWrapped = useContext(StoreContext);
2777
2918
  if (isWrapped) {
2778
2919
  // we need to wrap it with a fragment because it's not allowed for children to be a ReactNode
2779
2920
  // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18051
2780
2921
  return jsx(Fragment, { children: children });
2781
2922
  }
2782
- return (jsx(ReactFlowProvider, { initialNodes: nodes, initialEdges: edges, defaultNodes: defaultNodes, defaultEdges: defaultEdges, initialWidth: width, initialHeight: height, fitView: fitView, children: children }));
2923
+ return (jsx(ReactFlowProvider, { initialNodes: nodes, initialEdges: edges, defaultNodes: defaultNodes, defaultEdges: defaultEdges, initialWidth: width, initialHeight: height, fitView: fitView, nodeOrigin: nodeOrigin, children: children }));
2783
2924
  }
2784
2925
 
2785
2926
  const wrapperStyle = {
@@ -2789,25 +2930,25 @@ const wrapperStyle = {
2789
2930
  position: 'relative',
2790
2931
  zIndex: 0,
2791
2932
  };
2792
- const ReactFlow = forwardRef(({ nodes, edges, defaultNodes, defaultEdges, className, nodeTypes, edgeTypes, onNodeClick, onEdgeClick, onInit, onMove, onMoveStart, onMoveEnd, onConnect, onConnectStart, onConnectEnd, onClickConnectStart, onClickConnectEnd, onNodeMouseEnter, onNodeMouseMove, onNodeMouseLeave, onNodeContextMenu, onNodeDoubleClick, onNodeDragStart, onNodeDrag, onNodeDragStop, onNodesDelete, onEdgesDelete, onDelete, onSelectionChange, onSelectionDragStart, onSelectionDrag, onSelectionDragStop, onSelectionContextMenu, onSelectionStart, onSelectionEnd, onBeforeDelete, connectionMode, connectionLineType = ConnectionLineType.Bezier, connectionLineStyle, connectionLineComponent, connectionLineContainerStyle, deleteKeyCode = 'Backspace', selectionKeyCode = 'Shift', selectionOnDrag = false, selectionMode = SelectionMode.Full, panActivationKeyCode = 'Space', multiSelectionKeyCode = isMacOs() ? 'Meta' : 'Control', zoomActivationKeyCode = isMacOs() ? 'Meta' : 'Control', snapToGrid, snapGrid, onlyRenderVisibleElements = false, selectNodesOnDrag, nodesDraggable, nodesConnectable, nodesFocusable, nodeOrigin = defaultNodeOrigin, edgesFocusable, edgesUpdatable, elementsSelectable = true, defaultViewport: defaultViewport$1 = defaultViewport, minZoom = 0.5, maxZoom = 2, translateExtent = infiniteExtent, preventScrolling = true, nodeExtent, defaultMarkerColor = '#b1b1b7', zoomOnScroll = true, zoomOnPinch = true, panOnScroll = false, panOnScrollSpeed = 0.5, panOnScrollMode = PanOnScrollMode.Free, zoomOnDoubleClick = true, panOnDrag = true, onPaneClick, onPaneMouseEnter, onPaneMouseMove, onPaneMouseLeave, onPaneScroll, onPaneContextMenu, children, onEdgeUpdate, onEdgeContextMenu, onEdgeDoubleClick, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, onEdgeUpdateStart, onEdgeUpdateEnd, edgeUpdaterRadius = 10, onNodesChange, onEdgesChange, noDragClassName = 'nodrag', noWheelClassName = 'nowheel', noPanClassName = 'nopan', fitView, fitViewOptions, connectOnClick, attributionPosition, proOptions, defaultEdgeOptions, elevateNodesOnSelect, elevateEdgesOnSelect, disableKeyboardA11y = false, autoPanOnConnect, autoPanOnNodeDrag, connectionRadius, isValidConnection, onError, style, id, nodeDragThreshold, viewport, onViewportChange, width, height, colorMode = 'light', ...rest }, ref) => {
2933
+ function ReactFlow({ nodes, edges, defaultNodes, defaultEdges, className, nodeTypes, edgeTypes, onNodeClick, onEdgeClick, onInit, onMove, onMoveStart, onMoveEnd, onConnect, onConnectStart, onConnectEnd, onClickConnectStart, onClickConnectEnd, onNodeMouseEnter, onNodeMouseMove, onNodeMouseLeave, onNodeContextMenu, onNodeDoubleClick, onNodeDragStart, onNodeDrag, onNodeDragStop, onNodesDelete, onEdgesDelete, onDelete, onSelectionChange, onSelectionDragStart, onSelectionDrag, onSelectionDragStop, onSelectionContextMenu, onSelectionStart, onSelectionEnd, onBeforeDelete, connectionMode, connectionLineType = ConnectionLineType.Bezier, connectionLineStyle, connectionLineComponent, connectionLineContainerStyle, deleteKeyCode = 'Backspace', selectionKeyCode = 'Shift', selectionOnDrag = false, selectionMode = SelectionMode.Full, panActivationKeyCode = 'Space', multiSelectionKeyCode = isMacOs() ? 'Meta' : 'Control', zoomActivationKeyCode = isMacOs() ? 'Meta' : 'Control', snapToGrid, snapGrid, onlyRenderVisibleElements = false, selectNodesOnDrag, nodesDraggable, nodesConnectable, nodesFocusable, nodeOrigin = defaultNodeOrigin, edgesFocusable, edgesReconnectable, elementsSelectable = true, defaultViewport: defaultViewport$1 = defaultViewport, minZoom = 0.5, maxZoom = 2, translateExtent = infiniteExtent, preventScrolling = true, nodeExtent, defaultMarkerColor = '#b1b1b7', zoomOnScroll = true, zoomOnPinch = true, panOnScroll = false, panOnScrollSpeed = 0.5, panOnScrollMode = PanOnScrollMode.Free, zoomOnDoubleClick = true, panOnDrag = true, onPaneClick, onPaneMouseEnter, onPaneMouseMove, onPaneMouseLeave, onPaneScroll, onPaneContextMenu, paneClickDistance = 0, children, onReconnect, onReconnectStart, onReconnectEnd, onEdgeContextMenu, onEdgeDoubleClick, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, reconnectRadius = 10, onNodesChange, onEdgesChange, noDragClassName = 'nodrag', noWheelClassName = 'nowheel', noPanClassName = 'nopan', fitView, fitViewOptions, connectOnClick, attributionPosition, proOptions, defaultEdgeOptions, elevateNodesOnSelect, elevateEdgesOnSelect, disableKeyboardA11y = false, autoPanOnConnect, autoPanOnNodeDrag, autoPanSpeed, connectionRadius, isValidConnection, onError, style, id, nodeDragThreshold, viewport, onViewportChange, width, height, colorMode = 'light', debug, ...rest }, ref) {
2793
2934
  const rfId = id || '1';
2794
2935
  const colorModeClassName = useColorModeClass(colorMode);
2795
- return (jsx("div", { ...rest, style: { ...style, ...wrapperStyle }, ref: ref, className: cc(['react-flow', className, colorModeClassName]), "data-testid": "rf__wrapper", id: id, children: jsxs(Wrapper, { nodes: nodes, edges: edges, defaultNodes: defaultNodes, defaultEdges: defaultEdges, width: width, height: height, fitView: fitView, children: [jsx(GraphView, { onInit: onInit, onNodeClick: onNodeClick, onEdgeClick: onEdgeClick, onNodeMouseEnter: onNodeMouseEnter, onNodeMouseMove: onNodeMouseMove, onNodeMouseLeave: onNodeMouseLeave, onNodeContextMenu: onNodeContextMenu, onNodeDoubleClick: onNodeDoubleClick, nodeTypes: nodeTypes, edgeTypes: edgeTypes, connectionLineType: connectionLineType, connectionLineStyle: connectionLineStyle, connectionLineComponent: connectionLineComponent, connectionLineContainerStyle: connectionLineContainerStyle, selectionKeyCode: selectionKeyCode, selectionOnDrag: selectionOnDrag, selectionMode: selectionMode, deleteKeyCode: deleteKeyCode, multiSelectionKeyCode: multiSelectionKeyCode, panActivationKeyCode: panActivationKeyCode, zoomActivationKeyCode: zoomActivationKeyCode, onlyRenderVisibleElements: onlyRenderVisibleElements, defaultViewport: defaultViewport$1, translateExtent: translateExtent, minZoom: minZoom, maxZoom: maxZoom, preventScrolling: preventScrolling, zoomOnScroll: zoomOnScroll, zoomOnPinch: zoomOnPinch, zoomOnDoubleClick: zoomOnDoubleClick, panOnScroll: panOnScroll, panOnScrollSpeed: panOnScrollSpeed, panOnScrollMode: panOnScrollMode, panOnDrag: panOnDrag, onPaneClick: onPaneClick, onPaneMouseEnter: onPaneMouseEnter, onPaneMouseMove: onPaneMouseMove, onPaneMouseLeave: onPaneMouseLeave, onPaneScroll: onPaneScroll, onPaneContextMenu: onPaneContextMenu, onSelectionContextMenu: onSelectionContextMenu, onSelectionStart: onSelectionStart, onSelectionEnd: onSelectionEnd, onEdgeUpdate: onEdgeUpdate, onEdgeContextMenu: onEdgeContextMenu, onEdgeDoubleClick: onEdgeDoubleClick, onEdgeMouseEnter: onEdgeMouseEnter, onEdgeMouseMove: onEdgeMouseMove, onEdgeMouseLeave: onEdgeMouseLeave, onEdgeUpdateStart: onEdgeUpdateStart, onEdgeUpdateEnd: onEdgeUpdateEnd, edgeUpdaterRadius: edgeUpdaterRadius, defaultMarkerColor: defaultMarkerColor, noDragClassName: noDragClassName, noWheelClassName: noWheelClassName, noPanClassName: noPanClassName, rfId: rfId, disableKeyboardA11y: disableKeyboardA11y, nodeOrigin: nodeOrigin, nodeExtent: nodeExtent, viewport: viewport, onViewportChange: onViewportChange }), jsx(StoreUpdater, { nodes: nodes, edges: edges, defaultNodes: defaultNodes, defaultEdges: defaultEdges, onConnect: onConnect, onConnectStart: onConnectStart, onConnectEnd: onConnectEnd, onClickConnectStart: onClickConnectStart, onClickConnectEnd: onClickConnectEnd, nodesDraggable: nodesDraggable, nodesConnectable: nodesConnectable, nodesFocusable: nodesFocusable, edgesFocusable: edgesFocusable, edgesUpdatable: edgesUpdatable, elementsSelectable: elementsSelectable, elevateNodesOnSelect: elevateNodesOnSelect, elevateEdgesOnSelect: elevateEdgesOnSelect, minZoom: minZoom, maxZoom: maxZoom, nodeExtent: nodeExtent, onNodesChange: onNodesChange, onEdgesChange: onEdgesChange, snapToGrid: snapToGrid, snapGrid: snapGrid, connectionMode: connectionMode, translateExtent: translateExtent, connectOnClick: connectOnClick, defaultEdgeOptions: defaultEdgeOptions, fitView: fitView, fitViewOptions: fitViewOptions, onNodesDelete: onNodesDelete, onEdgesDelete: onEdgesDelete, onDelete: onDelete, onNodeDragStart: onNodeDragStart, onNodeDrag: onNodeDrag, onNodeDragStop: onNodeDragStop, onSelectionDrag: onSelectionDrag, onSelectionDragStart: onSelectionDragStart, onSelectionDragStop: onSelectionDragStop, onMove: onMove, onMoveStart: onMoveStart, onMoveEnd: onMoveEnd, noPanClassName: noPanClassName, nodeOrigin: nodeOrigin, rfId: rfId, autoPanOnConnect: autoPanOnConnect, autoPanOnNodeDrag: autoPanOnNodeDrag, onError: onError, connectionRadius: connectionRadius, isValidConnection: isValidConnection, selectNodesOnDrag: selectNodesOnDrag, nodeDragThreshold: nodeDragThreshold, onBeforeDelete: onBeforeDelete }), jsx(SelectionListener, { onSelectionChange: onSelectionChange }), children, jsx(Attribution, { proOptions: proOptions, position: attributionPosition }), jsx(A11yDescriptions, { rfId: rfId, disableKeyboardA11y: disableKeyboardA11y })] }) }));
2796
- });
2797
- ReactFlow.displayName = 'ReactFlow';
2936
+ return (jsx("div", { ...rest, style: { ...style, ...wrapperStyle }, ref: ref, className: cc(['react-flow', className, colorModeClassName]), "data-testid": "rf__wrapper", id: id, children: jsxs(Wrapper, { nodes: nodes, edges: edges, width: width, height: height, fitView: fitView, nodeOrigin: nodeOrigin, children: [jsx(GraphView, { onInit: onInit, onNodeClick: onNodeClick, onEdgeClick: onEdgeClick, onNodeMouseEnter: onNodeMouseEnter, onNodeMouseMove: onNodeMouseMove, onNodeMouseLeave: onNodeMouseLeave, onNodeContextMenu: onNodeContextMenu, onNodeDoubleClick: onNodeDoubleClick, nodeTypes: nodeTypes, edgeTypes: edgeTypes, connectionLineType: connectionLineType, connectionLineStyle: connectionLineStyle, connectionLineComponent: connectionLineComponent, connectionLineContainerStyle: connectionLineContainerStyle, selectionKeyCode: selectionKeyCode, selectionOnDrag: selectionOnDrag, selectionMode: selectionMode, deleteKeyCode: deleteKeyCode, multiSelectionKeyCode: multiSelectionKeyCode, panActivationKeyCode: panActivationKeyCode, zoomActivationKeyCode: zoomActivationKeyCode, onlyRenderVisibleElements: onlyRenderVisibleElements, defaultViewport: defaultViewport$1, translateExtent: translateExtent, minZoom: minZoom, maxZoom: maxZoom, preventScrolling: preventScrolling, zoomOnScroll: zoomOnScroll, zoomOnPinch: zoomOnPinch, zoomOnDoubleClick: zoomOnDoubleClick, panOnScroll: panOnScroll, panOnScrollSpeed: panOnScrollSpeed, panOnScrollMode: panOnScrollMode, panOnDrag: panOnDrag, onPaneClick: onPaneClick, onPaneMouseEnter: onPaneMouseEnter, onPaneMouseMove: onPaneMouseMove, onPaneMouseLeave: onPaneMouseLeave, onPaneScroll: onPaneScroll, onPaneContextMenu: onPaneContextMenu, paneClickDistance: paneClickDistance, onSelectionContextMenu: onSelectionContextMenu, onSelectionStart: onSelectionStart, onSelectionEnd: onSelectionEnd, onReconnect: onReconnect, onReconnectStart: onReconnectStart, onReconnectEnd: onReconnectEnd, onEdgeContextMenu: onEdgeContextMenu, onEdgeDoubleClick: onEdgeDoubleClick, onEdgeMouseEnter: onEdgeMouseEnter, onEdgeMouseMove: onEdgeMouseMove, onEdgeMouseLeave: onEdgeMouseLeave, reconnectRadius: reconnectRadius, defaultMarkerColor: defaultMarkerColor, noDragClassName: noDragClassName, noWheelClassName: noWheelClassName, noPanClassName: noPanClassName, rfId: rfId, disableKeyboardA11y: disableKeyboardA11y, nodeExtent: nodeExtent, viewport: viewport, onViewportChange: onViewportChange }), jsx(StoreUpdater, { nodes: nodes, edges: edges, defaultNodes: defaultNodes, defaultEdges: defaultEdges, onConnect: onConnect, onConnectStart: onConnectStart, onConnectEnd: onConnectEnd, onClickConnectStart: onClickConnectStart, onClickConnectEnd: onClickConnectEnd, nodesDraggable: nodesDraggable, nodesConnectable: nodesConnectable, nodesFocusable: nodesFocusable, edgesFocusable: edgesFocusable, edgesReconnectable: edgesReconnectable, elementsSelectable: elementsSelectable, elevateNodesOnSelect: elevateNodesOnSelect, elevateEdgesOnSelect: elevateEdgesOnSelect, minZoom: minZoom, maxZoom: maxZoom, nodeExtent: nodeExtent, onNodesChange: onNodesChange, onEdgesChange: onEdgesChange, snapToGrid: snapToGrid, snapGrid: snapGrid, connectionMode: connectionMode, translateExtent: translateExtent, connectOnClick: connectOnClick, defaultEdgeOptions: defaultEdgeOptions, fitView: fitView, fitViewOptions: fitViewOptions, onNodesDelete: onNodesDelete, onEdgesDelete: onEdgesDelete, onDelete: onDelete, onNodeDragStart: onNodeDragStart, onNodeDrag: onNodeDrag, onNodeDragStop: onNodeDragStop, onSelectionDrag: onSelectionDrag, onSelectionDragStart: onSelectionDragStart, onSelectionDragStop: onSelectionDragStop, onMove: onMove, onMoveStart: onMoveStart, onMoveEnd: onMoveEnd, noPanClassName: noPanClassName, nodeOrigin: nodeOrigin, rfId: rfId, autoPanOnConnect: autoPanOnConnect, autoPanOnNodeDrag: autoPanOnNodeDrag, autoPanSpeed: autoPanSpeed, onError: onError, connectionRadius: connectionRadius, isValidConnection: isValidConnection, selectNodesOnDrag: selectNodesOnDrag, nodeDragThreshold: nodeDragThreshold, onBeforeDelete: onBeforeDelete, paneClickDistance: paneClickDistance, debug: debug }), jsx(SelectionListener, { onSelectionChange: onSelectionChange }), children, jsx(Attribution, { proOptions: proOptions, position: attributionPosition }), jsx(A11yDescriptions, { rfId: rfId, disableKeyboardA11y: disableKeyboardA11y })] }) }));
2937
+ }
2938
+ var index = fixedForwardRef(ReactFlow);
2798
2939
 
2799
- const selector$8 = (s) => s.domNode?.querySelector('.react-flow__edgelabel-renderer');
2940
+ const selector$6 = (s) => s.domNode?.querySelector('.react-flow__edgelabel-renderer');
2800
2941
  function EdgeLabelRenderer({ children }) {
2801
- const edgeLabelRenderer = useStore(selector$8);
2942
+ const edgeLabelRenderer = useStore(selector$6);
2802
2943
  if (!edgeLabelRenderer) {
2803
2944
  return null;
2804
2945
  }
2805
2946
  return createPortal(children, edgeLabelRenderer);
2806
2947
  }
2807
2948
 
2808
- const selector$7 = (s) => s.domNode?.querySelector('.react-flow__viewport-portal');
2949
+ const selector$5 = (s) => s.domNode?.querySelector('.react-flow__viewport-portal');
2809
2950
  function ViewportPortal({ children }) {
2810
- const viewPortalDiv = useStore(selector$7);
2951
+ const viewPortalDiv = useStore(selector$5);
2811
2952
  if (!viewPortalDiv) {
2812
2953
  return null;
2813
2954
  }
@@ -2823,16 +2964,16 @@ function ViewportPortal({ children }) {
2823
2964
  function useUpdateNodeInternals() {
2824
2965
  const store = useStoreApi();
2825
2966
  return useCallback((id) => {
2826
- const { domNode, updateNodeDimensions } = store.getState();
2967
+ const { domNode, updateNodeInternals } = store.getState();
2827
2968
  const updateIds = Array.isArray(id) ? id : [id];
2828
2969
  const updates = new Map();
2829
2970
  updateIds.forEach((updateId) => {
2830
2971
  const nodeElement = domNode?.querySelector(`.react-flow__node[data-id="${updateId}"]`);
2831
2972
  if (nodeElement) {
2832
- updates.set(updateId, { id: updateId, nodeElement, forceUpdate: true });
2973
+ updates.set(updateId, { id: updateId, nodeElement, force: true });
2833
2974
  }
2834
2975
  });
2835
- requestAnimationFrame(() => updateNodeDimensions(updates));
2976
+ requestAnimationFrame(() => updateNodeInternals(updates));
2836
2977
  }, []);
2837
2978
  }
2838
2979
 
@@ -2940,13 +3081,13 @@ function useOnSelectionChange({ onChange }) {
2940
3081
  }, [onChange]);
2941
3082
  }
2942
3083
 
2943
- const selector$6 = (options) => (s) => {
2944
- if (s.nodes.length === 0) {
3084
+ const selector$4 = (options) => (s) => {
3085
+ if (s.nodeLookup.size === 0) {
2945
3086
  return false;
2946
3087
  }
2947
- for (const node of s.nodes) {
2948
- if (options.includeHiddenNodes || !node.hidden) {
2949
- if (node[internalsSymbol]?.handleBounds === undefined) {
3088
+ for (const [, { hidden, internals }] of s.nodeLookup) {
3089
+ if (options.includeHiddenNodes || !hidden) {
3090
+ if (internals.handleBounds === undefined || !nodeHasDimensions(internals.userNode)) {
2950
3091
  return false;
2951
3092
  }
2952
3093
  }
@@ -2964,7 +3105,7 @@ const defaultOptions = {
2964
3105
  * @returns boolean indicating whether all nodes are initialized
2965
3106
  */
2966
3107
  function useNodesInitialized(options = defaultOptions) {
2967
- const initialized = useStore(selector$6(options));
3108
+ const initialized = useStore(selector$4(options));
2968
3109
  return initialized;
2969
3110
  }
2970
3111
 
@@ -2999,36 +3140,34 @@ function useHandleConnections({ type, id = null, nodeId, onConnect, onDisconnect
2999
3140
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
3000
3141
  function useNodesData(nodeIds) {
3001
3142
  const nodesData = useStore(useCallback((s) => {
3002
- if (!Array.isArray(nodeIds)) {
3003
- return s.nodeLookup.get(nodeIds)?.data || null;
3004
- }
3005
3143
  const data = [];
3006
- for (const nodeId of nodeIds) {
3007
- const nodeData = s.nodeLookup.get(nodeId)?.data;
3008
- if (nodeData) {
3009
- data.push(nodeData);
3144
+ const isArrayOfIds = Array.isArray(nodeIds);
3145
+ const _nodeIds = isArrayOfIds ? nodeIds : [nodeIds];
3146
+ for (const nodeId of _nodeIds) {
3147
+ const node = s.nodeLookup.get(nodeId);
3148
+ if (node) {
3149
+ data.push({
3150
+ id: node.id,
3151
+ type: node.type,
3152
+ data: node.data,
3153
+ });
3010
3154
  }
3011
3155
  }
3012
- return data;
3013
- }, [nodeIds]), shallow);
3156
+ return isArrayOfIds ? data : data[0] ?? null;
3157
+ }, [nodeIds]), shallowNodeData);
3014
3158
  return nodesData;
3015
3159
  }
3016
3160
 
3017
- const selector$5 = (s) => ({
3018
- startHandle: s.connectionStartHandle,
3019
- endHandle: s.connectionEndHandle,
3020
- status: s.connectionStatus,
3021
- position: s.connectionStartHandle ? s.connectionPosition : null,
3022
- });
3023
3161
  /**
3024
- * Hook for accessing the ongoing connection.
3162
+ * Hook for getting an internal node by id
3025
3163
  *
3026
3164
  * @public
3027
- * @returns ongoing connection
3165
+ * @param id - id of the node
3166
+ * @returns array with visible node ids
3028
3167
  */
3029
- function useConnection() {
3030
- const ongoingConnection = useStore(selector$5, shallow);
3031
- return ongoingConnection;
3168
+ function useInternalNode(id) {
3169
+ const node = useStore(useCallback((s) => s.nodeLookup.get(id), [id]), shallow);
3170
+ return node;
3032
3171
  }
3033
3172
 
3034
3173
  function LinePattern({ dimensions, lineWidth, variant, className }) {
@@ -3050,14 +3189,14 @@ const defaultSize = {
3050
3189
  [BackgroundVariant.Lines]: 1,
3051
3190
  [BackgroundVariant.Cross]: 6,
3052
3191
  };
3053
- const selector$4 = (s) => ({ transform: s.transform, patternId: `pattern-${s.rfId}` });
3192
+ const selector$3 = (s) => ({ transform: s.transform, patternId: `pattern-${s.rfId}` });
3054
3193
  function BackgroundComponent({ id, variant = BackgroundVariant.Dots,
3055
3194
  // only used for dots and cross
3056
3195
  gap = 20,
3057
3196
  // only used for lines and cross
3058
3197
  size, lineWidth = 1, offset = 2, color, bgColor, style, className, patternClassName, }) {
3059
3198
  const ref = useRef(null);
3060
- const { transform, patternId } = useStore(selector$4, shallow);
3199
+ const { transform, patternId } = useStore(selector$3, shallow);
3061
3200
  const patternSize = size || defaultSize[variant];
3062
3201
  const isDots = variant === BackgroundVariant.Dots;
3063
3202
  const isCross = variant === BackgroundVariant.Cross;
@@ -3103,14 +3242,14 @@ function ControlButton({ children, className, ...rest }) {
3103
3242
  return (jsx("button", { type: "button", className: cc(['react-flow__controls-button', className]), ...rest, children: children }));
3104
3243
  }
3105
3244
 
3106
- const selector$3 = (s) => ({
3245
+ const selector$2 = (s) => ({
3107
3246
  isInteractive: s.nodesDraggable || s.nodesConnectable || s.elementsSelectable,
3108
3247
  minZoomReached: s.transform[2] <= s.minZoom,
3109
3248
  maxZoomReached: s.transform[2] >= s.maxZoom,
3110
3249
  });
3111
- 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', }) {
3250
+ 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', }) {
3112
3251
  const store = useStoreApi();
3113
- const { isInteractive, minZoomReached, maxZoomReached } = useStore(selector$3, shallow);
3252
+ const { isInteractive, minZoomReached, maxZoomReached } = useStore(selector$2, shallow);
3114
3253
  const { zoomIn, zoomOut, fitView } = useReactFlow();
3115
3254
  const onZoomInHandler = () => {
3116
3255
  zoomIn();
@@ -3132,7 +3271,8 @@ function ControlsComponent({ style, showZoom = true, showFitView = true, showInt
3132
3271
  });
3133
3272
  onInteractiveChange?.(!isInteractive);
3134
3273
  };
3135
- 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] }));
3274
+ const orientationClass = orientation === 'horizontal' ? 'horizontal' : 'vertical';
3275
+ 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] }));
3136
3276
  }
3137
3277
  ControlsComponent.displayName = 'Controls';
3138
3278
  const Controls = memo(ControlsComponent);
@@ -3148,15 +3288,13 @@ function MiniMapNodeComponent({ id, x, y, width, height, style, color, strokeCol
3148
3288
  }
3149
3289
  const MiniMapNode = memo(MiniMapNodeComponent);
3150
3290
 
3151
- const selector$2 = (s) => s.nodeOrigin;
3152
3291
  const selectorNodeIds = (s) => s.nodes.map((node) => node.id);
3153
- const getAttrFunction = (func) => (func instanceof Function ? func : () => func);
3292
+ const getAttrFunction = (func) => func instanceof Function ? func : () => func;
3154
3293
  function MiniMapNodes({ nodeStrokeColor, nodeColor, nodeClassName = '', nodeBorderRadius = 5, nodeStrokeWidth,
3155
3294
  // We need to rename the prop to be `CapitalCase` so that JSX will render it as
3156
3295
  // a component properly.
3157
3296
  nodeComponent: NodeComponent = MiniMapNode, onClick, }) {
3158
3297
  const nodeIds = useStore(selectorNodeIds, shallow);
3159
- const nodeOrigin = useStore(selector$2);
3160
3298
  const nodeColorFunc = getAttrFunction(nodeColor);
3161
3299
  const nodeStrokeColorFunc = getAttrFunction(nodeStrokeColor);
3162
3300
  const nodeClassNameFunc = getAttrFunction(nodeClassName);
@@ -3167,23 +3305,25 @@ nodeComponent: NodeComponent = MiniMapNode, onClick, }) {
3167
3305
  // minimize the cost of updates when individual nodes change.
3168
3306
  //
3169
3307
  // For more details, see a similar commit in `NodeRenderer/index.tsx`.
3170
- jsx(NodeComponentWrapper, { id: nodeId, nodeOrigin: nodeOrigin, nodeColorFunc: nodeColorFunc, nodeStrokeColorFunc: nodeStrokeColorFunc, nodeClassNameFunc: nodeClassNameFunc, nodeBorderRadius: nodeBorderRadius, nodeStrokeWidth: nodeStrokeWidth, NodeComponent: NodeComponent, onClick: onClick, shapeRendering: shapeRendering }, nodeId))) }));
3308
+ jsx(NodeComponentWrapper, { id: nodeId, nodeColorFunc: nodeColorFunc, nodeStrokeColorFunc: nodeStrokeColorFunc, nodeClassNameFunc: nodeClassNameFunc, nodeBorderRadius: nodeBorderRadius, nodeStrokeWidth: nodeStrokeWidth, NodeComponent: NodeComponent, onClick: onClick, shapeRendering: shapeRendering }, nodeId))) }));
3171
3309
  }
3172
- const NodeComponentWrapper = memo(function NodeComponentWrapper({ id, nodeOrigin, nodeColorFunc, nodeStrokeColorFunc, nodeClassNameFunc, nodeBorderRadius, nodeStrokeWidth, shapeRendering, NodeComponent, onClick, }) {
3310
+ function NodeComponentWrapperInner({ id, nodeColorFunc, nodeStrokeColorFunc, nodeClassNameFunc, nodeBorderRadius, nodeStrokeWidth, shapeRendering, NodeComponent, onClick, }) {
3173
3311
  const { node, x, y } = useStore((s) => {
3174
3312
  const node = s.nodeLookup.get(id);
3175
- const { x, y } = getNodePositionWithOrigin(node, node?.origin || nodeOrigin).positionAbsolute;
3313
+ const { x, y } = node.internals.positionAbsolute;
3176
3314
  return {
3177
3315
  node,
3178
3316
  x,
3179
3317
  y,
3180
3318
  };
3181
3319
  }, shallow);
3182
- if (!node || node.hidden || !(node.computed?.width || node.width) || !(node.computed?.height || node.height)) {
3320
+ if (!node || node.hidden || !nodeHasDimensions(node)) {
3183
3321
  return null;
3184
3322
  }
3185
- return (jsx(NodeComponent, { x: x, y: y, width: node.computed?.width ?? node.width ?? 0, height: node.computed?.height ?? node.height ?? 0, style: node.style, selected: !!node.selected, className: nodeClassNameFunc(node), color: nodeColorFunc(node), borderRadius: nodeBorderRadius, strokeColor: nodeStrokeColorFunc(node), strokeWidth: nodeStrokeWidth, shapeRendering: shapeRendering, onClick: onClick, id: node.id }));
3186
- });
3323
+ const { width, height } = getNodeDimensions(node);
3324
+ return (jsx(NodeComponent, { x: x, y: y, width: width, height: height, style: node.style, selected: !!node.selected, className: nodeClassNameFunc(node), color: nodeColorFunc(node), borderRadius: nodeBorderRadius, strokeColor: nodeStrokeColorFunc(node), strokeWidth: nodeStrokeWidth, shapeRendering: shapeRendering, onClick: onClick, id: node.id }));
3325
+ }
3326
+ const NodeComponentWrapper = memo(NodeComponentWrapperInner);
3187
3327
  var MiniMapNodes$1 = memo(MiniMapNodes);
3188
3328
 
3189
3329
  const defaultWidth = 200;
@@ -3197,9 +3337,8 @@ const selector$1 = (s) => {
3197
3337
  };
3198
3338
  return {
3199
3339
  viewBB,
3200
- boundingRect: s.nodes.length > 0 ? getBoundsOfRects(getNodesBounds(s.nodes, { nodeOrigin: s.nodeOrigin }), viewBB) : viewBB,
3340
+ boundingRect: s.nodeLookup.size > 0 ? getBoundsOfRects(getInternalNodesBounds(s.nodeLookup), viewBB) : viewBB,
3201
3341
  rfId: s.rfId,
3202
- nodeOrigin: s.nodeOrigin,
3203
3342
  panZoom: s.panZoom,
3204
3343
  translateExtent: s.translateExtent,
3205
3344
  flowWidth: s.width,
@@ -3298,33 +3437,57 @@ function ResizeControl({ nodeId, position, variant = ResizeControlVariant.Handle
3298
3437
  domNode: resizeControlRef.current,
3299
3438
  nodeId: id,
3300
3439
  getStoreItems: () => {
3301
- const { nodeLookup, transform, snapGrid, snapToGrid } = store.getState();
3440
+ const { nodeLookup, transform, snapGrid, snapToGrid, nodeOrigin } = store.getState();
3302
3441
  return {
3303
3442
  nodeLookup,
3304
3443
  transform,
3305
3444
  snapGrid,
3306
3445
  snapToGrid,
3446
+ nodeOrigin,
3307
3447
  };
3308
3448
  },
3309
3449
  onChange: (change, childChanges) => {
3310
- const { triggerNodeChanges } = store.getState();
3450
+ const { triggerNodeChanges, nodeLookup, parentLookup, nodeOrigin } = store.getState();
3311
3451
  const changes = [];
3312
- if (change.isXPosChange || change.isYPosChange) {
3452
+ const nextPosition = { x: change.x, y: change.y };
3453
+ const node = nodeLookup.get(id);
3454
+ if (node && node.expandParent && node.parentId) {
3455
+ const origin = node.origin ?? nodeOrigin;
3456
+ const width = change.width ?? node.measured.width;
3457
+ const height = change.height ?? node.measured.height;
3458
+ const child = {
3459
+ id: node.id,
3460
+ parentId: node.parentId,
3461
+ rect: {
3462
+ width,
3463
+ height,
3464
+ ...evaluateAbsolutePosition({
3465
+ x: change.x ?? node.position.x,
3466
+ y: change.y ?? node.position.y,
3467
+ }, { width, height }, node.parentId, nodeLookup, origin),
3468
+ },
3469
+ };
3470
+ const parentExpandChanges = handleExpandParent([child], nodeLookup, parentLookup, nodeOrigin);
3471
+ changes.push(...parentExpandChanges);
3472
+ // when the parent was expanded by the child node, its position will be clamped at
3473
+ // 0,0 when node origin is 0,0 and to width, height if it's 1,1
3474
+ nextPosition.x = change.x ? Math.max(origin[0] * width, change.x) : undefined;
3475
+ nextPosition.y = change.y ? Math.max(origin[1] * height, change.y) : undefined;
3476
+ }
3477
+ if (nextPosition.x !== undefined && nextPosition.y !== undefined) {
3313
3478
  const positionChange = {
3314
3479
  id,
3315
3480
  type: 'position',
3316
- position: {
3317
- x: change.x,
3318
- y: change.y,
3319
- },
3481
+ position: { ...nextPosition },
3320
3482
  };
3321
3483
  changes.push(positionChange);
3322
3484
  }
3323
- if (change.isWidthChange || change.isHeightChange) {
3485
+ if (change.width !== undefined && change.height !== undefined) {
3324
3486
  const dimensionChange = {
3325
3487
  id,
3326
3488
  type: 'dimensions',
3327
3489
  resizing: true,
3490
+ setAttributes: true,
3328
3491
  dimensions: {
3329
3492
  width: change.width,
3330
3493
  height: change.height,
@@ -3403,55 +3566,61 @@ function NodeToolbarPortal({ children }) {
3403
3566
  return createPortal(children, wrapperRef);
3404
3567
  }
3405
3568
 
3406
- const nodeEqualityFn = (a, b) => a?.computed?.positionAbsolute?.x !== b?.computed?.positionAbsolute?.x ||
3407
- a?.computed?.positionAbsolute?.y !== b?.computed?.positionAbsolute?.y ||
3408
- a?.computed?.width !== b?.computed?.width ||
3409
- a?.computed?.height !== b?.computed?.height ||
3569
+ const nodeEqualityFn = (a, b) => a?.internals.positionAbsolute.x !== b?.internals.positionAbsolute.x ||
3570
+ a?.internals.positionAbsolute.y !== b?.internals.positionAbsolute.y ||
3571
+ a?.measured.width !== b?.measured.width ||
3572
+ a?.measured.height !== b?.measured.height ||
3410
3573
  a?.selected !== b?.selected ||
3411
- a?.[internalsSymbol]?.z !== b?.[internalsSymbol]?.z;
3574
+ a?.internals.z !== b?.internals.z;
3412
3575
  const nodesEqualityFn = (a, b) => {
3413
- if (a.length !== b.length) {
3576
+ if (a.size !== b.size) {
3414
3577
  return false;
3415
3578
  }
3416
- return !a.some((node, i) => nodeEqualityFn(node, b[i]));
3579
+ for (const [key, node] of a) {
3580
+ if (nodeEqualityFn(node, b.get(key))) {
3581
+ return false;
3582
+ }
3583
+ }
3584
+ return true;
3417
3585
  };
3418
3586
  const storeSelector = (state) => ({
3419
- viewport: {
3420
- x: state.transform[0],
3421
- y: state.transform[1],
3422
- zoom: state.transform[2],
3423
- },
3424
- nodeOrigin: state.nodeOrigin,
3587
+ x: state.transform[0],
3588
+ y: state.transform[1],
3589
+ zoom: state.transform[2],
3425
3590
  selectedNodesCount: state.nodes.filter((node) => node.selected).length,
3426
3591
  });
3427
3592
  function NodeToolbar({ nodeId, children, className, style, isVisible, position = Position.Top, offset = 10, align = 'center', ...rest }) {
3428
3593
  const contextNodeId = useNodeId();
3429
3594
  const nodesSelector = useCallback((state) => {
3430
3595
  const nodeIds = Array.isArray(nodeId) ? nodeId : [nodeId || contextNodeId || ''];
3431
- return nodeIds.reduce((acc, id) => {
3596
+ const internalNodes = nodeIds.reduce((res, id) => {
3432
3597
  const node = state.nodeLookup.get(id);
3433
3598
  if (node) {
3434
- acc.push(node);
3599
+ res.set(node.id, node);
3435
3600
  }
3436
- return acc;
3437
- }, []);
3601
+ return res;
3602
+ }, new Map());
3603
+ return internalNodes;
3438
3604
  }, [nodeId, contextNodeId]);
3439
3605
  const nodes = useStore(nodesSelector, nodesEqualityFn);
3440
- const { viewport, nodeOrigin, selectedNodesCount } = useStore(storeSelector, shallow);
3606
+ const { x, y, zoom, selectedNodesCount } = useStore(storeSelector, shallow);
3441
3607
  // if isVisible is not set, we show the toolbar only if its node is selected and no other node is selected
3442
- const isActive = typeof isVisible === 'boolean' ? isVisible : nodes.length === 1 && nodes[0].selected && selectedNodesCount === 1;
3443
- if (!isActive || !nodes.length) {
3608
+ const isActive = typeof isVisible === 'boolean'
3609
+ ? isVisible
3610
+ : nodes.size === 1 && nodes.values().next().value.selected && selectedNodesCount === 1;
3611
+ if (!isActive || !nodes.size) {
3444
3612
  return null;
3445
3613
  }
3446
- const nodeRect = getNodesBounds(nodes, { nodeOrigin });
3447
- const zIndex = Math.max(...nodes.map((node) => (node[internalsSymbol]?.z || 1) + 1));
3614
+ const nodeRect = getInternalNodesBounds(nodes);
3615
+ const nodesArray = Array.from(nodes.values());
3616
+ const zIndex = Math.max(...nodesArray.map((node) => node.internals.z + 1));
3448
3617
  const wrapperStyle = {
3449
3618
  position: 'absolute',
3450
- transform: getNodeToolbarTransform(nodeRect, viewport, position, offset, align),
3619
+ transform: getNodeToolbarTransform(nodeRect, { x, y, zoom }, position, offset, align),
3451
3620
  zIndex,
3452
3621
  ...style,
3453
3622
  };
3454
- 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 }) }));
3623
+ return (jsx(NodeToolbarPortal, { children: jsx("div", { style: wrapperStyle, className: cc(['react-flow__node-toolbar', className]), ...rest, "data-id": nodesArray.reduce((acc, node) => `${acc}${node.id} `, '').trim(), children: children }) }));
3455
3624
  }
3456
3625
 
3457
- export { Background, BackgroundVariant, BaseEdge, BezierEdge, ControlButton, Controls, EdgeLabelRenderer, EdgeText, Handle, MiniMap, NodeResizeControl, NodeResizer, NodeToolbar, Panel, 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 };
3626
+ 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 };