@xyflow/react 12.0.0-next.9 → 12.0.0

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 +4 -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 +985 -818
  148. package/dist/esm/index.mjs +985 -818
  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 +33 -33
  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 +32 -30
  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 +4 -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 +33 -33
  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 +32 -30
  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 +4 -4
  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
+ container.current?.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,55 +1241,55 @@ 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
+ container.current?.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.
@@ -1235,16 +1299,13 @@ function Pane({ isSelecting, selectionMode = SelectionMode.Full, panOnDrag, onSe
1235
1299
  store.setState({ nodesSelectionActive: prevSelectedNodesCount.current > 0 });
1236
1300
  resetUserSelection();
1237
1301
  onSelectionEnd?.(event);
1238
- };
1239
- const onMouseLeave = (event) => {
1240
- if (userSelectionActive) {
1241
- store.setState({ nodesSelectionActive: prevSelectedNodesCount.current > 0 });
1242
- onSelectionEnd?.(event);
1302
+ // If the user kept holding the selectionKey during the selection,
1303
+ // we need to reset the selectionInProgress, so the next click event is not prevented
1304
+ if (selectionKeyPressed) {
1305
+ selectionInProgress.current = false;
1243
1306
  }
1244
- resetUserSelection();
1245
1307
  };
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, {})] }));
1308
+ 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
1309
  }
1249
1310
 
1250
1311
  // this handler is called by
@@ -1278,31 +1339,28 @@ function useDrag({ nodeRef, disabled = false, noDragClassName, handleSelector, n
1278
1339
  const [dragging, setDragging] = useState(false);
1279
1340
  const xyDrag = useRef();
1280
1341
  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
- }
1342
+ xyDrag.current = XYDrag({
1343
+ getStoreItems: () => store.getState(),
1344
+ onNodeMouseDown: (id) => {
1345
+ handleNodeClick({
1346
+ id,
1347
+ store,
1348
+ nodeRef,
1349
+ });
1350
+ },
1351
+ onDragStart: () => {
1352
+ setDragging(true);
1353
+ },
1354
+ onDragStop: () => {
1355
+ setDragging(false);
1356
+ },
1357
+ });
1300
1358
  }, []);
1301
1359
  useEffect(() => {
1302
1360
  if (disabled) {
1303
1361
  xyDrag.current?.destroy();
1304
1362
  }
1305
- else {
1363
+ else if (nodeRef.current) {
1306
1364
  xyDrag.current?.update({
1307
1365
  noDragClassName,
1308
1366
  handleSelector,
@@ -1328,36 +1386,38 @@ const selectedAndDraggable = (nodesDraggable) => (n) => n.selected && (n.draggab
1328
1386
  function useMoveSelectedNodes() {
1329
1387
  const store = useStoreApi();
1330
1388
  const moveSelectedNodes = useCallback((params) => {
1331
- const { nodeExtent, nodes, snapToGrid, snapGrid, nodesDraggable, onError, updateNodePositions, nodeLookup, nodeOrigin, } = store.getState();
1332
- const selectedNodes = nodes.filter(selectedAndDraggable(nodesDraggable));
1389
+ const { nodeExtent, snapToGrid, snapGrid, nodesDraggable, onError, updateNodePositions, nodeLookup, nodeOrigin } = store.getState();
1390
+ const nodeUpdates = new Map();
1391
+ const isSelected = selectedAndDraggable(nodesDraggable);
1333
1392
  // by default a node moves 5px on each key press
1334
1393
  // if snap grid is enabled, we use that for the velocity
1335
1394
  const xVelo = snapToGrid ? snapGrid[0] : 5;
1336
1395
  const yVelo = snapToGrid ? snapGrid[1] : 5;
1337
1396
  const xDiff = params.direction.x * xVelo * params.factor;
1338
1397
  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;
1398
+ for (const [, node] of nodeLookup) {
1399
+ if (!isSelected(node)) {
1400
+ continue;
1358
1401
  }
1359
- return node;
1360
- });
1402
+ let nextPosition = {
1403
+ x: node.internals.positionAbsolute.x + xDiff,
1404
+ y: node.internals.positionAbsolute.y + yDiff,
1405
+ };
1406
+ if (snapToGrid) {
1407
+ nextPosition = snapPosition(nextPosition, snapGrid);
1408
+ }
1409
+ const { position, positionAbsolute } = calculateNodePosition({
1410
+ nodeId: node.id,
1411
+ nextPosition,
1412
+ nodeLookup,
1413
+ nodeExtent,
1414
+ nodeOrigin,
1415
+ onError,
1416
+ });
1417
+ node.position = position;
1418
+ node.internals.positionAbsolute = positionAbsolute;
1419
+ nodeUpdates.set(node.id, node);
1420
+ }
1361
1421
  updateNodePositions(nodeUpdates);
1362
1422
  }, []);
1363
1423
  return moveSelectedNodes;
@@ -1371,26 +1431,33 @@ const useNodeId = () => {
1371
1431
  return nodeId;
1372
1432
  };
1373
1433
 
1374
- const selector$i = (s) => ({
1434
+ const selector$h = (s) => ({
1375
1435
  connectOnClick: s.connectOnClick,
1376
1436
  noPanClassName: s.noPanClassName,
1377
1437
  rfId: s.rfId,
1378
1438
  });
1379
1439
  const connectingSelector = (nodeId, handleId, type) => (state) => {
1380
- const { connectionStartHandle: startHandle, connectionEndHandle: endHandle, connectionClickStartHandle: clickHandle, } = state;
1440
+ const { connectionClickStartHandle: clickHandle, connectionMode, connection } = state;
1441
+ const { fromHandle, toHandle, isValid } = connection;
1442
+ const connectingTo = toHandle?.nodeId === nodeId && toHandle?.id === handleId && toHandle?.type === type;
1381
1443
  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,
1444
+ connectingFrom: fromHandle?.nodeId === nodeId && fromHandle?.id === handleId && fromHandle?.type === type,
1445
+ connectingTo,
1446
+ clickConnecting: clickHandle?.nodeId === nodeId && clickHandle?.id === handleId && clickHandle?.type === type,
1447
+ isPossibleEndHandle: connectionMode === ConnectionMode.Strict
1448
+ ? fromHandle?.type !== type
1449
+ : nodeId !== fromHandle?.nodeId || handleId !== fromHandle?.id,
1450
+ connectionInProcess: !!fromHandle,
1451
+ valid: connectingTo && isValid,
1385
1452
  };
1386
1453
  };
1387
- const HandleComponent = forwardRef(({ type = 'source', position = Position.Top, isValidConnection, isConnectable = true, isConnectableStart = true, isConnectableEnd = true, id, onConnect, children, className, onMouseDown, onTouchStart, ...rest }, ref) => {
1454
+ function HandleComponent({ type = 'source', position = Position.Top, isValidConnection, isConnectable = true, isConnectableStart = true, isConnectableEnd = true, id, onConnect, children, className, onMouseDown, onTouchStart, ...rest }, ref) {
1388
1455
  const handleId = id || null;
1389
1456
  const isTarget = type === 'target';
1390
1457
  const store = useStoreApi();
1391
1458
  const nodeId = useNodeId();
1392
- const { connectOnClick, noPanClassName, rfId } = useStore(selector$i, shallow);
1393
- const { connecting, clickConnecting } = useStore(connectingSelector(nodeId, handleId, type), shallow);
1459
+ const { connectOnClick, noPanClassName, rfId } = useStore(selector$h, shallow);
1460
+ const { connectingFrom, connectingTo, clickConnecting, isPossibleEndHandle, connectionInProcess, valid } = useStore(connectingSelector(nodeId, handleId, type), shallow);
1394
1461
  if (!nodeId) {
1395
1462
  store.getState().onError?.('010', errorMessages['error010']());
1396
1463
  }
@@ -1420,7 +1487,7 @@ const HandleComponent = forwardRef(({ type = 'source', position = Position.Top,
1420
1487
  connectionMode: currentStore.connectionMode,
1421
1488
  connectionRadius: currentStore.connectionRadius,
1422
1489
  domNode: currentStore.domNode,
1423
- nodes: currentStore.nodes,
1490
+ nodeLookup: currentStore.nodeLookup,
1424
1491
  lib: currentStore.lib,
1425
1492
  isTarget,
1426
1493
  handleId,
@@ -1434,6 +1501,8 @@ const HandleComponent = forwardRef(({ type = 'source', position = Position.Top,
1434
1501
  onConnect: onConnectExtended,
1435
1502
  isValidConnection: isValidConnection || currentStore.isValidConnection,
1436
1503
  getTransform: () => store.getState().transform,
1504
+ getFromHandle: () => store.getState().connection.fromHandle,
1505
+ autoPanSpeed: currentStore.autoPanSpeed,
1437
1506
  });
1438
1507
  }
1439
1508
  if (isMouseTriggered) {
@@ -1450,7 +1519,7 @@ const HandleComponent = forwardRef(({ type = 'source', position = Position.Top,
1450
1519
  }
1451
1520
  if (!connectionClickStartHandle) {
1452
1521
  onClickConnectStart?.(event.nativeEvent, { nodeId, handleId, handleType: type });
1453
- store.setState({ connectionClickStartHandle: { nodeId, type, handleId } });
1522
+ store.setState({ connectionClickStartHandle: { nodeId, type, id: handleId } });
1454
1523
  return;
1455
1524
  }
1456
1525
  const doc = getHostForElement(event.target);
@@ -1463,7 +1532,7 @@ const HandleComponent = forwardRef(({ type = 'source', position = Position.Top,
1463
1532
  },
1464
1533
  connectionMode,
1465
1534
  fromNodeId: connectionClickStartHandle.nodeId,
1466
- fromHandleId: connectionClickStartHandle.handleId || null,
1535
+ fromHandleId: connectionClickStartHandle.id || null,
1467
1536
  fromType: connectionClickStartHandle.type,
1468
1537
  isValidConnection: isValidConnectionHandler,
1469
1538
  flowId,
@@ -1488,17 +1557,22 @@ const HandleComponent = forwardRef(({ type = 'source', position = Position.Top,
1488
1557
  connectable: isConnectable,
1489
1558
  connectablestart: isConnectableStart,
1490
1559
  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)),
1560
+ clickconnecting: clickConnecting,
1561
+ connectingfrom: connectingFrom,
1562
+ connectingto: connectingTo,
1563
+ valid,
1564
+ // shows where you can start a connection from
1565
+ // and where you can end it while connecting
1566
+ connectionindicator: isConnectable &&
1567
+ (!connectionInProcess || isPossibleEndHandle) &&
1568
+ (connectionInProcess ? isConnectableEnd : isConnectableStart),
1494
1569
  },
1495
1570
  ]), onMouseDown: onPointerDown, onTouchStart: onPointerDown, onClick: connectOnClick ? onClick : undefined, ref: ref, ...rest, children: children }));
1496
- });
1497
- HandleComponent.displayName = 'Handle';
1571
+ }
1498
1572
  /**
1499
- * The Handle component is the part of a node that can be used to connect nodes.
1573
+ * The Handle component is a UI element that is used to connect nodes.
1500
1574
  */
1501
- const Handle = memo(HandleComponent);
1575
+ const Handle = memo(fixedForwardRef(HandleComponent));
1502
1576
 
1503
1577
  function InputNode({ data, isConnectable, sourcePosition = Position.Bottom }) {
1504
1578
  return (jsxs(Fragment, { children: [data?.label, jsx(Handle, { type: "source", position: sourcePosition, isConnectable: isConnectable })] }));
@@ -1528,20 +1602,33 @@ const builtinNodeTypes = {
1528
1602
  output: OutputNode,
1529
1603
  group: GroupNode,
1530
1604
  };
1605
+ function getNodeInlineStyleDimensions(node) {
1606
+ if (node.internals.handleBounds === undefined) {
1607
+ return {
1608
+ width: node.width ?? node.initialWidth ?? node.style?.width,
1609
+ height: node.height ?? node.initialHeight ?? node.style?.height,
1610
+ };
1611
+ }
1612
+ return {
1613
+ width: node.width ?? node.style?.width,
1614
+ height: node.height ?? node.style?.height,
1615
+ };
1616
+ }
1531
1617
 
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 });
1618
+ const selector$g = (s) => {
1619
+ const { width, height, x, y } = getInternalNodesBounds(s.nodeLookup, {
1620
+ filter: (node) => !!node.selected,
1621
+ });
1535
1622
  return {
1536
- width,
1537
- height,
1623
+ width: isNumeric(width) ? width : null,
1624
+ height: isNumeric(height) ? height : null,
1538
1625
  userSelectionActive: s.userSelectionActive,
1539
1626
  transformString: `translate(${s.transform[0]}px,${s.transform[1]}px) scale(${s.transform[2]}) translate(${x}px,${y}px)`,
1540
1627
  };
1541
1628
  };
1542
- function NodesSelection({ onSelectionContextMenu, noPanClassName, disableKeyboardA11y }) {
1629
+ function NodesSelection({ onSelectionContextMenu, noPanClassName, disableKeyboardA11y, }) {
1543
1630
  const store = useStoreApi();
1544
- const { width, height, transformString, userSelectionActive } = useStore(selector$h, shallow);
1631
+ const { width, height, transformString, userSelectionActive } = useStore(selector$g, shallow);
1545
1632
  const moveSelectedNodes = useMoveSelectedNodes();
1546
1633
  const nodeRef = useRef(null);
1547
1634
  useEffect(() => {
@@ -1579,25 +1666,26 @@ function NodesSelection({ onSelectionContextMenu, noPanClassName, disableKeyboar
1579
1666
  } }) }));
1580
1667
  }
1581
1668
 
1582
- const selector$g = (s) => {
1669
+ const win = typeof window !== 'undefined' ? window : undefined;
1670
+ const selector$f = (s) => {
1583
1671
  return { nodesSelectionActive: s.nodesSelectionActive, userSelectionActive: s.userSelectionActive };
1584
1672
  };
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);
1673
+ 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, }) {
1674
+ const { nodesSelectionActive, userSelectionActive } = useStore(selector$f);
1675
+ const selectionKeyPressed = useKeyPress(selectionKeyCode, { target: win });
1676
+ const panActivationKeyPressed = useKeyPress(panActivationKeyCode, { target: win });
1589
1677
  const panOnDrag = panActivationKeyPressed || _panOnDrag;
1590
1678
  const panOnScroll = panActivationKeyPressed || _panOnScroll;
1591
1679
  const isSelecting = selectionKeyPressed || userSelectionActive || (selectionOnDrag && panOnDrag !== true);
1592
1680
  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
- };
1681
+ 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 }))] }) }));
1682
+ }
1595
1683
  FlowRendererComponent.displayName = 'FlowRenderer';
1596
1684
  const FlowRenderer = memo(FlowRendererComponent);
1597
1685
 
1598
- const selector$f = (onlyRenderVisible) => (s) => {
1686
+ const selector$e = (onlyRenderVisible) => (s) => {
1599
1687
  return onlyRenderVisible
1600
- ? getNodesInside(s.nodes, { x: 0, y: 0, width: s.width, height: s.height }, s.transform, true).map((node) => node.id)
1688
+ ? getNodesInside(s.nodeLookup, { x: 0, y: 0, width: s.width, height: s.height }, s.transform, true).map((node) => node.id)
1601
1689
  : Array.from(s.nodeLookup.keys());
1602
1690
  };
1603
1691
  /**
@@ -1608,55 +1696,97 @@ const selector$f = (onlyRenderVisible) => (s) => {
1608
1696
  * @returns array with visible node ids
1609
1697
  */
1610
1698
  function useVisibleNodeIds(onlyRenderVisible) {
1611
- const nodeIds = useStore(useCallback(selector$f(onlyRenderVisible), [onlyRenderVisible]), shallow);
1699
+ const nodeIds = useStore(useCallback(selector$e(onlyRenderVisible), [onlyRenderVisible]), shallow);
1612
1700
  return nodeIds;
1613
1701
  }
1614
1702
 
1615
- const selector$e = (s) => s.updateNodeDimensions;
1703
+ const selector$d = (s) => s.updateNodeInternals;
1616
1704
  function useResizeObserver() {
1617
- const updateNodeDimensions = useStore(selector$e);
1618
- const resizeObserverRef = useRef();
1619
- const resizeObserver = useMemo(() => {
1705
+ const updateNodeInternals = useStore(selector$d);
1706
+ const [resizeObserver] = useState(() => {
1620
1707
  if (typeof ResizeObserver === 'undefined') {
1621
1708
  return null;
1622
1709
  }
1623
- const observer = new ResizeObserver((entries) => {
1710
+ return new ResizeObserver((entries) => {
1624
1711
  const updates = new Map();
1625
1712
  entries.forEach((entry) => {
1626
1713
  const id = entry.target.getAttribute('data-id');
1627
1714
  updates.set(id, {
1628
1715
  id,
1629
1716
  nodeElement: entry.target,
1630
- forceUpdate: true,
1717
+ force: true,
1631
1718
  });
1632
1719
  });
1633
- updateNodeDimensions(updates);
1720
+ updateNodeInternals(updates);
1634
1721
  });
1635
- resizeObserverRef.current = observer;
1636
- return observer;
1637
- }, []);
1722
+ });
1638
1723
  useEffect(() => {
1639
1724
  return () => {
1640
- resizeObserverRef?.current?.disconnect();
1725
+ resizeObserver?.disconnect();
1641
1726
  };
1642
- }, []);
1727
+ }, [resizeObserver]);
1643
1728
  return resizeObserver;
1644
1729
  }
1645
1730
 
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) => {
1731
+ /**
1732
+ * Hook to handle the resize observation + internal updates for the passed node.
1733
+ *
1734
+ * @internal
1735
+ * @returns nodeRef - reference to the node element
1736
+ */
1737
+ function useNodeObserver({ node, nodeType, hasDimensions, resizeObserver, }) {
1738
+ const store = useStoreApi();
1739
+ const nodeRef = useRef(null);
1740
+ const observedNode = useRef(null);
1741
+ const prevSourcePosition = useRef(node.sourcePosition);
1742
+ const prevTargetPosition = useRef(node.targetPosition);
1743
+ const prevType = useRef(nodeType);
1744
+ const isInitialized = hasDimensions && !!node.internals.handleBounds;
1745
+ useEffect(() => {
1746
+ if (nodeRef.current && !node.hidden && (!isInitialized || observedNode.current !== nodeRef.current)) {
1747
+ if (observedNode.current) {
1748
+ resizeObserver?.unobserve(observedNode.current);
1749
+ }
1750
+ resizeObserver?.observe(nodeRef.current);
1751
+ observedNode.current = nodeRef.current;
1752
+ }
1753
+ }, [isInitialized, node.hidden]);
1754
+ useEffect(() => {
1755
+ return () => {
1756
+ if (observedNode.current) {
1757
+ resizeObserver?.unobserve(observedNode.current);
1758
+ observedNode.current = null;
1759
+ }
1760
+ };
1761
+ }, []);
1762
+ useEffect(() => {
1763
+ if (nodeRef.current) {
1764
+ // when the user programmatically changes the source or handle position, we need to update the internals
1765
+ // to make sure the edges are updated correctly
1766
+ const typeChanged = prevType.current !== nodeType;
1767
+ const sourcePosChanged = prevSourcePosition.current !== node.sourcePosition;
1768
+ const targetPosChanged = prevTargetPosition.current !== node.targetPosition;
1769
+ if (typeChanged || sourcePosChanged || targetPosChanged) {
1770
+ prevType.current = nodeType;
1771
+ prevSourcePosition.current = node.sourcePosition;
1772
+ prevTargetPosition.current = node.targetPosition;
1773
+ store
1774
+ .getState()
1775
+ .updateNodeInternals(new Map([[node.id, { id: node.id, nodeElement: nodeRef.current, force: true }]]));
1776
+ }
1777
+ }
1778
+ }, [node.id, nodeType, node.sourcePosition, node.targetPosition]);
1779
+ return nodeRef;
1780
+ }
1781
+
1782
+ function NodeWrapper({ id, onClick, onMouseEnter, onMouseMove, onMouseLeave, onContextMenu, onDoubleClick, nodesDraggable, elementsSelectable, nodesConnectable, nodesFocusable, resizeObserver, noDragClassName, noPanClassName, disableKeyboardA11y, rfId, nodeTypes, nodeExtent, onError, }) {
1783
+ const { node, internals, isParent } = useStore((s) => {
1648
1784
  const node = s.nodeLookup.get(id);
1649
- const positionAbsolute = nodeExtent
1650
- ? clampPosition(node.computed?.positionAbsolute, nodeExtent)
1651
- : node.computed?.positionAbsolute || { x: 0, y: 0 };
1785
+ const isParent = s.parentLookup.has(id);
1652
1786
  return {
1653
1787
  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,
1788
+ internals: node.internals,
1789
+ isParent,
1660
1790
  };
1661
1791
  }, shallow);
1662
1792
  let nodeType = node.type || 'default';
@@ -1671,51 +1801,8 @@ function NodeWrapper({ id, onClick, onMouseEnter, onMouseMove, onMouseLeave, onC
1671
1801
  const isConnectable = !!(node.connectable || (nodesConnectable && typeof node.connectable === 'undefined'));
1672
1802
  const isFocusable = !!(node.focusable || (nodesFocusable && typeof node.focusable === 'undefined'));
1673
1803
  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]);
1804
+ const hasDimensions = nodeHasDimensions(node);
1805
+ const nodeRef = useNodeObserver({ node, nodeType, hasDimensions, resizeObserver });
1719
1806
  const dragging = useDrag({
1720
1807
  nodeRef,
1721
1808
  disabled: node.hidden || !isDraggable,
@@ -1724,22 +1811,32 @@ function NodeWrapper({ id, onClick, onMouseEnter, onMouseMove, onMouseLeave, onC
1724
1811
  nodeId: id,
1725
1812
  isSelectable,
1726
1813
  });
1814
+ const moveSelectedNodes = useMoveSelectedNodes();
1727
1815
  if (node.hidden) {
1728
1816
  return null;
1729
1817
  }
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
- });
1818
+ const nodeDimensions = getNodeDimensions(node);
1819
+ const inlineDimensions = getNodeInlineStyleDimensions(node);
1820
+ // TODO: clamping should happen earlier
1821
+ const clampedPosition = nodeExtent
1822
+ ? clampPosition(internals.positionAbsolute, nodeExtent)
1823
+ : internals.positionAbsolute;
1737
1824
  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;
1825
+ const onMouseEnterHandler = onMouseEnter
1826
+ ? (event) => onMouseEnter(event, { ...internals.userNode })
1827
+ : undefined;
1828
+ const onMouseMoveHandler = onMouseMove
1829
+ ? (event) => onMouseMove(event, { ...internals.userNode })
1830
+ : undefined;
1831
+ const onMouseLeaveHandler = onMouseLeave
1832
+ ? (event) => onMouseLeave(event, { ...internals.userNode })
1833
+ : undefined;
1834
+ const onContextMenuHandler = onContextMenu
1835
+ ? (event) => onContextMenu(event, { ...internals.userNode })
1836
+ : undefined;
1837
+ const onDoubleClickHandler = onDoubleClick
1838
+ ? (event) => onDoubleClick(event, { ...internals.userNode })
1839
+ : undefined;
1743
1840
  const onSelectNodeHandler = (event) => {
1744
1841
  const { selectNodesOnDrag, nodeDragThreshold } = store.getState();
1745
1842
  if (isSelectable && (!selectNodesOnDrag || !isDraggable || nodeDragThreshold > 0)) {
@@ -1752,11 +1849,11 @@ function NodeWrapper({ id, onClick, onMouseEnter, onMouseMove, onMouseLeave, onC
1752
1849
  });
1753
1850
  }
1754
1851
  if (onClick) {
1755
- onClick(event, { ...node });
1852
+ onClick(event, { ...internals.userNode });
1756
1853
  }
1757
1854
  };
1758
1855
  const onKeyDown = (event) => {
1759
- if (isInputDOMNode(event.nativeEvent)) {
1856
+ if (isInputDOMNode(event.nativeEvent) || disableKeyboardA11y) {
1760
1857
  return;
1761
1858
  }
1762
1859
  if (elementSelectionKeys.includes(event.key) && isSelectable) {
@@ -1768,14 +1865,11 @@ function NodeWrapper({ id, onClick, onMouseEnter, onMouseMove, onMouseLeave, onC
1768
1865
  nodeRef,
1769
1866
  });
1770
1867
  }
1771
- else if (!disableKeyboardA11y &&
1772
- isDraggable &&
1773
- node.selected &&
1774
- Object.prototype.hasOwnProperty.call(arrowKeyDiffs, event.key)) {
1868
+ else if (isDraggable && node.selected && Object.prototype.hasOwnProperty.call(arrowKeyDiffs, event.key)) {
1775
1869
  store.setState({
1776
1870
  ariaLiveMessage: `Moved selected node ${event.key
1777
1871
  .replace('Arrow', '')
1778
- .toLowerCase()}. New position, x: ${~~positionAbsoluteX}, y: ${~~positionAbsoluteY}`,
1872
+ .toLowerCase()}. New position, x: ${~~clampedPosition.x}, y: ${~~clampedPosition.y}`,
1779
1873
  });
1780
1874
  moveSelectedNodes({
1781
1875
  direction: arrowKeyDiffs[event.key],
@@ -1795,28 +1889,28 @@ function NodeWrapper({ id, onClick, onMouseEnter, onMouseMove, onMouseLeave, onC
1795
1889
  selected: node.selected,
1796
1890
  selectable: isSelectable,
1797
1891
  parent: isParent,
1892
+ draggable: isDraggable,
1798
1893
  dragging,
1799
1894
  },
1800
1895
  ]), ref: nodeRef, style: {
1801
- zIndex,
1802
- transform: `translate(${positionAbsoluteOrigin.x}px,${positionAbsoluteOrigin.y}px)`,
1896
+ zIndex: internals.z,
1897
+ transform: `translate(${clampedPosition.x}px,${clampedPosition.y}px)`,
1803
1898
  pointerEvents: hasPointerEvents ? 'all' : 'none',
1804
- visibility: initialized ? 'visible' : 'hidden',
1899
+ visibility: hasDimensions ? 'visible' : 'hidden',
1805
1900
  ...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 }) }) }));
1901
+ ...inlineDimensions,
1902
+ }, "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
1903
  }
1810
1904
 
1811
- const selector$d = (s) => ({
1905
+ const selector$c = (s) => ({
1812
1906
  nodesDraggable: s.nodesDraggable,
1813
1907
  nodesConnectable: s.nodesConnectable,
1814
1908
  nodesFocusable: s.nodesFocusable,
1815
1909
  elementsSelectable: s.elementsSelectable,
1816
1910
  onError: s.onError,
1817
1911
  });
1818
- const NodeRendererComponent = (props) => {
1819
- const { nodesDraggable, nodesConnectable, nodesFocusable, elementsSelectable, onError } = useStore(selector$d, shallow);
1912
+ function NodeRendererComponent(props) {
1913
+ const { nodesDraggable, nodesConnectable, nodesFocusable, elementsSelectable, onError } = useStore(selector$c, shallow);
1820
1914
  const nodeIds = useVisibleNodeIds(props.onlyRenderVisibleElements);
1821
1915
  const resizeObserver = useResizeObserver();
1822
1916
  return (jsx("div", { className: "react-flow__nodes", style: containerStyle, children: nodeIds.map((nodeId) => {
@@ -1844,9 +1938,9 @@ const NodeRendererComponent = (props) => {
1844
1938
  // moved into `NodeComponentWrapper`. This ensures they are
1845
1939
  // memorized – so if `NodeRenderer` *has* to rerender, it only
1846
1940
  // 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));
1941
+ 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
1942
  }) }));
1849
- };
1943
+ }
1850
1944
  NodeRendererComponent.displayName = 'NodeRenderer';
1851
1945
  const NodeRenderer = memo(NodeRendererComponent);
1852
1946
 
@@ -1948,21 +2042,22 @@ var MarkerDefinitions$1 = memo(MarkerDefinitions);
1948
2042
  function EdgeTextComponent({ x, y, label, labelStyle = {}, labelShowBg = true, labelBgStyle = {}, labelBgPadding = [2, 4], labelBgBorderRadius = 2, children, className, ...rest }) {
1949
2043
  const [edgeTextBbox, setEdgeTextBbox] = useState({ x: 1, y: 0, width: 0, height: 0 });
1950
2044
  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
- }, []);
2045
+ const edgeTextRef = useRef(null);
2046
+ useEffect(() => {
2047
+ if (edgeTextRef.current) {
2048
+ const textBbox = edgeTextRef.current.getBBox();
2049
+ setEdgeTextBbox({
2050
+ x: textBbox.x,
2051
+ y: textBbox.y,
2052
+ width: textBbox.width,
2053
+ height: textBbox.height,
2054
+ });
2055
+ }
2056
+ }, [label]);
1962
2057
  if (typeof label === 'undefined' || !label) {
1963
2058
  return null;
1964
2059
  }
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] }));
2060
+ 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
2061
  }
1967
2062
  EdgeTextComponent.displayName = 'EdgeText';
1968
2063
  const EdgeText = memo(EdgeTextComponent);
@@ -2133,25 +2228,25 @@ function EdgeAnchor({ position, centerX, centerY, radius = 10, onMouseDown, onMo
2133
2228
  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
2229
  }
2135
2230
 
2136
- function EdgeUpdateAnchors({ isUpdatable, edgeUpdaterRadius, edge, targetHandleId, sourceHandleId, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, onEdgeUpdate, onEdgeUpdateStart, onEdgeUpdateEnd, setUpdating, setUpdateHover, }) {
2231
+ function EdgeUpdateAnchors({ isReconnectable, reconnectRadius, edge, targetHandleId, sourceHandleId, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, onReconnect, onReconnectStart, onReconnectEnd, setReconnecting, setUpdateHover, }) {
2137
2232
  const store = useStoreApi();
2138
2233
  const handleEdgeUpdater = (event, isSourceHandle) => {
2139
2234
  // avoid triggering edge updater if mouse btn is not left
2140
2235
  if (event.button !== 0) {
2141
2236
  return;
2142
2237
  }
2143
- const { autoPanOnConnect, domNode, isValidConnection, connectionMode, connectionRadius, lib, onConnectStart, onConnectEnd, cancelConnection, nodes, rfId: flowId, panBy, updateConnection, } = store.getState();
2238
+ const { autoPanOnConnect, domNode, isValidConnection, connectionMode, connectionRadius, lib, onConnectStart, onConnectEnd, cancelConnection, nodeLookup, rfId: flowId, panBy, updateConnection, } = store.getState();
2144
2239
  const nodeId = isSourceHandle ? edge.target : edge.source;
2145
2240
  const handleId = (isSourceHandle ? targetHandleId : sourceHandleId) || null;
2146
2241
  const handleType = isSourceHandle ? 'target' : 'source';
2147
2242
  const isTarget = isSourceHandle;
2148
- setUpdating(true);
2149
- onEdgeUpdateStart?.(event, edge, handleType);
2150
- const _onEdgeUpdateEnd = (evt) => {
2151
- setUpdating(false);
2152
- onEdgeUpdateEnd?.(evt, edge, handleType);
2243
+ setReconnecting(true);
2244
+ onReconnectStart?.(event, edge, handleType);
2245
+ const _onReconnectEnd = (evt) => {
2246
+ setReconnecting(false);
2247
+ onReconnectEnd?.(evt, edge, handleType);
2153
2248
  };
2154
- const onConnectEdge = (connection) => onEdgeUpdate?.(edge, connection);
2249
+ const onConnectEdge = (connection) => onReconnect?.(edge, connection);
2155
2250
  XYHandle.onPointerDown(event.nativeEvent, {
2156
2251
  autoPanOnConnect,
2157
2252
  connectionMode,
@@ -2159,7 +2254,7 @@ function EdgeUpdateAnchors({ isUpdatable, edgeUpdaterRadius, edge, targetHandleI
2159
2254
  domNode,
2160
2255
  handleId,
2161
2256
  nodeId,
2162
- nodes,
2257
+ nodeLookup,
2163
2258
  isTarget,
2164
2259
  edgeUpdaterType: handleType,
2165
2260
  lib,
@@ -2170,19 +2265,20 @@ function EdgeUpdateAnchors({ isUpdatable, edgeUpdaterRadius, edge, targetHandleI
2170
2265
  onConnect: onConnectEdge,
2171
2266
  onConnectStart,
2172
2267
  onConnectEnd,
2173
- onEdgeUpdateEnd: _onEdgeUpdateEnd,
2268
+ onReconnectEnd: _onReconnectEnd,
2174
2269
  updateConnection,
2175
2270
  getTransform: () => store.getState().transform,
2271
+ getFromHandle: () => store.getState().connection.fromHandle,
2176
2272
  });
2177
2273
  };
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" }))] }));
2274
+ const onReconnectSourceMouseDown = (event) => handleEdgeUpdater(event, true);
2275
+ const onReconnectTargetMouseDown = (event) => handleEdgeUpdater(event, false);
2276
+ const onReconnectMouseEnter = () => setUpdateHover(true);
2277
+ const onReconnectMouseOut = () => setUpdateHover(false);
2278
+ 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
2279
  }
2184
2280
 
2185
- function EdgeWrapper({ id, edgesFocusable, edgesUpdatable, elementsSelectable, onClick, onDoubleClick, onContextMenu, onMouseEnter, onMouseMove, onMouseLeave, edgeUpdaterRadius, onEdgeUpdate, onEdgeUpdateStart, onEdgeUpdateEnd, rfId, edgeTypes, noPanClassName, onError, }) {
2281
+ function EdgeWrapper({ id, edgesFocusable, edgesReconnectable, elementsSelectable, onClick, onDoubleClick, onContextMenu, onMouseEnter, onMouseMove, onMouseLeave, reconnectRadius, onReconnect, onReconnectStart, onReconnectEnd, rfId, edgeTypes, noPanClassName, onError, disableKeyboardA11y, }) {
2186
2282
  let edge = useStore((s) => s.edgeLookup.get(id));
2187
2283
  const defaultEdgeOptions = useStore((s) => s.defaultEdgeOptions);
2188
2284
  edge = defaultEdgeOptions ? { ...defaultEdgeOptions, ...edge } : edge;
@@ -2194,12 +2290,12 @@ function EdgeWrapper({ id, edgesFocusable, edgesUpdatable, elementsSelectable, o
2194
2290
  EdgeComponent = builtinEdgeTypes.default;
2195
2291
  }
2196
2292
  const isFocusable = !!(edge.focusable || (edgesFocusable && typeof edge.focusable === 'undefined'));
2197
- const isUpdatable = typeof onEdgeUpdate !== 'undefined' &&
2198
- (edge.updatable || (edgesUpdatable && typeof edge.updatable === 'undefined'));
2293
+ const isReconnectable = typeof onReconnect !== 'undefined' &&
2294
+ (edge.reconnectable || (edgesReconnectable && typeof edge.reconnectable === 'undefined'));
2199
2295
  const isSelectable = !!(edge.selectable || (elementsSelectable && typeof edge.selectable === 'undefined'));
2200
2296
  const edgeRef = useRef(null);
2201
2297
  const [updateHover, setUpdateHover] = useState(false);
2202
- const [updating, setUpdating] = useState(false);
2298
+ const [reconnecting, setReconnecting] = useState(false);
2203
2299
  const store = useStoreApi();
2204
2300
  const { zIndex, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition } = useStore(useCallback((store) => {
2205
2301
  const sourceNode = store.nodeLookup.get(edge.source);
@@ -2233,7 +2329,7 @@ function EdgeWrapper({ id, edgesFocusable, edgesUpdatable, elementsSelectable, o
2233
2329
  }, [edge.source, edge.target, edge.sourceHandle, edge.targetHandle, edge.selected, edge.zIndex]), shallow);
2234
2330
  const markerStartUrl = useMemo(() => (edge.markerStart ? `url('#${getMarkerId(edge.markerStart, rfId)}')` : undefined), [edge.markerStart, rfId]);
2235
2331
  const markerEndUrl = useMemo(() => (edge.markerEnd ? `url('#${getMarkerId(edge.markerEnd, rfId)}')` : undefined), [edge.markerEnd, rfId]);
2236
- if (edge.hidden || !sourceX || !sourceY || !targetX || !targetY) {
2332
+ if (edge.hidden || sourceX === null || sourceY === null || targetX === null || targetY === null) {
2237
2333
  return null;
2238
2334
  }
2239
2335
  const onEdgeClick = (event) => {
@@ -2278,7 +2374,7 @@ function EdgeWrapper({ id, edgesFocusable, edgesUpdatable, elementsSelectable, o
2278
2374
  }
2279
2375
  : undefined;
2280
2376
  const onKeyDown = (event) => {
2281
- if (elementSelectionKeys.includes(event.key) && isSelectable) {
2377
+ if (!disableKeyboardA11y && elementSelectionKeys.includes(event.key) && isSelectable) {
2282
2378
  const { unselectNodesAndEdges, addSelectedEdges } = store.getState();
2283
2379
  const unselect = event.key === 'Escape';
2284
2380
  if (unselect) {
@@ -2302,31 +2398,31 @@ function EdgeWrapper({ id, edgesFocusable, edgesUpdatable, elementsSelectable, o
2302
2398
  updating: updateHover,
2303
2399
  selectable: isSelectable,
2304
2400
  },
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 }))] }) }));
2401
+ ]), 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
2402
  }
2307
2403
 
2308
- const selector$c = (s) => ({
2404
+ const selector$b = (s) => ({
2309
2405
  width: s.width,
2310
2406
  height: s.height,
2311
2407
  edgesFocusable: s.edgesFocusable,
2312
- edgesUpdatable: s.edgesUpdatable,
2408
+ edgesReconnectable: s.edgesReconnectable,
2313
2409
  elementsSelectable: s.elementsSelectable,
2314
2410
  connectionMode: s.connectionMode,
2315
2411
  onError: s.onError,
2316
2412
  });
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);
2413
+ function EdgeRendererComponent({ defaultMarkerColor, onlyRenderVisibleElements, rfId, edgeTypes, noPanClassName, onReconnect, onEdgeContextMenu, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, onEdgeClick, reconnectRadius, onEdgeDoubleClick, onReconnectStart, onReconnectEnd, disableKeyboardA11y, }) {
2414
+ const { edgesFocusable, edgesReconnectable, elementsSelectable, onError } = useStore(selector$b, shallow);
2319
2415
  const edgeIds = useVisibleEdgeIds(onlyRenderVisibleElements);
2320
2416
  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));
2417
+ 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
2418
  })] }));
2323
2419
  }
2324
2420
  EdgeRendererComponent.displayName = 'EdgeRenderer';
2325
2421
  const EdgeRenderer = memo(EdgeRendererComponent);
2326
2422
 
2327
- const selector$b = (s) => `translate(${s.transform[0]}px,${s.transform[1]}px) scale(${s.transform[2]})`;
2423
+ const selector$a = (s) => `translate(${s.transform[0]}px,${s.transform[1]}px) scale(${s.transform[2]})`;
2328
2424
  function Viewport({ children }) {
2329
- const transform = useStore(selector$b);
2425
+ const transform = useStore(selector$a);
2330
2426
  return (jsx("div", { className: "react-flow__viewport xyflow__viewport react-flow__container", style: { transform }, children: children }));
2331
2427
  }
2332
2428
 
@@ -2346,7 +2442,7 @@ function useOnInitHandler(onInit) {
2346
2442
  }, [onInit, rfInstance.viewportInitialized]);
2347
2443
  }
2348
2444
 
2349
- const selector$a = (state) => state.panZoom?.syncViewport;
2445
+ const selector$9 = (state) => state.panZoom?.syncViewport;
2350
2446
  /**
2351
2447
  * Hook for syncing the viewport with the panzoom instance.
2352
2448
  *
@@ -2354,7 +2450,7 @@ const selector$a = (state) => state.panZoom?.syncViewport;
2354
2450
  * @param viewport
2355
2451
  */
2356
2452
  function useViewportSync(viewport) {
2357
- const syncViewport = useStore(selector$a);
2453
+ const syncViewport = useStore(selector$9);
2358
2454
  const store = useStoreApi();
2359
2455
  useEffect(() => {
2360
2456
  if (viewport) {
@@ -2365,130 +2461,140 @@ function useViewportSync(viewport) {
2365
2461
  return null;
2366
2462
  }
2367
2463
 
2368
- const oppositePosition = {
2369
- [Position.Left]: Position.Right,
2370
- [Position.Right]: Position.Left,
2371
- [Position.Top]: Position.Bottom,
2372
- [Position.Bottom]: Position.Top,
2464
+ const selector$8 = (s) => {
2465
+ return s.connection.inProgress
2466
+ ? { ...s.connection, to: pointToRendererPoint(s.connection.to, s.transform) }
2467
+ : { ...s.connection };
2373
2468
  };
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) {
2469
+ /**
2470
+ * Hook for accessing the connection state.
2471
+ *
2472
+ * @public
2473
+ * @returns ConnectionState
2474
+ */
2475
+ function useConnection() {
2476
+ return useStore(selector$8, shallow);
2477
+ }
2478
+
2479
+ const selector$7 = (s) => ({
2480
+ nodesConnectable: s.nodesConnectable,
2481
+ isValid: s.connection.isValid,
2482
+ inProgress: s.connection.inProgress,
2483
+ width: s.width,
2484
+ height: s.height,
2485
+ });
2486
+ function ConnectionLineWrapper({ containerStyle, style, type, component }) {
2487
+ const { nodesConnectable, width, height, isValid, inProgress } = useStore(selector$7, shallow);
2488
+ const renderConnection = !!(width && nodesConnectable && inProgress);
2489
+ if (!renderConnection) {
2388
2490
  return null;
2389
2491
  }
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;
2492
+ 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 }) }) }));
2493
+ }
2494
+ const ConnectionLine = ({ style, type = ConnectionLineType.Bezier, CustomComponent, isValid }) => {
2495
+ const { inProgress, from, fromNode, fromHandle, fromPosition, to, toNode, toHandle, toPosition } = useConnection();
2496
+ if (!inProgress) {
2497
+ return;
2399
2498
  }
2400
2499
  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 }));
2500
+ 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
2501
  }
2403
- let dAttr = '';
2502
+ let path = '';
2404
2503
  const pathParams = {
2405
- sourceX: fromX,
2406
- sourceY: fromY,
2504
+ sourceX: from.x,
2505
+ sourceY: from.y,
2407
2506
  sourcePosition: fromPosition,
2408
- targetX: toX,
2409
- targetY: toY,
2507
+ targetX: to.x,
2508
+ targetY: to.y,
2410
2509
  targetPosition: toPosition,
2411
2510
  };
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}`;
2511
+ switch (type) {
2512
+ case ConnectionLineType.Bezier:
2513
+ [path] = getBezierPath(pathParams);
2514
+ break;
2515
+ case ConnectionLineType.SimpleBezier:
2516
+ [path] = getSimpleBezierPath(pathParams);
2517
+ break;
2518
+ case ConnectionLineType.Step:
2519
+ [path] = getSmoothStepPath({
2520
+ ...pathParams,
2521
+ borderRadius: 0,
2522
+ });
2523
+ break;
2524
+ case ConnectionLineType.SmoothStep:
2525
+ [path] = getSmoothStepPath(pathParams);
2526
+ break;
2527
+ default:
2528
+ [path] = getStraightPath(pathParams);
2430
2529
  }
2431
- return jsx("path", { d: dAttr, fill: "none", className: "react-flow__connection-path", style: style });
2530
+ return jsx("path", { d: path, fill: "none", className: "react-flow__connection-path", style: style });
2432
2531
  };
2433
2532
  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
2533
 
2451
2534
  const emptyTypes = {};
2452
2535
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
2453
2536
  function useNodeOrEdgeTypesWarning(nodeOrEdgeTypes = emptyTypes) {
2454
- const updateCount = useRef(0);
2537
+ const typesRef = useRef(nodeOrEdgeTypes);
2455
2538
  const store = useStoreApi();
2456
2539
  useEffect(() => {
2457
2540
  if (process.env.NODE_ENV === 'development') {
2458
- if (updateCount.current > 1) {
2459
- store.getState().onError?.('002', errorMessages['error002']());
2541
+ const usedKeys = new Set([...Object.keys(typesRef.current), ...Object.keys(nodeOrEdgeTypes)]);
2542
+ for (const key of usedKeys) {
2543
+ if (typesRef.current[key] !== nodeOrEdgeTypes[key]) {
2544
+ store.getState().onError?.('002', errorMessages['error002']());
2545
+ break;
2546
+ }
2460
2547
  }
2461
- updateCount.current += 1;
2548
+ typesRef.current = nodeOrEdgeTypes;
2462
2549
  }
2463
2550
  }, [nodeOrEdgeTypes]);
2464
2551
  }
2465
2552
 
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, }) {
2553
+ function useStylesLoadedWarning() {
2554
+ const store = useStoreApi();
2555
+ const checked = useRef(false);
2556
+ useEffect(() => {
2557
+ if (process.env.NODE_ENV === 'development') {
2558
+ if (!checked.current) {
2559
+ const pane = document.querySelector('.react-flow__pane');
2560
+ if (pane && !(window.getComputedStyle(pane).zIndex === '1')) {
2561
+ store.getState().onError?.('013', errorMessages['error013']('react'));
2562
+ }
2563
+ checked.current = true;
2564
+ }
2565
+ }
2566
+ }, []);
2567
+ }
2568
+
2569
+ 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
2570
  useNodeOrEdgeTypesWarning(nodeTypes);
2468
2571
  useNodeOrEdgeTypesWarning(edgeTypes);
2572
+ useStylesLoadedWarning();
2469
2573
  useOnInitHandler(onInit);
2470
2574
  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 })] }) }));
2575
+ 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
2576
  }
2473
2577
  GraphViewComponent.displayName = 'GraphView';
2474
2578
  const GraphView = memo(GraphViewComponent);
2475
2579
 
2476
- const getInitialState = ({ nodes, edges, defaultNodes, defaultEdges, width, height, fitView, } = {}) => {
2580
+ const getInitialState = ({ nodes, edges, defaultNodes, defaultEdges, width, height, fitView, nodeOrigin, } = {}) => {
2477
2581
  const nodeLookup = new Map();
2582
+ const parentLookup = new Map();
2478
2583
  const connectionLookup = new Map();
2479
2584
  const edgeLookup = new Map();
2480
2585
  const storeEdges = defaultEdges ?? edges ?? [];
2481
2586
  const storeNodes = defaultNodes ?? nodes ?? [];
2587
+ const storeNodeOrigin = nodeOrigin ?? [0, 0];
2482
2588
  updateConnectionLookup(connectionLookup, edgeLookup, storeEdges);
2483
- const nextNodes = adoptUserProvidedNodes(storeNodes, nodeLookup, {
2484
- nodeOrigin: [0, 0],
2589
+ adoptUserNodes(storeNodes, nodeLookup, parentLookup, {
2590
+ nodeOrigin: storeNodeOrigin,
2485
2591
  elevateNodesOnSelect: false,
2486
2592
  });
2487
2593
  let transform = [0, 0, 1];
2488
2594
  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] });
2595
+ const bounds = getInternalNodesBounds(nodeLookup, {
2596
+ filter: (node) => !!((node.width || node.initialWidth) && (node.height || node.initialHeight)),
2597
+ });
2492
2598
  const { x, y, zoom } = getViewportForBounds(bounds, width, height, 0.5, 2, 0.1);
2493
2599
  transform = [x, y, zoom];
2494
2600
  }
@@ -2497,8 +2603,9 @@ const getInitialState = ({ nodes, edges, defaultNodes, defaultEdges, width, heig
2497
2603
  width: 0,
2498
2604
  height: 0,
2499
2605
  transform,
2500
- nodes: nextNodes,
2606
+ nodes: storeNodes,
2501
2607
  nodeLookup,
2608
+ parentLookup,
2502
2609
  edges: storeEdges,
2503
2610
  edgeLookup,
2504
2611
  connectionLookup,
@@ -2514,13 +2621,11 @@ const getInitialState = ({ nodes, edges, defaultNodes, defaultEdges, width, heig
2514
2621
  nodesSelectionActive: false,
2515
2622
  userSelectionActive: false,
2516
2623
  userSelectionRect: null,
2517
- connectionPosition: { x: 0, y: 0 },
2518
- connectionStatus: null,
2519
2624
  connectionMode: ConnectionMode.Strict,
2520
2625
  domNode: null,
2521
2626
  paneDragging: false,
2522
2627
  noPanClassName: 'nopan',
2523
- nodeOrigin: [0, 0],
2628
+ nodeOrigin: storeNodeOrigin,
2524
2629
  nodeDragThreshold: 1,
2525
2630
  snapGrid: [15, 15],
2526
2631
  snapToGrid: false,
@@ -2528,7 +2633,7 @@ const getInitialState = ({ nodes, edges, defaultNodes, defaultEdges, width, heig
2528
2633
  nodesConnectable: true,
2529
2634
  nodesFocusable: true,
2530
2635
  edgesFocusable: true,
2531
- edgesUpdatable: true,
2636
+ edgesReconnectable: true,
2532
2637
  elementsSelectable: true,
2533
2638
  elevateNodesOnSelect: true,
2534
2639
  elevateEdgesOnSelect: false,
@@ -2537,33 +2642,34 @@ const getInitialState = ({ nodes, edges, defaultNodes, defaultEdges, width, heig
2537
2642
  fitViewOnInitOptions: undefined,
2538
2643
  selectNodesOnDrag: true,
2539
2644
  multiSelectionActive: false,
2540
- connectionStartHandle: null,
2541
- connectionEndHandle: null,
2645
+ connection: { ...initialConnection },
2542
2646
  connectionClickStartHandle: null,
2543
2647
  connectOnClick: true,
2544
2648
  ariaLiveMessage: '',
2545
2649
  autoPanOnConnect: true,
2546
2650
  autoPanOnNodeDrag: true,
2651
+ autoPanSpeed: 15,
2547
2652
  connectionRadius: 20,
2548
2653
  onError: devWarn,
2549
2654
  isValidConnection: undefined,
2550
2655
  onSelectionChangeHandlers: [],
2551
2656
  lib: 'react',
2657
+ debug: false,
2552
2658
  };
2553
2659
  };
2554
2660
 
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 }),
2661
+ const createStore = ({ nodes, edges, defaultNodes, defaultEdges, width, height, fitView: fitView$1, nodeOrigin, }) => createWithEqualityFn((set, get) => ({
2662
+ ...getInitialState({ nodes, edges, width, height, fitView: fitView$1, nodeOrigin, defaultNodes, defaultEdges }),
2557
2663
  setNodes: (nodes) => {
2558
- const { nodeLookup, nodeOrigin, elevateNodesOnSelect } = get();
2664
+ const { nodeLookup, parentLookup, nodeOrigin, elevateNodesOnSelect } = get();
2559
2665
  // setNodes() is called exclusively in response to user actions:
2560
2666
  // - either when the `<ReactFlow nodes>` prop is updated in the controlled ReactFlow setup,
2561
2667
  // - or when the user calls something like `reactFlowInstance.setNodes()` in an uncontrolled ReactFlow setup.
2562
2668
  //
2563
2669
  // When this happens, we take the note objects passed by the user and extend them with fields
2564
2670
  // relevant for internal React Flow operations.
2565
- const nodesWithInternalData = adoptUserProvidedNodes(nodes, nodeLookup, { nodeOrigin, elevateNodesOnSelect });
2566
- set({ nodes: nodesWithInternalData });
2671
+ adoptUserNodes(nodes, nodeLookup, parentLookup, { nodeOrigin, elevateNodesOnSelect, checkEquality: true });
2672
+ set({ nodes });
2567
2673
  },
2568
2674
  setEdges: (edges) => {
2569
2675
  const { connectionLookup, edgeLookup } = get();
@@ -2585,26 +2691,19 @@ const createRFStore = ({ nodes, edges, defaultNodes, defaultEdges, width, height
2585
2691
  // Every node gets registerd at a ResizeObserver. Whenever a node
2586
2692
  // changes its dimensions, this function is called to measure the
2587
2693
  // 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) {
2694
+ updateNodeInternals: (updates) => {
2695
+ const { triggerNodeChanges, nodeLookup, parentLookup, fitViewOnInit, fitViewDone, fitViewOnInitOptions, domNode, nodeOrigin, debug, fitViewSync, } = get();
2696
+ const { changes, updatedInternals } = updateNodeInternals(updates, nodeLookup, parentLookup, domNode, nodeOrigin);
2697
+ if (!updatedInternals) {
2599
2698
  return;
2600
2699
  }
2601
- const nextNodes = updateAbsolutePositions(updatedNodes, nodeLookup, nodeOrigin);
2700
+ updateAbsolutePositions(nodeLookup, parentLookup, { nodeOrigin });
2602
2701
  // we call fitView once initially after all dimensions are set
2603
2702
  let nextFitViewDone = fitViewDone;
2604
2703
  if (!fitViewDone && fitViewOnInit) {
2605
- nextFitViewDone = fitView(nextNodes, {
2704
+ nextFitViewDone = fitViewSync({
2606
2705
  ...fitViewOnInitOptions,
2607
- nodes: fitViewOnInitOptions?.nodes || nextNodes,
2706
+ nodes: fitViewOnInitOptions?.nodes,
2608
2707
  });
2609
2708
  }
2610
2709
  // here we are cirmumventing the onNodesChange handler
@@ -2612,63 +2711,91 @@ const createRFStore = ({ nodes, edges, defaultNodes, defaultEdges, width, height
2612
2711
  // has not provided an onNodesChange handler.
2613
2712
  // Nodes are only rendered if they have a width and height
2614
2713
  // attribute which they get from this handler.
2615
- set({ nodes: nextNodes, fitViewDone: nextFitViewDone });
2714
+ set({ fitViewDone: nextFitViewDone });
2616
2715
  if (changes?.length > 0) {
2617
- onNodesChange?.(changes);
2716
+ if (debug) {
2717
+ console.log('React Flow: trigger node changes', changes);
2718
+ }
2719
+ triggerNodeChanges?.(changes);
2618
2720
  }
2619
2721
  },
2620
2722
  updateNodePositions: (nodeDragItems, dragging = false) => {
2621
- const changes = nodeDragItems.map((node) => {
2723
+ const parentExpandChildren = [];
2724
+ const changes = [];
2725
+ for (const [id, dragItem] of nodeDragItems) {
2622
2726
  const change = {
2623
- id: node.id,
2727
+ id,
2624
2728
  type: 'position',
2625
- position: node.position,
2626
- positionAbsolute: node.computed?.positionAbsolute,
2729
+ position: dragItem.position,
2627
2730
  dragging,
2628
2731
  };
2629
- return change;
2630
- });
2732
+ if (dragItem?.expandParent && dragItem?.parentId && change.position) {
2733
+ parentExpandChildren.push({
2734
+ id,
2735
+ parentId: dragItem.parentId,
2736
+ rect: {
2737
+ ...dragItem.internals.positionAbsolute,
2738
+ width: dragItem.measured.width,
2739
+ height: dragItem.measured.height,
2740
+ },
2741
+ });
2742
+ change.position.x = Math.max(0, change.position.x);
2743
+ change.position.y = Math.max(0, change.position.y);
2744
+ }
2745
+ changes.push(change);
2746
+ }
2747
+ if (parentExpandChildren.length > 0) {
2748
+ const { nodeLookup, parentLookup, nodeOrigin } = get();
2749
+ const parentExpandChanges = handleExpandParent(parentExpandChildren, nodeLookup, parentLookup, nodeOrigin);
2750
+ changes.push(...parentExpandChanges);
2751
+ }
2631
2752
  get().triggerNodeChanges(changes);
2632
2753
  },
2633
2754
  triggerNodeChanges: (changes) => {
2634
- const { onNodesChange, setNodes, nodes, hasDefaultNodes } = get();
2755
+ const { onNodesChange, setNodes, nodes, hasDefaultNodes, debug } = get();
2635
2756
  if (changes?.length) {
2636
2757
  if (hasDefaultNodes) {
2637
2758
  const updatedNodes = applyNodeChanges(changes, nodes);
2638
2759
  setNodes(updatedNodes);
2639
2760
  }
2761
+ if (debug) {
2762
+ console.log('React Flow: trigger node changes', changes);
2763
+ }
2640
2764
  onNodesChange?.(changes);
2641
2765
  }
2642
2766
  },
2643
2767
  triggerEdgeChanges: (changes) => {
2644
- const { onEdgesChange, setEdges, edges, hasDefaultEdges } = get();
2768
+ const { onEdgesChange, setEdges, edges, hasDefaultEdges, debug } = get();
2645
2769
  if (changes?.length) {
2646
2770
  if (hasDefaultEdges) {
2647
2771
  const updatedEdges = applyEdgeChanges(changes, edges);
2648
2772
  setEdges(updatedEdges);
2649
2773
  }
2774
+ if (debug) {
2775
+ console.log('React Flow: trigger edge changes', changes);
2776
+ }
2650
2777
  onEdgesChange?.(changes);
2651
2778
  }
2652
2779
  },
2653
2780
  addSelectedNodes: (selectedNodeIds) => {
2654
- const { multiSelectionActive, edges, nodes, triggerNodeChanges, triggerEdgeChanges } = get();
2781
+ const { multiSelectionActive, edgeLookup, nodeLookup, triggerNodeChanges, triggerEdgeChanges } = get();
2655
2782
  if (multiSelectionActive) {
2656
2783
  const nodeChanges = selectedNodeIds.map((nodeId) => createSelectionChange(nodeId, true));
2657
2784
  triggerNodeChanges(nodeChanges);
2658
2785
  return;
2659
2786
  }
2660
- triggerNodeChanges(getSelectionChanges(nodes, new Set([...selectedNodeIds]), true));
2661
- triggerEdgeChanges(getSelectionChanges(edges));
2787
+ triggerNodeChanges(getSelectionChanges(nodeLookup, new Set([...selectedNodeIds]), true));
2788
+ triggerEdgeChanges(getSelectionChanges(edgeLookup));
2662
2789
  },
2663
2790
  addSelectedEdges: (selectedEdgeIds) => {
2664
- const { multiSelectionActive, edges, nodes, triggerNodeChanges, triggerEdgeChanges } = get();
2791
+ const { multiSelectionActive, edgeLookup, nodeLookup, triggerNodeChanges, triggerEdgeChanges } = get();
2665
2792
  if (multiSelectionActive) {
2666
2793
  const changedEdges = selectedEdgeIds.map((edgeId) => createSelectionChange(edgeId, true));
2667
2794
  triggerEdgeChanges(changedEdges);
2668
2795
  return;
2669
2796
  }
2670
- triggerEdgeChanges(getSelectionChanges(edges, new Set([...selectedEdgeIds])));
2671
- triggerNodeChanges(getSelectionChanges(nodes, new Set(), true));
2797
+ triggerEdgeChanges(getSelectionChanges(edgeLookup, new Set([...selectedEdgeIds])));
2798
+ triggerNodeChanges(getSelectionChanges(nodeLookup, new Set(), true));
2672
2799
  },
2673
2800
  unselectNodesAndEdges: ({ nodes, edges } = {}) => {
2674
2801
  const { edges: storeEdges, nodes: storeNodes, triggerNodeChanges, triggerEdgeChanges } = get();
@@ -2696,6 +2823,9 @@ const createRFStore = ({ nodes, edges, defaultNodes, defaultEdges, width, height
2696
2823
  get().panZoom?.setTranslateExtent(translateExtent);
2697
2824
  set({ translateExtent });
2698
2825
  },
2826
+ setPaneClickDistance: (clickDistance) => {
2827
+ get().panZoom?.setClickDistance(clickDistance);
2828
+ },
2699
2829
  resetSelectedElements: () => {
2700
2830
  const { edges, nodes, triggerNodeChanges, triggerEdgeChanges } = get();
2701
2831
  const nodeChanges = nodes.reduce((res, node) => (node.selected ? [...res, createSelectionChange(node.id, false)] : res), []);
@@ -2704,82 +2834,91 @@ const createRFStore = ({ nodes, edges, defaultNodes, defaultEdges, width, height
2704
2834
  triggerEdgeChanges(edgeChanges);
2705
2835
  },
2706
2836
  setNodeExtent: (nodeExtent) => {
2707
- const { nodes } = get();
2837
+ const { nodeLookup } = get();
2838
+ for (const [, node] of nodeLookup) {
2839
+ const positionAbsolute = clampPosition(node.position, nodeExtent);
2840
+ nodeLookup.set(node.id, {
2841
+ ...node,
2842
+ internals: {
2843
+ ...node.internals,
2844
+ positionAbsolute,
2845
+ },
2846
+ });
2847
+ }
2708
2848
  set({
2709
2849
  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
2850
  });
2721
2851
  },
2722
2852
  panBy: (delta) => {
2723
2853
  const { transform, width, height, panZoom, translateExtent } = get();
2724
2854
  return panBy({ delta, panZoom, transform, translateExtent, width, height });
2725
2855
  },
2726
- fitView: (nodes, options) => {
2727
- const { panZoom, width, height, minZoom, maxZoom, nodeOrigin } = get();
2856
+ fitView: (options) => {
2857
+ const { panZoom, width, height, minZoom, maxZoom, nodeLookup } = get();
2728
2858
  if (!panZoom) {
2729
- return false;
2859
+ return Promise.resolve(false);
2730
2860
  }
2861
+ const fitViewNodes = getFitViewNodes(nodeLookup, options);
2731
2862
  return fitView({
2732
- nodes,
2863
+ nodes: fitViewNodes,
2733
2864
  width,
2734
2865
  height,
2735
2866
  panZoom,
2736
2867
  minZoom,
2737
2868
  maxZoom,
2738
- nodeOrigin,
2739
2869
  }, options);
2740
2870
  },
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);
2871
+ // we can't call an asnychronous function in updateNodeInternals
2872
+ // for that we created this sync version of fitView
2873
+ fitViewSync: (options) => {
2874
+ const { panZoom, width, height, minZoom, maxZoom, nodeLookup } = get();
2875
+ if (!panZoom) {
2876
+ return false;
2877
+ }
2878
+ const fitViewNodes = getFitViewNodes(nodeLookup, options);
2879
+ fitView({
2880
+ nodes: fitViewNodes,
2881
+ width,
2882
+ height,
2883
+ panZoom,
2884
+ minZoom,
2885
+ maxZoom,
2886
+ }, options);
2887
+ return fitViewNodes.size > 0;
2888
+ },
2889
+ cancelConnection: () => {
2890
+ set({
2891
+ connection: { ...initialConnection },
2892
+ });
2893
+ },
2894
+ updateConnection: (connection) => {
2895
+ set({ connection });
2755
2896
  },
2756
2897
  reset: () => set({ ...getInitialState() }),
2757
2898
  }), Object.is);
2758
2899
 
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 });
2900
+ function ReactFlowProvider({ initialNodes: nodes, initialEdges: edges, defaultNodes, defaultEdges, initialWidth: width, initialHeight: height, fitView, nodeOrigin, children, }) {
2901
+ const [store] = useState(() => createStore({
2902
+ nodes,
2903
+ edges,
2904
+ defaultNodes,
2905
+ defaultEdges,
2906
+ width,
2907
+ height,
2908
+ fitView,
2909
+ nodeOrigin,
2910
+ }));
2911
+ return (jsx(Provider$1, { value: store, children: jsx(BatchProvider, { children: children }) }));
2773
2912
  }
2774
2913
 
2775
- function Wrapper({ children, nodes, edges, defaultNodes, defaultEdges, width, height, fitView, }) {
2914
+ function Wrapper({ children, nodes, edges, defaultNodes, defaultEdges, width, height, fitView, nodeOrigin, }) {
2776
2915
  const isWrapped = useContext(StoreContext);
2777
2916
  if (isWrapped) {
2778
2917
  // we need to wrap it with a fragment because it's not allowed for children to be a ReactNode
2779
2918
  // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18051
2780
2919
  return jsx(Fragment, { children: children });
2781
2920
  }
2782
- return (jsx(ReactFlowProvider, { initialNodes: nodes, initialEdges: edges, defaultNodes: defaultNodes, defaultEdges: defaultEdges, initialWidth: width, initialHeight: height, fitView: fitView, children: children }));
2921
+ return (jsx(ReactFlowProvider, { initialNodes: nodes, initialEdges: edges, defaultNodes: defaultNodes, defaultEdges: defaultEdges, initialWidth: width, initialHeight: height, fitView: fitView, nodeOrigin: nodeOrigin, children: children }));
2783
2922
  }
2784
2923
 
2785
2924
  const wrapperStyle = {
@@ -2789,25 +2928,25 @@ const wrapperStyle = {
2789
2928
  position: 'relative',
2790
2929
  zIndex: 0,
2791
2930
  };
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) => {
2931
+ 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
2932
  const rfId = id || '1';
2794
2933
  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';
2934
+ 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 })] }) }));
2935
+ }
2936
+ var index = fixedForwardRef(ReactFlow);
2798
2937
 
2799
- const selector$8 = (s) => s.domNode?.querySelector('.react-flow__edgelabel-renderer');
2938
+ const selector$6 = (s) => s.domNode?.querySelector('.react-flow__edgelabel-renderer');
2800
2939
  function EdgeLabelRenderer({ children }) {
2801
- const edgeLabelRenderer = useStore(selector$8);
2940
+ const edgeLabelRenderer = useStore(selector$6);
2802
2941
  if (!edgeLabelRenderer) {
2803
2942
  return null;
2804
2943
  }
2805
2944
  return createPortal(children, edgeLabelRenderer);
2806
2945
  }
2807
2946
 
2808
- const selector$7 = (s) => s.domNode?.querySelector('.react-flow__viewport-portal');
2947
+ const selector$5 = (s) => s.domNode?.querySelector('.react-flow__viewport-portal');
2809
2948
  function ViewportPortal({ children }) {
2810
- const viewPortalDiv = useStore(selector$7);
2949
+ const viewPortalDiv = useStore(selector$5);
2811
2950
  if (!viewPortalDiv) {
2812
2951
  return null;
2813
2952
  }
@@ -2823,16 +2962,16 @@ function ViewportPortal({ children }) {
2823
2962
  function useUpdateNodeInternals() {
2824
2963
  const store = useStoreApi();
2825
2964
  return useCallback((id) => {
2826
- const { domNode, updateNodeDimensions } = store.getState();
2965
+ const { domNode, updateNodeInternals } = store.getState();
2827
2966
  const updateIds = Array.isArray(id) ? id : [id];
2828
2967
  const updates = new Map();
2829
2968
  updateIds.forEach((updateId) => {
2830
2969
  const nodeElement = domNode?.querySelector(`.react-flow__node[data-id="${updateId}"]`);
2831
2970
  if (nodeElement) {
2832
- updates.set(updateId, { id: updateId, nodeElement, forceUpdate: true });
2971
+ updates.set(updateId, { id: updateId, nodeElement, force: true });
2833
2972
  }
2834
2973
  });
2835
- requestAnimationFrame(() => updateNodeDimensions(updates));
2974
+ requestAnimationFrame(() => updateNodeInternals(updates));
2836
2975
  }, []);
2837
2976
  }
2838
2977
 
@@ -2940,13 +3079,13 @@ function useOnSelectionChange({ onChange }) {
2940
3079
  }, [onChange]);
2941
3080
  }
2942
3081
 
2943
- const selector$6 = (options) => (s) => {
2944
- if (s.nodes.length === 0) {
3082
+ const selector$4 = (options) => (s) => {
3083
+ if (s.nodeLookup.size === 0) {
2945
3084
  return false;
2946
3085
  }
2947
- for (const node of s.nodes) {
2948
- if (options.includeHiddenNodes || !node.hidden) {
2949
- if (node[internalsSymbol]?.handleBounds === undefined) {
3086
+ for (const [, { hidden, internals }] of s.nodeLookup) {
3087
+ if (options.includeHiddenNodes || !hidden) {
3088
+ if (internals.handleBounds === undefined || !nodeHasDimensions(internals.userNode)) {
2950
3089
  return false;
2951
3090
  }
2952
3091
  }
@@ -2964,7 +3103,7 @@ const defaultOptions = {
2964
3103
  * @returns boolean indicating whether all nodes are initialized
2965
3104
  */
2966
3105
  function useNodesInitialized(options = defaultOptions) {
2967
- const initialized = useStore(selector$6(options));
3106
+ const initialized = useStore(selector$4(options));
2968
3107
  return initialized;
2969
3108
  }
2970
3109
 
@@ -2999,36 +3138,34 @@ function useHandleConnections({ type, id = null, nodeId, onConnect, onDisconnect
2999
3138
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
3000
3139
  function useNodesData(nodeIds) {
3001
3140
  const nodesData = useStore(useCallback((s) => {
3002
- if (!Array.isArray(nodeIds)) {
3003
- return s.nodeLookup.get(nodeIds)?.data || null;
3004
- }
3005
3141
  const data = [];
3006
- for (const nodeId of nodeIds) {
3007
- const nodeData = s.nodeLookup.get(nodeId)?.data;
3008
- if (nodeData) {
3009
- data.push(nodeData);
3142
+ const isArrayOfIds = Array.isArray(nodeIds);
3143
+ const _nodeIds = isArrayOfIds ? nodeIds : [nodeIds];
3144
+ for (const nodeId of _nodeIds) {
3145
+ const node = s.nodeLookup.get(nodeId);
3146
+ if (node) {
3147
+ data.push({
3148
+ id: node.id,
3149
+ type: node.type,
3150
+ data: node.data,
3151
+ });
3010
3152
  }
3011
3153
  }
3012
- return data;
3013
- }, [nodeIds]), shallow);
3154
+ return isArrayOfIds ? data : data[0] ?? null;
3155
+ }, [nodeIds]), shallowNodeData);
3014
3156
  return nodesData;
3015
3157
  }
3016
3158
 
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
3159
  /**
3024
- * Hook for accessing the ongoing connection.
3160
+ * Hook for getting an internal node by id
3025
3161
  *
3026
3162
  * @public
3027
- * @returns ongoing connection
3163
+ * @param id - id of the node
3164
+ * @returns array with visible node ids
3028
3165
  */
3029
- function useConnection() {
3030
- const ongoingConnection = useStore(selector$5, shallow);
3031
- return ongoingConnection;
3166
+ function useInternalNode(id) {
3167
+ const node = useStore(useCallback((s) => s.nodeLookup.get(id), [id]), shallow);
3168
+ return node;
3032
3169
  }
3033
3170
 
3034
3171
  function LinePattern({ dimensions, lineWidth, variant, className }) {
@@ -3050,14 +3187,14 @@ const defaultSize = {
3050
3187
  [BackgroundVariant.Lines]: 1,
3051
3188
  [BackgroundVariant.Cross]: 6,
3052
3189
  };
3053
- const selector$4 = (s) => ({ transform: s.transform, patternId: `pattern-${s.rfId}` });
3190
+ const selector$3 = (s) => ({ transform: s.transform, patternId: `pattern-${s.rfId}` });
3054
3191
  function BackgroundComponent({ id, variant = BackgroundVariant.Dots,
3055
3192
  // only used for dots and cross
3056
3193
  gap = 20,
3057
3194
  // only used for lines and cross
3058
3195
  size, lineWidth = 1, offset = 2, color, bgColor, style, className, patternClassName, }) {
3059
3196
  const ref = useRef(null);
3060
- const { transform, patternId } = useStore(selector$4, shallow);
3197
+ const { transform, patternId } = useStore(selector$3, shallow);
3061
3198
  const patternSize = size || defaultSize[variant];
3062
3199
  const isDots = variant === BackgroundVariant.Dots;
3063
3200
  const isCross = variant === BackgroundVariant.Cross;
@@ -3103,14 +3240,14 @@ function ControlButton({ children, className, ...rest }) {
3103
3240
  return (jsx("button", { type: "button", className: cc(['react-flow__controls-button', className]), ...rest, children: children }));
3104
3241
  }
3105
3242
 
3106
- const selector$3 = (s) => ({
3243
+ const selector$2 = (s) => ({
3107
3244
  isInteractive: s.nodesDraggable || s.nodesConnectable || s.elementsSelectable,
3108
3245
  minZoomReached: s.transform[2] <= s.minZoom,
3109
3246
  maxZoomReached: s.transform[2] >= s.maxZoom,
3110
3247
  });
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', }) {
3248
+ 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
3249
  const store = useStoreApi();
3113
- const { isInteractive, minZoomReached, maxZoomReached } = useStore(selector$3, shallow);
3250
+ const { isInteractive, minZoomReached, maxZoomReached } = useStore(selector$2, shallow);
3114
3251
  const { zoomIn, zoomOut, fitView } = useReactFlow();
3115
3252
  const onZoomInHandler = () => {
3116
3253
  zoomIn();
@@ -3132,7 +3269,8 @@ function ControlsComponent({ style, showZoom = true, showFitView = true, showInt
3132
3269
  });
3133
3270
  onInteractiveChange?.(!isInteractive);
3134
3271
  };
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] }));
3272
+ const orientationClass = orientation === 'horizontal' ? 'horizontal' : 'vertical';
3273
+ 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
3274
  }
3137
3275
  ControlsComponent.displayName = 'Controls';
3138
3276
  const Controls = memo(ControlsComponent);
@@ -3148,15 +3286,13 @@ function MiniMapNodeComponent({ id, x, y, width, height, style, color, strokeCol
3148
3286
  }
3149
3287
  const MiniMapNode = memo(MiniMapNodeComponent);
3150
3288
 
3151
- const selector$2 = (s) => s.nodeOrigin;
3152
3289
  const selectorNodeIds = (s) => s.nodes.map((node) => node.id);
3153
- const getAttrFunction = (func) => (func instanceof Function ? func : () => func);
3290
+ const getAttrFunction = (func) => func instanceof Function ? func : () => func;
3154
3291
  function MiniMapNodes({ nodeStrokeColor, nodeColor, nodeClassName = '', nodeBorderRadius = 5, nodeStrokeWidth,
3155
3292
  // We need to rename the prop to be `CapitalCase` so that JSX will render it as
3156
3293
  // a component properly.
3157
3294
  nodeComponent: NodeComponent = MiniMapNode, onClick, }) {
3158
3295
  const nodeIds = useStore(selectorNodeIds, shallow);
3159
- const nodeOrigin = useStore(selector$2);
3160
3296
  const nodeColorFunc = getAttrFunction(nodeColor);
3161
3297
  const nodeStrokeColorFunc = getAttrFunction(nodeStrokeColor);
3162
3298
  const nodeClassNameFunc = getAttrFunction(nodeClassName);
@@ -3167,23 +3303,25 @@ nodeComponent: NodeComponent = MiniMapNode, onClick, }) {
3167
3303
  // minimize the cost of updates when individual nodes change.
3168
3304
  //
3169
3305
  // 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))) }));
3306
+ jsx(NodeComponentWrapper, { id: nodeId, nodeColorFunc: nodeColorFunc, nodeStrokeColorFunc: nodeStrokeColorFunc, nodeClassNameFunc: nodeClassNameFunc, nodeBorderRadius: nodeBorderRadius, nodeStrokeWidth: nodeStrokeWidth, NodeComponent: NodeComponent, onClick: onClick, shapeRendering: shapeRendering }, nodeId))) }));
3171
3307
  }
3172
- const NodeComponentWrapper = memo(function NodeComponentWrapper({ id, nodeOrigin, nodeColorFunc, nodeStrokeColorFunc, nodeClassNameFunc, nodeBorderRadius, nodeStrokeWidth, shapeRendering, NodeComponent, onClick, }) {
3308
+ function NodeComponentWrapperInner({ id, nodeColorFunc, nodeStrokeColorFunc, nodeClassNameFunc, nodeBorderRadius, nodeStrokeWidth, shapeRendering, NodeComponent, onClick, }) {
3173
3309
  const { node, x, y } = useStore((s) => {
3174
3310
  const node = s.nodeLookup.get(id);
3175
- const { x, y } = getNodePositionWithOrigin(node, node?.origin || nodeOrigin).positionAbsolute;
3311
+ const { x, y } = node.internals.positionAbsolute;
3176
3312
  return {
3177
3313
  node,
3178
3314
  x,
3179
3315
  y,
3180
3316
  };
3181
3317
  }, shallow);
3182
- if (!node || node.hidden || !(node.computed?.width || node.width) || !(node.computed?.height || node.height)) {
3318
+ if (!node || node.hidden || !nodeHasDimensions(node)) {
3183
3319
  return null;
3184
3320
  }
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
- });
3321
+ const { width, height } = getNodeDimensions(node);
3322
+ 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 }));
3323
+ }
3324
+ const NodeComponentWrapper = memo(NodeComponentWrapperInner);
3187
3325
  var MiniMapNodes$1 = memo(MiniMapNodes);
3188
3326
 
3189
3327
  const defaultWidth = 200;
@@ -3197,9 +3335,8 @@ const selector$1 = (s) => {
3197
3335
  };
3198
3336
  return {
3199
3337
  viewBB,
3200
- boundingRect: s.nodes.length > 0 ? getBoundsOfRects(getNodesBounds(s.nodes, { nodeOrigin: s.nodeOrigin }), viewBB) : viewBB,
3338
+ boundingRect: s.nodeLookup.size > 0 ? getBoundsOfRects(getInternalNodesBounds(s.nodeLookup), viewBB) : viewBB,
3201
3339
  rfId: s.rfId,
3202
- nodeOrigin: s.nodeOrigin,
3203
3340
  panZoom: s.panZoom,
3204
3341
  translateExtent: s.translateExtent,
3205
3342
  flowWidth: s.width,
@@ -3298,33 +3435,57 @@ function ResizeControl({ nodeId, position, variant = ResizeControlVariant.Handle
3298
3435
  domNode: resizeControlRef.current,
3299
3436
  nodeId: id,
3300
3437
  getStoreItems: () => {
3301
- const { nodeLookup, transform, snapGrid, snapToGrid } = store.getState();
3438
+ const { nodeLookup, transform, snapGrid, snapToGrid, nodeOrigin } = store.getState();
3302
3439
  return {
3303
3440
  nodeLookup,
3304
3441
  transform,
3305
3442
  snapGrid,
3306
3443
  snapToGrid,
3444
+ nodeOrigin,
3307
3445
  };
3308
3446
  },
3309
3447
  onChange: (change, childChanges) => {
3310
- const { triggerNodeChanges } = store.getState();
3448
+ const { triggerNodeChanges, nodeLookup, parentLookup, nodeOrigin } = store.getState();
3311
3449
  const changes = [];
3312
- if (change.isXPosChange || change.isYPosChange) {
3450
+ const nextPosition = { x: change.x, y: change.y };
3451
+ const node = nodeLookup.get(id);
3452
+ if (node && node.expandParent && node.parentId) {
3453
+ const origin = node.origin ?? nodeOrigin;
3454
+ const width = change.width ?? node.measured.width;
3455
+ const height = change.height ?? node.measured.height;
3456
+ const child = {
3457
+ id: node.id,
3458
+ parentId: node.parentId,
3459
+ rect: {
3460
+ width,
3461
+ height,
3462
+ ...evaluateAbsolutePosition({
3463
+ x: change.x ?? node.position.x,
3464
+ y: change.y ?? node.position.y,
3465
+ }, { width, height }, node.parentId, nodeLookup, origin),
3466
+ },
3467
+ };
3468
+ const parentExpandChanges = handleExpandParent([child], nodeLookup, parentLookup, nodeOrigin);
3469
+ changes.push(...parentExpandChanges);
3470
+ // when the parent was expanded by the child node, its position will be clamped at
3471
+ // 0,0 when node origin is 0,0 and to width, height if it's 1,1
3472
+ nextPosition.x = change.x ? Math.max(origin[0] * width, change.x) : undefined;
3473
+ nextPosition.y = change.y ? Math.max(origin[1] * height, change.y) : undefined;
3474
+ }
3475
+ if (nextPosition.x !== undefined && nextPosition.y !== undefined) {
3313
3476
  const positionChange = {
3314
3477
  id,
3315
3478
  type: 'position',
3316
- position: {
3317
- x: change.x,
3318
- y: change.y,
3319
- },
3479
+ position: { ...nextPosition },
3320
3480
  };
3321
3481
  changes.push(positionChange);
3322
3482
  }
3323
- if (change.isWidthChange || change.isHeightChange) {
3483
+ if (change.width !== undefined && change.height !== undefined) {
3324
3484
  const dimensionChange = {
3325
3485
  id,
3326
3486
  type: 'dimensions',
3327
3487
  resizing: true,
3488
+ setAttributes: true,
3328
3489
  dimensions: {
3329
3490
  width: change.width,
3330
3491
  height: change.height,
@@ -3403,55 +3564,61 @@ function NodeToolbarPortal({ children }) {
3403
3564
  return createPortal(children, wrapperRef);
3404
3565
  }
3405
3566
 
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 ||
3567
+ const nodeEqualityFn = (a, b) => a?.internals.positionAbsolute.x !== b?.internals.positionAbsolute.x ||
3568
+ a?.internals.positionAbsolute.y !== b?.internals.positionAbsolute.y ||
3569
+ a?.measured.width !== b?.measured.width ||
3570
+ a?.measured.height !== b?.measured.height ||
3410
3571
  a?.selected !== b?.selected ||
3411
- a?.[internalsSymbol]?.z !== b?.[internalsSymbol]?.z;
3572
+ a?.internals.z !== b?.internals.z;
3412
3573
  const nodesEqualityFn = (a, b) => {
3413
- if (a.length !== b.length) {
3574
+ if (a.size !== b.size) {
3414
3575
  return false;
3415
3576
  }
3416
- return !a.some((node, i) => nodeEqualityFn(node, b[i]));
3577
+ for (const [key, node] of a) {
3578
+ if (nodeEqualityFn(node, b.get(key))) {
3579
+ return false;
3580
+ }
3581
+ }
3582
+ return true;
3417
3583
  };
3418
3584
  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,
3585
+ x: state.transform[0],
3586
+ y: state.transform[1],
3587
+ zoom: state.transform[2],
3425
3588
  selectedNodesCount: state.nodes.filter((node) => node.selected).length,
3426
3589
  });
3427
3590
  function NodeToolbar({ nodeId, children, className, style, isVisible, position = Position.Top, offset = 10, align = 'center', ...rest }) {
3428
3591
  const contextNodeId = useNodeId();
3429
3592
  const nodesSelector = useCallback((state) => {
3430
3593
  const nodeIds = Array.isArray(nodeId) ? nodeId : [nodeId || contextNodeId || ''];
3431
- return nodeIds.reduce((acc, id) => {
3594
+ const internalNodes = nodeIds.reduce((res, id) => {
3432
3595
  const node = state.nodeLookup.get(id);
3433
3596
  if (node) {
3434
- acc.push(node);
3597
+ res.set(node.id, node);
3435
3598
  }
3436
- return acc;
3437
- }, []);
3599
+ return res;
3600
+ }, new Map());
3601
+ return internalNodes;
3438
3602
  }, [nodeId, contextNodeId]);
3439
3603
  const nodes = useStore(nodesSelector, nodesEqualityFn);
3440
- const { viewport, nodeOrigin, selectedNodesCount } = useStore(storeSelector, shallow);
3604
+ const { x, y, zoom, selectedNodesCount } = useStore(storeSelector, shallow);
3441
3605
  // 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) {
3606
+ const isActive = typeof isVisible === 'boolean'
3607
+ ? isVisible
3608
+ : nodes.size === 1 && nodes.values().next().value.selected && selectedNodesCount === 1;
3609
+ if (!isActive || !nodes.size) {
3444
3610
  return null;
3445
3611
  }
3446
- const nodeRect = getNodesBounds(nodes, { nodeOrigin });
3447
- const zIndex = Math.max(...nodes.map((node) => (node[internalsSymbol]?.z || 1) + 1));
3612
+ const nodeRect = getInternalNodesBounds(nodes);
3613
+ const nodesArray = Array.from(nodes.values());
3614
+ const zIndex = Math.max(...nodesArray.map((node) => node.internals.z + 1));
3448
3615
  const wrapperStyle = {
3449
3616
  position: 'absolute',
3450
- transform: getNodeToolbarTransform(nodeRect, viewport, position, offset, align),
3617
+ transform: getNodeToolbarTransform(nodeRect, { x, y, zoom }, position, offset, align),
3451
3618
  zIndex,
3452
3619
  ...style,
3453
3620
  };
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 }) }));
3621
+ 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
3622
  }
3456
3623
 
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 };
3624
+ 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 };