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