@xyflow/react 12.0.0-next.2 → 12.0.0-next.21

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 (473) hide show
  1. package/LICENSE +1 -1
  2. package/dist/base.css +145 -22
  3. package/dist/esm/additional-components/Background/Background.d.ts +5 -5
  4. package/dist/esm/additional-components/Background/Background.d.ts.map +1 -1
  5. package/dist/esm/additional-components/Background/Patterns.d.ts.map +1 -1
  6. package/dist/esm/additional-components/Background/index.d.ts +2 -2
  7. package/dist/esm/additional-components/Background/index.d.ts.map +1 -1
  8. package/dist/esm/additional-components/Background/types.d.ts +13 -0
  9. package/dist/esm/additional-components/Background/types.d.ts.map +1 -1
  10. package/dist/esm/additional-components/Controls/ControlButton.d.ts +1 -3
  11. package/dist/esm/additional-components/Controls/ControlButton.d.ts.map +1 -1
  12. package/dist/esm/additional-components/Controls/Controls.d.ts +7 -3
  13. package/dist/esm/additional-components/Controls/Controls.d.ts.map +1 -1
  14. package/dist/esm/additional-components/Controls/Icons/FitView.d.ts +1 -2
  15. package/dist/esm/additional-components/Controls/Icons/FitView.d.ts.map +1 -1
  16. package/dist/esm/additional-components/Controls/Icons/Lock.d.ts +1 -2
  17. package/dist/esm/additional-components/Controls/Icons/Lock.d.ts.map +1 -1
  18. package/dist/esm/additional-components/Controls/Icons/Minus.d.ts +1 -2
  19. package/dist/esm/additional-components/Controls/Icons/Minus.d.ts.map +1 -1
  20. package/dist/esm/additional-components/Controls/Icons/Plus.d.ts +1 -2
  21. package/dist/esm/additional-components/Controls/Icons/Plus.d.ts.map +1 -1
  22. package/dist/esm/additional-components/Controls/Icons/Unlock.d.ts +1 -2
  23. package/dist/esm/additional-components/Controls/Icons/Unlock.d.ts.map +1 -1
  24. package/dist/esm/additional-components/Controls/index.d.ts +3 -3
  25. package/dist/esm/additional-components/Controls/index.d.ts.map +1 -1
  26. package/dist/esm/additional-components/Controls/types.d.ts +21 -2
  27. package/dist/esm/additional-components/Controls/types.d.ts.map +1 -1
  28. package/dist/esm/additional-components/MiniMap/MiniMap.d.ts +5 -5
  29. package/dist/esm/additional-components/MiniMap/MiniMap.d.ts.map +1 -1
  30. package/dist/esm/additional-components/MiniMap/MiniMapNode.d.ts +3 -3
  31. package/dist/esm/additional-components/MiniMap/MiniMapNode.d.ts.map +1 -1
  32. package/dist/esm/additional-components/MiniMap/MiniMapNodes.d.ts +3 -3
  33. package/dist/esm/additional-components/MiniMap/MiniMapNodes.d.ts.map +1 -1
  34. package/dist/esm/additional-components/MiniMap/index.d.ts +1 -1
  35. package/dist/esm/additional-components/MiniMap/index.d.ts.map +1 -1
  36. package/dist/esm/additional-components/MiniMap/types.d.ts +23 -0
  37. package/dist/esm/additional-components/MiniMap/types.d.ts.map +1 -1
  38. package/dist/esm/additional-components/NodeResizer/{ResizeControl.d.ts → NodeResizeControl.d.ts} +4 -4
  39. package/dist/esm/additional-components/NodeResizer/NodeResizeControl.d.ts.map +1 -0
  40. package/dist/esm/additional-components/NodeResizer/NodeResizer.d.ts +2 -2
  41. package/dist/esm/additional-components/NodeResizer/NodeResizer.d.ts.map +1 -1
  42. package/dist/esm/additional-components/NodeResizer/index.d.ts +2 -2
  43. package/dist/esm/additional-components/NodeResizer/index.d.ts.map +1 -1
  44. package/dist/esm/additional-components/NodeResizer/types.d.ts +26 -23
  45. package/dist/esm/additional-components/NodeResizer/types.d.ts.map +1 -1
  46. package/dist/esm/additional-components/NodeToolbar/NodeToolbar.d.ts +2 -3
  47. package/dist/esm/additional-components/NodeToolbar/NodeToolbar.d.ts.map +1 -1
  48. package/dist/esm/additional-components/NodeToolbar/NodeToolbarPortal.d.ts +1 -2
  49. package/dist/esm/additional-components/NodeToolbar/NodeToolbarPortal.d.ts.map +1 -1
  50. package/dist/esm/additional-components/NodeToolbar/index.d.ts +2 -2
  51. package/dist/esm/additional-components/NodeToolbar/index.d.ts.map +1 -1
  52. package/dist/esm/additional-components/NodeToolbar/types.d.ts +10 -0
  53. package/dist/esm/additional-components/NodeToolbar/types.d.ts.map +1 -1
  54. package/dist/esm/additional-components/index.d.ts.map +1 -1
  55. package/dist/esm/components/A11yDescriptions/index.d.ts +1 -2
  56. package/dist/esm/components/A11yDescriptions/index.d.ts.map +1 -1
  57. package/dist/esm/components/Attribution/index.d.ts +2 -2
  58. package/dist/esm/components/Attribution/index.d.ts.map +1 -1
  59. package/dist/esm/components/BatchProvider/index.d.ts +17 -0
  60. package/dist/esm/components/BatchProvider/index.d.ts.map +1 -0
  61. package/dist/esm/components/BatchProvider/types.d.ts +7 -0
  62. package/dist/esm/components/BatchProvider/types.d.ts.map +1 -0
  63. package/dist/esm/components/BatchProvider/useQueue.d.ts +11 -0
  64. package/dist/esm/components/BatchProvider/useQueue.d.ts.map +1 -0
  65. package/dist/esm/components/ConnectionLine/index.d.ts +2 -2
  66. package/dist/esm/components/ConnectionLine/index.d.ts.map +1 -1
  67. package/dist/esm/components/EdgeLabelRenderer/index.d.ts +1 -2
  68. package/dist/esm/components/EdgeLabelRenderer/index.d.ts.map +1 -1
  69. package/dist/esm/components/EdgeWrapper/EdgeUpdateAnchors.d.ts +7 -7
  70. package/dist/esm/components/EdgeWrapper/EdgeUpdateAnchors.d.ts.map +1 -1
  71. package/dist/esm/components/EdgeWrapper/index.d.ts +2 -7
  72. package/dist/esm/components/EdgeWrapper/index.d.ts.map +1 -1
  73. package/dist/esm/components/EdgeWrapper/utils.d.ts.map +1 -1
  74. package/dist/esm/components/Edges/BaseEdge.d.ts +1 -5
  75. package/dist/esm/components/Edges/BaseEdge.d.ts.map +1 -1
  76. package/dist/esm/components/Edges/BezierEdge.d.ts.map +1 -1
  77. package/dist/esm/components/Edges/EdgeAnchor.d.ts +2 -2
  78. package/dist/esm/components/Edges/EdgeAnchor.d.ts.map +1 -1
  79. package/dist/esm/components/Edges/EdgeText.d.ts +7 -3
  80. package/dist/esm/components/Edges/EdgeText.d.ts.map +1 -1
  81. package/dist/esm/components/Edges/SimpleBezierEdge.d.ts.map +1 -1
  82. package/dist/esm/components/Edges/SmoothStepEdge.d.ts.map +1 -1
  83. package/dist/esm/components/Edges/StepEdge.d.ts.map +1 -1
  84. package/dist/esm/components/Edges/StraightEdge.d.ts.map +1 -1
  85. package/dist/esm/components/Edges/index.d.ts.map +1 -1
  86. package/dist/esm/components/Handle/index.d.ts +10 -5
  87. package/dist/esm/components/Handle/index.d.ts.map +1 -1
  88. package/dist/esm/components/NodeWrapper/index.d.ts +2 -7
  89. package/dist/esm/components/NodeWrapper/index.d.ts.map +1 -1
  90. package/dist/esm/components/NodeWrapper/useNodeObserver.d.ts +15 -0
  91. package/dist/esm/components/NodeWrapper/useNodeObserver.d.ts.map +1 -0
  92. package/dist/esm/components/NodeWrapper/utils.d.ts +5 -1
  93. package/dist/esm/components/NodeWrapper/utils.d.ts.map +1 -1
  94. package/dist/esm/components/Nodes/DefaultNode.d.ts +2 -7
  95. package/dist/esm/components/Nodes/DefaultNode.d.ts.map +1 -1
  96. package/dist/esm/components/Nodes/GroupNode.d.ts +1 -5
  97. package/dist/esm/components/Nodes/GroupNode.d.ts.map +1 -1
  98. package/dist/esm/components/Nodes/InputNode.d.ts +2 -7
  99. package/dist/esm/components/Nodes/InputNode.d.ts.map +1 -1
  100. package/dist/esm/components/Nodes/OutputNode.d.ts +2 -7
  101. package/dist/esm/components/Nodes/OutputNode.d.ts.map +1 -1
  102. package/dist/esm/components/Nodes/utils.d.ts.map +1 -1
  103. package/dist/esm/components/NodesSelection/index.d.ts +3 -5
  104. package/dist/esm/components/NodesSelection/index.d.ts.map +1 -1
  105. package/dist/esm/components/Panel/index.d.ts +5 -3
  106. package/dist/esm/components/Panel/index.d.ts.map +1 -1
  107. package/dist/esm/components/ReactFlowProvider/index.d.ts +6 -7
  108. package/dist/esm/components/ReactFlowProvider/index.d.ts.map +1 -1
  109. package/dist/esm/components/SelectionListener/index.d.ts +2 -2
  110. package/dist/esm/components/SelectionListener/index.d.ts.map +1 -1
  111. package/dist/esm/components/StoreUpdater/index.d.ts +5 -5
  112. package/dist/esm/components/StoreUpdater/index.d.ts.map +1 -1
  113. package/dist/esm/components/UserSelection/index.d.ts +1 -2
  114. package/dist/esm/components/UserSelection/index.d.ts.map +1 -1
  115. package/dist/esm/components/ViewportPortal/index.d.ts +1 -2
  116. package/dist/esm/components/ViewportPortal/index.d.ts.map +1 -1
  117. package/dist/esm/container/EdgeRenderer/MarkerDefinitions.d.ts.map +1 -1
  118. package/dist/esm/container/EdgeRenderer/MarkerSymbols.d.ts +1 -1
  119. package/dist/esm/container/EdgeRenderer/MarkerSymbols.d.ts.map +1 -1
  120. package/dist/esm/container/EdgeRenderer/index.d.ts +8 -6
  121. package/dist/esm/container/EdgeRenderer/index.d.ts.map +1 -1
  122. package/dist/esm/container/FlowRenderer/index.d.ts +8 -6
  123. package/dist/esm/container/FlowRenderer/index.d.ts.map +1 -1
  124. package/dist/esm/container/GraphView/index.d.ts +8 -8
  125. package/dist/esm/container/GraphView/index.d.ts.map +1 -1
  126. package/dist/esm/container/GraphView/useNodeOrEdgeTypesWarning.d.ts +6 -1
  127. package/dist/esm/container/GraphView/useNodeOrEdgeTypesWarning.d.ts.map +1 -1
  128. package/dist/esm/container/GraphView/useStylesLoadedWarning.d.ts +2 -0
  129. package/dist/esm/container/GraphView/useStylesLoadedWarning.d.ts.map +1 -0
  130. package/dist/esm/container/NodeRenderer/index.d.ts +8 -7
  131. package/dist/esm/container/NodeRenderer/index.d.ts.map +1 -1
  132. package/dist/esm/container/NodeRenderer/useResizeObserver.d.ts +1 -1
  133. package/dist/esm/container/NodeRenderer/useResizeObserver.d.ts.map +1 -1
  134. package/dist/esm/container/Pane/index.d.ts +2 -2
  135. package/dist/esm/container/Pane/index.d.ts.map +1 -1
  136. package/dist/esm/container/ReactFlow/Wrapper.d.ts +3 -5
  137. package/dist/esm/container/ReactFlow/Wrapper.d.ts.map +1 -1
  138. package/dist/esm/container/ReactFlow/index.d.ts +4 -119
  139. package/dist/esm/container/ReactFlow/index.d.ts.map +1 -1
  140. package/dist/esm/container/ReactFlow/init-values.d.ts +4 -0
  141. package/dist/esm/container/ReactFlow/init-values.d.ts.map +1 -0
  142. package/dist/esm/container/Viewport/index.d.ts +1 -1
  143. package/dist/esm/container/Viewport/index.d.ts.map +1 -1
  144. package/dist/esm/container/ZoomPane/index.d.ts +2 -2
  145. package/dist/esm/container/ZoomPane/index.d.ts.map +1 -1
  146. package/dist/esm/contexts/NodeIdContext.d.ts.map +1 -1
  147. package/dist/esm/contexts/{RFStoreContext.d.ts → StoreContext.d.ts} +1 -1
  148. package/dist/esm/contexts/StoreContext.d.ts.map +1 -0
  149. package/dist/esm/hooks/useColorModeClass.d.ts +1 -1
  150. package/dist/esm/hooks/useColorModeClass.d.ts.map +1 -1
  151. package/dist/esm/hooks/useConnection.d.ts +13 -7
  152. package/dist/esm/hooks/useConnection.d.ts.map +1 -1
  153. package/dist/esm/hooks/useDrag.d.ts +3 -3
  154. package/dist/esm/hooks/useDrag.d.ts.map +1 -1
  155. package/dist/esm/hooks/useEdges.d.ts +1 -2
  156. package/dist/esm/hooks/useEdges.d.ts.map +1 -1
  157. package/dist/esm/hooks/useGlobalKeyHandler.d.ts +2 -3
  158. package/dist/esm/hooks/useGlobalKeyHandler.d.ts.map +1 -1
  159. package/dist/esm/hooks/useHandleConnections.d.ts +4 -4
  160. package/dist/esm/hooks/useHandleConnections.d.ts.map +1 -1
  161. package/dist/esm/hooks/useInternalNode.d.ts +10 -0
  162. package/dist/esm/hooks/useInternalNode.d.ts.map +1 -0
  163. package/dist/esm/hooks/useIsomorphicLayoutEffect.d.ts +3 -0
  164. package/dist/esm/hooks/useIsomorphicLayoutEffect.d.ts.map +1 -0
  165. package/dist/esm/hooks/useKeyPress.d.ts +1 -2
  166. package/dist/esm/hooks/useKeyPress.d.ts.map +1 -1
  167. package/dist/esm/hooks/useMoveSelectedNodes.d.ts +12 -0
  168. package/dist/esm/hooks/useMoveSelectedNodes.d.ts.map +1 -0
  169. package/dist/esm/hooks/useNodes.d.ts +1 -2
  170. package/dist/esm/hooks/useNodes.d.ts.map +1 -1
  171. package/dist/esm/hooks/useNodesData.d.ts +3 -4
  172. package/dist/esm/hooks/useNodesData.d.ts.map +1 -1
  173. package/dist/esm/hooks/useNodesEdgesState.d.ts +3 -3
  174. package/dist/esm/hooks/useNodesEdgesState.d.ts.map +1 -1
  175. package/dist/esm/hooks/useNodesInitialized.d.ts +1 -2
  176. package/dist/esm/hooks/useNodesInitialized.d.ts.map +1 -1
  177. package/dist/esm/hooks/useOnInitHandler.d.ts +2 -3
  178. package/dist/esm/hooks/useOnInitHandler.d.ts.map +1 -1
  179. package/dist/esm/hooks/useOnSelectionChange.d.ts +2 -3
  180. package/dist/esm/hooks/useOnSelectionChange.d.ts.map +1 -1
  181. package/dist/esm/hooks/useOnViewportChange.d.ts +1 -2
  182. package/dist/esm/hooks/useOnViewportChange.d.ts.map +1 -1
  183. package/dist/esm/hooks/useReactFlow.d.ts +1 -1
  184. package/dist/esm/hooks/useReactFlow.d.ts.map +1 -1
  185. package/dist/esm/hooks/useResizeHandler.d.ts +1 -2
  186. package/dist/esm/hooks/useResizeHandler.d.ts.map +1 -1
  187. package/dist/esm/hooks/useStore.d.ts +10 -11
  188. package/dist/esm/hooks/useStore.d.ts.map +1 -1
  189. package/dist/esm/hooks/useUpdateNodeInternals.d.ts +1 -2
  190. package/dist/esm/hooks/useUpdateNodeInternals.d.ts.map +1 -1
  191. package/dist/esm/hooks/useViewport.d.ts +1 -2
  192. package/dist/esm/hooks/useViewport.d.ts.map +1 -1
  193. package/dist/esm/hooks/useViewportHelper.d.ts.map +1 -1
  194. package/dist/esm/hooks/useViewportSync.d.ts +1 -1
  195. package/dist/esm/hooks/useViewportSync.d.ts.map +1 -1
  196. package/dist/esm/hooks/useVisibleEdgeIds.d.ts +1 -2
  197. package/dist/esm/hooks/useVisibleEdgeIds.d.ts.map +1 -1
  198. package/dist/esm/hooks/useVisibleNodeIds.d.ts +1 -2
  199. package/dist/esm/hooks/useVisibleNodeIds.d.ts.map +1 -1
  200. package/dist/esm/index.d.ts +22 -21
  201. package/dist/esm/index.d.ts.map +1 -1
  202. package/dist/esm/index.js +1181 -1127
  203. package/dist/esm/index.mjs +1181 -1127
  204. package/dist/esm/store/index.d.ts +6 -4
  205. package/dist/esm/store/index.d.ts.map +1 -1
  206. package/dist/esm/store/initialState.d.ts +5 -3
  207. package/dist/esm/store/initialState.d.ts.map +1 -1
  208. package/dist/esm/styles/utils.d.ts.map +1 -1
  209. package/dist/esm/types/component-props.d.ts +380 -38
  210. package/dist/esm/types/component-props.d.ts.map +1 -1
  211. package/dist/esm/types/edges.d.ts +35 -25
  212. package/dist/esm/types/edges.d.ts.map +1 -1
  213. package/dist/esm/types/general.d.ts +99 -20
  214. package/dist/esm/types/general.d.ts.map +1 -1
  215. package/dist/esm/types/index.d.ts +0 -1
  216. package/dist/esm/types/index.d.ts.map +1 -1
  217. package/dist/esm/types/instance.d.ts +146 -44
  218. package/dist/esm/types/instance.d.ts.map +1 -1
  219. package/dist/esm/types/nodes.d.ts +23 -12
  220. package/dist/esm/types/nodes.d.ts.map +1 -1
  221. package/dist/esm/types/store.d.ts +26 -23
  222. package/dist/esm/types/store.d.ts.map +1 -1
  223. package/dist/esm/utils/changes.d.ts +25 -7
  224. package/dist/esm/utils/changes.d.ts.map +1 -1
  225. package/dist/esm/utils/general.d.ts +4 -49
  226. package/dist/esm/utils/general.d.ts.map +1 -1
  227. package/dist/esm/utils/index.d.ts.map +1 -1
  228. package/dist/style.css +68 -32
  229. package/dist/umd/additional-components/Background/Background.d.ts +5 -5
  230. package/dist/umd/additional-components/Background/Background.d.ts.map +1 -1
  231. package/dist/umd/additional-components/Background/Patterns.d.ts.map +1 -1
  232. package/dist/umd/additional-components/Background/index.d.ts +2 -2
  233. package/dist/umd/additional-components/Background/index.d.ts.map +1 -1
  234. package/dist/umd/additional-components/Background/types.d.ts +13 -0
  235. package/dist/umd/additional-components/Background/types.d.ts.map +1 -1
  236. package/dist/umd/additional-components/Controls/ControlButton.d.ts +1 -3
  237. package/dist/umd/additional-components/Controls/ControlButton.d.ts.map +1 -1
  238. package/dist/umd/additional-components/Controls/Controls.d.ts +7 -3
  239. package/dist/umd/additional-components/Controls/Controls.d.ts.map +1 -1
  240. package/dist/umd/additional-components/Controls/Icons/FitView.d.ts +1 -2
  241. package/dist/umd/additional-components/Controls/Icons/FitView.d.ts.map +1 -1
  242. package/dist/umd/additional-components/Controls/Icons/Lock.d.ts +1 -2
  243. package/dist/umd/additional-components/Controls/Icons/Lock.d.ts.map +1 -1
  244. package/dist/umd/additional-components/Controls/Icons/Minus.d.ts +1 -2
  245. package/dist/umd/additional-components/Controls/Icons/Minus.d.ts.map +1 -1
  246. package/dist/umd/additional-components/Controls/Icons/Plus.d.ts +1 -2
  247. package/dist/umd/additional-components/Controls/Icons/Plus.d.ts.map +1 -1
  248. package/dist/umd/additional-components/Controls/Icons/Unlock.d.ts +1 -2
  249. package/dist/umd/additional-components/Controls/Icons/Unlock.d.ts.map +1 -1
  250. package/dist/umd/additional-components/Controls/index.d.ts +3 -3
  251. package/dist/umd/additional-components/Controls/index.d.ts.map +1 -1
  252. package/dist/umd/additional-components/Controls/types.d.ts +21 -2
  253. package/dist/umd/additional-components/Controls/types.d.ts.map +1 -1
  254. package/dist/umd/additional-components/MiniMap/MiniMap.d.ts +5 -5
  255. package/dist/umd/additional-components/MiniMap/MiniMap.d.ts.map +1 -1
  256. package/dist/umd/additional-components/MiniMap/MiniMapNode.d.ts +3 -3
  257. package/dist/umd/additional-components/MiniMap/MiniMapNode.d.ts.map +1 -1
  258. package/dist/umd/additional-components/MiniMap/MiniMapNodes.d.ts +3 -3
  259. package/dist/umd/additional-components/MiniMap/MiniMapNodes.d.ts.map +1 -1
  260. package/dist/umd/additional-components/MiniMap/index.d.ts +1 -1
  261. package/dist/umd/additional-components/MiniMap/index.d.ts.map +1 -1
  262. package/dist/umd/additional-components/MiniMap/types.d.ts +23 -0
  263. package/dist/umd/additional-components/MiniMap/types.d.ts.map +1 -1
  264. package/dist/umd/additional-components/NodeResizer/{ResizeControl.d.ts → NodeResizeControl.d.ts} +4 -4
  265. package/dist/umd/additional-components/NodeResizer/NodeResizeControl.d.ts.map +1 -0
  266. package/dist/umd/additional-components/NodeResizer/NodeResizer.d.ts +2 -2
  267. package/dist/umd/additional-components/NodeResizer/NodeResizer.d.ts.map +1 -1
  268. package/dist/umd/additional-components/NodeResizer/index.d.ts +2 -2
  269. package/dist/umd/additional-components/NodeResizer/index.d.ts.map +1 -1
  270. package/dist/umd/additional-components/NodeResizer/types.d.ts +26 -23
  271. package/dist/umd/additional-components/NodeResizer/types.d.ts.map +1 -1
  272. package/dist/umd/additional-components/NodeToolbar/NodeToolbar.d.ts +2 -3
  273. package/dist/umd/additional-components/NodeToolbar/NodeToolbar.d.ts.map +1 -1
  274. package/dist/umd/additional-components/NodeToolbar/NodeToolbarPortal.d.ts +1 -2
  275. package/dist/umd/additional-components/NodeToolbar/NodeToolbarPortal.d.ts.map +1 -1
  276. package/dist/umd/additional-components/NodeToolbar/index.d.ts +2 -2
  277. package/dist/umd/additional-components/NodeToolbar/index.d.ts.map +1 -1
  278. package/dist/umd/additional-components/NodeToolbar/types.d.ts +10 -0
  279. package/dist/umd/additional-components/NodeToolbar/types.d.ts.map +1 -1
  280. package/dist/umd/additional-components/index.d.ts.map +1 -1
  281. package/dist/umd/components/A11yDescriptions/index.d.ts +1 -2
  282. package/dist/umd/components/A11yDescriptions/index.d.ts.map +1 -1
  283. package/dist/umd/components/Attribution/index.d.ts +2 -2
  284. package/dist/umd/components/Attribution/index.d.ts.map +1 -1
  285. package/dist/umd/components/BatchProvider/index.d.ts +17 -0
  286. package/dist/umd/components/BatchProvider/index.d.ts.map +1 -0
  287. package/dist/umd/components/BatchProvider/types.d.ts +7 -0
  288. package/dist/umd/components/BatchProvider/types.d.ts.map +1 -0
  289. package/dist/umd/components/BatchProvider/useQueue.d.ts +11 -0
  290. package/dist/umd/components/BatchProvider/useQueue.d.ts.map +1 -0
  291. package/dist/umd/components/ConnectionLine/index.d.ts +2 -2
  292. package/dist/umd/components/ConnectionLine/index.d.ts.map +1 -1
  293. package/dist/umd/components/EdgeLabelRenderer/index.d.ts +1 -2
  294. package/dist/umd/components/EdgeLabelRenderer/index.d.ts.map +1 -1
  295. package/dist/umd/components/EdgeWrapper/EdgeUpdateAnchors.d.ts +7 -7
  296. package/dist/umd/components/EdgeWrapper/EdgeUpdateAnchors.d.ts.map +1 -1
  297. package/dist/umd/components/EdgeWrapper/index.d.ts +2 -7
  298. package/dist/umd/components/EdgeWrapper/index.d.ts.map +1 -1
  299. package/dist/umd/components/EdgeWrapper/utils.d.ts.map +1 -1
  300. package/dist/umd/components/Edges/BaseEdge.d.ts +1 -5
  301. package/dist/umd/components/Edges/BaseEdge.d.ts.map +1 -1
  302. package/dist/umd/components/Edges/BezierEdge.d.ts.map +1 -1
  303. package/dist/umd/components/Edges/EdgeAnchor.d.ts +2 -2
  304. package/dist/umd/components/Edges/EdgeAnchor.d.ts.map +1 -1
  305. package/dist/umd/components/Edges/EdgeText.d.ts +7 -3
  306. package/dist/umd/components/Edges/EdgeText.d.ts.map +1 -1
  307. package/dist/umd/components/Edges/SimpleBezierEdge.d.ts.map +1 -1
  308. package/dist/umd/components/Edges/SmoothStepEdge.d.ts.map +1 -1
  309. package/dist/umd/components/Edges/StepEdge.d.ts.map +1 -1
  310. package/dist/umd/components/Edges/StraightEdge.d.ts.map +1 -1
  311. package/dist/umd/components/Edges/index.d.ts.map +1 -1
  312. package/dist/umd/components/Handle/index.d.ts +10 -5
  313. package/dist/umd/components/Handle/index.d.ts.map +1 -1
  314. package/dist/umd/components/NodeWrapper/index.d.ts +2 -7
  315. package/dist/umd/components/NodeWrapper/index.d.ts.map +1 -1
  316. package/dist/umd/components/NodeWrapper/useNodeObserver.d.ts +15 -0
  317. package/dist/umd/components/NodeWrapper/useNodeObserver.d.ts.map +1 -0
  318. package/dist/umd/components/NodeWrapper/utils.d.ts +5 -1
  319. package/dist/umd/components/NodeWrapper/utils.d.ts.map +1 -1
  320. package/dist/umd/components/Nodes/DefaultNode.d.ts +2 -7
  321. package/dist/umd/components/Nodes/DefaultNode.d.ts.map +1 -1
  322. package/dist/umd/components/Nodes/GroupNode.d.ts +1 -5
  323. package/dist/umd/components/Nodes/GroupNode.d.ts.map +1 -1
  324. package/dist/umd/components/Nodes/InputNode.d.ts +2 -7
  325. package/dist/umd/components/Nodes/InputNode.d.ts.map +1 -1
  326. package/dist/umd/components/Nodes/OutputNode.d.ts +2 -7
  327. package/dist/umd/components/Nodes/OutputNode.d.ts.map +1 -1
  328. package/dist/umd/components/Nodes/utils.d.ts.map +1 -1
  329. package/dist/umd/components/NodesSelection/index.d.ts +3 -5
  330. package/dist/umd/components/NodesSelection/index.d.ts.map +1 -1
  331. package/dist/umd/components/Panel/index.d.ts +5 -3
  332. package/dist/umd/components/Panel/index.d.ts.map +1 -1
  333. package/dist/umd/components/ReactFlowProvider/index.d.ts +6 -7
  334. package/dist/umd/components/ReactFlowProvider/index.d.ts.map +1 -1
  335. package/dist/umd/components/SelectionListener/index.d.ts +2 -2
  336. package/dist/umd/components/SelectionListener/index.d.ts.map +1 -1
  337. package/dist/umd/components/StoreUpdater/index.d.ts +5 -5
  338. package/dist/umd/components/StoreUpdater/index.d.ts.map +1 -1
  339. package/dist/umd/components/UserSelection/index.d.ts +1 -2
  340. package/dist/umd/components/UserSelection/index.d.ts.map +1 -1
  341. package/dist/umd/components/ViewportPortal/index.d.ts +1 -2
  342. package/dist/umd/components/ViewportPortal/index.d.ts.map +1 -1
  343. package/dist/umd/container/EdgeRenderer/MarkerDefinitions.d.ts.map +1 -1
  344. package/dist/umd/container/EdgeRenderer/MarkerSymbols.d.ts +1 -1
  345. package/dist/umd/container/EdgeRenderer/MarkerSymbols.d.ts.map +1 -1
  346. package/dist/umd/container/EdgeRenderer/index.d.ts +8 -6
  347. package/dist/umd/container/EdgeRenderer/index.d.ts.map +1 -1
  348. package/dist/umd/container/FlowRenderer/index.d.ts +8 -6
  349. package/dist/umd/container/FlowRenderer/index.d.ts.map +1 -1
  350. package/dist/umd/container/GraphView/index.d.ts +8 -8
  351. package/dist/umd/container/GraphView/index.d.ts.map +1 -1
  352. package/dist/umd/container/GraphView/useNodeOrEdgeTypesWarning.d.ts +6 -1
  353. package/dist/umd/container/GraphView/useNodeOrEdgeTypesWarning.d.ts.map +1 -1
  354. package/dist/umd/container/GraphView/useStylesLoadedWarning.d.ts +2 -0
  355. package/dist/umd/container/GraphView/useStylesLoadedWarning.d.ts.map +1 -0
  356. package/dist/umd/container/NodeRenderer/index.d.ts +8 -7
  357. package/dist/umd/container/NodeRenderer/index.d.ts.map +1 -1
  358. package/dist/umd/container/NodeRenderer/useResizeObserver.d.ts +1 -1
  359. package/dist/umd/container/NodeRenderer/useResizeObserver.d.ts.map +1 -1
  360. package/dist/umd/container/Pane/index.d.ts +2 -2
  361. package/dist/umd/container/Pane/index.d.ts.map +1 -1
  362. package/dist/umd/container/ReactFlow/Wrapper.d.ts +3 -5
  363. package/dist/umd/container/ReactFlow/Wrapper.d.ts.map +1 -1
  364. package/dist/umd/container/ReactFlow/index.d.ts +4 -119
  365. package/dist/umd/container/ReactFlow/index.d.ts.map +1 -1
  366. package/dist/umd/container/ReactFlow/init-values.d.ts +4 -0
  367. package/dist/umd/container/ReactFlow/init-values.d.ts.map +1 -0
  368. package/dist/umd/container/Viewport/index.d.ts +1 -1
  369. package/dist/umd/container/Viewport/index.d.ts.map +1 -1
  370. package/dist/umd/container/ZoomPane/index.d.ts +2 -2
  371. package/dist/umd/container/ZoomPane/index.d.ts.map +1 -1
  372. package/dist/umd/contexts/NodeIdContext.d.ts.map +1 -1
  373. package/dist/umd/contexts/{RFStoreContext.d.ts → StoreContext.d.ts} +1 -1
  374. package/dist/umd/contexts/StoreContext.d.ts.map +1 -0
  375. package/dist/umd/hooks/useColorModeClass.d.ts +1 -1
  376. package/dist/umd/hooks/useColorModeClass.d.ts.map +1 -1
  377. package/dist/umd/hooks/useConnection.d.ts +13 -7
  378. package/dist/umd/hooks/useConnection.d.ts.map +1 -1
  379. package/dist/umd/hooks/useDrag.d.ts +3 -3
  380. package/dist/umd/hooks/useDrag.d.ts.map +1 -1
  381. package/dist/umd/hooks/useEdges.d.ts +1 -2
  382. package/dist/umd/hooks/useEdges.d.ts.map +1 -1
  383. package/dist/umd/hooks/useGlobalKeyHandler.d.ts +2 -3
  384. package/dist/umd/hooks/useGlobalKeyHandler.d.ts.map +1 -1
  385. package/dist/umd/hooks/useHandleConnections.d.ts +4 -4
  386. package/dist/umd/hooks/useHandleConnections.d.ts.map +1 -1
  387. package/dist/umd/hooks/useInternalNode.d.ts +10 -0
  388. package/dist/umd/hooks/useInternalNode.d.ts.map +1 -0
  389. package/dist/umd/hooks/useIsomorphicLayoutEffect.d.ts +3 -0
  390. package/dist/umd/hooks/useIsomorphicLayoutEffect.d.ts.map +1 -0
  391. package/dist/umd/hooks/useKeyPress.d.ts +1 -2
  392. package/dist/umd/hooks/useKeyPress.d.ts.map +1 -1
  393. package/dist/umd/hooks/useMoveSelectedNodes.d.ts +12 -0
  394. package/dist/umd/hooks/useMoveSelectedNodes.d.ts.map +1 -0
  395. package/dist/umd/hooks/useNodes.d.ts +1 -2
  396. package/dist/umd/hooks/useNodes.d.ts.map +1 -1
  397. package/dist/umd/hooks/useNodesData.d.ts +3 -4
  398. package/dist/umd/hooks/useNodesData.d.ts.map +1 -1
  399. package/dist/umd/hooks/useNodesEdgesState.d.ts +3 -3
  400. package/dist/umd/hooks/useNodesEdgesState.d.ts.map +1 -1
  401. package/dist/umd/hooks/useNodesInitialized.d.ts +1 -2
  402. package/dist/umd/hooks/useNodesInitialized.d.ts.map +1 -1
  403. package/dist/umd/hooks/useOnInitHandler.d.ts +2 -3
  404. package/dist/umd/hooks/useOnInitHandler.d.ts.map +1 -1
  405. package/dist/umd/hooks/useOnSelectionChange.d.ts +2 -3
  406. package/dist/umd/hooks/useOnSelectionChange.d.ts.map +1 -1
  407. package/dist/umd/hooks/useOnViewportChange.d.ts +1 -2
  408. package/dist/umd/hooks/useOnViewportChange.d.ts.map +1 -1
  409. package/dist/umd/hooks/useReactFlow.d.ts +1 -1
  410. package/dist/umd/hooks/useReactFlow.d.ts.map +1 -1
  411. package/dist/umd/hooks/useResizeHandler.d.ts +1 -2
  412. package/dist/umd/hooks/useResizeHandler.d.ts.map +1 -1
  413. package/dist/umd/hooks/useStore.d.ts +10 -11
  414. package/dist/umd/hooks/useStore.d.ts.map +1 -1
  415. package/dist/umd/hooks/useUpdateNodeInternals.d.ts +1 -2
  416. package/dist/umd/hooks/useUpdateNodeInternals.d.ts.map +1 -1
  417. package/dist/umd/hooks/useViewport.d.ts +1 -2
  418. package/dist/umd/hooks/useViewport.d.ts.map +1 -1
  419. package/dist/umd/hooks/useViewportHelper.d.ts.map +1 -1
  420. package/dist/umd/hooks/useViewportSync.d.ts +1 -1
  421. package/dist/umd/hooks/useViewportSync.d.ts.map +1 -1
  422. package/dist/umd/hooks/useVisibleEdgeIds.d.ts +1 -2
  423. package/dist/umd/hooks/useVisibleEdgeIds.d.ts.map +1 -1
  424. package/dist/umd/hooks/useVisibleNodeIds.d.ts +1 -2
  425. package/dist/umd/hooks/useVisibleNodeIds.d.ts.map +1 -1
  426. package/dist/umd/index.d.ts +22 -21
  427. package/dist/umd/index.d.ts.map +1 -1
  428. package/dist/umd/index.js +2 -2
  429. package/dist/umd/store/index.d.ts +6 -4
  430. package/dist/umd/store/index.d.ts.map +1 -1
  431. package/dist/umd/store/initialState.d.ts +5 -3
  432. package/dist/umd/store/initialState.d.ts.map +1 -1
  433. package/dist/umd/styles/utils.d.ts.map +1 -1
  434. package/dist/umd/types/component-props.d.ts +380 -38
  435. package/dist/umd/types/component-props.d.ts.map +1 -1
  436. package/dist/umd/types/edges.d.ts +35 -25
  437. package/dist/umd/types/edges.d.ts.map +1 -1
  438. package/dist/umd/types/general.d.ts +99 -20
  439. package/dist/umd/types/general.d.ts.map +1 -1
  440. package/dist/umd/types/index.d.ts +0 -1
  441. package/dist/umd/types/index.d.ts.map +1 -1
  442. package/dist/umd/types/instance.d.ts +146 -44
  443. package/dist/umd/types/instance.d.ts.map +1 -1
  444. package/dist/umd/types/nodes.d.ts +23 -12
  445. package/dist/umd/types/nodes.d.ts.map +1 -1
  446. package/dist/umd/types/store.d.ts +26 -23
  447. package/dist/umd/types/store.d.ts.map +1 -1
  448. package/dist/umd/utils/changes.d.ts +25 -7
  449. package/dist/umd/utils/changes.d.ts.map +1 -1
  450. package/dist/umd/utils/general.d.ts +4 -49
  451. package/dist/umd/utils/general.d.ts.map +1 -1
  452. package/dist/umd/utils/index.d.ts.map +1 -1
  453. package/package.json +4 -11
  454. package/dist/esm/additional-components/NodeResizer/ResizeControl.d.ts.map +0 -1
  455. package/dist/esm/additional-components/NodeResizer/utils.d.ts +0 -11
  456. package/dist/esm/additional-components/NodeResizer/utils.d.ts.map +0 -1
  457. package/dist/esm/contexts/RFStoreContext.d.ts.map +0 -1
  458. package/dist/esm/hooks/useUpdateNodePositions.d.ts +0 -13
  459. package/dist/esm/hooks/useUpdateNodePositions.d.ts.map +0 -1
  460. package/dist/esm/store/utils.d.ts +0 -12
  461. package/dist/esm/store/utils.d.ts.map +0 -1
  462. package/dist/esm/types/changes.d.ts +0 -50
  463. package/dist/esm/types/changes.d.ts.map +0 -1
  464. package/dist/umd/additional-components/NodeResizer/ResizeControl.d.ts.map +0 -1
  465. package/dist/umd/additional-components/NodeResizer/utils.d.ts +0 -11
  466. package/dist/umd/additional-components/NodeResizer/utils.d.ts.map +0 -1
  467. package/dist/umd/contexts/RFStoreContext.d.ts.map +0 -1
  468. package/dist/umd/hooks/useUpdateNodePositions.d.ts +0 -13
  469. package/dist/umd/hooks/useUpdateNodePositions.d.ts.map +0 -1
  470. package/dist/umd/store/utils.d.ts +0 -12
  471. package/dist/umd/store/utils.d.ts.map +0 -1
  472. package/dist/umd/types/changes.d.ts +0 -50
  473. package/dist/umd/types/changes.d.ts.map +0 -1
package/dist/esm/index.js CHANGED
@@ -1,14 +1,12 @@
1
1
  "use client"
2
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
- import { createContext, useContext, useMemo, memo, useEffect, useRef, useState, useCallback, forwardRef } from 'react';
2
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
4
3
  import cc from 'classcat';
5
- import { errorMessages, infiniteExtent, isInputDOMNode, fitView, getViewportForBounds, pointToRendererPoint, rendererPointToPoint, isNodeBase, isEdgeBase, getOutgoersBase, getIncomersBase, addEdgeBase, updateEdgeBase, getConnectedEdgesBase, getElementsToRemove, isRectObject, nodeToRect, getOverlappingArea, getDimensions, XYPanZoom, PanOnScrollMode, SelectionMode, getEventPosition, getNodesInside, XYDrag, snapPosition, calcNextPosition, Position, isMouseEvent, XYHandle, getHostForElement, getNodesBounds, clampPosition, internalsSymbol, getPositionWithOrigin, elementSelectionKeys, isEdgeVisible, MarkerType, createMarkerIds, isNumeric, getBezierEdgeCenter, getSmoothStepPath, getStraightPath, getBezierPath, getEdgePosition, getElevatedEdgeZIndex, getMarkerId, ConnectionMode, ConnectionLineType, updateConnectionLookup, adoptUserProvidedNodes, updateNodeDimensions, updateAbsolutePositions, panBy, isMacOs, areConnectionMapsEqual, handleConnectionChange, getNodePositionWithOrigin, XYMinimap, getBoundsOfRects, getPointerPosition, clamp, getNodeToolbarTransform } from '@xyflow/system';
6
- export { ConnectionLineType, ConnectionMode, MarkerType, PanOnScrollMode, Position, SelectionMode, getBezierEdgeCenter, getBezierPath, getEdgeCenter, getNodesBounds, getSmoothStepPath, getStraightPath, getViewportForBounds, internalsSymbol } from '@xyflow/system';
4
+ import { errorMessages, infiniteExtent, isInputDOMNode, 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, getPositionWithOrigin, elementSelectionKeys, isEdgeVisible, MarkerType, createMarkerIds, getBezierEdgeCenter, getSmoothStepPath, getStraightPath, getBezierPath, getEdgePosition, getElevatedEdgeZIndex, getMarkerId, ConnectionLineType, updateConnectionLookup, adoptUserNodes, devWarn, updateNodeInternals, updateAbsolutePositions, handleExpandParent, panBy, isMacOs, areConnectionMapsEqual, handleConnectionChange, shallowNodeData, getNodePositionWithOrigin, XYMinimap, getBoundsOfRects, ResizeControlVariant, XYResizer, XY_RESIZER_LINE_POSITIONS, XY_RESIZER_HANDLE_POSITIONS, getNodesBounds, getNodeToolbarTransform } from '@xyflow/system';
5
+ export { ConnectionLineType, ConnectionMode, MarkerType, PanOnScrollMode, Position, SelectionMode, addEdge, getBezierEdgeCenter, getBezierPath, getConnectedEdges, getEdgeCenter, getIncomers, getNodesBounds, getOutgoers, getSmoothStepPath, getStraightPath, getViewportForBounds, updateEdge } from '@xyflow/system';
6
+ 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';
10
- import { drag } from 'd3-drag';
11
- import { select } from 'd3-selection';
12
10
 
13
11
  const StoreContext = createContext(null);
14
12
  const Provider$1 = StoreContext.Provider;
@@ -21,6 +19,10 @@ const zustandErrorMessage = errorMessages['error001']();
21
19
  * @param selector
22
20
  * @param equalityFn
23
21
  * @returns The selected state slice
22
+ *
23
+ * @example
24
+ * const nodes = useStore((state: ReactFlowState<MyNodeType>) => state.nodes);
25
+ *
24
26
  */
25
27
  function useStore(selector, equalityFn) {
26
28
  const store = useContext(StoreContext);
@@ -29,7 +31,7 @@ function useStore(selector, equalityFn) {
29
31
  }
30
32
  return useStoreWithEqualityFn(store, selector, equalityFn);
31
33
  }
32
- const useStoreApi = () => {
34
+ function useStoreApi() {
33
35
  const store = useContext(StoreContext);
34
36
  if (store === null) {
35
37
  throw new Error(zustandErrorMessage);
@@ -38,13 +40,36 @@ const useStoreApi = () => {
38
40
  getState: store.getState,
39
41
  setState: store.setState,
40
42
  subscribe: store.subscribe,
41
- destroy: store.destroy,
42
43
  }), [store]);
44
+ }
45
+
46
+ const style = { display: 'none' };
47
+ const ariaLiveStyle = {
48
+ position: 'absolute',
49
+ width: 1,
50
+ height: 1,
51
+ margin: -1,
52
+ border: 0,
53
+ padding: 0,
54
+ overflow: 'hidden',
55
+ clip: 'rect(0px, 0px, 0px, 0px)',
56
+ clipPath: 'inset(100%)',
43
57
  };
58
+ const ARIA_NODE_DESC_KEY = 'react-flow__node-desc';
59
+ const ARIA_EDGE_DESC_KEY = 'react-flow__edge-desc';
60
+ const ARIA_LIVE_MESSAGE = 'react-flow__aria-live';
61
+ const selector$q = (s) => s.ariaLiveMessage;
62
+ function AriaLiveMessage({ rfId }) {
63
+ const ariaLiveMessage = useStore(selector$q);
64
+ return (jsx("div", { id: `${ARIA_LIVE_MESSAGE}-${rfId}`, "aria-live": "assertive", "aria-atomic": "true", style: ariaLiveStyle, children: ariaLiveMessage }));
65
+ }
66
+ function A11yDescriptions({ rfId, disableKeyboardA11y }) {
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 })] }));
68
+ }
44
69
 
45
- const selector$q = (s) => (s.userSelectionActive ? 'none' : 'all');
46
- function Panel({ position, children, className, style, ...rest }) {
47
- const pointerEvents = useStore(selector$q);
70
+ const selector$p = (s) => (s.userSelectionActive ? 'none' : 'all');
71
+ function Panel({ position = 'top-left', children, className, style, ...rest }) {
72
+ const pointerEvents = useStore(selector$p);
48
73
  const positionClasses = `${position}`.split('-');
49
74
  return (jsx("div", { className: cc(['react-flow__panel', className, ...positionClasses]), style: { ...style, pointerEvents }, ...rest, children: children }));
50
75
  }
@@ -56,35 +81,48 @@ function Attribution({ proOptions, position = 'bottom-right' }) {
56
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" }) }));
57
82
  }
58
83
 
59
- const selector$p = (s) => ({
60
- selectedNodes: s.nodes.filter((n) => n.selected),
61
- selectedEdges: s.edges.filter((e) => e.selected),
62
- });
84
+ const selector$o = (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
+ };
63
99
  const selectId = (obj) => obj.id;
64
100
  function areEqual(a, b) {
65
101
  return (shallow(a.selectedNodes.map(selectId), b.selectedNodes.map(selectId)) &&
66
102
  shallow(a.selectedEdges.map(selectId), b.selectedEdges.map(selectId)));
67
103
  }
68
- const SelectionListener = memo(({ onSelectionChange }) => {
104
+ function SelectionListenerInner({ onSelectionChange }) {
69
105
  const store = useStoreApi();
70
- const { selectedNodes, selectedEdges } = useStore(selector$p, areEqual);
106
+ const { selectedNodes, selectedEdges } = useStore(selector$o, areEqual);
71
107
  useEffect(() => {
72
108
  const params = { nodes: selectedNodes, edges: selectedEdges };
73
109
  onSelectionChange?.(params);
74
110
  store.getState().onSelectionChangeHandlers.forEach((fn) => fn(params));
75
111
  }, [selectedNodes, selectedEdges, onSelectionChange]);
76
112
  return null;
77
- });
78
- SelectionListener.displayName = 'SelectionListener';
113
+ }
79
114
  const changeSelector = (s) => !!s.onSelectionChangeHandlers;
80
- function Wrapper$1({ onSelectionChange }) {
115
+ function SelectionListener({ onSelectionChange }) {
81
116
  const storeHasSelectionChangeHandlers = useStore(changeSelector);
82
117
  if (onSelectionChange || storeHasSelectionChangeHandlers) {
83
- return jsx(SelectionListener, { onSelectionChange: onSelectionChange });
118
+ return jsx(SelectionListenerInner, { onSelectionChange: onSelectionChange });
84
119
  }
85
120
  return null;
86
121
  }
87
122
 
123
+ const defaultNodeOrigin = [0, 0];
124
+ const defaultViewport = { x: 0, y: 0, zoom: 1 };
125
+
88
126
  /*
89
127
  * This component helps us to update the store with the vlues coming from the user.
90
128
  * We distinguish between values we can update directly with `useDirectStoreUpdater` (like `snapGrid`)
@@ -144,41 +182,44 @@ const reactFlowFieldsToTrack = [
144
182
  'selectNodesOnDrag',
145
183
  'nodeDragThreshold',
146
184
  'onBeforeDelete',
185
+ 'debug',
147
186
  ];
148
187
  // rfId doesn't exist in ReactFlowProps, but it's one of the fields we want to update
149
188
  const fieldsToTrack = [...reactFlowFieldsToTrack, 'rfId'];
150
- const selector$o = (s) => ({
189
+ const selector$n = (s) => ({
151
190
  setNodes: s.setNodes,
152
191
  setEdges: s.setEdges,
153
- setDefaultNodesAndEdges: s.setDefaultNodesAndEdges,
154
192
  setMinZoom: s.setMinZoom,
155
193
  setMaxZoom: s.setMaxZoom,
156
194
  setTranslateExtent: s.setTranslateExtent,
157
195
  setNodeExtent: s.setNodeExtent,
158
196
  reset: s.reset,
197
+ setDefaultNodesAndEdges: s.setDefaultNodesAndEdges,
159
198
  });
160
- const StoreUpdater = (props) => {
161
- const { setNodes, setEdges, setDefaultNodesAndEdges, setMinZoom, setMaxZoom, setTranslateExtent, setNodeExtent, reset, } = useStore(selector$o, shallow);
199
+ const initPrevValues = {
200
+ // these are values that are also passed directly to other components
201
+ // than the StoreUpdater. We can reduce the number of setStore calls
202
+ // by setting the same values here as prev fields.
203
+ translateExtent: infiniteExtent,
204
+ nodeOrigin: defaultNodeOrigin,
205
+ minZoom: 0.5,
206
+ maxZoom: 2,
207
+ elementsSelectable: true,
208
+ noPanClassName: 'nopan',
209
+ rfId: '1',
210
+ };
211
+ function StoreUpdater(props) {
212
+ const { setNodes, setEdges, setMinZoom, setMaxZoom, setTranslateExtent, setNodeExtent, reset, setDefaultNodesAndEdges, } = useStore(selector$n, shallow);
162
213
  const store = useStoreApi();
163
214
  useEffect(() => {
164
- const edgesWithDefaults = props.defaultEdges?.map((e) => ({ ...e, ...props.defaultEdgeOptions }));
165
- setDefaultNodesAndEdges(props.defaultNodes, edgesWithDefaults);
215
+ setDefaultNodesAndEdges(props.defaultNodes, props.defaultEdges);
166
216
  return () => {
217
+ // when we reset the store we also need to reset the previous fields
218
+ previousFields.current = initPrevValues;
167
219
  reset();
168
220
  };
169
221
  }, []);
170
- const previousFields = useRef({
171
- // these are values that are also passed directly to other components
172
- // than the StoreUpdater. We can reduce the number of setStore calls
173
- // by setting the same values here as prev fields.
174
- translateExtent: infiniteExtent,
175
- nodeOrigin: initNodeOrigin,
176
- minZoom: 0.5,
177
- maxZoom: 2,
178
- elementsSelectable: true,
179
- noPanClassName: 'nopan',
180
- rfId: '1',
181
- });
222
+ const previousFields = useRef(initPrevValues);
182
223
  useEffect(() => {
183
224
  for (const fieldName of fieldsToTrack) {
184
225
  const fieldValue = props[fieldName];
@@ -214,30 +255,36 @@ const StoreUpdater = (props) => {
214
255
  // Only re-run the effect if one of the fields we track changes
215
256
  fieldsToTrack.map((fieldName) => props[fieldName]));
216
257
  return null;
217
- };
258
+ }
218
259
 
219
- const style = { display: 'none' };
220
- const ariaLiveStyle = {
221
- position: 'absolute',
222
- width: 1,
223
- height: 1,
224
- margin: -1,
225
- border: 0,
226
- padding: 0,
227
- overflow: 'hidden',
228
- clip: 'rect(0px, 0px, 0px, 0px)',
229
- clipPath: 'inset(100%)',
230
- };
231
- const ARIA_NODE_DESC_KEY = 'react-flow__node-desc';
232
- const ARIA_EDGE_DESC_KEY = 'react-flow__edge-desc';
233
- const ARIA_LIVE_MESSAGE = 'react-flow__aria-live';
234
- const selector$n = (s) => s.ariaLiveMessage;
235
- function AriaLiveMessage({ rfId }) {
236
- const ariaLiveMessage = useStore(selector$n);
237
- return (jsx("div", { id: `${ARIA_LIVE_MESSAGE}-${rfId}`, "aria-live": "assertive", "aria-atomic": "true", style: ariaLiveStyle, children: ariaLiveMessage }));
260
+ function getMediaQuery() {
261
+ if (typeof window === 'undefined' || !window.matchMedia) {
262
+ return null;
263
+ }
264
+ return window.matchMedia('(prefers-color-scheme: dark)');
238
265
  }
239
- function A11yDescriptions({ rfId, disableKeyboardA11y }) {
240
- 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 })] }));
266
+ /**
267
+ * Hook for receiving the current color mode class 'dark' or 'light'.
268
+ *
269
+ * @internal
270
+ * @param colorMode - The color mode to use ('dark', 'light' or 'system')
271
+ */
272
+ function useColorModeClass(colorMode) {
273
+ const [colorModeClass, setColorModeClass] = useState(colorMode === 'system' ? null : colorMode);
274
+ useEffect(() => {
275
+ if (colorMode !== 'system') {
276
+ setColorModeClass(colorMode);
277
+ return;
278
+ }
279
+ const mediaQuery = getMediaQuery();
280
+ const updateColorModeClass = () => setColorModeClass(mediaQuery?.matches ? 'dark' : 'light');
281
+ updateColorModeClass();
282
+ mediaQuery?.addEventListener('change', updateColorModeClass);
283
+ return () => {
284
+ mediaQuery?.removeEventListener('change', updateColorModeClass);
285
+ };
286
+ }, [colorMode]);
287
+ return colorModeClass !== null ? colorModeClass : getMediaQuery()?.matches ? 'dark' : 'light';
241
288
  }
242
289
 
243
290
  const defaultDoc = typeof document !== 'undefined' ? document : null;
@@ -249,12 +296,12 @@ const defaultDoc = typeof document !== 'undefined' ? document : null;
249
296
  * @param param.options - Options
250
297
  * @returns boolean
251
298
  */
252
- var useKeyPress = (
299
+ function useKeyPress(
253
300
  // the keycode can be a string 'a' or an array of strings ['a', 'a+d']
254
301
  // a string means a single key 'a' or a combination when '+' is used 'a+d'
255
302
  // an array means different possibilites. Explainer: ['a', 'd+s'] here the
256
303
  // user can use the single key 'a' or the combination 'd' + 's'
257
- keyCode = null, options = { target: defaultDoc, actInsideInputWithModifier: true }) => {
304
+ keyCode = null, options = { target: defaultDoc, actInsideInputWithModifier: true }) {
258
305
  const [keyPressed, setKeyPressed] = useState(false);
259
306
  // we need to remember if a modifier key is pressed in order to track it
260
307
  const modifierPressed = useRef(false);
@@ -306,6 +353,10 @@ keyCode = null, options = { target: defaultDoc, actInsideInputWithModifier: true
306
353
  else {
307
354
  pressedKeys.current.delete(event[keyOrCode]);
308
355
  }
356
+ // fix for Mac: when cmd key is pressed, keyup is not triggered for any other key, see: https://stackoverflow.com/questions/27380018/when-cmd-key-is-kept-pressed-keyup-is-not-triggered-for-any-other-key
357
+ if (event.key === 'Meta') {
358
+ pressedKeys.current.clear();
359
+ }
309
360
  modifierPressed.current = false;
310
361
  };
311
362
  const resetHandler = () => {
@@ -315,15 +366,17 @@ keyCode = null, options = { target: defaultDoc, actInsideInputWithModifier: true
315
366
  target?.addEventListener('keydown', downHandler);
316
367
  target?.addEventListener('keyup', upHandler);
317
368
  window.addEventListener('blur', resetHandler);
369
+ window.addEventListener('contextmenu', resetHandler);
318
370
  return () => {
319
371
  target?.removeEventListener('keydown', downHandler);
320
372
  target?.removeEventListener('keyup', upHandler);
321
373
  window.removeEventListener('blur', resetHandler);
374
+ window.removeEventListener('contextmenu', resetHandler);
322
375
  };
323
376
  }
324
377
  }, [keyCode, setKeyPressed]);
325
378
  return keyPressed;
326
- };
379
+ }
327
380
  // utils
328
381
  function isMatchingKey(keyCodes, pressedKeys, isUp) {
329
382
  return (keyCodes
@@ -339,7 +392,6 @@ function useKeyOrCode(eventCode, keysToWatch) {
339
392
  return keysToWatch.includes(eventCode) ? 'code' : 'key';
340
393
  }
341
394
 
342
- const selector$m = (s) => !!s.panZoom;
343
395
  /**
344
396
  * Hook for getting viewport helper functions.
345
397
  *
@@ -348,8 +400,7 @@ const selector$m = (s) => !!s.panZoom;
348
400
  */
349
401
  const useViewportHelper = () => {
350
402
  const store = useStoreApi();
351
- const panZoomInitialized = useStore(selector$m);
352
- const viewportHelperFunctions = useMemo(() => {
403
+ return useMemo(() => {
353
404
  return {
354
405
  zoomIn: (options) => store.getState().panZoom?.scaleBy(1.2, { duration: options?.duration }),
355
406
  zoomOut: (options) => store.getState().panZoom?.scaleBy(1 / 1.2, { duration: options?.duration }),
@@ -368,10 +419,10 @@ const useViewportHelper = () => {
368
419
  return { x, y, zoom };
369
420
  },
370
421
  fitView: (options) => {
371
- const { nodes, width, height, nodeOrigin, minZoom, maxZoom, panZoom } = store.getState();
422
+ const { nodeLookup, width, height, nodeOrigin, minZoom, maxZoom, panZoom } = store.getState();
372
423
  return panZoom
373
424
  ? fitView({
374
- nodes,
425
+ nodeLookup,
375
426
  width,
376
427
  height,
377
428
  nodeOrigin,
@@ -397,154 +448,123 @@ const useViewportHelper = () => {
397
448
  const viewport = getViewportForBounds(bounds, width, height, minZoom, maxZoom, options?.padding ?? 0.1);
398
449
  panZoom?.setViewport(viewport, { duration: options?.duration });
399
450
  },
400
- screenToFlowPosition: (position) => {
401
- const { transform, snapToGrid, snapGrid, domNode } = store.getState();
451
+ screenToFlowPosition: (clientPosition, options = { snapToGrid: true }) => {
452
+ const { transform, snapGrid, domNode } = store.getState();
402
453
  if (!domNode) {
403
- return position;
454
+ return clientPosition;
404
455
  }
405
456
  const { x: domX, y: domY } = domNode.getBoundingClientRect();
406
457
  const correctedPosition = {
407
- x: position.x - domX,
408
- y: position.y - domY,
458
+ x: clientPosition.x - domX,
459
+ y: clientPosition.y - domY,
409
460
  };
410
- return pointToRendererPoint(correctedPosition, transform, snapToGrid, snapGrid || [1, 1]);
461
+ return pointToRendererPoint(correctedPosition, transform, options.snapToGrid, snapGrid);
411
462
  },
412
- flowToScreenPosition: (position) => {
463
+ flowToScreenPosition: (flowPosition) => {
413
464
  const { transform, domNode } = store.getState();
414
465
  if (!domNode) {
415
- return position;
466
+ return flowPosition;
416
467
  }
417
468
  const { x: domX, y: domY } = domNode.getBoundingClientRect();
418
- const rendererPosition = rendererPointToPoint(position, transform);
469
+ const rendererPosition = rendererPointToPoint(flowPosition, transform);
419
470
  return {
420
471
  x: rendererPosition.x + domX,
421
472
  y: rendererPosition.y + domY,
422
473
  };
423
474
  },
424
- viewportInitialized: panZoomInitialized,
425
475
  };
426
- }, [panZoomInitialized]);
427
- return viewportHelperFunctions;
476
+ }, []);
428
477
  };
429
478
 
430
- function handleParentExpand(res, updateItem) {
431
- const parent = res.find((e) => e.id === updateItem.parentNode);
432
- if (parent) {
433
- if (!parent.computed) {
434
- parent.computed = {};
435
- }
436
- const extendWidth = updateItem.position.x + updateItem.computed.width - parent.computed.width;
437
- const extendHeight = updateItem.position.y + updateItem.computed.height - parent.computed.height;
438
- if (extendWidth > 0 || extendHeight > 0 || updateItem.position.x < 0 || updateItem.position.y < 0) {
439
- parent.style = { ...parent.style } || {};
440
- parent.style.width = parent.style.width ?? parent.computed.width;
441
- parent.style.height = parent.style.height ?? parent.computed.height;
442
- if (extendWidth > 0) {
443
- parent.style.width += extendWidth;
444
- }
445
- if (extendHeight > 0) {
446
- parent.style.height += extendHeight;
447
- }
448
- if (updateItem.position.x < 0) {
449
- const xDiff = Math.abs(updateItem.position.x);
450
- parent.position.x = parent.position.x - xDiff;
451
- parent.style.width += xDiff;
452
- updateItem.position.x = 0;
453
- }
454
- if (updateItem.position.y < 0) {
455
- const yDiff = Math.abs(updateItem.position.y);
456
- parent.position.y = parent.position.y - yDiff;
457
- parent.style.height += yDiff;
458
- updateItem.position.y = 0;
459
- }
460
- parent.computed.width = parent.style.width;
461
- parent.computed.height = parent.style.height;
462
- }
463
- }
464
- }
465
479
  // This function applies changes to nodes or edges that are triggered by React Flow internally.
466
480
  // When you drag a node for example, React Flow will send a position change update.
467
481
  // This function then applies the changes and returns the updated elements.
468
482
  function applyChanges(changes, elements) {
469
- // we need this hack to handle the setNodes and setEdges function of the useReactFlow hook for controlled flows
470
- if (changes.some((c) => c.type === 'reset')) {
471
- return changes.filter((c) => c.type === 'reset').map((c) => c.item);
472
- }
473
- let remainingChanges = changes;
474
483
  const updatedElements = [];
475
- for (const item of elements) {
476
- const nextChanges = [];
477
- const _remainingChanges = [];
478
- for (const c of remainingChanges) {
479
- if (c.type === 'add') {
480
- updatedElements.push(c.item);
481
- }
482
- else if (c.id === item.id) {
483
- nextChanges.push(c);
484
+ // By storing a map of changes for each element, we can a quick lookup as we
485
+ // iterate over the elements array!
486
+ const changesMap = new Map();
487
+ for (const change of changes) {
488
+ if (change.type === 'add') {
489
+ updatedElements.push(change.item);
490
+ continue;
491
+ }
492
+ else if (change.type === 'remove' || change.type === 'replace') {
493
+ // For a 'remove' change we can safely ignore any other changes queued for
494
+ // the same element, it's going to be removed anyway!
495
+ changesMap.set(change.id, [change]);
496
+ }
497
+ else {
498
+ const elementChanges = changesMap.get(change.id);
499
+ if (elementChanges) {
500
+ // If we have some changes queued already, we can do a mutable update of
501
+ // that array and save ourselves some copying.
502
+ elementChanges.push(change);
484
503
  }
485
504
  else {
486
- _remainingChanges.push(c);
505
+ changesMap.set(change.id, [change]);
487
506
  }
488
507
  }
489
- remainingChanges = _remainingChanges;
490
- if (nextChanges.length === 0) {
491
- updatedElements.push(item);
508
+ }
509
+ for (const element of elements) {
510
+ const changes = changesMap.get(element.id);
511
+ // When there are no changes for an element we can just push it unmodified,
512
+ // no need to copy it.
513
+ if (!changes) {
514
+ updatedElements.push(element);
492
515
  continue;
493
516
  }
494
- const updateItem = { ...item };
495
- for (const currentChange of nextChanges) {
496
- if (currentChange) {
497
- switch (currentChange.type) {
498
- case 'select': {
499
- updateItem.selected = currentChange.selected;
500
- break;
501
- }
502
- case 'position': {
503
- if (typeof currentChange.position !== 'undefined') {
504
- updateItem.position = currentChange.position;
505
- }
506
- if (typeof currentChange.positionAbsolute !== 'undefined') {
507
- if (!updateItem.computed) {
508
- updateItem.computed = {};
509
- }
510
- updateItem.computed.positionAbsolute = currentChange.positionAbsolute;
511
- }
512
- if (typeof currentChange.dragging !== 'undefined') {
513
- updateItem.dragging = currentChange.dragging;
514
- }
515
- if (updateItem.expandParent) {
516
- handleParentExpand(updatedElements, updateItem);
517
- }
518
- break;
519
- }
520
- case 'dimensions': {
521
- if (typeof currentChange.dimensions !== 'undefined') {
522
- if (!updateItem.computed) {
523
- updateItem.computed = {};
524
- }
525
- updateItem.computed.width = currentChange.dimensions.width;
526
- updateItem.computed.height = currentChange.dimensions.height;
527
- }
528
- if (typeof currentChange.updateStyle !== 'undefined') {
529
- updateItem.style = { ...(updateItem.style || {}), ...currentChange.dimensions };
530
- }
531
- if (typeof currentChange.resizing === 'boolean') {
532
- updateItem.resizing = currentChange.resizing;
533
- }
534
- if (updateItem.expandParent) {
535
- handleParentExpand(updatedElements, updateItem);
536
- }
537
- break;
538
- }
539
- case 'remove': {
540
- continue;
541
- }
517
+ // If we have a 'remove' change queued, it'll be the only change in the array
518
+ if (changes[0].type === 'remove') {
519
+ continue;
520
+ }
521
+ if (changes[0].type === 'replace') {
522
+ updatedElements.push({ ...changes[0].item });
523
+ continue;
524
+ }
525
+ // For other types of changes, we want to start with a shallow copy of the
526
+ // object so React knows this element has changed. Sequential changes will
527
+ /// each _mutate_ this object, so there's only ever one copy.
528
+ const updatedElement = { ...element };
529
+ for (const change of changes) {
530
+ applyChange(change, updatedElement);
531
+ }
532
+ updatedElements.push(updatedElement);
533
+ }
534
+ return updatedElements;
535
+ }
536
+ // Applies a single change to an element. This is a *mutable* update.
537
+ function applyChange(change, element) {
538
+ switch (change.type) {
539
+ case 'select': {
540
+ element.selected = change.selected;
541
+ break;
542
+ }
543
+ case 'position': {
544
+ if (typeof change.position !== 'undefined') {
545
+ element.position = change.position;
546
+ }
547
+ if (typeof change.dragging !== 'undefined') {
548
+ element.dragging = change.dragging;
549
+ }
550
+ break;
551
+ }
552
+ case 'dimensions': {
553
+ if (typeof change.dimensions !== 'undefined') {
554
+ element.measured ??= {};
555
+ element.measured.width = change.dimensions.width;
556
+ element.measured.height = change.dimensions.height;
557
+ if (change.setAttributes) {
558
+ element.width = change.dimensions.width;
559
+ element.height = change.dimensions.height;
542
560
  }
543
561
  }
544
- updatedElements.push(updateItem);
562
+ if (typeof change.resizing === 'boolean') {
563
+ element.resizing = change.resizing;
564
+ }
565
+ break;
545
566
  }
546
567
  }
547
- return updatedElements;
548
568
  }
549
569
  /**
550
570
  * Drop in function that applies node changes to an array of nodes.
@@ -586,21 +606,23 @@ function applyNodeChanges(changes, nodes) {
586
606
  );
587
607
 
588
608
  return (
589
- <ReactFLow nodes={nodes} edges={edges} onEdgesChange={onEdgesChange} />
609
+ <ReactFlow nodes={nodes} edges={edges} onEdgesChange={onEdgesChange} />
590
610
  );
591
611
  */
592
612
  function applyEdgeChanges(changes, edges) {
593
613
  return applyChanges(changes, edges);
594
614
  }
595
- const createSelectionChange = (id, selected) => ({
596
- id,
597
- type: 'select',
598
- selected,
599
- });
615
+ function createSelectionChange(id, selected) {
616
+ return {
617
+ id,
618
+ type: 'select',
619
+ selected,
620
+ };
621
+ }
600
622
  function getSelectionChanges(items, selectedIds = new Set(), mutateItem = false) {
601
623
  const changes = [];
602
- for (const item of items) {
603
- const willBeSelected = selectedIds.has(item.id);
624
+ for (const [id, item] of items) {
625
+ const willBeSelected = selectedIds.has(id);
604
626
  // we don't want to set all items to selected=false on the first selection
605
627
  if (!(item.selected === undefined && !willBeSelected) && item.selected !== willBeSelected) {
606
628
  if (mutateItem) {
@@ -614,6 +636,33 @@ function getSelectionChanges(items, selectedIds = new Set(), mutateItem = false)
614
636
  }
615
637
  return changes;
616
638
  }
639
+ function getElementsDiffChanges({ items = [], lookup, }) {
640
+ const changes = [];
641
+ const itemsLookup = new Map(items.map((item) => [item.id, item]));
642
+ for (const item of items) {
643
+ const lookupItem = lookup.get(item.id);
644
+ const storeItem = lookupItem?.internals?.userNode ?? lookupItem;
645
+ if (storeItem !== undefined && storeItem !== item) {
646
+ changes.push({ id: item.id, item: item, type: 'replace' });
647
+ }
648
+ if (storeItem === undefined) {
649
+ changes.push({ item: item, type: 'add' });
650
+ }
651
+ }
652
+ for (const [id] of lookup) {
653
+ const nextNode = itemsLookup.get(id);
654
+ if (nextNode === undefined) {
655
+ changes.push({ id, type: 'remove' });
656
+ }
657
+ }
658
+ return changes;
659
+ }
660
+ function elementToRemoveChange(item) {
661
+ return {
662
+ id: item.id,
663
+ type: 'remove',
664
+ };
665
+ }
617
666
 
618
667
  /**
619
668
  * Test whether an object is useable as a Node
@@ -622,7 +671,7 @@ function getSelectionChanges(items, selectedIds = new Set(), mutateItem = false)
622
671
  * @param element - The element to test
623
672
  * @returns A boolean indicating whether the element is an Node
624
673
  */
625
- const isNode = (isNodeBase);
674
+ const isNode = (element) => isNodeBase(element);
626
675
  /**
627
676
  * Test whether an object is useable as an Edge
628
677
  * @public
@@ -630,253 +679,289 @@ const isNode = (isNodeBase);
630
679
  * @param element - The element to test
631
680
  * @returns A boolean indicating whether the element is an Edge
632
681
  */
633
- const isEdge = (isEdgeBase);
634
- /**
635
- * Pass in a node, and get connected nodes where edge.source === node.id
636
- * @public
637
- * @param node - The node to get the connected nodes from
638
- * @param nodes - The array of all nodes
639
- * @param edges - The array of all edges
640
- * @returns An array of nodes that are connected over eges where the source is the given node
641
- */
642
- const getOutgoers = (getOutgoersBase);
643
- /**
644
- * Pass in a node, and get connected nodes where edge.target === node.id
645
- * @public
646
- * @param node - The node to get the connected nodes from
647
- * @param nodes - The array of all nodes
648
- * @param edges - The array of all edges
649
- * @returns An array of nodes that are connected over eges where the target is the given node
650
- */
651
- const getIncomers = (getIncomersBase);
652
- /**
653
- * This util is a convenience function to add a new Edge to an array of edges
654
- * @remarks It also performs some validation to make sure you don't add an invalid edge or duplicate an existing one.
655
- * @public
656
- * @param edgeParams - Either an Edge or a Connection you want to add
657
- * @param edges - The array of all current edges
658
- * @returns A new array of edges with the new edge added
659
- */
660
- const addEdge = (addEdgeBase);
661
- /**
662
- * A handy utility to update an existing Edge with new properties
663
- * @param oldEdge - The edge you want to update
664
- * @param newConnection - The new connection you want to update the edge with
665
- * @param edges - The array of all current edges
666
- * @param options.shouldReplaceId - should the id of the old edge be replaced with the new connection id
667
- * @returns the updated edges array
668
- */
669
- const updateEdge = (updateEdgeBase);
682
+ const isEdge = (element) => isEdgeBase(element);
683
+ // eslint-disable-next-line @typescript-eslint/ban-types
684
+ function fixedForwardRef(render) {
685
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
686
+ return forwardRef(render);
687
+ }
688
+
689
+ // we need this hook to prevent a warning when using react-flow in SSR
690
+ const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
691
+
670
692
  /**
671
- * Get all connecting edges for a given set of nodes
672
- * @param nodes - Nodes you want to get the connected edges for
673
- * @param edges - All edges
674
- * @returns Array of edges that connect any of the given nodes with each other
693
+ * This hook returns a queue that can be used to batch updates.
694
+ *
695
+ * @param runQueue - a function that gets called when the queue is flushed
696
+ * @internal
697
+ *
698
+ * @returns a Queue object
675
699
  */
676
- const getConnectedEdges = (getConnectedEdgesBase);
700
+ function useQueue(runQueue) {
701
+ // Because we're using a ref above, we need some way to let React know when to
702
+ // actually process the queue. We flip this bit of state to `true` any time we
703
+ // mutate the queue and then flip it back to `false` after flushing the queue.
704
+ const [shouldFlush, setShouldFlush] = useState(false);
705
+ // A reference of all the batched updates to process before the next render. We
706
+ // want a reference here so multiple synchronous calls to `setNodes` etc can be
707
+ // batched together.
708
+ const [queue] = useState(() => createQueue(() => setShouldFlush(true)));
709
+ // Layout effects are guaranteed to run before the next render which means we
710
+ // shouldn't run into any issues with stale state or weird issues that come from
711
+ // rendering things one frame later than expected (we used to use `setTimeout`).
712
+ useIsomorphicLayoutEffect(() => {
713
+ // Because we need to flip the state back to false after flushing, this should
714
+ // trigger the hook again (!). If the hook is being run again we know that any
715
+ // updates should have been processed by now and we can safely clear the queue
716
+ // and bail early.
717
+ if (!shouldFlush) {
718
+ queue.reset();
719
+ return;
720
+ }
721
+ const queueItems = queue.get();
722
+ if (queueItems.length) {
723
+ runQueue(queueItems);
724
+ queue.reset();
725
+ }
726
+ // Beacuse we're using reactive state to trigger this effect, we need to flip
727
+ // it back to false.
728
+ setShouldFlush(false);
729
+ }, [shouldFlush]);
730
+ return queue;
731
+ }
732
+ function createQueue(cb) {
733
+ let queue = [];
734
+ return {
735
+ get: () => queue,
736
+ reset: () => {
737
+ queue = [];
738
+ },
739
+ push: (item) => {
740
+ queue.push(item);
741
+ cb();
742
+ },
743
+ };
744
+ }
677
745
 
746
+ const BatchContext = createContext(null);
678
747
  /**
679
- * Hook for accessing the ReactFlow instance.
748
+ * This is a context provider that holds and processes the node and edge update queues
749
+ * that are needed to handle setNodes, addNodes, setEdges and addEdges.
680
750
  *
681
- * @public
682
- * @returns ReactFlowInstance
751
+ * @internal
683
752
  */
684
- function useReactFlow() {
685
- const viewportHelper = useViewportHelper();
753
+ function BatchProvider({ children, }) {
686
754
  const store = useStoreApi();
687
- const getNodes = useCallback(() => {
688
- return store.getState().nodes.map((n) => ({ ...n }));
689
- }, []);
690
- const getNode = useCallback((id) => {
691
- return store.getState().nodeLookup.get(id);
692
- }, []);
693
- const getEdges = useCallback(() => {
694
- const { edges = [] } = store.getState();
695
- return edges.map((e) => ({ ...e }));
696
- }, []);
697
- const getEdge = useCallback((id) => {
698
- const { edges = [] } = store.getState();
699
- return edges.find((e) => e.id === id);
700
- }, []);
701
- const setNodes = useCallback((payload) => {
702
- const { nodes, setNodes, hasDefaultNodes, onNodesChange } = store.getState();
703
- const nextNodes = typeof payload === 'function' ? payload(nodes) : payload;
704
- if (hasDefaultNodes) {
705
- setNodes(nextNodes);
706
- }
707
- else if (onNodesChange) {
708
- const changes = nextNodes.length === 0
709
- ? nodes.map((node) => ({ type: 'remove', id: node.id }))
710
- : nextNodes.map((node) => ({ item: node, type: 'reset' }));
711
- onNodesChange(changes);
755
+ const nodeQueueHandler = useCallback((queueItems) => {
756
+ const { nodes = [], setNodes, hasDefaultNodes, onNodesChange, nodeLookup } = store.getState();
757
+ // This is essentially an `Array.reduce` in imperative clothing. Processing
758
+ // this queue is a relatively hot path so we'd like to avoid the overhead of
759
+ // array methods where we can.
760
+ let next = nodes;
761
+ for (const payload of queueItems) {
762
+ next = typeof payload === 'function' ? payload(next) : payload;
712
763
  }
713
- }, []);
714
- const setEdges = useCallback((payload) => {
715
- const { edges = [], setEdges, hasDefaultEdges, onEdgesChange } = store.getState();
716
- const nextEdges = typeof payload === 'function' ? payload(edges) : payload;
717
- if (hasDefaultEdges) {
718
- setEdges(nextEdges);
719
- }
720
- else if (onEdgesChange) {
721
- const changes = nextEdges.length === 0
722
- ? edges.map((edge) => ({ type: 'remove', id: edge.id }))
723
- : nextEdges.map((edge) => ({ item: edge, type: 'reset' }));
724
- onEdgesChange(changes);
725
- }
726
- }, []);
727
- const addNodes = useCallback((payload) => {
728
- const nodes = Array.isArray(payload) ? payload : [payload];
729
- const { nodes: currentNodes, hasDefaultNodes, onNodesChange, setNodes } = store.getState();
730
764
  if (hasDefaultNodes) {
731
- const nextNodes = [...currentNodes, ...nodes];
732
- setNodes(nextNodes);
765
+ setNodes(next);
733
766
  }
734
767
  else if (onNodesChange) {
735
- const changes = nodes.map((node) => ({ item: node, type: 'add' }));
736
- onNodesChange(changes);
768
+ onNodesChange(getElementsDiffChanges({
769
+ items: next,
770
+ lookup: nodeLookup,
771
+ }));
737
772
  }
738
773
  }, []);
739
- const addEdges = useCallback((payload) => {
740
- const nextEdges = Array.isArray(payload) ? payload : [payload];
741
- const { edges = [], setEdges, hasDefaultEdges, onEdgesChange } = store.getState();
774
+ const nodeQueue = useQueue(nodeQueueHandler);
775
+ const edgeQueueHandler = useCallback((queueItems) => {
776
+ const { edges = [], setEdges, hasDefaultEdges, onEdgesChange, edgeLookup } = store.getState();
777
+ let next = edges;
778
+ for (const payload of queueItems) {
779
+ next = typeof payload === 'function' ? payload(next) : payload;
780
+ }
742
781
  if (hasDefaultEdges) {
743
- setEdges([...edges, ...nextEdges]);
782
+ setEdges(next);
744
783
  }
745
784
  else if (onEdgesChange) {
746
- const changes = nextEdges.map((edge) => ({ item: edge, type: 'add' }));
747
- onEdgesChange(changes);
785
+ onEdgesChange(getElementsDiffChanges({
786
+ items: next,
787
+ lookup: edgeLookup,
788
+ }));
748
789
  }
749
790
  }, []);
750
- const toObject = useCallback(() => {
751
- const { nodes = [], edges = [], transform } = store.getState();
752
- const [x, y, zoom] = transform;
791
+ const edgeQueue = useQueue(edgeQueueHandler);
792
+ const value = useMemo(() => ({ nodeQueue, edgeQueue }), []);
793
+ return jsx(BatchContext.Provider, { value: value, children: children });
794
+ }
795
+ function useBatchContext() {
796
+ const batchContext = useContext(BatchContext);
797
+ if (!batchContext) {
798
+ throw new Error('useBatchContext must be used within a BatchProvider');
799
+ }
800
+ return batchContext;
801
+ }
802
+
803
+ const selector$m = (s) => !!s.panZoom;
804
+ /**
805
+ * Hook for accessing the ReactFlow instance.
806
+ *
807
+ * @public
808
+ * @returns ReactFlowInstance
809
+ */
810
+ function useReactFlow() {
811
+ const viewportHelper = useViewportHelper();
812
+ const store = useStoreApi();
813
+ const batchContext = useBatchContext();
814
+ const viewportInitialized = useStore(selector$m);
815
+ const generalHelper = useMemo(() => {
816
+ const getInternalNode = (id) => store.getState().nodeLookup.get(id);
817
+ const setNodes = (payload) => {
818
+ batchContext.nodeQueue.push(payload);
819
+ };
820
+ const setEdges = (payload) => {
821
+ batchContext.edgeQueue.push(payload);
822
+ };
823
+ const getNodeRect = (node) => {
824
+ const { nodeLookup, nodeOrigin } = store.getState();
825
+ const nodeToUse = isNode(node) ? node : nodeLookup.get(node.id);
826
+ const position = nodeToUse.parentId
827
+ ? evaluateAbsolutePosition(nodeToUse.position, nodeToUse.parentId, nodeLookup, nodeOrigin)
828
+ : nodeToUse.position;
829
+ const nodeWithPosition = {
830
+ id: nodeToUse.id,
831
+ position,
832
+ width: nodeToUse.measured?.width ?? nodeToUse.width,
833
+ height: nodeToUse.measured?.height ?? nodeToUse.height,
834
+ data: nodeToUse.data,
835
+ };
836
+ return nodeToRect(nodeWithPosition);
837
+ };
838
+ const updateNode = (id, nodeUpdate, options = { replace: false }) => {
839
+ setNodes((prevNodes) => prevNodes.map((node) => {
840
+ if (node.id === id) {
841
+ const nextNode = typeof nodeUpdate === 'function' ? nodeUpdate(node) : nodeUpdate;
842
+ return options.replace && isNode(nextNode) ? nextNode : { ...node, ...nextNode };
843
+ }
844
+ return node;
845
+ }));
846
+ };
847
+ const updateEdge = (id, edgeUpdate, options = { replace: false }) => {
848
+ setEdges((prevEdges) => prevEdges.map((edge) => {
849
+ if (edge.id === id) {
850
+ const nextEdge = typeof edgeUpdate === 'function' ? edgeUpdate(edge) : edgeUpdate;
851
+ return options.replace && isEdge(nextEdge) ? nextEdge : { ...edge, ...nextEdge };
852
+ }
853
+ return edge;
854
+ }));
855
+ };
753
856
  return {
754
- nodes: nodes.map((n) => ({ ...n })),
755
- edges: edges.map((e) => ({ ...e })),
756
- viewport: {
757
- x,
758
- y,
759
- zoom,
857
+ getNodes: () => store.getState().nodes.map((n) => ({ ...n })),
858
+ getNode: (id) => getInternalNode(id)?.internals.userNode,
859
+ getInternalNode,
860
+ getEdges: () => {
861
+ const { edges = [] } = store.getState();
862
+ return edges.map((e) => ({ ...e }));
760
863
  },
761
- };
762
- }, []);
763
- const deleteElements = useCallback(async ({ nodes: nodesToRemove = [], edges: edgesToRemove = [], onBeforeDelete }) => {
764
- const { nodes, edges, hasDefaultNodes, hasDefaultEdges, onNodesDelete, onEdgesDelete, onNodesChange, onEdgesChange, onDelete, } = store.getState();
765
- const { nodes: matchingNodes, edges: matchingEdges } = await getElementsToRemove({
766
- nodesToRemove,
767
- edgesToRemove,
768
- nodes,
769
- edges,
770
- onBeforeDelete,
771
- });
772
- const hasMatchingEdges = matchingEdges.length > 0;
773
- const hasMatchingNodes = matchingNodes.length > 0;
774
- if (hasMatchingEdges) {
775
- if (hasDefaultEdges) {
776
- store.setState({
777
- edges: edges.filter((e) => !matchingEdges.some((mE) => mE.id === e.id)),
864
+ getEdge: (id) => store.getState().edgeLookup.get(id),
865
+ setNodes,
866
+ setEdges,
867
+ addNodes: (payload) => {
868
+ const newNodes = Array.isArray(payload) ? payload : [payload];
869
+ batchContext.nodeQueue.push((nodes) => [...nodes, ...newNodes]);
870
+ },
871
+ addEdges: (payload) => {
872
+ const newEdges = Array.isArray(payload) ? payload : [payload];
873
+ batchContext.edgeQueue.push((edges) => [...edges, ...newEdges]);
874
+ },
875
+ toObject: () => {
876
+ const { nodes = [], edges = [], transform } = store.getState();
877
+ const [x, y, zoom] = transform;
878
+ return {
879
+ nodes: nodes.map((n) => ({ ...n })),
880
+ edges: edges.map((e) => ({ ...e })),
881
+ viewport: {
882
+ x,
883
+ y,
884
+ zoom,
885
+ },
886
+ };
887
+ },
888
+ deleteElements: async ({ nodes: nodesToRemove = [], edges: edgesToRemove = [] }) => {
889
+ const { nodes, edges, onNodesDelete, onEdgesDelete, triggerNodeChanges, triggerEdgeChanges, onDelete, onBeforeDelete, } = store.getState();
890
+ const { nodes: matchingNodes, edges: matchingEdges } = await getElementsToRemove({
891
+ nodesToRemove,
892
+ edgesToRemove,
893
+ nodes,
894
+ edges,
895
+ onBeforeDelete,
778
896
  });
779
- }
780
- onEdgesDelete?.(matchingEdges);
781
- onEdgesChange?.(matchingEdges.map((edge) => ({
782
- id: edge.id,
783
- type: 'remove',
784
- })));
785
- }
786
- if (hasMatchingNodes) {
787
- if (hasDefaultNodes) {
788
- store.setState({
789
- nodes: nodes.filter((n) => !matchingNodes.some((mN) => mN.id === n.id)),
897
+ const hasMatchingEdges = matchingEdges.length > 0;
898
+ const hasMatchingNodes = matchingNodes.length > 0;
899
+ if (hasMatchingEdges) {
900
+ const edgeChanges = matchingEdges.map(elementToRemoveChange);
901
+ onEdgesDelete?.(matchingEdges);
902
+ triggerEdgeChanges(edgeChanges);
903
+ }
904
+ if (hasMatchingNodes) {
905
+ const nodeChanges = matchingNodes.map(elementToRemoveChange);
906
+ onNodesDelete?.(matchingNodes);
907
+ triggerNodeChanges(nodeChanges);
908
+ }
909
+ if (hasMatchingNodes || hasMatchingEdges) {
910
+ onDelete?.({ nodes: matchingNodes, edges: matchingEdges });
911
+ }
912
+ return { deletedNodes: matchingNodes, deletedEdges: matchingEdges };
913
+ },
914
+ getIntersectingNodes: (nodeOrRect, partially = true, nodes) => {
915
+ const isRect = isRectObject(nodeOrRect);
916
+ const nodeRect = isRect ? nodeOrRect : getNodeRect(nodeOrRect);
917
+ const hasNodesOption = nodes !== undefined;
918
+ if (!nodeRect) {
919
+ return [];
920
+ }
921
+ return (nodes || store.getState().nodes).filter((n) => {
922
+ const internalNode = store.getState().nodeLookup.get(n.id);
923
+ if (internalNode && !isRect && (n.id === nodeOrRect.id || !internalNode.internals.positionAbsolute)) {
924
+ return false;
925
+ }
926
+ const currNodeRect = nodeToRect(hasNodesOption ? n : internalNode);
927
+ const overlappingArea = getOverlappingArea(currNodeRect, nodeRect);
928
+ const partiallyVisible = partially && overlappingArea > 0;
929
+ return partiallyVisible || overlappingArea >= nodeRect.width * nodeRect.height;
790
930
  });
791
- }
792
- onNodesDelete?.(matchingNodes);
793
- onNodesChange?.(matchingNodes.map((node) => ({ id: node.id, type: 'remove' })));
794
- }
795
- if (hasMatchingNodes || hasMatchingEdges) {
796
- onDelete?.({ nodes: matchingNodes, edges: matchingEdges });
797
- }
798
- return { deletedNodes: matchingNodes, deletedEdges: matchingEdges };
799
- }, []);
800
- const getNodeRect = useCallback((nodeOrRect) => {
801
- const isRect = isRectObject(nodeOrRect);
802
- const node = isRect ? null : store.getState().nodeLookup.get(nodeOrRect.id);
803
- const nodeRect = isRect ? nodeOrRect : nodeToRect(node);
804
- return [nodeRect, node, isRect];
805
- }, []);
806
- const getIntersectingNodes = useCallback((nodeOrRect, partially = true, nodes) => {
807
- const [nodeRect, node, isRect] = getNodeRect(nodeOrRect);
808
- if (!nodeRect) {
809
- return [];
810
- }
811
- return (nodes || store.getState().nodes).filter((n) => {
812
- if (!isRect && (n.id === node.id || !n.computed?.positionAbsolute)) {
813
- return false;
814
- }
815
- const currNodeRect = nodeToRect(n);
816
- const overlappingArea = getOverlappingArea(currNodeRect, nodeRect);
817
- const partiallyVisible = partially && overlappingArea > 0;
818
- return partiallyVisible || overlappingArea >= nodeRect.width * nodeRect.height;
819
- });
820
- }, []);
821
- const isNodeIntersecting = useCallback((nodeOrRect, area, partially = true) => {
822
- const [nodeRect] = getNodeRect(nodeOrRect);
823
- if (!nodeRect) {
824
- return false;
825
- }
826
- const overlappingArea = getOverlappingArea(nodeRect, area);
827
- const partiallyVisible = partially && overlappingArea > 0;
828
- return partiallyVisible || overlappingArea >= nodeRect.width * nodeRect.height;
931
+ },
932
+ isNodeIntersecting: (nodeOrRect, area, partially = true) => {
933
+ const isRect = isRectObject(nodeOrRect);
934
+ const nodeRect = isRect ? nodeOrRect : getNodeRect(nodeOrRect);
935
+ if (!nodeRect) {
936
+ return false;
937
+ }
938
+ const overlappingArea = getOverlappingArea(nodeRect, area);
939
+ const partiallyVisible = partially && overlappingArea > 0;
940
+ return partiallyVisible || overlappingArea >= nodeRect.width * nodeRect.height;
941
+ },
942
+ updateNode,
943
+ updateNodeData: (id, dataUpdate, options = { replace: false }) => {
944
+ updateNode(id, (node) => {
945
+ const nextData = typeof dataUpdate === 'function' ? dataUpdate(node) : dataUpdate;
946
+ return options.replace ? { ...node, data: nextData } : { ...node, data: { ...node.data, ...nextData } };
947
+ }, options);
948
+ },
949
+ updateEdge,
950
+ updateEdgeData: (id, dataUpdate, options = { replace: false }) => {
951
+ updateEdge(id, (edge) => {
952
+ const nextData = typeof dataUpdate === 'function' ? dataUpdate(edge) : dataUpdate;
953
+ return options.replace ? { ...edge, data: nextData } : { ...edge, data: { ...edge.data, ...nextData } };
954
+ }, options);
955
+ },
956
+ };
829
957
  }, []);
830
- const updateNode = useCallback((id, nodeUpdate, options = { replace: true }) => {
831
- setNodes((prevNodes) => prevNodes.map((node) => {
832
- if (node.id === id) {
833
- const nextNode = typeof nodeUpdate === 'function' ? nodeUpdate(node) : nodeUpdate;
834
- return options.replace && isNode(nextNode) ? nextNode : { ...node, ...nextNode };
835
- }
836
- return node;
837
- }));
838
- }, [setNodes]);
839
- const updateNodeData = useCallback((id, dataUpdate, options = { replace: false }) => {
840
- updateNode(id, (node) => {
841
- const nextData = typeof dataUpdate === 'function' ? dataUpdate(node) : dataUpdate;
842
- return options.replace ? { ...node, data: nextData } : { ...node, data: { ...node.data, ...nextData } };
843
- }, options);
844
- }, [updateNode]);
845
958
  return useMemo(() => {
846
959
  return {
960
+ ...generalHelper,
847
961
  ...viewportHelper,
848
- getNodes,
849
- getNode,
850
- getEdges,
851
- getEdge,
852
- setNodes,
853
- setEdges,
854
- addNodes,
855
- addEdges,
856
- toObject,
857
- deleteElements,
858
- getIntersectingNodes,
859
- isNodeIntersecting,
860
- updateNode,
861
- updateNodeData,
962
+ viewportInitialized,
862
963
  };
863
- }, [
864
- viewportHelper,
865
- getNodes,
866
- getNode,
867
- getEdges,
868
- getEdge,
869
- setNodes,
870
- setEdges,
871
- addNodes,
872
- addEdges,
873
- toObject,
874
- deleteElements,
875
- getIntersectingNodes,
876
- isNodeIntersecting,
877
- updateNode,
878
- updateNodeData,
879
- ]);
964
+ }, [viewportInitialized]);
880
965
  }
881
966
 
882
967
  const selected = (item) => item.selected;
@@ -886,22 +971,22 @@ const deleteKeyOptions = { actInsideInputWithModifier: false };
886
971
  *
887
972
  * @internal
888
973
  */
889
- var useGlobalKeyHandler = ({ deleteKeyCode, multiSelectionKeyCode, }) => {
974
+ function useGlobalKeyHandler({ deleteKeyCode, multiSelectionKeyCode, }) {
890
975
  const store = useStoreApi();
891
976
  const { deleteElements } = useReactFlow();
892
977
  const deleteKeyPressed = useKeyPress(deleteKeyCode, deleteKeyOptions);
893
978
  const multiSelectionKeyPressed = useKeyPress(multiSelectionKeyCode);
894
979
  useEffect(() => {
895
980
  if (deleteKeyPressed) {
896
- const { edges, nodes, onBeforeDelete } = store.getState();
897
- deleteElements({ nodes: nodes.filter(selected), edges: edges.filter(selected), onBeforeDelete });
981
+ const { edges, nodes } = store.getState();
982
+ deleteElements({ nodes: nodes.filter(selected), edges: edges.filter(selected) });
898
983
  store.setState({ nodesSelectionActive: false });
899
984
  }
900
985
  }, [deleteKeyPressed]);
901
986
  useEffect(() => {
902
987
  store.setState({ multiSelectionActive: multiSelectionKeyPressed });
903
988
  }, [multiSelectionKeyPressed]);
904
- };
989
+ }
905
990
 
906
991
  /**
907
992
  * Hook for handling resize events.
@@ -948,7 +1033,7 @@ const selector$l = (s) => ({
948
1033
  userSelectionActive: s.userSelectionActive,
949
1034
  lib: s.lib,
950
1035
  });
951
- const 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, }) => {
1036
+ 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, }) {
952
1037
  const store = useStoreApi();
953
1038
  const zoomPane = useRef(null);
954
1039
  const { userSelectionActive, lib } = useStore(selector$l, shallow);
@@ -1031,7 +1116,7 @@ const ZoomPane = ({ onPaneContextMenu, zoomOnScroll = true, zoomOnPinch = true,
1031
1116
  lib,
1032
1117
  ]);
1033
1118
  return (jsx("div", { className: "react-flow__renderer", ref: zoomPane, style: containerStyle, children: children }));
1034
- };
1119
+ }
1035
1120
 
1036
1121
  const selector$k = (s) => ({
1037
1122
  userSelectionActive: s.userSelectionActive,
@@ -1063,12 +1148,13 @@ const selector$j = (s) => ({
1063
1148
  elementsSelectable: s.elementsSelectable,
1064
1149
  dragging: s.paneDragging,
1065
1150
  });
1066
- const Pane = memo(({ isSelecting, selectionMode = SelectionMode.Full, panOnDrag, onSelectionStart, onSelectionEnd, onPaneClick, onPaneContextMenu, onPaneScroll, onPaneMouseEnter, onPaneMouseMove, onPaneMouseLeave, children, }) => {
1151
+ function Pane({ isSelecting, selectionMode = SelectionMode.Full, panOnDrag, onSelectionStart, onSelectionEnd, onPaneClick, onPaneContextMenu, onPaneScroll, onPaneMouseEnter, onPaneMouseMove, onPaneMouseLeave, children, }) {
1067
1152
  const container = useRef(null);
1068
1153
  const store = useStoreApi();
1069
1154
  const prevSelectedNodesCount = useRef(0);
1070
1155
  const prevSelectedEdgesCount = useRef(0);
1071
1156
  const containerBounds = useRef();
1157
+ const edgeIdLookup = useRef(new Map());
1072
1158
  const { userSelectionActive, elementsSelectable, dragging } = useStore(selector$j, shallow);
1073
1159
  const resetUserSelection = () => {
1074
1160
  store.setState({ userSelectionActive: false, userSelectionRect: null });
@@ -1089,7 +1175,7 @@ const Pane = memo(({ isSelecting, selectionMode = SelectionMode.Full, panOnDrag,
1089
1175
  };
1090
1176
  const onWheel = onPaneScroll ? (event) => onPaneScroll(event) : undefined;
1091
1177
  const onMouseDown = (event) => {
1092
- const { resetSelectedElements, domNode } = store.getState();
1178
+ const { resetSelectedElements, domNode, edgeLookup } = store.getState();
1093
1179
  containerBounds.current = domNode?.getBoundingClientRect();
1094
1180
  if (!elementsSelectable ||
1095
1181
  !isSelecting ||
@@ -1098,6 +1184,11 @@ const Pane = memo(({ isSelecting, selectionMode = SelectionMode.Full, panOnDrag,
1098
1184
  !containerBounds.current) {
1099
1185
  return;
1100
1186
  }
1187
+ edgeIdLookup.current = new Map();
1188
+ for (const [id, edge] of edgeLookup) {
1189
+ edgeIdLookup.current.set(edge.source, edgeIdLookup.current.get(edge.source)?.add(id) || new Set([id]));
1190
+ edgeIdLookup.current.set(edge.target, edgeIdLookup.current.get(edge.target)?.add(id) || new Set([id]));
1191
+ }
1101
1192
  const { x, y } = getEventPosition(event.nativeEvent, containerBounds.current);
1102
1193
  resetSelectedElements();
1103
1194
  store.setState({
@@ -1113,48 +1204,46 @@ const Pane = memo(({ isSelecting, selectionMode = SelectionMode.Full, panOnDrag,
1113
1204
  onSelectionStart?.(event);
1114
1205
  };
1115
1206
  const onMouseMove = (event) => {
1116
- const { userSelectionRect, edges, transform, nodeOrigin, nodes, onNodesChange, onEdgesChange } = store.getState();
1207
+ const { userSelectionRect, edgeLookup, transform, nodeOrigin, nodeLookup, triggerNodeChanges, triggerEdgeChanges } = store.getState();
1117
1208
  if (!isSelecting || !containerBounds.current || !userSelectionRect) {
1118
1209
  return;
1119
1210
  }
1120
- store.setState({ userSelectionActive: true, nodesSelectionActive: false });
1121
- const mousePos = getEventPosition(event.nativeEvent, containerBounds.current);
1122
- const startX = userSelectionRect.startX ?? 0;
1123
- const startY = userSelectionRect.startY ?? 0;
1211
+ const { x: mouseX, y: mouseY } = getEventPosition(event.nativeEvent, containerBounds.current);
1212
+ const { startX, startY } = userSelectionRect;
1124
1213
  const nextUserSelectRect = {
1125
- ...userSelectionRect,
1126
- x: mousePos.x < startX ? mousePos.x : startX,
1127
- y: mousePos.y < startY ? mousePos.y : startY,
1128
- width: Math.abs(mousePos.x - startX),
1129
- height: Math.abs(mousePos.y - startY),
1214
+ startX,
1215
+ startY,
1216
+ x: mouseX < startX ? mouseX : startX,
1217
+ y: mouseY < startY ? mouseY : startY,
1218
+ width: Math.abs(mouseX - startX),
1219
+ height: Math.abs(mouseY - startY),
1130
1220
  };
1131
- const selectedNodes = getNodesInside(nodes, nextUserSelectRect, transform, selectionMode === SelectionMode.Partial, true, nodeOrigin);
1221
+ const selectedNodes = getNodesInside(nodeLookup, nextUserSelectRect, transform, selectionMode === SelectionMode.Partial, true, nodeOrigin);
1132
1222
  const selectedEdgeIds = new Set();
1133
1223
  const selectedNodeIds = new Set();
1134
1224
  for (const selectedNode of selectedNodes) {
1135
1225
  selectedNodeIds.add(selectedNode.id);
1136
- for (const edge of edges) {
1137
- if (edge.source === selectedNode.id || edge.target === selectedNode.id) {
1138
- selectedEdgeIds.add(edge.id);
1226
+ const edgeIds = edgeIdLookup.current.get(selectedNode.id);
1227
+ if (edgeIds) {
1228
+ for (const edgeId of edgeIds) {
1229
+ selectedEdgeIds.add(edgeId);
1139
1230
  }
1140
1231
  }
1141
1232
  }
1142
1233
  if (prevSelectedNodesCount.current !== selectedNodeIds.size) {
1143
1234
  prevSelectedNodesCount.current = selectedNodeIds.size;
1144
- const changes = getSelectionChanges(nodes, selectedNodeIds, true);
1145
- if (changes.length) {
1146
- onNodesChange?.(changes);
1147
- }
1235
+ const changes = getSelectionChanges(nodeLookup, selectedNodeIds, true);
1236
+ triggerNodeChanges(changes);
1148
1237
  }
1149
1238
  if (prevSelectedEdgesCount.current !== selectedEdgeIds.size) {
1150
1239
  prevSelectedEdgesCount.current = selectedEdgeIds.size;
1151
- const changes = getSelectionChanges(edges, selectedEdgeIds);
1152
- if (changes.length) {
1153
- onEdgesChange?.(changes);
1154
- }
1240
+ const changes = getSelectionChanges(edgeLookup, selectedEdgeIds);
1241
+ triggerEdgeChanges(changes);
1155
1242
  }
1156
1243
  store.setState({
1157
1244
  userSelectionRect: nextUserSelectRect,
1245
+ userSelectionActive: true,
1246
+ nodesSelectionActive: false,
1158
1247
  });
1159
1248
  };
1160
1249
  const onMouseUp = (event) => {
@@ -1179,9 +1268,8 @@ const Pane = memo(({ isSelecting, selectionMode = SelectionMode.Full, panOnDrag,
1179
1268
  resetUserSelection();
1180
1269
  };
1181
1270
  const hasActiveSelection = elementsSelectable && (isSelecting || userSelectionActive);
1182
- 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, {})] }));
1183
- });
1184
- Pane.displayName = 'Pane';
1271
+ 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), 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, {})] }));
1272
+ }
1185
1273
 
1186
1274
  // this handler is called by
1187
1275
  // 1. the click handler when node is not draggable or selectNodesOnDrag = false
@@ -1209,36 +1297,33 @@ function handleNodeClick({ id, store, unselect = false, nodeRef, }) {
1209
1297
  *
1210
1298
  * @internal
1211
1299
  */
1212
- function useDrag({ nodeRef, disabled = false, noDragClassName, handleSelector, nodeId, isSelectable }) {
1300
+ function useDrag({ nodeRef, disabled = false, noDragClassName, handleSelector, nodeId, isSelectable, }) {
1213
1301
  const store = useStoreApi();
1214
1302
  const [dragging, setDragging] = useState(false);
1215
1303
  const xyDrag = useRef();
1216
1304
  useEffect(() => {
1217
- if (nodeRef?.current) {
1218
- xyDrag.current = XYDrag({
1219
- domNode: nodeRef.current,
1220
- getStoreItems: () => store.getState(),
1221
- onNodeMouseDown: (id) => {
1222
- handleNodeClick({
1223
- id,
1224
- store,
1225
- nodeRef: nodeRef,
1226
- });
1227
- },
1228
- onDragStart: () => {
1229
- setDragging(true);
1230
- },
1231
- onDragStop: () => {
1232
- setDragging(false);
1233
- },
1234
- });
1235
- }
1305
+ xyDrag.current = XYDrag({
1306
+ getStoreItems: () => store.getState(),
1307
+ onNodeMouseDown: (id) => {
1308
+ handleNodeClick({
1309
+ id,
1310
+ store,
1311
+ nodeRef,
1312
+ });
1313
+ },
1314
+ onDragStart: () => {
1315
+ setDragging(true);
1316
+ },
1317
+ onDragStop: () => {
1318
+ setDragging(false);
1319
+ },
1320
+ });
1236
1321
  }, []);
1237
1322
  useEffect(() => {
1238
1323
  if (disabled) {
1239
1324
  xyDrag.current?.destroy();
1240
1325
  }
1241
- else {
1326
+ else if (nodeRef.current) {
1242
1327
  xyDrag.current?.update({
1243
1328
  noDragClassName,
1244
1329
  handleSelector,
@@ -1256,44 +1341,49 @@ function useDrag({ nodeRef, disabled = false, noDragClassName, handleSelector, n
1256
1341
 
1257
1342
  const selectedAndDraggable = (nodesDraggable) => (n) => n.selected && (n.draggable || (nodesDraggable && typeof n.draggable === 'undefined'));
1258
1343
  /**
1259
- * Hook for updating node positions.
1344
+ * Hook for updating node positions by passing a direction and factor
1260
1345
  *
1261
1346
  * @internal
1262
1347
  * @returns function for updating node positions
1263
1348
  */
1264
- function useUpdateNodePositions() {
1349
+ function useMoveSelectedNodes() {
1265
1350
  const store = useStoreApi();
1266
- const updatePositions = useCallback((params) => {
1267
- const { nodeExtent, nodes, snapToGrid, snapGrid, nodesDraggable, onError, updateNodePositions } = store.getState();
1268
- const selectedNodes = nodes.filter(selectedAndDraggable(nodesDraggable));
1269
- // by default a node moves 5px on each key press, or 20px if shift is pressed
1270
- // if snap grid is enabled, we use that for the velocity.
1351
+ const moveSelectedNodes = useCallback((params) => {
1352
+ const { nodeExtent, snapToGrid, snapGrid, nodesDraggable, onError, updateNodePositions, nodeLookup, nodeOrigin } = store.getState();
1353
+ const nodeUpdates = new Map();
1354
+ const isSelected = selectedAndDraggable(nodesDraggable);
1355
+ // by default a node moves 5px on each key press
1356
+ // if snap grid is enabled, we use that for the velocity
1271
1357
  const xVelo = snapToGrid ? snapGrid[0] : 5;
1272
1358
  const yVelo = snapToGrid ? snapGrid[1] : 5;
1273
- const factor = params.isShiftPressed ? 4 : 1;
1274
- const xDiff = params.x * xVelo * factor;
1275
- const yDiff = params.y * yVelo * factor;
1276
- const nodeUpdates = selectedNodes.map((node) => {
1277
- if (node.computed?.positionAbsolute) {
1278
- let nextPosition = {
1279
- x: node.computed?.positionAbsolute.x + xDiff,
1280
- y: node.computed?.positionAbsolute.y + yDiff,
1281
- };
1282
- if (snapToGrid) {
1283
- nextPosition = snapPosition(nextPosition, snapGrid);
1284
- }
1285
- const { positionAbsolute, position } = calcNextPosition(node, nextPosition, nodes, nodeExtent, undefined, onError);
1286
- node.position = position;
1287
- if (!node.computed) {
1288
- node.computed = {};
1289
- }
1290
- node.computed.positionAbsolute = positionAbsolute;
1359
+ const xDiff = params.direction.x * xVelo * params.factor;
1360
+ const yDiff = params.direction.y * yVelo * params.factor;
1361
+ for (const [, node] of nodeLookup) {
1362
+ if (!isSelected(node)) {
1363
+ continue;
1291
1364
  }
1292
- return node;
1293
- });
1294
- updateNodePositions(nodeUpdates, true, false);
1365
+ let nextPosition = {
1366
+ x: node.internals.positionAbsolute.x + xDiff,
1367
+ y: node.internals.positionAbsolute.y + yDiff,
1368
+ };
1369
+ if (snapToGrid) {
1370
+ nextPosition = snapPosition(nextPosition, snapGrid);
1371
+ }
1372
+ const { position, positionAbsolute } = calculateNodePosition({
1373
+ nodeId: node.id,
1374
+ nextPosition,
1375
+ nodeLookup,
1376
+ nodeExtent,
1377
+ nodeOrigin,
1378
+ onError,
1379
+ });
1380
+ node.position = position;
1381
+ node.internals.positionAbsolute = positionAbsolute;
1382
+ nodeUpdates.set(node.id, node);
1383
+ }
1384
+ updateNodePositions(nodeUpdates);
1295
1385
  }, []);
1296
- return updatePositions;
1386
+ return moveSelectedNodes;
1297
1387
  }
1298
1388
 
1299
1389
  const NodeIdContext = createContext(null);
@@ -1305,25 +1395,31 @@ const useNodeId = () => {
1305
1395
  };
1306
1396
 
1307
1397
  const selector$i = (s) => ({
1308
- connectionStartHandle: s.connectionStartHandle,
1309
1398
  connectOnClick: s.connectOnClick,
1310
1399
  noPanClassName: s.noPanClassName,
1400
+ rfId: s.rfId,
1311
1401
  });
1312
1402
  const connectingSelector = (nodeId, handleId, type) => (state) => {
1313
- const { connectionStartHandle: startHandle, connectionEndHandle: endHandle, connectionClickStartHandle: clickHandle, } = state;
1403
+ const { connectionStartHandle: startHandle, connectionEndHandle: endHandle, connectionClickStartHandle: clickHandle, connectionMode, connectionStatus, } = state;
1404
+ const connectingTo = endHandle?.nodeId === nodeId && endHandle?.handleId === handleId && endHandle?.type === type;
1314
1405
  return {
1315
- connecting: (startHandle?.nodeId === nodeId && startHandle?.handleId === handleId && startHandle?.type === type) ||
1316
- (endHandle?.nodeId === nodeId && endHandle?.handleId === handleId && endHandle?.type === type),
1406
+ connectingFrom: startHandle?.nodeId === nodeId && startHandle?.handleId === handleId && startHandle?.type === type,
1407
+ connectingTo,
1317
1408
  clickConnecting: clickHandle?.nodeId === nodeId && clickHandle?.handleId === handleId && clickHandle?.type === type,
1409
+ isPossibleEndHandle: connectionMode === ConnectionMode.Strict
1410
+ ? startHandle?.type !== type
1411
+ : nodeId !== startHandle?.nodeId || handleId !== startHandle?.handleId,
1412
+ connectionInProcess: !!startHandle,
1413
+ valid: connectingTo && connectionStatus === 'valid',
1318
1414
  };
1319
1415
  };
1320
- const Handle = forwardRef(({ type = 'source', position = Position.Top, isValidConnection, isConnectable = true, isConnectableStart = true, isConnectableEnd = true, id, onConnect, children, className, onMouseDown, onTouchStart, ...rest }, ref) => {
1416
+ function HandleComponent({ type = 'source', position = Position.Top, isValidConnection, isConnectable = true, isConnectableStart = true, isConnectableEnd = true, id, onConnect, children, className, onMouseDown, onTouchStart, ...rest }, ref) {
1321
1417
  const handleId = id || null;
1322
1418
  const isTarget = type === 'target';
1323
1419
  const store = useStoreApi();
1324
1420
  const nodeId = useNodeId();
1325
- const { connectOnClick, noPanClassName } = useStore(selector$i, shallow);
1326
- const { connecting, clickConnecting } = useStore(connectingSelector(nodeId, handleId, type), shallow);
1421
+ const { connectOnClick, noPanClassName, rfId } = useStore(selector$i, shallow);
1422
+ const { connectingFrom, connectingTo, clickConnecting, isPossibleEndHandle, connectionInProcess, valid } = useStore(connectingSelector(nodeId, handleId, type), shallow);
1327
1423
  if (!nodeId) {
1328
1424
  store.getState().onError?.('010', errorMessages['error010']());
1329
1425
  }
@@ -1353,11 +1449,12 @@ const Handle = forwardRef(({ type = 'source', position = Position.Top, isValidCo
1353
1449
  connectionMode: currentStore.connectionMode,
1354
1450
  connectionRadius: currentStore.connectionRadius,
1355
1451
  domNode: currentStore.domNode,
1356
- nodes: currentStore.nodes,
1452
+ nodeLookup: currentStore.nodeLookup,
1357
1453
  lib: currentStore.lib,
1358
1454
  isTarget,
1359
1455
  handleId,
1360
1456
  nodeId,
1457
+ flowId: currentStore.rfId,
1361
1458
  panBy: currentStore.panBy,
1362
1459
  cancelConnection: currentStore.cancelConnection,
1363
1460
  onConnectStart: currentStore.onConnectStart,
@@ -1366,6 +1463,7 @@ const Handle = forwardRef(({ type = 'source', position = Position.Top, isValidCo
1366
1463
  onConnect: onConnectExtended,
1367
1464
  isValidConnection: isValidConnection || currentStore.isValidConnection,
1368
1465
  getTransform: () => store.getState().transform,
1466
+ getConnectionStartHandle: () => store.getState().connectionStartHandle,
1369
1467
  });
1370
1468
  }
1371
1469
  if (isMouseTriggered) {
@@ -1376,7 +1474,7 @@ const Handle = forwardRef(({ type = 'source', position = Position.Top, isValidCo
1376
1474
  }
1377
1475
  };
1378
1476
  const onClick = (event) => {
1379
- const { onClickConnectStart, onClickConnectEnd, connectionClickStartHandle, connectionMode, isValidConnection: isValidConnectionStore, lib, } = store.getState();
1477
+ const { onClickConnectStart, onClickConnectEnd, connectionClickStartHandle, connectionMode, isValidConnection: isValidConnectionStore, lib, rfId: flowId, } = store.getState();
1380
1478
  if (!nodeId || (!connectionClickStartHandle && !isConnectableStart)) {
1381
1479
  return;
1382
1480
  }
@@ -1398,6 +1496,7 @@ const Handle = forwardRef(({ type = 'source', position = Position.Top, isValidCo
1398
1496
  fromHandleId: connectionClickStartHandle.handleId || null,
1399
1497
  fromType: connectionClickStartHandle.type,
1400
1498
  isValidConnection: isValidConnectionHandler,
1499
+ flowId,
1401
1500
  doc,
1402
1501
  lib,
1403
1502
  });
@@ -1407,7 +1506,7 @@ const Handle = forwardRef(({ type = 'source', position = Position.Top, isValidCo
1407
1506
  onClickConnectEnd?.(event);
1408
1507
  store.setState({ connectionClickStartHandle: null });
1409
1508
  };
1410
- return (jsx("div", { "data-handleid": handleId, "data-nodeid": nodeId, "data-handlepos": position, "data-id": `${nodeId}-${handleId}-${type}`, className: cc([
1509
+ return (jsx("div", { "data-handleid": handleId, "data-nodeid": nodeId, "data-handlepos": position, "data-id": `${rfId}-${nodeId}-${handleId}-${type}`, className: cc([
1411
1510
  'react-flow__handle',
1412
1511
  `react-flow__handle-${position}`,
1413
1512
  'nodrag',
@@ -1419,31 +1518,38 @@ const Handle = forwardRef(({ type = 'source', position = Position.Top, isValidCo
1419
1518
  connectable: isConnectable,
1420
1519
  connectablestart: isConnectableStart,
1421
1520
  connectableend: isConnectableEnd,
1422
- connecting: clickConnecting,
1423
- // this class is used to style the handle when the user is connecting
1424
- connectionindicator: isConnectable && ((isConnectableStart && !connecting) || (isConnectableEnd && connecting)),
1521
+ clickconnecting: clickConnecting,
1522
+ connectingfrom: connectingFrom,
1523
+ connectingto: connectingTo,
1524
+ valid,
1525
+ // shows where you can start a connection from
1526
+ // and where you can end it while connecting
1527
+ connectionindicator: isConnectable &&
1528
+ (!connectionInProcess || isPossibleEndHandle) &&
1529
+ (connectionInProcess ? isConnectableEnd : isConnectableStart),
1425
1530
  },
1426
1531
  ]), onMouseDown: onPointerDown, onTouchStart: onPointerDown, onClick: connectOnClick ? onClick : undefined, ref: ref, ...rest, children: children }));
1427
- });
1428
- Handle.displayName = 'Handle';
1429
- var Handle$1 = memo(Handle);
1532
+ }
1533
+ /**
1534
+ * The Handle component is a UI element that is used to connect nodes.
1535
+ */
1536
+ const Handle = memo(fixedForwardRef(HandleComponent));
1430
1537
 
1431
- const InputNode = ({ data, isConnectable, sourcePosition = Position.Bottom }) => (jsxs(Fragment, { children: [data?.label, jsx(Handle$1, { type: "source", position: sourcePosition, isConnectable: isConnectable })] }));
1432
- InputNode.displayName = 'InputNode';
1433
- var InputNode$1 = memo(InputNode);
1538
+ function InputNode({ data, isConnectable, sourcePosition = Position.Bottom }) {
1539
+ return (jsxs(Fragment, { children: [data?.label, jsx(Handle, { type: "source", position: sourcePosition, isConnectable: isConnectable })] }));
1540
+ }
1434
1541
 
1435
- const DefaultNode = ({ data, isConnectable, targetPosition = Position.Top, sourcePosition = Position.Bottom, }) => {
1436
- return (jsxs(Fragment, { children: [jsx(Handle$1, { type: "target", position: targetPosition, isConnectable: isConnectable }), data?.label, jsx(Handle$1, { type: "source", position: sourcePosition, isConnectable: isConnectable })] }));
1437
- };
1438
- DefaultNode.displayName = 'DefaultNode';
1439
- var DefaultNode$1 = memo(DefaultNode);
1542
+ function DefaultNode({ data, isConnectable, targetPosition = Position.Top, sourcePosition = Position.Bottom, }) {
1543
+ return (jsxs(Fragment, { children: [jsx(Handle, { type: "target", position: targetPosition, isConnectable: isConnectable }), data?.label, jsx(Handle, { type: "source", position: sourcePosition, isConnectable: isConnectable })] }));
1544
+ }
1440
1545
 
1441
- const GroupNode = () => null;
1442
- GroupNode.displayName = 'GroupNode';
1546
+ function GroupNode() {
1547
+ return null;
1548
+ }
1443
1549
 
1444
- const OutputNode = ({ data, isConnectable, targetPosition = Position.Top }) => (jsxs(Fragment, { children: [jsx(Handle$1, { type: "target", position: targetPosition, isConnectable: isConnectable }), data?.label] }));
1445
- OutputNode.displayName = 'OutputNode';
1446
- var OutputNode$1 = memo(OutputNode);
1550
+ function OutputNode({ data, isConnectable, targetPosition = Position.Top }) {
1551
+ return (jsxs(Fragment, { children: [jsx(Handle, { type: "target", position: targetPosition, isConnectable: isConnectable }), data?.label] }));
1552
+ }
1447
1553
 
1448
1554
  const arrowKeyDiffs = {
1449
1555
  ArrowUp: { x: 0, y: -1 },
@@ -1452,26 +1558,40 @@ const arrowKeyDiffs = {
1452
1558
  ArrowRight: { x: 1, y: 0 },
1453
1559
  };
1454
1560
  const builtinNodeTypes = {
1455
- input: InputNode$1,
1456
- default: DefaultNode$1,
1457
- output: OutputNode$1,
1561
+ input: InputNode,
1562
+ default: DefaultNode,
1563
+ output: OutputNode,
1458
1564
  group: GroupNode,
1459
1565
  };
1566
+ function getNodeInlineStyleDimensions(node) {
1567
+ if (node.internals.handleBounds === undefined) {
1568
+ return {
1569
+ width: node.width ?? node.initialWidth ?? node.style?.width,
1570
+ height: node.height ?? node.initialHeight ?? node.style?.height,
1571
+ };
1572
+ }
1573
+ return {
1574
+ width: node.width ?? node.style?.width,
1575
+ height: node.height ?? node.style?.height,
1576
+ };
1577
+ }
1460
1578
 
1461
1579
  const selector$h = (s) => {
1462
- const selectedNodes = s.nodes.filter((n) => n.selected);
1463
- const { width, height, x, y } = getNodesBounds(selectedNodes, s.nodeOrigin);
1580
+ const { width, height, x, y } = getInternalNodesBounds(s.nodeLookup, {
1581
+ nodeOrigin: s.nodeOrigin,
1582
+ filter: (node) => !!node.selected,
1583
+ });
1464
1584
  return {
1465
- width,
1466
- height,
1585
+ width: isNumeric(width) ? width : null,
1586
+ height: isNumeric(height) ? height : null,
1467
1587
  userSelectionActive: s.userSelectionActive,
1468
1588
  transformString: `translate(${s.transform[0]}px,${s.transform[1]}px) scale(${s.transform[2]}) translate(${x}px,${y}px)`,
1469
1589
  };
1470
1590
  };
1471
- function NodesSelection({ onSelectionContextMenu, noPanClassName, disableKeyboardA11y }) {
1591
+ function NodesSelection({ onSelectionContextMenu, noPanClassName, disableKeyboardA11y, }) {
1472
1592
  const store = useStoreApi();
1473
1593
  const { width, height, transformString, userSelectionActive } = useStore(selector$h, shallow);
1474
- const updatePositions = useUpdateNodePositions();
1594
+ const moveSelectedNodes = useMoveSelectedNodes();
1475
1595
  const nodeRef = useRef(null);
1476
1596
  useEffect(() => {
1477
1597
  if (!disableKeyboardA11y) {
@@ -1494,10 +1614,9 @@ function NodesSelection({ onSelectionContextMenu, noPanClassName, disableKeyboar
1494
1614
  : undefined;
1495
1615
  const onKeyDown = (event) => {
1496
1616
  if (Object.prototype.hasOwnProperty.call(arrowKeyDiffs, event.key)) {
1497
- updatePositions({
1498
- x: arrowKeyDiffs[event.key].x,
1499
- y: arrowKeyDiffs[event.key].y,
1500
- isShiftPressed: event.shiftKey,
1617
+ moveSelectedNodes({
1618
+ direction: arrowKeyDiffs[event.key],
1619
+ factor: event.shiftKey ? 4 : 1,
1501
1620
  });
1502
1621
  }
1503
1622
  };
@@ -1508,25 +1627,26 @@ function NodesSelection({ onSelectionContextMenu, noPanClassName, disableKeyboar
1508
1627
  height,
1509
1628
  } }) }));
1510
1629
  }
1511
- var NodesSelection$1 = memo(NodesSelection);
1512
1630
 
1513
- const selector$g = (s) => s.nodesSelectionActive;
1514
- const FlowRenderer = ({ 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, }) => {
1515
- const nodesSelectionActive = useStore(selector$g);
1631
+ const selector$g = (s) => {
1632
+ return { nodesSelectionActive: s.nodesSelectionActive, userSelectionActive: s.userSelectionActive };
1633
+ };
1634
+ function 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, }) {
1635
+ const { nodesSelectionActive, userSelectionActive } = useStore(selector$g);
1516
1636
  const selectionKeyPressed = useKeyPress(selectionKeyCode);
1517
1637
  const panActivationKeyPressed = useKeyPress(panActivationKeyCode);
1518
1638
  const panOnDrag = panActivationKeyPressed || _panOnDrag;
1519
1639
  const panOnScroll = panActivationKeyPressed || _panOnScroll;
1520
- const isSelecting = selectionKeyPressed || (selectionOnDrag && panOnDrag !== true);
1640
+ const isSelecting = selectionKeyPressed || userSelectionActive || (selectionOnDrag && panOnDrag !== true);
1521
1641
  useGlobalKeyHandler({ deleteKeyCode, multiSelectionKeyCode });
1522
- 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$1, { onSelectionContextMenu: onSelectionContextMenu, noPanClassName: noPanClassName, disableKeyboardA11y: disableKeyboardA11y }))] }) }));
1523
- };
1524
- FlowRenderer.displayName = 'FlowRenderer';
1525
- var FlowRenderer$1 = memo(FlowRenderer);
1642
+ 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 }))] }) }));
1643
+ }
1644
+ FlowRendererComponent.displayName = 'FlowRenderer';
1645
+ const FlowRenderer = memo(FlowRendererComponent);
1526
1646
 
1527
1647
  const selector$f = (onlyRenderVisible) => (s) => {
1528
1648
  return onlyRenderVisible
1529
- ? getNodesInside(s.nodes, { x: 0, y: 0, width: s.width, height: s.height }, s.transform, true).map((node) => node.id)
1649
+ ? getNodesInside(s.nodeLookup, { x: 0, y: 0, width: s.width, height: s.height }, s.transform, true).map((node) => node.id)
1530
1650
  : Array.from(s.nodeLookup.keys());
1531
1651
  };
1532
1652
  /**
@@ -1541,51 +1661,93 @@ function useVisibleNodeIds(onlyRenderVisible) {
1541
1661
  return nodeIds;
1542
1662
  }
1543
1663
 
1544
- const selector$e = (s) => s.updateNodeDimensions;
1664
+ const selector$e = (s) => s.updateNodeInternals;
1545
1665
  function useResizeObserver() {
1546
- const updateNodeDimensions = useStore(selector$e);
1547
- const resizeObserverRef = useRef();
1548
- const resizeObserver = useMemo(() => {
1666
+ const updateNodeInternals = useStore(selector$e);
1667
+ const [resizeObserver] = useState(() => {
1549
1668
  if (typeof ResizeObserver === 'undefined') {
1550
1669
  return null;
1551
1670
  }
1552
- const observer = new ResizeObserver((entries) => {
1671
+ return new ResizeObserver((entries) => {
1553
1672
  const updates = new Map();
1554
1673
  entries.forEach((entry) => {
1555
1674
  const id = entry.target.getAttribute('data-id');
1556
1675
  updates.set(id, {
1557
1676
  id,
1558
1677
  nodeElement: entry.target,
1559
- forceUpdate: true,
1678
+ force: true,
1560
1679
  });
1561
1680
  });
1562
- updateNodeDimensions(updates);
1681
+ updateNodeInternals(updates);
1563
1682
  });
1564
- resizeObserverRef.current = observer;
1565
- return observer;
1566
- }, []);
1683
+ });
1567
1684
  useEffect(() => {
1568
1685
  return () => {
1569
- resizeObserverRef?.current?.disconnect();
1686
+ resizeObserver?.disconnect();
1570
1687
  };
1571
- }, []);
1688
+ }, [resizeObserver]);
1572
1689
  return resizeObserver;
1573
1690
  }
1574
1691
 
1575
- const NodeWrapper = ({ id, onClick, onMouseEnter, onMouseMove, onMouseLeave, onContextMenu, onDoubleClick, nodesDraggable, elementsSelectable, nodesConnectable, nodesFocusable, resizeObserver, noDragClassName, noPanClassName, disableKeyboardA11y, rfId, nodeTypes, nodeExtent, nodeOrigin, onError, }) => {
1576
- const { node, positionAbsoluteX, positionAbsoluteY, zIndex, isParent } = useStore((s) => {
1692
+ /**
1693
+ * Hook to handle the resize observation + internal updates for the passed node.
1694
+ *
1695
+ * @internal
1696
+ * @returns nodeRef - reference to the node element
1697
+ */
1698
+ function useNodeObserver({ node, nodeType, hasDimensions, resizeObserver, }) {
1699
+ const store = useStoreApi();
1700
+ const nodeRef = useRef(null);
1701
+ const observedNode = useRef(null);
1702
+ const prevSourcePosition = useRef(node.sourcePosition);
1703
+ const prevTargetPosition = useRef(node.targetPosition);
1704
+ const prevType = useRef(nodeType);
1705
+ const isInitialized = hasDimensions && !!node.internals.handleBounds;
1706
+ useEffect(() => {
1707
+ if (nodeRef.current && !node.hidden && (!isInitialized || observedNode.current !== nodeRef.current)) {
1708
+ if (observedNode.current) {
1709
+ resizeObserver?.unobserve(observedNode.current);
1710
+ }
1711
+ resizeObserver?.observe(nodeRef.current);
1712
+ observedNode.current = nodeRef.current;
1713
+ }
1714
+ }, [isInitialized, node.hidden]);
1715
+ useEffect(() => {
1716
+ return () => {
1717
+ if (observedNode.current) {
1718
+ resizeObserver?.unobserve(observedNode.current);
1719
+ observedNode.current = null;
1720
+ }
1721
+ };
1722
+ }, []);
1723
+ useEffect(() => {
1724
+ if (nodeRef.current) {
1725
+ // when the user programmatically changes the source or handle position, we need to update the internals
1726
+ // to make sure the edges are updated correctly
1727
+ const typeChanged = prevType.current !== nodeType;
1728
+ const sourcePosChanged = prevSourcePosition.current !== node.sourcePosition;
1729
+ const targetPosChanged = prevTargetPosition.current !== node.targetPosition;
1730
+ if (typeChanged || sourcePosChanged || targetPosChanged) {
1731
+ prevType.current = nodeType;
1732
+ prevSourcePosition.current = node.sourcePosition;
1733
+ prevTargetPosition.current = node.targetPosition;
1734
+ store
1735
+ .getState()
1736
+ .updateNodeInternals(new Map([[node.id, { id: node.id, nodeElement: nodeRef.current, force: true }]]));
1737
+ }
1738
+ }
1739
+ }, [node.id, nodeType, node.sourcePosition, node.targetPosition]);
1740
+ return nodeRef;
1741
+ }
1742
+
1743
+ function NodeWrapper({ id, onClick, onMouseEnter, onMouseMove, onMouseLeave, onContextMenu, onDoubleClick, nodesDraggable, elementsSelectable, nodesConnectable, nodesFocusable, resizeObserver, noDragClassName, noPanClassName, disableKeyboardA11y, rfId, nodeTypes, nodeExtent, nodeOrigin, onError, }) {
1744
+ const { node, internals, isParent } = useStore((s) => {
1577
1745
  const node = s.nodeLookup.get(id);
1578
- const positionAbsolute = nodeExtent
1579
- ? clampPosition(node.computed?.positionAbsolute, nodeExtent)
1580
- : node.computed?.positionAbsolute || { x: 0, y: 0 };
1746
+ const isParent = s.parentLookup.has(id);
1581
1747
  return {
1582
1748
  node,
1583
- // we are mutating positionAbsolute, z and isParent attributes for sub flows
1584
- // so we we need to force a re-render when some change
1585
- positionAbsoluteX: positionAbsolute.x,
1586
- positionAbsoluteY: positionAbsolute.y,
1587
- zIndex: node[internalsSymbol]?.z ?? 0,
1588
- isParent: !!node[internalsSymbol]?.isParent,
1749
+ internals: node.internals,
1750
+ isParent,
1589
1751
  };
1590
1752
  }, shallow);
1591
1753
  let nodeType = node.type || 'default';
@@ -1600,36 +1762,8 @@ const NodeWrapper = ({ id, onClick, onMouseEnter, onMouseMove, onMouseLeave, onC
1600
1762
  const isConnectable = !!(node.connectable || (nodesConnectable && typeof node.connectable === 'undefined'));
1601
1763
  const isFocusable = !!(node.focusable || (nodesFocusable && typeof node.focusable === 'undefined'));
1602
1764
  const store = useStoreApi();
1603
- const nodeRef = useRef(null);
1604
- const prevSourcePosition = useRef(node.sourcePosition);
1605
- const prevTargetPosition = useRef(node.targetPosition);
1606
- const prevType = useRef(nodeType);
1607
- const updatePositions = useUpdateNodePositions();
1608
- useEffect(() => {
1609
- if (nodeRef.current && !node.hidden) {
1610
- const currNode = nodeRef.current;
1611
- resizeObserver?.observe(currNode);
1612
- return () => resizeObserver?.unobserve(currNode);
1613
- }
1614
- }, [node.hidden]);
1615
- useEffect(() => {
1616
- // when the user programmatically changes the source or handle position, we re-initialize the node
1617
- const typeChanged = prevType.current !== nodeType;
1618
- const sourcePosChanged = prevSourcePosition.current !== node.sourcePosition;
1619
- const targetPosChanged = prevTargetPosition.current !== node.targetPosition;
1620
- if (nodeRef.current && (typeChanged || sourcePosChanged || targetPosChanged)) {
1621
- if (typeChanged) {
1622
- prevType.current = nodeType;
1623
- }
1624
- if (sourcePosChanged) {
1625
- prevSourcePosition.current = node.sourcePosition;
1626
- }
1627
- if (targetPosChanged) {
1628
- prevTargetPosition.current = node.targetPosition;
1629
- }
1630
- store.getState().updateNodeDimensions(new Map([[id, { id, nodeElement: nodeRef.current, forceUpdate: true }]]));
1631
- }
1632
- }, [id, nodeType, node.sourcePosition, node.targetPosition]);
1765
+ const hasDimensions = nodeHasDimensions(node);
1766
+ const nodeRef = useNodeObserver({ node, nodeType, hasDimensions, resizeObserver });
1633
1767
  const dragging = useDrag({
1634
1768
  nodeRef,
1635
1769
  disabled: node.hidden || !isDraggable,
@@ -1638,27 +1772,36 @@ const NodeWrapper = ({ id, onClick, onMouseEnter, onMouseMove, onMouseLeave, onC
1638
1772
  nodeId: id,
1639
1773
  isSelectable,
1640
1774
  });
1775
+ const moveSelectedNodes = useMoveSelectedNodes();
1641
1776
  if (node.hidden) {
1642
1777
  return null;
1643
1778
  }
1644
- const width = node.width ?? undefined;
1645
- const height = node.height ?? undefined;
1646
- const computedWidth = node.computed?.width;
1647
- const computedHeight = node.computed?.height;
1648
- const positionAbsoluteOrigin = getPositionWithOrigin({
1649
- x: positionAbsoluteX,
1650
- y: positionAbsoluteY,
1651
- width: computedWidth ?? width ?? 0,
1652
- height: computedHeight ?? height ?? 0,
1779
+ const nodeDimensions = getNodeDimensions(node);
1780
+ const inlineDimensions = getNodeInlineStyleDimensions(node);
1781
+ const clampedPosition = nodeExtent
1782
+ ? clampPosition(internals.positionAbsolute, nodeExtent)
1783
+ : internals.positionAbsolute;
1784
+ const positionWithOrigin = getPositionWithOrigin({
1785
+ ...clampedPosition,
1786
+ ...nodeDimensions,
1653
1787
  origin: node.origin || nodeOrigin,
1654
1788
  });
1655
- const initialized = (!!computedWidth && !!computedHeight) || (!!width && !!height);
1656
1789
  const hasPointerEvents = isSelectable || isDraggable || onClick || onMouseEnter || onMouseMove || onMouseLeave;
1657
- const onMouseEnterHandler = onMouseEnter ? (event) => onMouseEnter(event, { ...node }) : undefined;
1658
- const onMouseMoveHandler = onMouseMove ? (event) => onMouseMove(event, { ...node }) : undefined;
1659
- const onMouseLeaveHandler = onMouseLeave ? (event) => onMouseLeave(event, { ...node }) : undefined;
1660
- const onContextMenuHandler = onContextMenu ? (event) => onContextMenu(event, { ...node }) : undefined;
1661
- const onDoubleClickHandler = onDoubleClick ? (event) => onDoubleClick(event, { ...node }) : undefined;
1790
+ const onMouseEnterHandler = onMouseEnter
1791
+ ? (event) => onMouseEnter(event, { ...internals.userNode })
1792
+ : undefined;
1793
+ const onMouseMoveHandler = onMouseMove
1794
+ ? (event) => onMouseMove(event, { ...internals.userNode })
1795
+ : undefined;
1796
+ const onMouseLeaveHandler = onMouseLeave
1797
+ ? (event) => onMouseLeave(event, { ...internals.userNode })
1798
+ : undefined;
1799
+ const onContextMenuHandler = onContextMenu
1800
+ ? (event) => onContextMenu(event, { ...internals.userNode })
1801
+ : undefined;
1802
+ const onDoubleClickHandler = onDoubleClick
1803
+ ? (event) => onDoubleClick(event, { ...internals.userNode })
1804
+ : undefined;
1662
1805
  const onSelectNodeHandler = (event) => {
1663
1806
  const { selectNodesOnDrag, nodeDragThreshold } = store.getState();
1664
1807
  if (isSelectable && (!selectNodesOnDrag || !isDraggable || nodeDragThreshold > 0)) {
@@ -1671,11 +1814,11 @@ const NodeWrapper = ({ id, onClick, onMouseEnter, onMouseMove, onMouseLeave, onC
1671
1814
  });
1672
1815
  }
1673
1816
  if (onClick) {
1674
- onClick(event, { ...node });
1817
+ onClick(event, { ...internals.userNode });
1675
1818
  }
1676
1819
  };
1677
1820
  const onKeyDown = (event) => {
1678
- if (isInputDOMNode(event.nativeEvent)) {
1821
+ if (isInputDOMNode(event.nativeEvent) || disableKeyboardA11y) {
1679
1822
  return;
1680
1823
  }
1681
1824
  if (elementSelectionKeys.includes(event.key) && isSelectable) {
@@ -1687,19 +1830,15 @@ const NodeWrapper = ({ id, onClick, onMouseEnter, onMouseMove, onMouseLeave, onC
1687
1830
  nodeRef,
1688
1831
  });
1689
1832
  }
1690
- else if (!disableKeyboardA11y &&
1691
- isDraggable &&
1692
- node.selected &&
1693
- Object.prototype.hasOwnProperty.call(arrowKeyDiffs, event.key)) {
1833
+ else if (isDraggable && node.selected && Object.prototype.hasOwnProperty.call(arrowKeyDiffs, event.key)) {
1694
1834
  store.setState({
1695
1835
  ariaLiveMessage: `Moved selected node ${event.key
1696
1836
  .replace('Arrow', '')
1697
- .toLowerCase()}. New position, x: ${~~positionAbsoluteX}, y: ${~~positionAbsoluteY}`,
1837
+ .toLowerCase()}. New position, x: ${~~clampedPosition.x}, y: ${~~clampedPosition.y}`,
1698
1838
  });
1699
- updatePositions({
1700
- x: arrowKeyDiffs[event.key].x,
1701
- y: arrowKeyDiffs[event.key].y,
1702
- isShiftPressed: event.shiftKey,
1839
+ moveSelectedNodes({
1840
+ direction: arrowKeyDiffs[event.key],
1841
+ factor: event.shiftKey ? 4 : 1,
1703
1842
  });
1704
1843
  }
1705
1844
  };
@@ -1715,20 +1854,18 @@ const NodeWrapper = ({ id, onClick, onMouseEnter, onMouseMove, onMouseLeave, onC
1715
1854
  selected: node.selected,
1716
1855
  selectable: isSelectable,
1717
1856
  parent: isParent,
1857
+ draggable: isDraggable,
1718
1858
  dragging,
1719
1859
  },
1720
1860
  ]), ref: nodeRef, style: {
1721
- zIndex,
1722
- transform: `translate(${positionAbsoluteOrigin.x}px,${positionAbsoluteOrigin.y}px)`,
1861
+ zIndex: internals.z,
1862
+ transform: `translate(${positionWithOrigin.x}px,${positionWithOrigin.y}px)`,
1723
1863
  pointerEvents: hasPointerEvents ? 'all' : 'none',
1724
- visibility: initialized ? 'visible' : 'hidden',
1725
- width,
1726
- height,
1864
+ visibility: hasDimensions ? 'visible' : 'hidden',
1727
1865
  ...node.style,
1728
- }, "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 }) }) }));
1729
- };
1730
- NodeWrapper.displayName = 'NodeWrapper';
1731
- var NodeWrapper$1 = memo(NodeWrapper);
1866
+ ...inlineDimensions,
1867
+ }, "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 }) }) }));
1868
+ }
1732
1869
 
1733
1870
  const selector$d = (s) => ({
1734
1871
  nodesDraggable: s.nodesDraggable,
@@ -1737,7 +1874,7 @@ const selector$d = (s) => ({
1737
1874
  elementsSelectable: s.elementsSelectable,
1738
1875
  onError: s.onError,
1739
1876
  });
1740
- const NodeRenderer = (props) => {
1877
+ function NodeRendererComponent(props) {
1741
1878
  const { nodesDraggable, nodesConnectable, nodesFocusable, elementsSelectable, onError } = useStore(selector$d, shallow);
1742
1879
  const nodeIds = useVisibleNodeIds(props.onlyRenderVisibleElements);
1743
1880
  const resizeObserver = useResizeObserver();
@@ -1766,11 +1903,11 @@ const NodeRenderer = (props) => {
1766
1903
  // moved into `NodeComponentWrapper`. This ensures they are
1767
1904
  // memorized – so if `NodeRenderer` *has* to rerender, it only
1768
1905
  // needs to regenerate the list of nodes, nothing else.
1769
- jsx(NodeWrapper$1, { 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));
1906
+ 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));
1770
1907
  }) }));
1771
- };
1772
- NodeRenderer.displayName = 'NodeRenderer';
1773
- var NodeRenderer$1 = memo(NodeRenderer);
1908
+ }
1909
+ NodeRendererComponent.displayName = 'NodeRenderer';
1910
+ const NodeRenderer = memo(NodeRendererComponent);
1774
1911
 
1775
1912
  /**
1776
1913
  * Hook for getting the visible edge ids from the store.
@@ -1844,18 +1981,21 @@ const Marker = ({ id, type, color, width = 12.5, height = 12.5, markerUnits = 's
1844
1981
  }
1845
1982
  return (jsx("marker", { className: "react-flow__arrowhead", id: id, markerWidth: `${width}`, markerHeight: `${height}`, viewBox: "-10 -10 20 20", markerUnits: markerUnits, orient: orient, refX: "0", refY: "0", children: jsx(Symbol, { color: color, strokeWidth: strokeWidth }) }));
1846
1983
  };
1847
- const markerSelector = ({ defaultColor, rfId }) => (s) => {
1848
- const markers = createMarkerIds(s.edges, { id: rfId, defaultColor });
1849
- return markers;
1850
- };
1851
- const markersEqual = (a, b) =>
1852
- // the id includes all marker options, so we just need to look at that part of the marker
1853
- !(a.length !== b.length || a.some((m, i) => m.id !== b[i].id));
1854
1984
  // when you have multiple flows on a page and you hide the first one, the other ones have no markers anymore
1855
1985
  // when they do have markers with the same ids. To prevent this the user can pass a unique id to the react flow wrapper
1856
1986
  // that we can then use for creating our unique marker ids
1857
1987
  const MarkerDefinitions = ({ defaultColor, rfId }) => {
1858
- const markers = useStore(useCallback(markerSelector({ defaultColor, rfId }), [defaultColor, rfId]), markersEqual);
1988
+ const edges = useStore((s) => s.edges);
1989
+ const defaultEdgeOptions = useStore((s) => s.defaultEdgeOptions);
1990
+ const markers = useMemo(() => {
1991
+ const markers = createMarkerIds(edges, {
1992
+ id: rfId,
1993
+ defaultColor,
1994
+ defaultMarkerStart: defaultEdgeOptions?.markerStart,
1995
+ defaultMarkerEnd: defaultEdgeOptions?.markerEnd,
1996
+ });
1997
+ return markers;
1998
+ }, [edges, defaultEdgeOptions, rfId, defaultColor]);
1859
1999
  if (!markers.length) {
1860
2000
  return null;
1861
2001
  }
@@ -1864,31 +2004,32 @@ const MarkerDefinitions = ({ defaultColor, rfId }) => {
1864
2004
  MarkerDefinitions.displayName = 'MarkerDefinitions';
1865
2005
  var MarkerDefinitions$1 = memo(MarkerDefinitions);
1866
2006
 
1867
- const EdgeText = ({ x, y, label, labelStyle = {}, labelShowBg = true, labelBgStyle = {}, labelBgPadding = [2, 4], labelBgBorderRadius = 2, children, className, ...rest }) => {
2007
+ function EdgeTextComponent({ x, y, label, labelStyle = {}, labelShowBg = true, labelBgStyle = {}, labelBgPadding = [2, 4], labelBgBorderRadius = 2, children, className, ...rest }) {
1868
2008
  const [edgeTextBbox, setEdgeTextBbox] = useState({ x: 1, y: 0, width: 0, height: 0 });
1869
2009
  const edgeTextClasses = cc(['react-flow__edge-textwrapper', className]);
1870
- const onEdgeTextRefChange = useCallback((edgeRef) => {
1871
- if (edgeRef === null)
1872
- return;
1873
- const textBbox = edgeRef.getBBox();
1874
- setEdgeTextBbox({
1875
- x: textBbox.x,
1876
- y: textBbox.y,
1877
- width: textBbox.width,
1878
- height: textBbox.height,
1879
- });
1880
- }, []);
2010
+ const edgeTextRef = useRef(null);
2011
+ useEffect(() => {
2012
+ if (edgeTextRef.current) {
2013
+ const textBbox = edgeTextRef.current.getBBox();
2014
+ setEdgeTextBbox({
2015
+ x: textBbox.x,
2016
+ y: textBbox.y,
2017
+ width: textBbox.width,
2018
+ height: textBbox.height,
2019
+ });
2020
+ }
2021
+ }, [label]);
1881
2022
  if (typeof label === 'undefined' || !label) {
1882
2023
  return null;
1883
2024
  }
1884
- 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] }));
1885
- };
1886
- var EdgeText$1 = memo(EdgeText);
2025
+ 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] }));
2026
+ }
2027
+ EdgeTextComponent.displayName = 'EdgeText';
2028
+ const EdgeText = memo(EdgeTextComponent);
1887
2029
 
1888
- const BaseEdge = ({ id, path, labelX, labelY, label, labelStyle, labelShowBg, labelBgStyle, labelBgPadding, labelBgBorderRadius, style, markerEnd, markerStart, className, interactionWidth = 20, }) => {
1889
- return (jsxs(Fragment, { children: [jsx("path", { id: id, style: style, d: path, fill: "none", className: cc(['react-flow__edge-path', className]), markerEnd: markerEnd, markerStart: markerStart }), interactionWidth && (jsx("path", { d: path, fill: "none", strokeOpacity: 0, strokeWidth: interactionWidth, className: "react-flow__edge-interaction" })), label && isNumeric(labelX) && isNumeric(labelY) ? (jsx(EdgeText$1, { x: labelX, y: labelY, label: label, labelStyle: labelStyle, labelShowBg: labelShowBg, labelBgStyle: labelBgStyle, labelBgPadding: labelBgPadding, labelBgBorderRadius: labelBgBorderRadius })) : null] }));
1890
- };
1891
- BaseEdge.displayName = 'BaseEdge';
2030
+ function BaseEdge({ id, path, labelX, labelY, label, labelStyle, labelShowBg, labelBgStyle, labelBgPadding, labelBgBorderRadius, style, markerEnd, markerStart, className, interactionWidth = 20, }) {
2031
+ return (jsxs(Fragment, { children: [jsx("path", { id: id, style: style, d: path, fill: "none", className: cc(['react-flow__edge-path', className]), markerEnd: markerEnd, markerStart: markerStart }), interactionWidth && (jsx("path", { d: path, fill: "none", strokeOpacity: 0, strokeWidth: interactionWidth, className: "react-flow__edge-interaction" })), label && isNumeric(labelX) && isNumeric(labelY) ? (jsx(EdgeText, { x: labelX, y: labelY, label: label, labelStyle: labelStyle, labelShowBg: labelShowBg, labelBgStyle: labelBgStyle, labelBgPadding: labelBgPadding, labelBgBorderRadius: labelBgBorderRadius })) : null] }));
2032
+ }
1892
2033
 
1893
2034
  function getControl({ pos, x1, y1, x2, y2 }) {
1894
2035
  if (pos === Position.Left || pos === Position.Right) {
@@ -2048,7 +2189,9 @@ const shiftY = (y, shift, position) => {
2048
2189
  return y;
2049
2190
  };
2050
2191
  const EdgeUpdaterClassName = 'react-flow__edgeupdater';
2051
- const EdgeAnchor = ({ position, centerX, centerY, radius = 10, onMouseDown, onMouseEnter, onMouseOut, type, }) => (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" }));
2192
+ function EdgeAnchor({ position, centerX, centerY, radius = 10, onMouseDown, onMouseEnter, onMouseOut, type, }) {
2193
+ 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" }));
2194
+ }
2052
2195
 
2053
2196
  function EdgeUpdateAnchors({ isUpdatable, edgeUpdaterRadius, edge, targetHandleId, sourceHandleId, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, onEdgeUpdate, onEdgeUpdateStart, onEdgeUpdateEnd, setUpdating, setUpdateHover, }) {
2054
2197
  const store = useStoreApi();
@@ -2057,7 +2200,7 @@ function EdgeUpdateAnchors({ isUpdatable, edgeUpdaterRadius, edge, targetHandleI
2057
2200
  if (event.button !== 0) {
2058
2201
  return;
2059
2202
  }
2060
- const { autoPanOnConnect, domNode, isValidConnection, connectionMode, connectionRadius, lib, onConnectStart, onConnectEnd, cancelConnection, nodes, panBy, updateConnection, } = store.getState();
2203
+ const { autoPanOnConnect, domNode, isValidConnection, connectionMode, connectionRadius, lib, onConnectStart, onConnectEnd, cancelConnection, nodeLookup, rfId: flowId, panBy, updateConnection, } = store.getState();
2061
2204
  const nodeId = isSourceHandle ? edge.target : edge.source;
2062
2205
  const handleId = (isSourceHandle ? targetHandleId : sourceHandleId) || null;
2063
2206
  const handleType = isSourceHandle ? 'target' : 'source';
@@ -2076,10 +2219,11 @@ function EdgeUpdateAnchors({ isUpdatable, edgeUpdaterRadius, edge, targetHandleI
2076
2219
  domNode,
2077
2220
  handleId,
2078
2221
  nodeId,
2079
- nodes,
2222
+ nodeLookup,
2080
2223
  isTarget,
2081
2224
  edgeUpdaterType: handleType,
2082
2225
  lib,
2226
+ flowId,
2083
2227
  cancelConnection,
2084
2228
  panBy,
2085
2229
  isValidConnection,
@@ -2089,6 +2233,7 @@ function EdgeUpdateAnchors({ isUpdatable, edgeUpdaterRadius, edge, targetHandleI
2089
2233
  onEdgeUpdateEnd: _onEdgeUpdateEnd,
2090
2234
  updateConnection,
2091
2235
  getTransform: () => store.getState().transform,
2236
+ getConnectionStartHandle: () => store.getState().connectionStartHandle,
2092
2237
  });
2093
2238
  };
2094
2239
  const onEdgeUpdaterSourceMouseDown = (event) => handleEdgeUpdater(event, true);
@@ -2098,7 +2243,7 @@ function EdgeUpdateAnchors({ isUpdatable, edgeUpdaterRadius, edge, targetHandleI
2098
2243
  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" }))] }));
2099
2244
  }
2100
2245
 
2101
- function EdgeWrapper({ id, edgesFocusable, edgesUpdatable, elementsSelectable, onClick, onDoubleClick, onContextMenu, onMouseEnter, onMouseMove, onMouseLeave, edgeUpdaterRadius, onEdgeUpdate, onEdgeUpdateStart, onEdgeUpdateEnd, rfId, edgeTypes, noPanClassName, onError, }) {
2246
+ function EdgeWrapper({ id, edgesFocusable, edgesUpdatable, elementsSelectable, onClick, onDoubleClick, onContextMenu, onMouseEnter, onMouseMove, onMouseLeave, edgeUpdaterRadius, onEdgeUpdate, onEdgeUpdateStart, onEdgeUpdateEnd, rfId, edgeTypes, noPanClassName, onError, disableKeyboardA11y, }) {
2102
2247
  let edge = useStore((s) => s.edgeLookup.get(id));
2103
2248
  const defaultEdgeOptions = useStore((s) => s.defaultEdgeOptions);
2104
2249
  edge = defaultEdgeOptions ? { ...defaultEdgeOptions, ...edge } : edge;
@@ -2147,9 +2292,9 @@ function EdgeWrapper({ id, edgesFocusable, edgesUpdatable, elementsSelectable, o
2147
2292
  ...(edgePosition || nullPosition),
2148
2293
  };
2149
2294
  }, [edge.source, edge.target, edge.sourceHandle, edge.targetHandle, edge.selected, edge.zIndex]), shallow);
2150
- const markerStartUrl = useMemo(() => (edge.markerStart ? `url(#${getMarkerId(edge.markerStart, rfId)})` : undefined), [edge.markerStart, rfId]);
2151
- const markerEndUrl = useMemo(() => (edge.markerEnd ? `url(#${getMarkerId(edge.markerEnd, rfId)})` : undefined), [edge.markerEnd, rfId]);
2152
- if (edge.hidden || !sourceX || !sourceY || !targetX || !targetY) {
2295
+ const markerStartUrl = useMemo(() => (edge.markerStart ? `url('#${getMarkerId(edge.markerStart, rfId)}')` : undefined), [edge.markerStart, rfId]);
2296
+ const markerEndUrl = useMemo(() => (edge.markerEnd ? `url('#${getMarkerId(edge.markerEnd, rfId)}')` : undefined), [edge.markerEnd, rfId]);
2297
+ if (edge.hidden || sourceX === null || sourceY === null || targetX === null || targetY === null) {
2153
2298
  return null;
2154
2299
  }
2155
2300
  const onEdgeClick = (event) => {
@@ -2194,7 +2339,7 @@ function EdgeWrapper({ id, edgesFocusable, edgesUpdatable, elementsSelectable, o
2194
2339
  }
2195
2340
  : undefined;
2196
2341
  const onKeyDown = (event) => {
2197
- if (elementSelectionKeys.includes(event.key) && isSelectable) {
2342
+ if (!disableKeyboardA11y && elementSelectionKeys.includes(event.key) && isSelectable) {
2198
2343
  const { unselectNodesAndEdges, addSelectedEdges } = store.getState();
2199
2344
  const unselect = event.key === 'Escape';
2200
2345
  if (unselect) {
@@ -2216,11 +2361,10 @@ function EdgeWrapper({ id, edgesFocusable, edgesUpdatable, elementsSelectable, o
2216
2361
  animated: edge.animated,
2217
2362
  inactive: !isSelectable && !onClick,
2218
2363
  updating: updateHover,
2364
+ selectable: isSelectable,
2219
2365
  },
2220
- ]), 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 }))] }) }));
2366
+ ]), 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, 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 })), 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 }))] }) }));
2221
2367
  }
2222
- EdgeWrapper.displayName = 'EdgeWrapper';
2223
- var EdgeWrapper$1 = memo(EdgeWrapper);
2224
2368
 
2225
2369
  const selector$c = (s) => ({
2226
2370
  width: s.width,
@@ -2231,15 +2375,15 @@ const selector$c = (s) => ({
2231
2375
  connectionMode: s.connectionMode,
2232
2376
  onError: s.onError,
2233
2377
  });
2234
- const EdgeRenderer = ({ defaultMarkerColor, onlyRenderVisibleElements, rfId, edgeTypes, noPanClassName, onEdgeUpdate, onEdgeContextMenu, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, onEdgeClick, edgeUpdaterRadius, onEdgeDoubleClick, onEdgeUpdateStart, onEdgeUpdateEnd, children, }) => {
2378
+ function EdgeRendererComponent({ defaultMarkerColor, onlyRenderVisibleElements, rfId, edgeTypes, noPanClassName, onEdgeUpdate, onEdgeContextMenu, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, onEdgeClick, edgeUpdaterRadius, onEdgeDoubleClick, onEdgeUpdateStart, onEdgeUpdateEnd, disableKeyboardA11y, }) {
2235
2379
  const { edgesFocusable, edgesUpdatable, elementsSelectable, onError } = useStore(selector$c, shallow);
2236
2380
  const edgeIds = useVisibleEdgeIds(onlyRenderVisibleElements);
2237
2381
  return (jsxs("div", { className: "react-flow__edges", children: [jsx(MarkerDefinitions$1, { defaultColor: defaultMarkerColor, rfId: rfId }), edgeIds.map((id) => {
2238
- return (jsx(EdgeWrapper$1, { 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));
2239
- }), children] }));
2240
- };
2241
- EdgeRenderer.displayName = 'EdgeRenderer';
2242
- var EdgeRenderer$1 = memo(EdgeRenderer);
2382
+ 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, disableKeyboardA11y: disableKeyboardA11y }, id));
2383
+ })] }));
2384
+ }
2385
+ EdgeRendererComponent.displayName = 'EdgeRenderer';
2386
+ const EdgeRenderer = memo(EdgeRendererComponent);
2243
2387
 
2244
2388
  const selector$b = (s) => `translate(${s.transform[0]}px,${s.transform[1]}px) scale(${s.transform[2]})`;
2245
2389
  function Viewport({ children }) {
@@ -2296,7 +2440,7 @@ const ConnectionLine = ({ nodeId, handleType, style, type = ConnectionLineType.B
2296
2440
  toY: (s.connectionPosition.y - s.transform[1]) / s.transform[2],
2297
2441
  connectionMode: s.connectionMode,
2298
2442
  }), [nodeId]), shallow);
2299
- const fromHandleBounds = fromNode?.[internalsSymbol]?.handleBounds;
2443
+ const fromHandleBounds = fromNode?.internals.handleBounds;
2300
2444
  let handleBounds = fromHandleBounds?.[handleType];
2301
2445
  if (connectionMode === ConnectionMode.Loose) {
2302
2446
  handleBounds = handleBounds ? handleBounds : fromHandleBounds?.[handleType === 'source' ? 'target' : 'source'];
@@ -2305,10 +2449,10 @@ const ConnectionLine = ({ nodeId, handleType, style, type = ConnectionLineType.B
2305
2449
  return null;
2306
2450
  }
2307
2451
  const fromHandle = handleId ? handleBounds.find((d) => d.id === handleId) : handleBounds[0];
2308
- const fromHandleX = fromHandle ? fromHandle.x + fromHandle.width / 2 : (fromNode.computed?.width ?? 0) / 2;
2309
- const fromHandleY = fromHandle ? fromHandle.y + fromHandle.height / 2 : fromNode.computed?.height ?? 0;
2310
- const fromX = (fromNode.computed?.positionAbsolute?.x ?? 0) + fromHandleX;
2311
- const fromY = (fromNode.computed?.positionAbsolute?.y ?? 0) + fromHandleY;
2452
+ const fromHandleX = fromHandle ? fromHandle.x + fromHandle.width / 2 : (fromNode.measured.width ?? 0) / 2;
2453
+ const fromHandleY = fromHandle ? fromHandle.y + fromHandle.height / 2 : fromNode.measured.height ?? 0;
2454
+ const fromX = fromNode.internals.positionAbsolute.x + fromHandleX;
2455
+ const fromY = fromNode.internals.positionAbsolute.y + fromHandleY;
2312
2456
  const fromPosition = fromHandle?.position;
2313
2457
  const toPosition = fromPosition ? oppositePosition[fromPosition] : null;
2314
2458
  if (!fromPosition || !toPosition) {
@@ -2368,66 +2512,68 @@ function ConnectionLineWrapper({ containerStyle, style, type, component }) {
2368
2512
  const emptyTypes = {};
2369
2513
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
2370
2514
  function useNodeOrEdgeTypesWarning(nodeOrEdgeTypes = emptyTypes) {
2371
- const updateCount = useRef(0);
2515
+ const typesRef = useRef(nodeOrEdgeTypes);
2372
2516
  const store = useStoreApi();
2373
2517
  useEffect(() => {
2374
2518
  if (process.env.NODE_ENV === 'development') {
2375
- if (updateCount.current > 1) {
2376
- store.getState().onError?.('002', errorMessages['error002']());
2519
+ const usedKeys = new Set([...Object.keys(typesRef.current), ...Object.keys(nodeOrEdgeTypes)]);
2520
+ for (const key of usedKeys) {
2521
+ if (typesRef.current[key] !== nodeOrEdgeTypes[key]) {
2522
+ store.getState().onError?.('002', errorMessages['error002']());
2523
+ break;
2524
+ }
2377
2525
  }
2378
- updateCount.current += 1;
2526
+ typesRef.current = nodeOrEdgeTypes;
2379
2527
  }
2380
2528
  }, [nodeOrEdgeTypes]);
2381
2529
  }
2382
2530
 
2383
- const GraphView = ({ 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, }) => {
2531
+ function useStylesLoadedWarning() {
2532
+ const store = useStoreApi();
2533
+ const checked = useRef(false);
2534
+ useEffect(() => {
2535
+ if (process.env.NODE_ENV === 'development') {
2536
+ if (!checked.current) {
2537
+ const pane = document.querySelector('.react-flow__pane');
2538
+ if (pane && !(window.getComputedStyle(pane).zIndex === '1')) {
2539
+ store.getState().onError?.('013', errorMessages['error013']('react'));
2540
+ }
2541
+ checked.current = true;
2542
+ }
2543
+ }
2544
+ }, []);
2545
+ }
2546
+
2547
+ 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, }) {
2384
2548
  useNodeOrEdgeTypesWarning(nodeTypes);
2385
2549
  useNodeOrEdgeTypesWarning(edgeTypes);
2550
+ useStylesLoadedWarning();
2386
2551
  useOnInitHandler(onInit);
2387
2552
  useViewportSync(viewport);
2388
- return (jsx(FlowRenderer$1, { 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$1, { 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$1, { 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 })] }) }));
2389
- };
2390
- GraphView.displayName = 'GraphView';
2391
- var GraphView$1 = memo(GraphView);
2392
-
2393
- function handleControlledSelectionChange(changes, items) {
2394
- return items.map((item) => {
2395
- const change = changes.find((change) => change.id === item.id);
2396
- if (change) {
2397
- item.selected = change.selected;
2398
- }
2399
- return item;
2400
- });
2401
- }
2402
- function updateNodesAndEdgesSelections({ changedNodes, changedEdges, get, set }) {
2403
- const { nodes, edges, onNodesChange, onEdgesChange, hasDefaultNodes, hasDefaultEdges } = get();
2404
- if (changedNodes?.length) {
2405
- if (hasDefaultNodes) {
2406
- set({ nodes: handleControlledSelectionChange(changedNodes, nodes) });
2407
- }
2408
- onNodesChange?.(changedNodes);
2409
- }
2410
- if (changedEdges?.length) {
2411
- if (hasDefaultEdges) {
2412
- set({ edges: handleControlledSelectionChange(changedEdges, edges) });
2413
- }
2414
- onEdgesChange?.(changedEdges);
2415
- }
2553
+ 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(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 }), jsx("div", { className: "react-flow__viewport-portal" })] }) }));
2416
2554
  }
2555
+ GraphViewComponent.displayName = 'GraphView';
2556
+ const GraphView = memo(GraphViewComponent);
2417
2557
 
2418
- const getInitialState = ({ nodes = [], edges = [], width, height, fitView, } = {}) => {
2558
+ const getInitialState = ({ nodes, edges, defaultNodes, defaultEdges, width, height, fitView, } = {}) => {
2419
2559
  const nodeLookup = new Map();
2560
+ const parentLookup = new Map();
2420
2561
  const connectionLookup = new Map();
2421
2562
  const edgeLookup = new Map();
2422
- updateConnectionLookup(connectionLookup, edgeLookup, edges);
2423
- const nextNodes = adoptUserProvidedNodes(nodes, nodeLookup, {
2563
+ const storeEdges = defaultEdges ?? edges ?? [];
2564
+ const storeNodes = defaultNodes ?? nodes ?? [];
2565
+ updateConnectionLookup(connectionLookup, edgeLookup, storeEdges);
2566
+ adoptUserNodes(storeNodes, nodeLookup, parentLookup, {
2424
2567
  nodeOrigin: [0, 0],
2425
2568
  elevateNodesOnSelect: false,
2426
2569
  });
2427
2570
  let transform = [0, 0, 1];
2428
2571
  if (fitView && width && height) {
2429
- const nodesWithDimensions = nextNodes.filter((node) => node.width && node.height);
2430
- const bounds = getNodesBounds(nodesWithDimensions, [0, 0]);
2572
+ // @todo users nodeOrigin should be used here
2573
+ const bounds = getInternalNodesBounds(nodeLookup, {
2574
+ nodeOrigin: [0, 0],
2575
+ filter: (node) => !!((node.width || node.initialWidth) && (node.height || node.initialHeight)),
2576
+ });
2431
2577
  const { x, y, zoom } = getViewportForBounds(bounds, width, height, 0.5, 2, 0.1);
2432
2578
  transform = [x, y, zoom];
2433
2579
  }
@@ -2436,15 +2582,16 @@ const getInitialState = ({ nodes = [], edges = [], width, height, fitView, } = {
2436
2582
  width: 0,
2437
2583
  height: 0,
2438
2584
  transform,
2439
- nodes: nextNodes,
2585
+ nodes: storeNodes,
2440
2586
  nodeLookup,
2441
- edges,
2587
+ parentLookup,
2588
+ edges: storeEdges,
2442
2589
  edgeLookup,
2443
2590
  connectionLookup,
2444
2591
  onNodesChange: null,
2445
2592
  onEdgesChange: null,
2446
- hasDefaultNodes: false,
2447
- hasDefaultEdges: false,
2593
+ hasDefaultNodes: defaultNodes !== undefined,
2594
+ hasDefaultEdges: defaultEdges !== undefined,
2448
2595
  panZoom: null,
2449
2596
  minZoom: 0.5,
2450
2597
  maxZoom: 2,
@@ -2484,78 +2631,60 @@ const getInitialState = ({ nodes = [], edges = [], width, height, fitView, } = {
2484
2631
  autoPanOnConnect: true,
2485
2632
  autoPanOnNodeDrag: true,
2486
2633
  connectionRadius: 20,
2487
- onError: () => null,
2634
+ onError: devWarn,
2488
2635
  isValidConnection: undefined,
2489
2636
  onSelectionChangeHandlers: [],
2490
2637
  lib: 'react',
2638
+ debug: false,
2491
2639
  };
2492
2640
  };
2493
2641
 
2494
- const createRFStore = ({ nodes, edges, width, height, fitView: fitView$1, }) => createWithEqualityFn((set, get) => ({
2495
- ...getInitialState({ nodes, edges, width, height, fitView: fitView$1 }),
2642
+ const createStore = ({ nodes, edges, defaultNodes, defaultEdges, width, height, fitView: fitView$1, }) => createWithEqualityFn((set, get) => ({
2643
+ ...getInitialState({ nodes, edges, width, height, fitView: fitView$1, defaultNodes, defaultEdges }),
2496
2644
  setNodes: (nodes) => {
2497
- const { nodeLookup, nodeOrigin, elevateNodesOnSelect } = get();
2645
+ const { nodeLookup, parentLookup, nodeOrigin, elevateNodesOnSelect } = get();
2498
2646
  // setNodes() is called exclusively in response to user actions:
2499
2647
  // - either when the `<ReactFlow nodes>` prop is updated in the controlled ReactFlow setup,
2500
2648
  // - or when the user calls something like `reactFlowInstance.setNodes()` in an uncontrolled ReactFlow setup.
2501
2649
  //
2502
2650
  // When this happens, we take the note objects passed by the user and extend them with fields
2503
2651
  // relevant for internal React Flow operations.
2504
- // TODO: consider updating the types to reflect the distinction between user-provided nodes and internal nodes.
2505
- const nodesWithInternalData = adoptUserProvidedNodes(nodes, nodeLookup, { nodeOrigin, elevateNodesOnSelect });
2506
- set({ nodes: nodesWithInternalData });
2652
+ adoptUserNodes(nodes, nodeLookup, parentLookup, { nodeOrigin, elevateNodesOnSelect, checkEquality: true });
2653
+ set({ nodes });
2507
2654
  },
2508
2655
  setEdges: (edges) => {
2509
2656
  const { connectionLookup, edgeLookup } = get();
2510
2657
  updateConnectionLookup(connectionLookup, edgeLookup, edges);
2511
2658
  set({ edges });
2512
2659
  },
2513
- // when the user works with an uncontrolled flow,
2514
- // we set a flag `hasDefaultNodes` / `hasDefaultEdges`
2515
2660
  setDefaultNodesAndEdges: (nodes, edges) => {
2516
- const hasDefaultNodes = typeof nodes !== 'undefined';
2517
- const hasDefaultEdges = typeof edges !== 'undefined';
2518
- const nextState = {
2519
- hasDefaultNodes,
2520
- hasDefaultEdges,
2521
- };
2522
- if (hasDefaultNodes) {
2523
- const { nodeLookup, nodeOrigin, elevateNodesOnSelect } = get();
2524
- nextState.nodes = adoptUserProvidedNodes(nodes, nodeLookup, {
2525
- nodeOrigin,
2526
- elevateNodesOnSelect,
2527
- });
2661
+ if (nodes) {
2662
+ const { setNodes } = get();
2663
+ setNodes(nodes);
2664
+ set({ hasDefaultNodes: true });
2528
2665
  }
2529
- if (hasDefaultEdges) {
2530
- const { connectionLookup, edgeLookup } = get();
2531
- updateConnectionLookup(connectionLookup, edgeLookup, edges);
2532
- nextState.edges = edges;
2666
+ if (edges) {
2667
+ const { setEdges } = get();
2668
+ setEdges(edges);
2669
+ set({ hasDefaultEdges: true });
2533
2670
  }
2534
- set(nextState);
2535
2671
  },
2536
2672
  // Every node gets registerd at a ResizeObserver. Whenever a node
2537
2673
  // changes its dimensions, this function is called to measure the
2538
2674
  // new dimensions and update the nodes.
2539
- updateNodeDimensions: (updates) => {
2540
- const { onNodesChange, fitView, nodes, nodeLookup, fitViewOnInit, fitViewDone, fitViewOnInitOptions, domNode, nodeOrigin, } = get();
2541
- const changes = [];
2542
- const updatedNodes = updateNodeDimensions(updates, nodes, nodeLookup, domNode, nodeOrigin, (id, dimensions) => {
2543
- changes.push({
2544
- id: id,
2545
- type: 'dimensions',
2546
- dimensions,
2547
- });
2548
- });
2549
- if (!updatedNodes) {
2675
+ updateNodeInternals: (updates) => {
2676
+ const { triggerNodeChanges, fitView, nodeLookup, parentLookup, fitViewOnInit, fitViewDone, fitViewOnInitOptions, domNode, nodeOrigin, debug, } = get();
2677
+ const { changes, updatedInternals } = updateNodeInternals(updates, nodeLookup, parentLookup, domNode, nodeOrigin);
2678
+ if (!updatedInternals) {
2550
2679
  return;
2551
2680
  }
2552
- const nextNodes = updateAbsolutePositions(updatedNodes, nodeLookup, nodeOrigin);
2681
+ updateAbsolutePositions(nodeLookup, { nodeOrigin });
2553
2682
  // we call fitView once initially after all dimensions are set
2554
2683
  let nextFitViewDone = fitViewDone;
2555
2684
  if (!fitViewDone && fitViewOnInit) {
2556
- nextFitViewDone = fitView(nextNodes, {
2685
+ nextFitViewDone = fitView({
2557
2686
  ...fitViewOnInitOptions,
2558
- nodes: fitViewOnInitOptions?.nodes || nextNodes,
2687
+ nodes: fitViewOnInitOptions?.nodes,
2559
2688
  });
2560
2689
  }
2561
2690
  // here we are cirmumventing the onNodesChange handler
@@ -2563,91 +2692,104 @@ const createRFStore = ({ nodes, edges, width, height, fitView: fitView$1, }) =>
2563
2692
  // has not provided an onNodesChange handler.
2564
2693
  // Nodes are only rendered if they have a width and height
2565
2694
  // attribute which they get from this handler.
2566
- set({ nodes: nextNodes, fitViewDone: nextFitViewDone });
2695
+ set({ fitViewDone: nextFitViewDone });
2567
2696
  if (changes?.length > 0) {
2568
- onNodesChange?.(changes);
2697
+ if (debug) {
2698
+ console.log('React Flow: trigger node changes', changes);
2699
+ }
2700
+ triggerNodeChanges?.(changes);
2569
2701
  }
2570
2702
  },
2571
- updateNodePositions: (nodeDragItems, positionChanged = true, dragging = false) => {
2572
- const changes = nodeDragItems.map((node) => {
2703
+ updateNodePositions: (nodeDragItems, dragging = false) => {
2704
+ const parentExpandChildren = [];
2705
+ const changes = [];
2706
+ for (const [id, dragItem] of nodeDragItems) {
2707
+ // @todo add expandParent to drag item so that we can get rid of the look up here
2573
2708
  const change = {
2574
- id: node.id,
2709
+ id,
2575
2710
  type: 'position',
2711
+ position: dragItem.position,
2576
2712
  dragging,
2577
2713
  };
2578
- if (positionChanged) {
2579
- change.positionAbsolute = node.computed?.positionAbsolute;
2580
- change.position = node.position;
2714
+ if (dragItem?.expandParent && dragItem?.parentId && change.position) {
2715
+ parentExpandChildren.push({
2716
+ id,
2717
+ parentId: dragItem.parentId,
2718
+ rect: {
2719
+ ...dragItem.internals.positionAbsolute,
2720
+ width: dragItem.measured.width,
2721
+ height: dragItem.measured.height,
2722
+ },
2723
+ });
2724
+ change.position.x = Math.max(0, change.position.x);
2725
+ change.position.y = Math.max(0, change.position.y);
2581
2726
  }
2582
- return change;
2583
- });
2727
+ changes.push(change);
2728
+ }
2729
+ if (parentExpandChildren.length > 0) {
2730
+ const { nodeLookup, parentLookup } = get();
2731
+ const parentExpandChanges = handleExpandParent(parentExpandChildren, nodeLookup, parentLookup);
2732
+ changes.push(...parentExpandChanges);
2733
+ }
2584
2734
  get().triggerNodeChanges(changes);
2585
2735
  },
2586
2736
  triggerNodeChanges: (changes) => {
2587
- const { onNodesChange, nodeLookup, nodes, hasDefaultNodes, nodeOrigin, elevateNodesOnSelect } = get();
2737
+ const { onNodesChange, setNodes, nodes, hasDefaultNodes, debug } = get();
2588
2738
  if (changes?.length) {
2589
2739
  if (hasDefaultNodes) {
2590
2740
  const updatedNodes = applyNodeChanges(changes, nodes);
2591
- const nextNodes = adoptUserProvidedNodes(updatedNodes, nodeLookup, {
2592
- nodeOrigin,
2593
- elevateNodesOnSelect,
2594
- });
2595
- set({ nodes: nextNodes });
2741
+ setNodes(updatedNodes);
2742
+ }
2743
+ if (debug) {
2744
+ console.log('React Flow: trigger node changes', changes);
2596
2745
  }
2597
2746
  onNodesChange?.(changes);
2598
2747
  }
2599
2748
  },
2749
+ triggerEdgeChanges: (changes) => {
2750
+ const { onEdgesChange, setEdges, edges, hasDefaultEdges, debug } = get();
2751
+ if (changes?.length) {
2752
+ if (hasDefaultEdges) {
2753
+ const updatedEdges = applyEdgeChanges(changes, edges);
2754
+ setEdges(updatedEdges);
2755
+ }
2756
+ if (debug) {
2757
+ console.log('React Flow: trigger edge changes', changes);
2758
+ }
2759
+ onEdgesChange?.(changes);
2760
+ }
2761
+ },
2600
2762
  addSelectedNodes: (selectedNodeIds) => {
2601
- const { multiSelectionActive, edges, nodes } = get();
2602
- let changedNodes;
2603
- let changedEdges = null;
2763
+ const { multiSelectionActive, edgeLookup, nodeLookup, triggerNodeChanges, triggerEdgeChanges } = get();
2604
2764
  if (multiSelectionActive) {
2605
- changedNodes = selectedNodeIds.map((nodeId) => createSelectionChange(nodeId, true));
2765
+ const nodeChanges = selectedNodeIds.map((nodeId) => createSelectionChange(nodeId, true));
2766
+ triggerNodeChanges(nodeChanges);
2767
+ return;
2606
2768
  }
2607
- else {
2608
- changedNodes = getSelectionChanges(nodes, new Set([...selectedNodeIds]), true);
2609
- changedEdges = getSelectionChanges(edges);
2610
- }
2611
- updateNodesAndEdgesSelections({
2612
- changedNodes,
2613
- changedEdges,
2614
- get,
2615
- set,
2616
- });
2769
+ triggerNodeChanges(getSelectionChanges(nodeLookup, new Set([...selectedNodeIds]), true));
2770
+ triggerEdgeChanges(getSelectionChanges(edgeLookup));
2617
2771
  },
2618
2772
  addSelectedEdges: (selectedEdgeIds) => {
2619
- const { multiSelectionActive, edges, nodes } = get();
2620
- let changedEdges;
2621
- let changedNodes = null;
2773
+ const { multiSelectionActive, edgeLookup, nodeLookup, triggerNodeChanges, triggerEdgeChanges } = get();
2622
2774
  if (multiSelectionActive) {
2623
- changedEdges = selectedEdgeIds.map((edgeId) => createSelectionChange(edgeId, true));
2775
+ const changedEdges = selectedEdgeIds.map((edgeId) => createSelectionChange(edgeId, true));
2776
+ triggerEdgeChanges(changedEdges);
2777
+ return;
2624
2778
  }
2625
- else {
2626
- changedEdges = getSelectionChanges(edges, new Set([...selectedEdgeIds]));
2627
- changedNodes = getSelectionChanges(nodes, new Set(), true);
2628
- }
2629
- updateNodesAndEdgesSelections({
2630
- changedNodes,
2631
- changedEdges,
2632
- get,
2633
- set,
2634
- });
2779
+ triggerEdgeChanges(getSelectionChanges(edgeLookup, new Set([...selectedEdgeIds])));
2780
+ triggerNodeChanges(getSelectionChanges(nodeLookup, new Set(), true));
2635
2781
  },
2636
2782
  unselectNodesAndEdges: ({ nodes, edges } = {}) => {
2637
- const { edges: storeEdges, nodes: storeNodes } = get();
2783
+ const { edges: storeEdges, nodes: storeNodes, triggerNodeChanges, triggerEdgeChanges } = get();
2638
2784
  const nodesToUnselect = nodes ? nodes : storeNodes;
2639
2785
  const edgesToUnselect = edges ? edges : storeEdges;
2640
- const changedNodes = nodesToUnselect.map((n) => {
2786
+ const nodeChanges = nodesToUnselect.map((n) => {
2641
2787
  n.selected = false;
2642
2788
  return createSelectionChange(n.id, false);
2643
2789
  });
2644
- const changedEdges = edgesToUnselect.map((edge) => createSelectionChange(edge.id, false));
2645
- updateNodesAndEdgesSelections({
2646
- changedNodes,
2647
- changedEdges,
2648
- get,
2649
- set,
2650
- });
2790
+ const edgeChanges = edgesToUnselect.map((edge) => createSelectionChange(edge.id, false));
2791
+ triggerNodeChanges(nodeChanges);
2792
+ triggerEdgeChanges(edgeChanges);
2651
2793
  },
2652
2794
  setMinZoom: (minZoom) => {
2653
2795
  const { panZoom, maxZoom } = get();
@@ -2664,47 +2806,39 @@ const createRFStore = ({ nodes, edges, width, height, fitView: fitView$1, }) =>
2664
2806
  set({ translateExtent });
2665
2807
  },
2666
2808
  resetSelectedElements: () => {
2667
- const { edges, nodes } = get();
2668
- const nodesToUnselect = nodes
2669
- .filter((e) => e.selected)
2670
- .map((n) => createSelectionChange(n.id, false));
2671
- const edgesToUnselect = edges
2672
- .filter((e) => e.selected)
2673
- .map((e) => createSelectionChange(e.id, false));
2674
- updateNodesAndEdgesSelections({
2675
- changedNodes: nodesToUnselect,
2676
- changedEdges: edgesToUnselect,
2677
- get,
2678
- set,
2679
- });
2809
+ const { edges, nodes, triggerNodeChanges, triggerEdgeChanges } = get();
2810
+ const nodeChanges = nodes.reduce((res, node) => (node.selected ? [...res, createSelectionChange(node.id, false)] : res), []);
2811
+ const edgeChanges = edges.reduce((res, edge) => (edge.selected ? [...res, createSelectionChange(edge.id, false)] : res), []);
2812
+ triggerNodeChanges(nodeChanges);
2813
+ triggerEdgeChanges(edgeChanges);
2680
2814
  },
2681
2815
  setNodeExtent: (nodeExtent) => {
2682
- const { nodes } = get();
2816
+ const { nodeLookup } = get();
2817
+ for (const [, node] of nodeLookup) {
2818
+ const positionAbsolute = clampPosition(node.position, nodeExtent);
2819
+ nodeLookup.set(node.id, {
2820
+ ...node,
2821
+ internals: {
2822
+ ...node.internals,
2823
+ positionAbsolute,
2824
+ },
2825
+ });
2826
+ }
2683
2827
  set({
2684
2828
  nodeExtent,
2685
- nodes: nodes.map((node) => {
2686
- const positionAbsolute = clampPosition(node.position, nodeExtent);
2687
- return {
2688
- ...node,
2689
- computed: {
2690
- ...node.computed,
2691
- positionAbsolute,
2692
- },
2693
- };
2694
- }),
2695
2829
  });
2696
2830
  },
2697
2831
  panBy: (delta) => {
2698
2832
  const { transform, width, height, panZoom, translateExtent } = get();
2699
2833
  return panBy({ delta, panZoom, transform, translateExtent, width, height });
2700
2834
  },
2701
- fitView: (nodes, options) => {
2702
- const { panZoom, width, height, minZoom, maxZoom, nodeOrigin } = get();
2835
+ fitView: (options) => {
2836
+ const { panZoom, width, height, minZoom, maxZoom, nodeOrigin, nodeLookup } = get();
2703
2837
  if (!panZoom) {
2704
2838
  return false;
2705
2839
  }
2706
2840
  return fitView({
2707
- nodes,
2841
+ nodeLookup,
2708
2842
  width,
2709
2843
  height,
2710
2844
  panZoom,
@@ -2719,82 +2853,39 @@ const createRFStore = ({ nodes, edges, width, height, fitView: fitView$1, }) =>
2719
2853
  connectionEndHandle: null,
2720
2854
  }),
2721
2855
  updateConnection: (params) => {
2722
- const { connectionStatus, connectionStartHandle, connectionEndHandle, connectionPosition } = get();
2856
+ const { connectionPosition } = get();
2723
2857
  const currentConnection = {
2858
+ ...params,
2724
2859
  connectionPosition: params.connectionPosition ?? connectionPosition,
2725
- connectionStatus: params.connectionStatus ?? connectionStatus,
2726
- connectionStartHandle: params.connectionStartHandle ?? connectionStartHandle,
2727
- connectionEndHandle: params.connectionEndHandle ?? connectionEndHandle,
2728
2860
  };
2729
2861
  set(currentConnection);
2730
2862
  },
2731
- reset: () => {
2732
- // @todo: what should we do about this? Do we still need it?
2733
- // if you are on a SPA with multiple flows, we want to make sure that the store gets resetted
2734
- // when you switch pages. Does this reset solves this? Currently it always gets called. This
2735
- // leads to an emtpy nodes array at the beginning.
2736
- // set({ ...getInitialState() });
2737
- },
2863
+ reset: () => set({ ...getInitialState() }),
2738
2864
  }), Object.is);
2739
2865
 
2740
- function ReactFlowProvider({ children, initialNodes, initialEdges, initialWidth, initialHeight, fitView, }) {
2741
- const storeRef = useRef(null);
2742
- if (!storeRef.current) {
2743
- storeRef.current = createRFStore({
2744
- nodes: initialNodes,
2745
- edges: initialEdges,
2746
- width: initialWidth,
2747
- height: initialHeight,
2748
- fitView,
2749
- });
2750
- }
2751
- return jsx(Provider$1, { value: storeRef.current, children: children });
2866
+ function ReactFlowProvider({ initialNodes: nodes, initialEdges: edges, defaultNodes, defaultEdges, initialWidth: width, initialHeight: height, fitView, children, }) {
2867
+ const [store] = useState(() => createStore({
2868
+ nodes,
2869
+ edges,
2870
+ defaultNodes,
2871
+ defaultEdges,
2872
+ width,
2873
+ height,
2874
+ fitView,
2875
+ }));
2876
+ return (jsx(Provider$1, { value: store, children: jsx(BatchProvider, { children: children }) }));
2752
2877
  }
2753
- ReactFlowProvider.displayName = 'ReactFlowProvider';
2754
2878
 
2755
- function Wrapper({ children, nodes, edges, width, height, fitView, }) {
2879
+ function Wrapper({ children, nodes, edges, defaultNodes, defaultEdges, width, height, fitView, }) {
2756
2880
  const isWrapped = useContext(StoreContext);
2757
2881
  if (isWrapped) {
2758
2882
  // we need to wrap it with a fragment because it's not allowed for children to be a ReactNode
2759
2883
  // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18051
2760
2884
  return jsx(Fragment, { children: children });
2761
2885
  }
2762
- return (jsx(ReactFlowProvider, { initialNodes: nodes, initialEdges: edges, initialWidth: width, initialHeight: height, fitView: fitView, children: children }));
2763
- }
2764
- Wrapper.displayName = 'ReactFlowWrapper';
2765
-
2766
- function getMediaQuery() {
2767
- if (typeof window === 'undefined' || !window.matchMedia) {
2768
- return null;
2769
- }
2770
- return window.matchMedia('(prefers-color-scheme: dark)');
2771
- }
2772
- /**
2773
- * Hook for receiving the current color mode class 'dark' or 'light'.
2774
- *
2775
- * @internal
2776
- * @param colorMode - The color mode to use ('dark', 'light' or 'system')
2777
- */
2778
- function useColorModeClass(colorMode) {
2779
- const [colorModeClass, setColorModeClass] = useState(colorMode === 'system' ? null : colorMode);
2780
- useEffect(() => {
2781
- if (colorMode !== 'system') {
2782
- setColorModeClass(colorMode);
2783
- return;
2784
- }
2785
- const mediaQuery = getMediaQuery();
2786
- const updateColorModeClass = () => setColorModeClass(mediaQuery?.matches ? 'dark' : 'light');
2787
- updateColorModeClass();
2788
- mediaQuery?.addEventListener('change', updateColorModeClass);
2789
- return () => {
2790
- mediaQuery?.removeEventListener('change', updateColorModeClass);
2791
- };
2792
- }, [colorMode]);
2793
- return colorModeClass !== null ? colorModeClass : getMediaQuery()?.matches ? 'dark' : 'light';
2886
+ return (jsx(ReactFlowProvider, { initialNodes: nodes, initialEdges: edges, defaultNodes: defaultNodes, defaultEdges: defaultEdges, initialWidth: width, initialHeight: height, fitView: fitView, children: children }));
2794
2887
  }
2795
2888
 
2796
- const initNodeOrigin = [0, 0];
2797
- const initDefaultViewport = { x: 0, y: 0, zoom: 1 };
2798
2889
  const wrapperStyle = {
2799
2890
  width: '100%',
2800
2891
  height: '100%',
@@ -2802,12 +2893,12 @@ const wrapperStyle = {
2802
2893
  position: 'relative',
2803
2894
  zIndex: 0,
2804
2895
  };
2805
- 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 = initNodeOrigin, edgesFocusable, edgesUpdatable, elementsSelectable = true, defaultViewport = initDefaultViewport, 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) => {
2896
+ 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, 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', debug, ...rest }, ref) {
2806
2897
  const rfId = id || '1';
2807
2898
  const colorModeClassName = useColorModeClass(colorMode);
2808
- 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, children: [jsx(GraphView$1, { 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, 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(Wrapper$1, { onSelectionChange: onSelectionChange }), children, jsx(Attribution, { proOptions: proOptions, position: attributionPosition }), jsx(A11yDescriptions, { rfId: rfId, disableKeyboardA11y: disableKeyboardA11y })] }) }));
2809
- });
2810
- ReactFlow.displayName = 'ReactFlow';
2899
+ 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, 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, debug: debug }), jsx(SelectionListener, { onSelectionChange: onSelectionChange }), children, jsx(Attribution, { proOptions: proOptions, position: attributionPosition }), jsx(A11yDescriptions, { rfId: rfId, disableKeyboardA11y: disableKeyboardA11y })] }) }));
2900
+ }
2901
+ var index = fixedForwardRef(ReactFlow);
2811
2902
 
2812
2903
  const selector$8 = (s) => s.domNode?.querySelector('.react-flow__edgelabel-renderer');
2813
2904
  function EdgeLabelRenderer({ children }) {
@@ -2836,16 +2927,16 @@ function ViewportPortal({ children }) {
2836
2927
  function useUpdateNodeInternals() {
2837
2928
  const store = useStoreApi();
2838
2929
  return useCallback((id) => {
2839
- const { domNode, updateNodeDimensions } = store.getState();
2930
+ const { domNode, updateNodeInternals } = store.getState();
2840
2931
  const updateIds = Array.isArray(id) ? id : [id];
2841
2932
  const updates = new Map();
2842
2933
  updateIds.forEach((updateId) => {
2843
2934
  const nodeElement = domNode?.querySelector(`.react-flow__node[data-id="${updateId}"]`);
2844
2935
  if (nodeElement) {
2845
- updates.set(updateId, { id: updateId, nodeElement, forceUpdate: true });
2936
+ updates.set(updateId, { id: updateId, nodeElement, force: true });
2846
2937
  }
2847
2938
  });
2848
- requestAnimationFrame(() => updateNodeDimensions(updates));
2939
+ requestAnimationFrame(() => updateNodeInternals(updates));
2849
2940
  }, []);
2850
2941
  }
2851
2942
 
@@ -2939,7 +3030,7 @@ function useOnViewportChange({ onStart, onChange, onEnd }) {
2939
3030
  * Hook for registering an onSelectionChange handler.
2940
3031
  *
2941
3032
  * @public
2942
- * @params params.onChange - The handler to register
3033
+ * @param params.onChange - The handler to register
2943
3034
  */
2944
3035
  function useOnSelectionChange({ onChange }) {
2945
3036
  const store = useStoreApi();
@@ -2954,12 +3045,17 @@ function useOnSelectionChange({ onChange }) {
2954
3045
  }
2955
3046
 
2956
3047
  const selector$6 = (options) => (s) => {
2957
- if (s.nodes.length === 0) {
3048
+ if (s.nodeLookup.size === 0) {
2958
3049
  return false;
2959
3050
  }
2960
- return s.nodes
2961
- .filter((n) => (options.includeHiddenNodes ? true : !n.hidden))
2962
- .every((n) => n[internalsSymbol]?.handleBounds !== undefined);
3051
+ for (const [, { hidden, internals }] of s.nodeLookup) {
3052
+ if (options.includeHiddenNodes || !hidden) {
3053
+ if (internals.handleBounds === undefined || !nodeHasDimensions(internals.userNode)) {
3054
+ return false;
3055
+ }
3056
+ }
3057
+ }
3058
+ return true;
2963
3059
  };
2964
3060
  const defaultOptions = {
2965
3061
  includeHiddenNodes: false,
@@ -2977,7 +3073,7 @@ function useNodesInitialized(options = defaultOptions) {
2977
3073
  }
2978
3074
 
2979
3075
  /**
2980
- * Hook to check if a <Handle /> is connected to another <Handle /> and get the connections.
3076
+ * Hook to check if a <Handle /> is connected to another <Handle /> and get the connections.
2981
3077
  *
2982
3078
  * @public
2983
3079
  * @param param.type - handle type 'source' or 'target'
@@ -2985,12 +3081,12 @@ function useNodesInitialized(options = defaultOptions) {
2985
3081
  * @param param.id - the handle id (this is only needed if the node has multiple handles of the same type)
2986
3082
  * @param param.onConnect - gets called when a connection is established
2987
3083
  * @param param.onDisconnect - gets called when a connection is removed
2988
- * @returns an array with connections
3084
+ * @returns an array with handle connections
2989
3085
  */
2990
3086
  function useHandleConnections({ type, id = null, nodeId, onConnect, onDisconnect, }) {
2991
3087
  const _nodeId = useNodeId();
3088
+ const currentNodeId = nodeId ?? _nodeId;
2992
3089
  const prevConnections = useRef(null);
2993
- const currentNodeId = nodeId || _nodeId;
2994
3090
  const connections = useStore((state) => state.connectionLookup.get(`${currentNodeId}-${type}-${id}`), areConnectionMapsEqual);
2995
3091
  useEffect(() => {
2996
3092
  // @todo dicuss if onConnect/onDisconnect should be called when the component mounts/unmounts
@@ -3007,18 +3103,21 @@ function useHandleConnections({ type, id = null, nodeId, onConnect, onDisconnect
3007
3103
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
3008
3104
  function useNodesData(nodeIds) {
3009
3105
  const nodesData = useStore(useCallback((s) => {
3010
- if (!Array.isArray(nodeIds)) {
3011
- return s.nodeLookup.get(nodeIds)?.data || null;
3012
- }
3013
3106
  const data = [];
3014
- for (const nodeId of nodeIds) {
3015
- const nodeData = s.nodeLookup.get(nodeId)?.data;
3016
- if (nodeData) {
3017
- data.push(nodeData);
3107
+ const isArrayOfIds = Array.isArray(nodeIds);
3108
+ const _nodeIds = isArrayOfIds ? nodeIds : [nodeIds];
3109
+ for (const nodeId of _nodeIds) {
3110
+ const node = s.nodeLookup.get(nodeId);
3111
+ if (node) {
3112
+ data.push({
3113
+ id: node.id,
3114
+ type: node.type,
3115
+ data: node.data,
3116
+ });
3018
3117
  }
3019
3118
  }
3020
- return data;
3021
- }, [nodeIds]), shallow);
3119
+ return isArrayOfIds ? data : data[0] ?? null;
3120
+ }, [nodeIds]), shallowNodeData);
3022
3121
  return nodesData;
3023
3122
  }
3024
3123
 
@@ -3032,19 +3131,24 @@ const selector$5 = (s) => ({
3032
3131
  * Hook for accessing the ongoing connection.
3033
3132
  *
3034
3133
  * @public
3035
- * @returns ongoing connection: startHandle, endHandle, status, position
3134
+ * @returns ongoing connection
3036
3135
  */
3037
3136
  function useConnection() {
3038
3137
  const ongoingConnection = useStore(selector$5, shallow);
3039
3138
  return ongoingConnection;
3040
3139
  }
3041
3140
 
3042
- var BackgroundVariant;
3043
- (function (BackgroundVariant) {
3044
- BackgroundVariant["Lines"] = "lines";
3045
- BackgroundVariant["Dots"] = "dots";
3046
- BackgroundVariant["Cross"] = "cross";
3047
- })(BackgroundVariant || (BackgroundVariant = {}));
3141
+ /**
3142
+ * Hook for getting an internal node by id
3143
+ *
3144
+ * @public
3145
+ * @param id - id of the node
3146
+ * @returns array with visible node ids
3147
+ */
3148
+ function useInternalNode(id) {
3149
+ const node = useStore(useCallback((s) => s.nodeLookup.get(id), [id]), shallow);
3150
+ return node;
3151
+ }
3048
3152
 
3049
3153
  function LinePattern({ dimensions, lineWidth, variant, className }) {
3050
3154
  return (jsx("path", { strokeWidth: lineWidth, d: `M${dimensions[0] / 2} 0 V${dimensions[1]} M0 ${dimensions[1] / 2} H${dimensions[0]}`, className: cc(['react-flow__background-pattern', variant, className]) }));
@@ -3053,13 +3157,20 @@ function DotPattern({ radius, className }) {
3053
3157
  return (jsx("circle", { cx: radius, cy: radius, r: radius, className: cc(['react-flow__background-pattern', 'dots', className]) }));
3054
3158
  }
3055
3159
 
3160
+ var BackgroundVariant;
3161
+ (function (BackgroundVariant) {
3162
+ BackgroundVariant["Lines"] = "lines";
3163
+ BackgroundVariant["Dots"] = "dots";
3164
+ BackgroundVariant["Cross"] = "cross";
3165
+ })(BackgroundVariant || (BackgroundVariant = {}));
3166
+
3056
3167
  const defaultSize = {
3057
3168
  [BackgroundVariant.Dots]: 1,
3058
3169
  [BackgroundVariant.Lines]: 1,
3059
3170
  [BackgroundVariant.Cross]: 6,
3060
3171
  };
3061
3172
  const selector$4 = (s) => ({ transform: s.transform, patternId: `pattern-${s.rfId}` });
3062
- function Background({ id, variant = BackgroundVariant.Dots,
3173
+ function BackgroundComponent({ id, variant = BackgroundVariant.Dots,
3063
3174
  // only used for dots and cross
3064
3175
  gap = 20,
3065
3176
  // only used for lines and cross
@@ -3084,8 +3195,8 @@ size, lineWidth = 1, offset = 2, color, bgColor, style, className, patternClassN
3084
3195
  '--xy-background-pattern-color-props': color,
3085
3196
  }, ref: ref, "data-testid": "rf__background", children: [jsx("pattern", { id: _patternId, x: transform[0] % scaledGap[0], y: transform[1] % scaledGap[1], width: scaledGap[0], height: scaledGap[1], patternUnits: "userSpaceOnUse", patternTransform: `translate(-${patternOffset[0]},-${patternOffset[1]})`, children: isDots ? (jsx(DotPattern, { radius: scaledSize / offset, className: patternClassName })) : (jsx(LinePattern, { dimensions: patternDimensions, lineWidth: lineWidth, variant: variant, className: patternClassName })) }), jsx("rect", { x: "0", y: "0", width: "100%", height: "100%", fill: `url(#${_patternId})` })] }));
3086
3197
  }
3087
- Background.displayName = 'Background';
3088
- var Background$1 = memo(Background);
3198
+ BackgroundComponent.displayName = 'Background';
3199
+ const Background = memo(BackgroundComponent);
3089
3200
 
3090
3201
  function PlusIcon() {
3091
3202
  return (jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 32 32", children: jsx("path", { d: "M32 18.133H18.133V32h-4.266V18.133H0v-4.266h13.867V0h4.266v13.867H32z" }) }));
@@ -3107,15 +3218,16 @@ function UnlockIcon() {
3107
3218
  return (jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 25 32", children: jsx("path", { d: "M21.333 10.667H19.81V7.619C19.81 3.429 16.38 0 12.19 0c-4.114 1.828-1.37 2.133.305 2.438 1.676.305 4.42 2.59 4.42 5.181v3.048H3.047A3.056 3.056 0 000 13.714v15.238A3.056 3.056 0 003.048 32h18.285a3.056 3.056 0 003.048-3.048V13.714a3.056 3.056 0 00-3.048-3.047zM12.19 24.533a3.056 3.056 0 01-3.047-3.047 3.056 3.056 0 013.047-3.048 3.056 3.056 0 013.048 3.048 3.056 3.056 0 01-3.048 3.047z" }) }));
3108
3219
  }
3109
3220
 
3110
- const ControlButton = ({ children, className, ...rest }) => (jsx("button", { type: "button", className: cc(['react-flow__controls-button', className]), ...rest, children: children }));
3111
- ControlButton.displayName = 'ControlButton';
3221
+ function ControlButton({ children, className, ...rest }) {
3222
+ return (jsx("button", { type: "button", className: cc(['react-flow__controls-button', className]), ...rest, children: children }));
3223
+ }
3112
3224
 
3113
3225
  const selector$3 = (s) => ({
3114
3226
  isInteractive: s.nodesDraggable || s.nodesConnectable || s.elementsSelectable,
3115
3227
  minZoomReached: s.transform[2] <= s.minZoom,
3116
3228
  maxZoomReached: s.transform[2] >= s.maxZoom,
3117
3229
  });
3118
- const Controls = ({ style, showZoom = true, showFitView = true, showInteractive = true, fitViewOptions, onZoomIn, onZoomOut, onFitView, onInteractiveChange, className, children, position = 'bottom-left', }) => {
3230
+ 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', }) {
3119
3231
  const store = useStoreApi();
3120
3232
  const { isInteractive, minZoomReached, maxZoomReached } = useStore(selector$3, shallow);
3121
3233
  const { zoomIn, zoomOut, fitView } = useReactFlow();
@@ -3139,12 +3251,13 @@ const Controls = ({ style, showZoom = true, showFitView = true, showInteractive
3139
3251
  });
3140
3252
  onInteractiveChange?.(!isInteractive);
3141
3253
  };
3142
- return (jsxs(Panel, { className: cc(['react-flow__controls', className]), position: position, style: style, "data-testid": "rf__controls", 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] }));
3143
- };
3144
- Controls.displayName = 'Controls';
3145
- var Controls$1 = memo(Controls);
3254
+ const orientationClass = orientation === 'horizontal' ? 'horizontal' : 'vertical';
3255
+ 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] }));
3256
+ }
3257
+ ControlsComponent.displayName = 'Controls';
3258
+ const Controls = memo(ControlsComponent);
3146
3259
 
3147
- function MiniMapNode({ id, x, y, width, height, style, color, strokeColor, strokeWidth, className, borderRadius, shapeRendering, selected, onClick, }) {
3260
+ function MiniMapNodeComponent({ id, x, y, width, height, style, color, strokeColor, strokeWidth, className, borderRadius, shapeRendering, selected, onClick, }) {
3148
3261
  const { background, backgroundColor } = style || {};
3149
3262
  const fill = (color || background || backgroundColor);
3150
3263
  return (jsx("rect", { className: cc(['react-flow__minimap-node', { selected }, className]), x: x, y: y, rx: borderRadius, ry: borderRadius, width: width, height: height, style: {
@@ -3153,15 +3266,15 @@ function MiniMapNode({ id, x, y, width, height, style, color, strokeColor, strok
3153
3266
  strokeWidth,
3154
3267
  }, shapeRendering: shapeRendering, onClick: onClick ? (event) => onClick(event, id) : undefined }));
3155
3268
  }
3156
- var MiniMapNode$1 = memo(MiniMapNode);
3269
+ const MiniMapNode = memo(MiniMapNodeComponent);
3157
3270
 
3158
3271
  const selector$2 = (s) => s.nodeOrigin;
3159
3272
  const selectorNodeIds = (s) => s.nodes.map((node) => node.id);
3160
- const getAttrFunction = (func) => (func instanceof Function ? func : () => func);
3273
+ const getAttrFunction = (func) => func instanceof Function ? func : () => func;
3161
3274
  function MiniMapNodes({ nodeStrokeColor, nodeColor, nodeClassName = '', nodeBorderRadius = 5, nodeStrokeWidth,
3162
3275
  // We need to rename the prop to be `CapitalCase` so that JSX will render it as
3163
3276
  // a component properly.
3164
- nodeComponent: NodeComponent = MiniMapNode$1, onClick, }) {
3277
+ nodeComponent: NodeComponent = MiniMapNode, onClick, }) {
3165
3278
  const nodeIds = useStore(selectorNodeIds, shallow);
3166
3279
  const nodeOrigin = useStore(selector$2);
3167
3280
  const nodeColorFunc = getAttrFunction(nodeColor);
@@ -3176,21 +3289,23 @@ nodeComponent: NodeComponent = MiniMapNode$1, onClick, }) {
3176
3289
  // For more details, see a similar commit in `NodeRenderer/index.tsx`.
3177
3290
  jsx(NodeComponentWrapper, { id: nodeId, nodeOrigin: nodeOrigin, nodeColorFunc: nodeColorFunc, nodeStrokeColorFunc: nodeStrokeColorFunc, nodeClassNameFunc: nodeClassNameFunc, nodeBorderRadius: nodeBorderRadius, nodeStrokeWidth: nodeStrokeWidth, NodeComponent: NodeComponent, onClick: onClick, shapeRendering: shapeRendering }, nodeId))) }));
3178
3291
  }
3179
- const NodeComponentWrapper = memo(function NodeComponentWrapper({ id, nodeOrigin, nodeColorFunc, nodeStrokeColorFunc, nodeClassNameFunc, nodeBorderRadius, nodeStrokeWidth, shapeRendering, NodeComponent, onClick, }) {
3292
+ function NodeComponentWrapperInner({ id, nodeOrigin, nodeColorFunc, nodeStrokeColorFunc, nodeClassNameFunc, nodeBorderRadius, nodeStrokeWidth, shapeRendering, NodeComponent, onClick, }) {
3180
3293
  const { node, x, y } = useStore((s) => {
3181
3294
  const node = s.nodeLookup.get(id);
3182
- const { x, y } = getNodePositionWithOrigin(node, node?.origin || nodeOrigin).positionAbsolute;
3295
+ const { x, y } = getNodePositionWithOrigin(node, nodeOrigin).positionAbsolute;
3183
3296
  return {
3184
3297
  node,
3185
3298
  x,
3186
3299
  y,
3187
3300
  };
3188
3301
  }, shallow);
3189
- if (!node || node.hidden || !(node.computed?.width || node.width) || !(node.computed?.height || node.height)) {
3302
+ if (!node || node.hidden || !nodeHasDimensions(node)) {
3190
3303
  return null;
3191
3304
  }
3192
- 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 }));
3193
- });
3305
+ const { width, height } = getNodeDimensions(node);
3306
+ 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 }));
3307
+ }
3308
+ const NodeComponentWrapper = memo(NodeComponentWrapperInner);
3194
3309
  var MiniMapNodes$1 = memo(MiniMapNodes);
3195
3310
 
3196
3311
  const defaultWidth = 200;
@@ -3204,7 +3319,9 @@ const selector$1 = (s) => {
3204
3319
  };
3205
3320
  return {
3206
3321
  viewBB,
3207
- boundingRect: s.nodes.length > 0 ? getBoundsOfRects(getNodesBounds(s.nodes, s.nodeOrigin), viewBB) : viewBB,
3322
+ boundingRect: s.nodeLookup.size > 0
3323
+ ? getBoundsOfRects(getInternalNodesBounds(s.nodeLookup, { nodeOrigin: s.nodeOrigin }), viewBB)
3324
+ : viewBB,
3208
3325
  rfId: s.rfId,
3209
3326
  nodeOrigin: s.nodeOrigin,
3210
3327
  panZoom: s.panZoom,
@@ -3214,10 +3331,10 @@ const selector$1 = (s) => {
3214
3331
  };
3215
3332
  };
3216
3333
  const ARIA_LABEL_KEY = 'react-flow__minimap-desc';
3217
- function MiniMap({ style, className, nodeStrokeColor, nodeColor, nodeClassName = '', nodeBorderRadius = 5, nodeStrokeWidth,
3334
+ function MiniMapComponent({ style, className, nodeStrokeColor, nodeColor, nodeClassName = '', nodeBorderRadius = 5, nodeStrokeWidth,
3218
3335
  // We need to rename the prop to be `CapitalCase` so that JSX will render it as
3219
3336
  // a component properly.
3220
- nodeComponent, maskColor, maskStrokeColor = 'none', maskStrokeWidth = 1, position = 'bottom-right', onClick, onNodeClick, pannable = false, zoomable = false, ariaLabel = 'React Flow mini map', inversePan, zoomStep = 10, offsetScale = 5, }) {
3337
+ nodeComponent, bgColor, maskColor, maskStrokeColor, maskStrokeWidth, position = 'bottom-right', onClick, onNodeClick, pannable = false, zoomable = false, ariaLabel = 'React Flow mini map', inversePan, zoomStep = 10, offsetScale = 5, }) {
3221
3338
  const store = useStoreApi();
3222
3339
  const svg = useRef(null);
3223
3340
  const { boundingRect, viewBB, rfId, panZoom, translateExtent, flowWidth, flowHeight } = useStore(selector$1, shallow);
@@ -3275,189 +3392,127 @@ nodeComponent, maskColor, maskStrokeColor = 'none', maskStrokeWidth = 1, positio
3275
3392
  : undefined;
3276
3393
  return (jsx(Panel, { position: position, style: {
3277
3394
  ...style,
3278
- '--xy-minimap-mask-color-props': typeof maskColor === 'string' ? maskColor : undefined,
3395
+ '--xy-minimap-background-color-props': typeof bgColor === 'string' ? bgColor : undefined,
3396
+ '--xy-minimap-mask-background-color-props': typeof maskColor === 'string' ? maskColor : undefined,
3397
+ '--xy-minimap-mask-stroke-color-props': typeof maskStrokeColor === 'string' ? maskStrokeColor : undefined,
3398
+ '--xy-minimap-mask-stroke-width-props': typeof maskStrokeWidth === 'number' ? maskStrokeWidth * viewScale : undefined,
3279
3399
  '--xy-minimap-node-background-color-props': typeof nodeColor === 'string' ? nodeColor : undefined,
3280
3400
  '--xy-minimap-node-stroke-color-props': typeof nodeStrokeColor === 'string' ? nodeStrokeColor : undefined,
3281
3401
  '--xy-minimap-node-stroke-width-props': typeof nodeStrokeWidth === 'string' ? nodeStrokeWidth : undefined,
3282
- }, className: cc(['react-flow__minimap', className]), "data-testid": "rf__minimap", children: jsxs("svg", { width: elementWidth, height: elementHeight, viewBox: `${x} ${y} ${width} ${height}`, role: "img", "aria-labelledby": labelledBy, ref: svg, onClick: onSvgClick, children: [ariaLabel && jsx("title", { id: labelledBy, children: ariaLabel }), jsx(MiniMapNodes$1, { onClick: onSvgNodeClick, nodeColor: nodeColor, nodeStrokeColor: nodeStrokeColor, nodeBorderRadius: nodeBorderRadius, nodeClassName: nodeClassName, nodeStrokeWidth: nodeStrokeWidth, nodeComponent: nodeComponent }), jsx("path", { className: "react-flow__minimap-mask", d: `M${x - offset},${y - offset}h${width + offset * 2}v${height + offset * 2}h${-width - offset * 2}z
3283
- M${viewBB.x},${viewBB.y}h${viewBB.width}v${viewBB.height}h${-viewBB.width}z`, fillRule: "evenodd", stroke: maskStrokeColor, strokeWidth: maskStrokeWidth, pointerEvents: "none" })] }) }));
3284
- }
3285
- MiniMap.displayName = 'MiniMap';
3286
- var MiniMap$1 = memo(MiniMap);
3287
-
3288
- var ResizeControlVariant;
3289
- (function (ResizeControlVariant) {
3290
- ResizeControlVariant["Line"] = "line";
3291
- ResizeControlVariant["Handle"] = "handle";
3292
- })(ResizeControlVariant || (ResizeControlVariant = {}));
3293
-
3294
- // returns an array of two numbers (0, 1 or -1) representing the direction of the resize
3295
- // 0 = no change, 1 = increase, -1 = decrease
3296
- function getDirection({ width, prevWidth, height, prevHeight, invertX, invertY }) {
3297
- const deltaWidth = width - prevWidth;
3298
- const deltaHeight = height - prevHeight;
3299
- const direction = [deltaWidth > 0 ? 1 : deltaWidth < 0 ? -1 : 0, deltaHeight > 0 ? 1 : deltaHeight < 0 ? -1 : 0];
3300
- if (deltaWidth && invertX) {
3301
- direction[0] = direction[0] * -1;
3302
- }
3303
- if (deltaHeight && invertY) {
3304
- direction[1] = direction[1] * -1;
3305
- }
3306
- return direction;
3402
+ }, className: cc(['react-flow__minimap', className]), "data-testid": "rf__minimap", children: jsxs("svg", { width: elementWidth, height: elementHeight, viewBox: `${x} ${y} ${width} ${height}`, className: "react-flow__minimap-svg", role: "img", "aria-labelledby": labelledBy, ref: svg, onClick: onSvgClick, children: [ariaLabel && jsx("title", { id: labelledBy, children: ariaLabel }), jsx(MiniMapNodes$1, { onClick: onSvgNodeClick, nodeColor: nodeColor, nodeStrokeColor: nodeStrokeColor, nodeBorderRadius: nodeBorderRadius, nodeClassName: nodeClassName, nodeStrokeWidth: nodeStrokeWidth, nodeComponent: nodeComponent }), jsx("path", { className: "react-flow__minimap-mask", d: `M${x - offset},${y - offset}h${width + offset * 2}v${height + offset * 2}h${-width - offset * 2}z
3403
+ M${viewBB.x},${viewBB.y}h${viewBB.width}v${viewBB.height}h${-viewBB.width}z`, fillRule: "evenodd", pointerEvents: "none" })] }) }));
3307
3404
  }
3405
+ MiniMapComponent.displayName = 'MiniMap';
3406
+ const MiniMap = memo(MiniMapComponent);
3308
3407
 
3309
- const initPrevValues = { width: 0, height: 0, x: 0, y: 0 };
3310
- const initStartValues = {
3311
- ...initPrevValues,
3312
- pointerX: 0,
3313
- pointerY: 0,
3314
- aspectRatio: 1,
3315
- };
3316
3408
  function ResizeControl({ nodeId, position, variant = ResizeControlVariant.Handle, className, style = {}, children, color, minWidth = 10, minHeight = 10, maxWidth = Number.MAX_VALUE, maxHeight = Number.MAX_VALUE, keepAspectRatio = false, shouldResize, onResizeStart, onResize, onResizeEnd, }) {
3317
3409
  const contextNodeId = useNodeId();
3318
3410
  const id = typeof nodeId === 'string' ? nodeId : contextNodeId;
3319
3411
  const store = useStoreApi();
3320
3412
  const resizeControlRef = useRef(null);
3321
- const startValues = useRef(initStartValues);
3322
- const prevValues = useRef(initPrevValues);
3323
3413
  const defaultPosition = variant === ResizeControlVariant.Line ? 'right' : 'bottom-right';
3324
3414
  const controlPosition = position ?? defaultPosition;
3415
+ const resizer = useRef(null);
3325
3416
  useEffect(() => {
3326
3417
  if (!resizeControlRef.current || !id) {
3327
3418
  return;
3328
3419
  }
3329
- const selection = select(resizeControlRef.current);
3330
- const enableX = controlPosition.includes('right') || controlPosition.includes('left');
3331
- const enableY = controlPosition.includes('bottom') || controlPosition.includes('top');
3332
- const invertX = controlPosition.includes('left');
3333
- const invertY = controlPosition.includes('top');
3334
- const dragHandler = drag()
3335
- .on('start', (event) => {
3336
- const { nodeLookup, transform, snapGrid, snapToGrid } = store.getState();
3337
- const node = nodeLookup.get(id);
3338
- const { xSnapped, ySnapped } = getPointerPosition(event.sourceEvent, { transform, snapGrid, snapToGrid });
3339
- prevValues.current = {
3340
- width: node?.computed?.width ?? 0,
3341
- height: node?.computed?.height ?? 0,
3342
- x: node?.position.x ?? 0,
3343
- y: node?.position.y ?? 0,
3344
- };
3345
- startValues.current = {
3346
- ...prevValues.current,
3347
- pointerX: xSnapped,
3348
- pointerY: ySnapped,
3349
- aspectRatio: prevValues.current.width / prevValues.current.height,
3350
- };
3351
- onResizeStart?.(event, { ...prevValues.current });
3352
- })
3353
- .on('drag', (event) => {
3354
- const { nodeLookup, transform, snapGrid, snapToGrid, triggerNodeChanges } = store.getState();
3355
- const { xSnapped, ySnapped } = getPointerPosition(event.sourceEvent, { transform, snapGrid, snapToGrid });
3356
- const node = nodeLookup.get(id);
3357
- if (node) {
3358
- const changes = [];
3359
- const { pointerX: startX, pointerY: startY, width: startWidth, height: startHeight, x: startNodeX, y: startNodeY, aspectRatio, } = startValues.current;
3360
- const { x: prevX, y: prevY, width: prevWidth, height: prevHeight } = prevValues.current;
3361
- const distX = Math.floor(enableX ? xSnapped - startX : 0);
3362
- const distY = Math.floor(enableY ? ySnapped - startY : 0);
3363
- let width = clamp(startWidth + (invertX ? -distX : distX), minWidth, maxWidth);
3364
- let height = clamp(startHeight + (invertY ? -distY : distY), minHeight, maxHeight);
3365
- if (keepAspectRatio) {
3366
- const nextAspectRatio = width / height;
3367
- const isDiagonal = enableX && enableY;
3368
- const isHorizontal = enableX && !enableY;
3369
- const isVertical = enableY && !enableX;
3370
- width = (nextAspectRatio <= aspectRatio && isDiagonal) || isVertical ? height * aspectRatio : width;
3371
- height = (nextAspectRatio > aspectRatio && isDiagonal) || isHorizontal ? width / aspectRatio : height;
3372
- if (width >= maxWidth) {
3373
- width = maxWidth;
3374
- height = maxWidth / aspectRatio;
3375
- }
3376
- else if (width <= minWidth) {
3377
- width = minWidth;
3378
- height = minWidth / aspectRatio;
3420
+ if (!resizer.current) {
3421
+ resizer.current = XYResizer({
3422
+ domNode: resizeControlRef.current,
3423
+ nodeId: id,
3424
+ getStoreItems: () => {
3425
+ const { nodeLookup, transform, snapGrid, snapToGrid, nodeOrigin } = store.getState();
3426
+ return {
3427
+ nodeLookup,
3428
+ transform,
3429
+ snapGrid,
3430
+ snapToGrid,
3431
+ nodeOrigin,
3432
+ };
3433
+ },
3434
+ onChange: (change, childChanges) => {
3435
+ const { triggerNodeChanges, nodeLookup, parentLookup, nodeOrigin } = store.getState();
3436
+ const changes = [];
3437
+ const nextPosition = { x: change.x, y: change.y };
3438
+ const node = nodeLookup.get(id);
3439
+ if (node && node.expandParent && node.parentId) {
3440
+ const child = {
3441
+ id: node.id,
3442
+ parentId: node.parentId,
3443
+ rect: {
3444
+ width: change.width ?? node.measured.width,
3445
+ height: change.height ?? node.measured.height,
3446
+ ...evaluateAbsolutePosition({
3447
+ x: change.x ?? node.position.x,
3448
+ y: change.y ?? node.position.y,
3449
+ }, node.parentId, nodeLookup, node.origin ?? nodeOrigin),
3450
+ },
3451
+ };
3452
+ const parentExpandChanges = handleExpandParent([child], nodeLookup, parentLookup, nodeOrigin);
3453
+ changes.push(...parentExpandChanges);
3454
+ // when the parent was expanded by the child node, its position will be clamped at 0,0
3455
+ nextPosition.x = change.x ? Math.max(0, change.x) : undefined;
3456
+ nextPosition.y = change.y ? Math.max(0, change.y) : undefined;
3379
3457
  }
3380
- if (height >= maxHeight) {
3381
- height = maxHeight;
3382
- width = maxHeight * aspectRatio;
3458
+ if (nextPosition.x !== undefined && nextPosition.y !== undefined) {
3459
+ const positionChange = {
3460
+ id,
3461
+ type: 'position',
3462
+ position: { ...nextPosition },
3463
+ };
3464
+ changes.push(positionChange);
3383
3465
  }
3384
- else if (height <= minHeight) {
3385
- height = minHeight;
3386
- width = minHeight * aspectRatio;
3466
+ if (change.width !== undefined && change.height !== undefined) {
3467
+ const dimensionChange = {
3468
+ id,
3469
+ type: 'dimensions',
3470
+ resizing: true,
3471
+ setAttributes: true,
3472
+ dimensions: {
3473
+ width: change.width,
3474
+ height: change.height,
3475
+ },
3476
+ };
3477
+ changes.push(dimensionChange);
3387
3478
  }
3388
- }
3389
- const isWidthChange = width !== prevWidth;
3390
- const isHeightChange = height !== prevHeight;
3391
- if (invertX || invertY) {
3392
- const x = invertX ? startNodeX - (width - startWidth) : startNodeX;
3393
- const y = invertY ? startNodeY - (height - startHeight) : startNodeY;
3394
- // only transform the node if the width or height changes
3395
- const isXPosChange = x !== prevX && isWidthChange;
3396
- const isYPosChange = y !== prevY && isHeightChange;
3397
- if (isXPosChange || isYPosChange) {
3479
+ for (const childChange of childChanges) {
3398
3480
  const positionChange = {
3399
- id: node.id,
3481
+ ...childChange,
3400
3482
  type: 'position',
3401
- position: {
3402
- x: isXPosChange ? x : prevX,
3403
- y: isYPosChange ? y : prevY,
3404
- },
3405
3483
  };
3406
3484
  changes.push(positionChange);
3407
- prevValues.current.x = positionChange.position.x;
3408
- prevValues.current.y = positionChange.position.y;
3409
3485
  }
3410
- }
3411
- if (isWidthChange || isHeightChange) {
3486
+ triggerNodeChanges(changes);
3487
+ },
3488
+ onEnd: () => {
3412
3489
  const dimensionChange = {
3413
3490
  id: id,
3414
3491
  type: 'dimensions',
3415
- updateStyle: true,
3416
- resizing: true,
3417
- dimensions: {
3418
- width: width,
3419
- height: height,
3420
- },
3492
+ resizing: false,
3421
3493
  };
3422
- changes.push(dimensionChange);
3423
- prevValues.current.width = width;
3424
- prevValues.current.height = height;
3425
- }
3426
- if (changes.length === 0) {
3427
- return;
3428
- }
3429
- const direction = getDirection({
3430
- width: prevValues.current.width,
3431
- prevWidth,
3432
- height: prevValues.current.height,
3433
- prevHeight,
3434
- invertX,
3435
- invertY,
3436
- });
3437
- const nextValues = { ...prevValues.current, direction };
3438
- const callResize = shouldResize?.(event, nextValues);
3439
- if (callResize === false) {
3440
- return;
3441
- }
3442
- onResize?.(event, nextValues);
3443
- triggerNodeChanges(changes);
3444
- }
3445
- })
3446
- .on('end', (event) => {
3447
- const dimensionChange = {
3448
- id: id,
3449
- type: 'dimensions',
3450
- resizing: false,
3451
- };
3452
- onResizeEnd?.(event, { ...prevValues.current });
3453
- store.getState().triggerNodeChanges([dimensionChange]);
3494
+ store.getState().triggerNodeChanges([dimensionChange]);
3495
+ },
3496
+ });
3497
+ }
3498
+ resizer.current.update({
3499
+ controlPosition,
3500
+ boundaries: {
3501
+ minWidth,
3502
+ minHeight,
3503
+ maxWidth,
3504
+ maxHeight,
3505
+ },
3506
+ keepAspectRatio,
3507
+ onResizeStart,
3508
+ onResize,
3509
+ onResizeEnd,
3510
+ shouldResize,
3454
3511
  });
3455
- selection.call(dragHandler);
3456
3512
  return () => {
3457
- selection.on('.drag', null);
3513
+ resizer.current?.destroy();
3458
3514
  };
3459
3515
  }, [
3460
- id,
3461
3516
  controlPosition,
3462
3517
  minWidth,
3463
3518
  minHeight,
@@ -3467,21 +3522,20 @@ function ResizeControl({ nodeId, position, variant = ResizeControlVariant.Handle
3467
3522
  onResizeStart,
3468
3523
  onResize,
3469
3524
  onResizeEnd,
3525
+ shouldResize,
3470
3526
  ]);
3471
3527
  const positionClassNames = controlPosition.split('-');
3472
3528
  const colorStyleProp = variant === ResizeControlVariant.Line ? 'borderColor' : 'backgroundColor';
3473
3529
  const controlStyle = color ? { ...style, [colorStyleProp]: color } : style;
3474
3530
  return (jsx("div", { className: cc(['react-flow__resize-control', 'nodrag', ...positionClassNames, variant, className]), ref: resizeControlRef, style: controlStyle, children: children }));
3475
3531
  }
3476
- var ResizeControl$1 = memo(ResizeControl);
3532
+ const NodeResizeControl = memo(ResizeControl);
3477
3533
 
3478
- const handleControls = ['top-left', 'top-right', 'bottom-left', 'bottom-right'];
3479
- const lineControls = ['top', 'right', 'bottom', 'left'];
3480
3534
  function NodeResizer({ nodeId, isVisible = true, handleClassName, handleStyle, lineClassName, lineStyle, color, minWidth = 10, minHeight = 10, maxWidth = Number.MAX_VALUE, maxHeight = Number.MAX_VALUE, keepAspectRatio = false, shouldResize, onResizeStart, onResize, onResizeEnd, }) {
3481
3535
  if (!isVisible) {
3482
3536
  return null;
3483
3537
  }
3484
- return (jsxs(Fragment, { children: [lineControls.map((c) => (jsx(ResizeControl$1, { className: lineClassName, style: lineStyle, nodeId: nodeId, position: c, variant: ResizeControlVariant.Line, color: color, minWidth: minWidth, minHeight: minHeight, maxWidth: maxWidth, maxHeight: maxHeight, onResizeStart: onResizeStart, keepAspectRatio: keepAspectRatio, shouldResize: shouldResize, onResize: onResize, onResizeEnd: onResizeEnd }, c))), handleControls.map((c) => (jsx(ResizeControl$1, { className: handleClassName, style: handleStyle, nodeId: nodeId, position: c, color: color, minWidth: minWidth, minHeight: minHeight, maxWidth: maxWidth, maxHeight: maxHeight, onResizeStart: onResizeStart, keepAspectRatio: keepAspectRatio, shouldResize: shouldResize, onResize: onResize, onResizeEnd: onResizeEnd }, c)))] }));
3538
+ return (jsxs(Fragment, { children: [XY_RESIZER_LINE_POSITIONS.map((position) => (jsx(NodeResizeControl, { className: lineClassName, style: lineStyle, nodeId: nodeId, position: position, variant: ResizeControlVariant.Line, color: color, minWidth: minWidth, minHeight: minHeight, maxWidth: maxWidth, maxHeight: maxHeight, onResizeStart: onResizeStart, keepAspectRatio: keepAspectRatio, shouldResize: shouldResize, onResize: onResize, onResizeEnd: onResizeEnd }, position))), XY_RESIZER_HANDLE_POSITIONS.map((position) => (jsx(NodeResizeControl, { className: handleClassName, style: handleStyle, nodeId: nodeId, position: position, color: color, minWidth: minWidth, minHeight: minHeight, maxWidth: maxWidth, maxHeight: maxHeight, onResizeStart: onResizeStart, keepAspectRatio: keepAspectRatio, shouldResize: shouldResize, onResize: onResize, onResizeEnd: onResizeEnd }, position)))] }));
3485
3539
  }
3486
3540
 
3487
3541
  const selector = (state) => state.domNode?.querySelector('.react-flow__renderer');
@@ -3493,12 +3547,12 @@ function NodeToolbarPortal({ children }) {
3493
3547
  return createPortal(children, wrapperRef);
3494
3548
  }
3495
3549
 
3496
- const nodeEqualityFn = (a, b) => a?.computed?.positionAbsolute?.x !== b?.computed?.positionAbsolute?.x ||
3497
- a?.computed?.positionAbsolute?.y !== b?.computed?.positionAbsolute?.y ||
3498
- a?.computed?.width !== b?.computed?.width ||
3499
- a?.computed?.height !== b?.computed?.height ||
3550
+ const nodeEqualityFn = (a, b) => a?.internals.positionAbsolute.x !== b?.internals.positionAbsolute.x ||
3551
+ a?.internals.positionAbsolute.y !== b?.internals.positionAbsolute.y ||
3552
+ a?.measured.width !== b?.measured.width ||
3553
+ a?.measured.height !== b?.measured.height ||
3500
3554
  a?.selected !== b?.selected ||
3501
- a?.[internalsSymbol]?.z !== b?.[internalsSymbol]?.z;
3555
+ a?.internals.z !== b?.internals.z;
3502
3556
  const nodesEqualityFn = (a, b) => {
3503
3557
  if (a.length !== b.length) {
3504
3558
  return false;
@@ -3533,8 +3587,8 @@ function NodeToolbar({ nodeId, children, className, style, isVisible, position =
3533
3587
  if (!isActive || !nodes.length) {
3534
3588
  return null;
3535
3589
  }
3536
- const nodeRect = getNodesBounds(nodes, nodeOrigin);
3537
- const zIndex = Math.max(...nodes.map((node) => (node[internalsSymbol]?.z || 1) + 1));
3590
+ const nodeRect = getNodesBounds(nodes, { nodeOrigin });
3591
+ const zIndex = Math.max(...nodes.map((node) => node.internals.z + 1));
3538
3592
  const wrapperStyle = {
3539
3593
  position: 'absolute',
3540
3594
  transform: getNodeToolbarTransform(nodeRect, viewport, position, offset, align),
@@ -3544,4 +3598,4 @@ function NodeToolbar({ nodeId, children, className, style, isVisible, position =
3544
3598
  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 }) }));
3545
3599
  }
3546
3600
 
3547
- export { Background$1 as Background, BackgroundVariant, BaseEdge, BezierEdge, ControlButton, Controls$1 as Controls, EdgeLabelRenderer, EdgeText$1 as EdgeText, Handle$1 as Handle, MiniMap$1 as MiniMap, ResizeControl$1 as NodeResizeControl, NodeResizer, NodeToolbar, Panel, ReactFlow, ReactFlowProvider, ResizeControlVariant, SimpleBezierEdge, SmoothStepEdge, StepEdge, StraightEdge, ViewportPortal, addEdge, applyEdgeChanges, applyNodeChanges, getConnectedEdges, getIncomers, getOutgoers, getSimpleBezierPath, handleParentExpand, isEdge, isNode, updateEdge, useConnection, useEdges, useEdgesState, useHandleConnections, useKeyPress, useNodeId, useNodes, useNodesData, useNodesInitialized, useNodesState, useOnSelectionChange, useOnViewportChange, useReactFlow, useStore, useStoreApi, useUpdateNodeInternals, useViewport };
3601
+ 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 };