refactor(state): separate nodes and edges
This commit is contained in:
@@ -52,15 +52,15 @@ export default ({
|
||||
setSourceNode(nextSourceNode);
|
||||
}, []);
|
||||
|
||||
if (!sourceNode || !isConnectable) {
|
||||
if (!sourceNode || !isConnectable || !sourceNode.handleBounds?.[connectionHandleType]) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const sourceHandle = handleId
|
||||
? sourceNode.handleBounds[connectionHandleType].find((d: HandleElement) => d.id === handleId)
|
||||
: sourceNode.handleBounds[connectionHandleType][0];
|
||||
? sourceNode.handleBounds[connectionHandleType]!.find((d: HandleElement) => d.id === handleId)
|
||||
: sourceNode.handleBounds[connectionHandleType]![0];
|
||||
const sourceHandleX = sourceHandle ? sourceHandle.x + sourceHandle.width / 2 : sourceNode.width! / 2;
|
||||
const sourceHandleY = sourceHandle ? sourceHandle.y + sourceHandle.height / 2 : sourceNode.height;
|
||||
const sourceHandleY = sourceHandle ? sourceHandle.y + sourceHandle.height / 2 : sourceNode.height!;
|
||||
const sourceX = sourceNode.position.x + sourceHandleX;
|
||||
const sourceY = sourceNode.position.y + sourceHandleY;
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ export default (EdgeComponent: ComponentType<EdgeProps>) => {
|
||||
data,
|
||||
onClick,
|
||||
onEdgeDoubleClick,
|
||||
selected,
|
||||
isSelected,
|
||||
animated,
|
||||
label,
|
||||
labelStyle,
|
||||
@@ -69,7 +69,7 @@ export default (EdgeComponent: ComponentType<EdgeProps>) => {
|
||||
'react-flow__edge',
|
||||
`react-flow__edge-${type}`,
|
||||
className,
|
||||
{ selected, animated, inactive, updating },
|
||||
{ selected: isSelected, animated, inactive, updating },
|
||||
]);
|
||||
|
||||
const edgeElement = useMemo<Edge>(() => {
|
||||
@@ -219,7 +219,7 @@ export default (EdgeComponent: ComponentType<EdgeProps>) => {
|
||||
id={id}
|
||||
source={source}
|
||||
target={target}
|
||||
selected={selected}
|
||||
isSelected={isSelected}
|
||||
animated={animated}
|
||||
label={label}
|
||||
labelStyle={labelStyle}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
import { useEffect } from 'react';
|
||||
import shallow from 'zustand/shallow';
|
||||
|
||||
import { useStore } from '../../store';
|
||||
import { Node, Edge, ReactFlowState } from '../../types';
|
||||
|
||||
interface ElementUpdaterProps {
|
||||
nodes: Node[];
|
||||
edges: Edge[];
|
||||
}
|
||||
|
||||
const selector = (s: ReactFlowState) => ({
|
||||
setNodes: s.setNodes,
|
||||
setEdges: s.setEdges,
|
||||
});
|
||||
|
||||
const ElementUpdater = ({ nodes, edges }: ElementUpdaterProps) => {
|
||||
const { setNodes, setEdges } = useStore(selector, shallow);
|
||||
|
||||
useEffect(() => {
|
||||
setNodes(nodes);
|
||||
}, [nodes]);
|
||||
|
||||
useEffect(() => {
|
||||
setEdges(edges);
|
||||
}, [edges]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export default ElementUpdater;
|
||||
@@ -9,9 +9,9 @@ import { NodeComponentProps, WrapNodeProps, ReactFlowState } from '../../types';
|
||||
|
||||
const selector = (s: ReactFlowState) => ({
|
||||
addSelectedElements: s.addSelectedElements,
|
||||
onNodesChange: s.onNodesChange,
|
||||
unsetNodesSelection: s.unsetNodesSelection,
|
||||
updateNodePosDiff: s.updateNodePosDiff,
|
||||
updateNodePosition: s.updateNodePosition,
|
||||
updateNodeDimensions: s.updateNodeDimensions,
|
||||
});
|
||||
|
||||
export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||
@@ -22,7 +22,7 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||
scale,
|
||||
xPos,
|
||||
yPos,
|
||||
selected,
|
||||
isSelected,
|
||||
onClick,
|
||||
onMouseEnter,
|
||||
onMouseMove,
|
||||
@@ -48,8 +48,10 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||
resizeObserver,
|
||||
dragHandle,
|
||||
}: WrapNodeProps) => {
|
||||
// const updateNodeDimensions = useStoreActions((actions) => actions.updateNodeDimensions);
|
||||
const { addSelectedElements, onNodesChange, unsetNodesSelection, updateNodePosDiff } = useStore(selector, shallow);
|
||||
const { addSelectedElements, unsetNodesSelection, updateNodePosition, updateNodeDimensions } = useStore(
|
||||
selector,
|
||||
shallow
|
||||
);
|
||||
const nodeElement = useRef<HTMLDivElement>(null);
|
||||
|
||||
const node = useMemo(() => ({ id, type, position: { x: xPos, y: yPos }, data }), [id, type, xPos, yPos, data]);
|
||||
@@ -57,7 +59,7 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||
|
||||
const nodeStyle: CSSProperties = useMemo(
|
||||
() => ({
|
||||
zIndex: selected ? 10 : 3,
|
||||
zIndex: isSelected ? 10 : 3,
|
||||
transform: `translate(${xPos}px,${yPos}px)`,
|
||||
pointerEvents:
|
||||
isSelectable || isDraggable || onClick || onMouseEnter || onMouseMove || onMouseLeave ? 'all' : 'none',
|
||||
@@ -66,7 +68,7 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||
...style,
|
||||
}),
|
||||
[
|
||||
selected,
|
||||
isSelected,
|
||||
xPos,
|
||||
yPos,
|
||||
isSelectable,
|
||||
@@ -118,7 +120,7 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||
if (isSelectable) {
|
||||
unsetNodesSelection();
|
||||
|
||||
if (!selected) {
|
||||
if (!isSelected) {
|
||||
addSelectedElements([node]);
|
||||
}
|
||||
}
|
||||
@@ -126,7 +128,7 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||
onClick?.(event, node);
|
||||
}
|
||||
},
|
||||
[isSelectable, selected, isDraggable, onClick, node]
|
||||
[isSelectable, isSelected, isDraggable, onClick, node]
|
||||
);
|
||||
|
||||
const onDragStart = useCallback(
|
||||
@@ -136,15 +138,15 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||
if (selectNodesOnDrag && isSelectable) {
|
||||
unsetNodesSelection();
|
||||
|
||||
if (!selected) {
|
||||
if (!isSelected) {
|
||||
addSelectedElements([node]);
|
||||
}
|
||||
} else if (!selectNodesOnDrag && !selected && isSelectable) {
|
||||
} else if (!selectNodesOnDrag && !isSelected && isSelectable) {
|
||||
unsetNodesSelection();
|
||||
addSelectedElements([]);
|
||||
}
|
||||
},
|
||||
[node, selected, selectNodesOnDrag, isSelectable, onNodeDragStart]
|
||||
[node, isSelected, selectNodesOnDrag, isSelectable, onNodeDragStart]
|
||||
);
|
||||
|
||||
const onDrag = useCallback(
|
||||
@@ -156,7 +158,7 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||
onNodeDrag(event as MouseEvent, node);
|
||||
}
|
||||
|
||||
updateNodePosDiff({ id, isDragging: true, diff: { x: draggableData.deltaX, y: draggableData.deltaY } });
|
||||
updateNodePosition({ id, isDragging: true, diff: { x: draggableData.deltaX, y: draggableData.deltaY } });
|
||||
},
|
||||
[id, node, onNodeDrag]
|
||||
);
|
||||
@@ -166,7 +168,7 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||
// onDragStop also gets called when user just clicks on a node.
|
||||
// Because of that we set dragging to true inside the onDrag handler and handle the click here
|
||||
if (!isDragging) {
|
||||
if (isSelectable && !selectNodesOnDrag && !selected) {
|
||||
if (isSelectable && !selectNodesOnDrag && !isSelected) {
|
||||
addSelectedElements([node]);
|
||||
}
|
||||
|
||||
@@ -175,18 +177,14 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||
return;
|
||||
}
|
||||
|
||||
onNodesChange?.([
|
||||
{
|
||||
id: node.id,
|
||||
change: {
|
||||
isDragging: true,
|
||||
},
|
||||
},
|
||||
]);
|
||||
updateNodePosition({
|
||||
id: node.id,
|
||||
isDragging: false,
|
||||
});
|
||||
|
||||
onNodeDragStop?.(event as MouseEvent, node);
|
||||
},
|
||||
[node, isSelectable, selectNodesOnDrag, onClick, onNodeDragStop, isDragging, selected]
|
||||
[node, isSelectable, selectNodesOnDrag, onClick, onNodeDragStop, isDragging, isSelected]
|
||||
);
|
||||
|
||||
const onNodeDoubleClickHandler = useCallback(
|
||||
@@ -196,11 +194,11 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||
[node, onNodeDoubleClick]
|
||||
);
|
||||
|
||||
// useEffect(() => {
|
||||
// if (nodeElement.current && !isHidden) {
|
||||
// updateNodeDimensions([{ id, nodeElement: nodeElement.current, forceUpdate: true }]);
|
||||
// }
|
||||
// }, [id, isHidden, sourcePosition, targetPosition]);
|
||||
useEffect(() => {
|
||||
if (nodeElement.current && !isHidden && !isInitialized) {
|
||||
updateNodeDimensions([{ id, nodeElement: nodeElement.current, forceUpdate: true }]);
|
||||
}
|
||||
}, [id, isHidden, sourcePosition, targetPosition, isInitialized]);
|
||||
|
||||
useEffect(() => {
|
||||
if (nodeElement.current) {
|
||||
@@ -220,7 +218,7 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||
`react-flow__node-${type}`,
|
||||
className,
|
||||
{
|
||||
selected,
|
||||
selected: isSelected,
|
||||
selectable: isSelectable,
|
||||
},
|
||||
]);
|
||||
@@ -257,7 +255,7 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||
type={type}
|
||||
xPos={xPos}
|
||||
yPos={yPos}
|
||||
selected={selected}
|
||||
isSelected={isSelected}
|
||||
isConnectable={isConnectable}
|
||||
sourcePosition={sourcePosition}
|
||||
targetPosition={targetPosition}
|
||||
|
||||
@@ -20,10 +20,10 @@ const selector = (s: ReactFlowState) => ({
|
||||
transform: s.transform,
|
||||
selectedNodesBbox: s.selectedNodesBbox,
|
||||
selectionActive: s.selectionActive,
|
||||
selectedNodes: s.nodes.filter((n) => n.selected),
|
||||
selectedNodes: s.nodes.filter((n) => n.isSelected),
|
||||
snapToGrid: s.snapToGrid,
|
||||
snapGrid: s.snapGrid,
|
||||
updateNodePosDiff: s.updateNodePosDiff,
|
||||
updateNodePosition: s.updateNodePosition,
|
||||
});
|
||||
|
||||
export default ({
|
||||
@@ -32,7 +32,7 @@ export default ({
|
||||
onSelectionDragStop,
|
||||
onSelectionContextMenu,
|
||||
}: NodesSelectionProps) => {
|
||||
const { transform, selectedNodesBbox, selectionActive, selectedNodes, snapToGrid, snapGrid, updateNodePosDiff } =
|
||||
const { transform, selectedNodesBbox, selectionActive, selectedNodes, snapToGrid, snapGrid, updateNodePosition } =
|
||||
useStore(selector);
|
||||
const [tX, tY, tScale] = transform;
|
||||
const nodeRef = useRef(null);
|
||||
@@ -69,7 +69,7 @@ export default ({
|
||||
onSelectionDrag(event, selectedNodes);
|
||||
}
|
||||
|
||||
updateNodePosDiff({
|
||||
updateNodePosition({
|
||||
diff: {
|
||||
x: data.deltaX,
|
||||
y: data.deltaY,
|
||||
@@ -77,12 +77,12 @@ export default ({
|
||||
isDragging: true,
|
||||
});
|
||||
},
|
||||
[onSelectionDrag, selectedNodes, updateNodePosDiff]
|
||||
[onSelectionDrag, selectedNodes, updateNodePosition]
|
||||
);
|
||||
|
||||
const onStop = useCallback(
|
||||
(event: MouseEvent) => {
|
||||
updateNodePosDiff({
|
||||
updateNodePosition({
|
||||
isDragging: false,
|
||||
});
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ interface SelectionListenerProps {
|
||||
}
|
||||
|
||||
const selectedElementsSelector = (s: ReactFlowState) => [
|
||||
...s.nodes.filter((n) => n.selected),
|
||||
...s.edges.filter((e) => e.selected),
|
||||
...s.nodes.filter((n) => n.isSelected),
|
||||
...s.edges.filter((e) => e.isSelected),
|
||||
];
|
||||
|
||||
// This is just a helper component for calling the onSelectionChange listener.
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
import { useEffect } from 'react';
|
||||
import shallow from 'zustand/shallow';
|
||||
|
||||
import { useStore } from '../../store';
|
||||
import {
|
||||
Node,
|
||||
Edge,
|
||||
ReactFlowState,
|
||||
OnConnectFunc,
|
||||
OnConnectStartFunc,
|
||||
OnConnectStopFunc,
|
||||
OnConnectEndFunc,
|
||||
NodeExtent,
|
||||
OnNodesChange,
|
||||
OnEdgesChange,
|
||||
ConnectionMode,
|
||||
SnapGrid,
|
||||
TranslateExtent,
|
||||
} from '../../types';
|
||||
|
||||
interface StoreUpdaterProps {
|
||||
nodes: Node[];
|
||||
edges: Edge[];
|
||||
onConnect?: OnConnectFunc;
|
||||
onConnectStart?: OnConnectStartFunc;
|
||||
onConnectStop?: OnConnectStopFunc;
|
||||
onConnectEnd?: OnConnectEndFunc;
|
||||
nodesDraggable?: boolean;
|
||||
nodesConnectable?: boolean;
|
||||
minZoom?: number;
|
||||
maxZoom?: number;
|
||||
nodeExtent?: NodeExtent;
|
||||
onNodesChange?: OnNodesChange;
|
||||
onEdgesChange?: OnEdgesChange;
|
||||
elementsSelectable?: boolean;
|
||||
connectionMode?: ConnectionMode;
|
||||
snapToGrid?: boolean;
|
||||
snapGrid?: SnapGrid;
|
||||
translateExtent?: TranslateExtent;
|
||||
}
|
||||
|
||||
const selector = (s: ReactFlowState) => ({
|
||||
setNodes: s.setNodes,
|
||||
setEdges: s.setEdges,
|
||||
setOnConnect: s.setOnConnect,
|
||||
setOnConnectStart: s.setOnConnectStart,
|
||||
setOnConnectStop: s.setOnConnectStop,
|
||||
setOnConnectEnd: s.setOnConnectEnd,
|
||||
setSnapGrid: s.setSnapGrid,
|
||||
setSnapToGrid: s.setSnapToGrid,
|
||||
setNodesDraggable: s.setNodesDraggable,
|
||||
setNodesConnectable: s.setNodesConnectable,
|
||||
setElementsSelectable: s.setElementsSelectable,
|
||||
setMinZoom: s.setMinZoom,
|
||||
setMaxZoom: s.setMaxZoom,
|
||||
setTranslateExtent: s.setTranslateExtent,
|
||||
setNodeExtent: s.setNodeExtent,
|
||||
setConnectionMode: s.setConnectionMode,
|
||||
setOnNodesChange: s.setOnNodesChange,
|
||||
setOnEdgesChange: s.setOnEdgesChange,
|
||||
});
|
||||
|
||||
const StoreUpdater = ({
|
||||
nodes,
|
||||
edges,
|
||||
onConnect,
|
||||
onConnectStart,
|
||||
onConnectStop,
|
||||
onConnectEnd,
|
||||
nodesDraggable,
|
||||
nodesConnectable,
|
||||
minZoom,
|
||||
maxZoom,
|
||||
nodeExtent,
|
||||
onNodesChange,
|
||||
onEdgesChange,
|
||||
elementsSelectable,
|
||||
connectionMode,
|
||||
snapGrid,
|
||||
snapToGrid,
|
||||
translateExtent,
|
||||
}: StoreUpdaterProps) => {
|
||||
const {
|
||||
setNodes,
|
||||
setEdges,
|
||||
setOnConnect,
|
||||
setOnConnectStart,
|
||||
setOnConnectStop,
|
||||
setOnConnectEnd,
|
||||
setNodesDraggable,
|
||||
setSnapGrid,
|
||||
setSnapToGrid,
|
||||
setNodesConnectable,
|
||||
setElementsSelectable,
|
||||
setMinZoom,
|
||||
setMaxZoom,
|
||||
setTranslateExtent,
|
||||
setNodeExtent,
|
||||
setOnNodesChange,
|
||||
setOnEdgesChange,
|
||||
setConnectionMode,
|
||||
} = useStore(selector, shallow);
|
||||
|
||||
useEffect(() => {
|
||||
setNodes(nodes);
|
||||
}, [nodes]);
|
||||
|
||||
useEffect(() => {
|
||||
setEdges(edges, nodes);
|
||||
}, [edges, nodes]);
|
||||
|
||||
useEffect(() => {
|
||||
if (onConnect) {
|
||||
setOnConnect(onConnect);
|
||||
}
|
||||
}, [onConnect]);
|
||||
|
||||
useEffect(() => {
|
||||
if (onConnectStart) {
|
||||
setOnConnectStart(onConnectStart);
|
||||
}
|
||||
}, [onConnectStart]);
|
||||
|
||||
useEffect(() => {
|
||||
if (onConnectStop) {
|
||||
setOnConnectStop(onConnectStop);
|
||||
}
|
||||
}, [onConnectStop]);
|
||||
|
||||
useEffect(() => {
|
||||
if (onConnectEnd) {
|
||||
setOnConnectEnd(onConnectEnd);
|
||||
}
|
||||
}, [onConnectEnd]);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof snapToGrid !== 'undefined') {
|
||||
setSnapToGrid(snapToGrid);
|
||||
}
|
||||
}, [snapToGrid]);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof snapGrid !== 'undefined') {
|
||||
setSnapGrid(snapGrid);
|
||||
}
|
||||
}, [snapGrid]);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof nodesDraggable !== 'undefined') {
|
||||
setNodesDraggable(nodesDraggable);
|
||||
}
|
||||
}, [nodesDraggable]);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof nodesConnectable !== 'undefined') {
|
||||
setNodesConnectable(nodesConnectable);
|
||||
}
|
||||
}, [nodesConnectable]);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof elementsSelectable !== 'undefined') {
|
||||
setElementsSelectable(elementsSelectable);
|
||||
}
|
||||
}, [elementsSelectable]);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof minZoom !== 'undefined') {
|
||||
setMinZoom(minZoom);
|
||||
}
|
||||
}, [minZoom]);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof maxZoom !== 'undefined') {
|
||||
setMaxZoom(maxZoom);
|
||||
}
|
||||
}, [maxZoom]);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof translateExtent !== 'undefined') {
|
||||
setTranslateExtent(translateExtent);
|
||||
}
|
||||
}, [translateExtent]);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof nodeExtent !== 'undefined') {
|
||||
setNodeExtent(nodeExtent);
|
||||
}
|
||||
}, [nodeExtent]);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof connectionMode !== 'undefined') {
|
||||
setConnectionMode(connectionMode);
|
||||
}
|
||||
}, [connectionMode]);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof onNodesChange !== 'undefined') {
|
||||
setOnNodesChange(onNodesChange);
|
||||
}
|
||||
}, [onNodesChange]);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof onEdgesChange !== 'undefined') {
|
||||
setOnEdgesChange(onEdgesChange);
|
||||
}
|
||||
}, [onEdgesChange]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export default StoreUpdater;
|
||||
Reference in New Issue
Block a user