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