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