refactor(zustand): use shallow when needed
This commit is contained in:
Generated
+4
-3
@@ -15,7 +15,6 @@
|
|||||||
"classcat": "^5.0.3",
|
"classcat": "^5.0.3",
|
||||||
"d3-selection": "^3.0.0",
|
"d3-selection": "^3.0.0",
|
||||||
"d3-zoom": "^3.0.0",
|
"d3-zoom": "^3.0.0",
|
||||||
"fast-deep-equal": "^3.1.3",
|
|
||||||
"react-draggable": "^4.4.4",
|
"react-draggable": "^4.4.4",
|
||||||
"react-redux": "^7.2.5",
|
"react-redux": "^7.2.5",
|
||||||
"redux": "^4.1.1",
|
"redux": "^4.1.1",
|
||||||
@@ -5285,7 +5284,8 @@
|
|||||||
"node_modules/fast-deep-equal": {
|
"node_modules/fast-deep-equal": {
|
||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/fast-glob": {
|
"node_modules/fast-glob": {
|
||||||
"version": "3.2.7",
|
"version": "3.2.7",
|
||||||
@@ -15220,7 +15220,8 @@
|
|||||||
"fast-deep-equal": {
|
"fast-deep-equal": {
|
||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"fast-glob": {
|
"fast-glob": {
|
||||||
"version": "3.2.7",
|
"version": "3.2.7",
|
||||||
|
|||||||
@@ -37,7 +37,6 @@
|
|||||||
"classcat": "^5.0.3",
|
"classcat": "^5.0.3",
|
||||||
"d3-selection": "^3.0.0",
|
"d3-selection": "^3.0.0",
|
||||||
"d3-zoom": "^3.0.0",
|
"d3-zoom": "^3.0.0",
|
||||||
"fast-deep-equal": "^3.1.3",
|
|
||||||
"react-draggable": "^4.4.4",
|
"react-draggable": "^4.4.4",
|
||||||
"react-redux": "^7.2.5",
|
"react-redux": "^7.2.5",
|
||||||
"redux": "^4.1.1",
|
"redux": "^4.1.1",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React, { memo, HTMLAttributes } from 'react';
|
import React, { memo, HTMLAttributes } from 'react';
|
||||||
import cc from 'classcat';
|
import cc from 'classcat';
|
||||||
|
import shallow from 'zustand/shallow';
|
||||||
|
|
||||||
import { useStore } from '../../store';
|
import { useStore } from '../../store';
|
||||||
import { getRectOfNodes, getBoundsofRects } from '../../utils/graph';
|
import { getRectOfNodes, getBoundsofRects } from '../../utils/graph';
|
||||||
@@ -34,7 +35,7 @@ const MiniMap = ({
|
|||||||
nodeStrokeWidth = 2,
|
nodeStrokeWidth = 2,
|
||||||
maskColor = 'rgb(240, 242, 243, 0.7)',
|
maskColor = 'rgb(240, 242, 243, 0.7)',
|
||||||
}: MiniMapProps) => {
|
}: MiniMapProps) => {
|
||||||
const { width: containerWidth, height: containerHeight, transform, nodes } = useStore(selector);
|
const { width: containerWidth, height: containerHeight, transform, nodes } = useStore(selector, shallow);
|
||||||
const [tX, tY, tScale] = transform;
|
const [tX, tY, tScale] = transform;
|
||||||
|
|
||||||
const mapClasses = cc(['react-flow__minimap', className]);
|
const mapClasses = cc(['react-flow__minimap', className]);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React, { memo, ComponentType, useCallback, useState, useMemo } from 'react';
|
import React, { memo, ComponentType, useCallback, useState, useMemo } from 'react';
|
||||||
import cc from 'classcat';
|
import cc from 'classcat';
|
||||||
|
import shallow from 'zustand/shallow';
|
||||||
|
|
||||||
import { useStore, useStoreApi } from '../../store';
|
import { useStore, useStoreApi } from '../../store';
|
||||||
import { Edge, EdgeProps, WrapEdgeProps, ReactFlowState } from '../../types';
|
import { Edge, EdgeProps, WrapEdgeProps, ReactFlowState } from '../../types';
|
||||||
@@ -56,8 +57,10 @@ export default (EdgeComponent: ComponentType<EdgeProps>) => {
|
|||||||
onEdgeUpdateEnd,
|
onEdgeUpdateEnd,
|
||||||
}: WrapEdgeProps): JSX.Element | null => {
|
}: WrapEdgeProps): JSX.Element | null => {
|
||||||
const store = useStoreApi();
|
const store = useStoreApi();
|
||||||
const { addSelectedElements, setConnectionNodeId, unsetNodesSelection, setPosition, connectionMode } =
|
const { addSelectedElements, setConnectionNodeId, unsetNodesSelection, setPosition, connectionMode } = useStore(
|
||||||
useStore(selector);
|
selector,
|
||||||
|
shallow
|
||||||
|
);
|
||||||
|
|
||||||
const [updating, setUpdating] = useState<boolean>(false);
|
const [updating, setUpdating] = useState<boolean>(false);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
import shallow from 'zustand/shallow';
|
||||||
|
|
||||||
import { useStore } from '../../store';
|
import { useStore } from '../../store';
|
||||||
import { Node, Edge, ReactFlowState } from '../../types';
|
import { Node, Edge, ReactFlowState } from '../../types';
|
||||||
@@ -14,7 +15,7 @@ const selector = (s: ReactFlowState) => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const ElementUpdater = ({ nodes, edges }: ElementUpdaterProps) => {
|
const ElementUpdater = ({ nodes, edges }: ElementUpdaterProps) => {
|
||||||
const { setNodes, setEdges } = useStore(selector);
|
const { setNodes, setEdges } = useStore(selector, shallow);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setNodes(nodes);
|
setNodes(nodes);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React, { memo, useContext, useCallback, HTMLAttributes, forwardRef } from 'react';
|
import React, { memo, useContext, useCallback, HTMLAttributes, forwardRef } from 'react';
|
||||||
import cc from 'classcat';
|
import cc from 'classcat';
|
||||||
|
import shallow from 'zustand/shallow';
|
||||||
|
|
||||||
import { useStore } from '../../store';
|
import { useStore } from '../../store';
|
||||||
import NodeIdContext from '../../contexts/NodeIdContext';
|
import NodeIdContext from '../../contexts/NodeIdContext';
|
||||||
@@ -45,7 +46,7 @@ const Handle = forwardRef<HTMLDivElement, HandleComponentProps>(
|
|||||||
onConnectStop,
|
onConnectStop,
|
||||||
onConnectEnd,
|
onConnectEnd,
|
||||||
connectionMode,
|
connectionMode,
|
||||||
} = useStore(selector);
|
} = useStore(selector, shallow);
|
||||||
|
|
||||||
const handleId = id || null;
|
const handleId = id || null;
|
||||||
const isTarget = type === 'target';
|
const isTarget = type === 'target';
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React, { useEffect, useRef, memo, ComponentType, CSSProperties, useMemo, MouseEvent, useCallback } from 'react';
|
import React, { useEffect, useRef, memo, ComponentType, CSSProperties, useMemo, MouseEvent, useCallback } from 'react';
|
||||||
import { DraggableCore, DraggableData, DraggableEvent } from 'react-draggable';
|
import { DraggableCore, DraggableData, DraggableEvent } from 'react-draggable';
|
||||||
import cc from 'classcat';
|
import cc from 'classcat';
|
||||||
|
import shallow from 'zustand/shallow';
|
||||||
|
|
||||||
import { useStore } from '../../store';
|
import { useStore } from '../../store';
|
||||||
import { Provider } from '../../contexts/NodeIdContext';
|
import { Provider } from '../../contexts/NodeIdContext';
|
||||||
@@ -10,6 +11,7 @@ const selector = (s: ReactFlowState) => ({
|
|||||||
addSelectedElements: s.addSelectedElements,
|
addSelectedElements: s.addSelectedElements,
|
||||||
onNodesChange: s.onNodesChange,
|
onNodesChange: s.onNodesChange,
|
||||||
unsetNodesSelection: s.unsetNodesSelection,
|
unsetNodesSelection: s.unsetNodesSelection,
|
||||||
|
updateNodePosDiff: s.updateNodePosDiff,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||||
@@ -47,7 +49,7 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
|||||||
dragHandle,
|
dragHandle,
|
||||||
}: WrapNodeProps) => {
|
}: WrapNodeProps) => {
|
||||||
// const updateNodeDimensions = useStoreActions((actions) => actions.updateNodeDimensions);
|
// const updateNodeDimensions = useStoreActions((actions) => actions.updateNodeDimensions);
|
||||||
const { addSelectedElements, onNodesChange, unsetNodesSelection } = useStore(selector);
|
const { addSelectedElements, onNodesChange, unsetNodesSelection, updateNodePosDiff } = useStore(selector, shallow);
|
||||||
const nodeElement = useRef<HTMLDivElement>(null);
|
const nodeElement = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const node = useMemo(() => ({ id, type, position: { x: xPos, y: yPos }, data }), [id, type, xPos, yPos, data]);
|
const node = useMemo(() => ({ id, type, position: { x: xPos, y: yPos }, data }), [id, type, xPos, yPos, data]);
|
||||||
@@ -154,18 +156,7 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
|||||||
onNodeDrag(event as MouseEvent, node);
|
onNodeDrag(event as MouseEvent, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
onNodesChange?.([
|
updateNodePosDiff({ id, isDragging: true, diff: { x: draggableData.deltaX, y: draggableData.deltaY } });
|
||||||
{
|
|
||||||
id,
|
|
||||||
change: {
|
|
||||||
position: {
|
|
||||||
x: node.position.x,
|
|
||||||
y: node.position.y,
|
|
||||||
},
|
|
||||||
isDragging: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
},
|
},
|
||||||
[id, node, onNodeDrag]
|
[id, node, onNodeDrag]
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import React, { useMemo, useCallback, useRef, MouseEvent } from 'react';
|
|||||||
import ReactDraggable, { DraggableData } from 'react-draggable';
|
import ReactDraggable, { DraggableData } from 'react-draggable';
|
||||||
|
|
||||||
import { useStore } from '../../store';
|
import { useStore } from '../../store';
|
||||||
import { isNode } from '../../utils/graph';
|
|
||||||
import { Node, ReactFlowState } from '../../types';
|
import { Node, ReactFlowState } from '../../types';
|
||||||
|
|
||||||
export interface NodesSelectionProps {
|
export interface NodesSelectionProps {
|
||||||
@@ -21,10 +20,9 @@ const selector = (s: ReactFlowState) => ({
|
|||||||
transform: s.transform,
|
transform: s.transform,
|
||||||
selectedNodesBbox: s.selectedNodesBbox,
|
selectedNodesBbox: s.selectedNodesBbox,
|
||||||
selectionActive: s.selectionActive,
|
selectionActive: s.selectionActive,
|
||||||
selectedElements: s.selectedElements,
|
selectedNodes: s.nodes.filter((n) => n.selected),
|
||||||
snapToGrid: s.snapToGrid,
|
snapToGrid: s.snapToGrid,
|
||||||
snapGrid: s.snapGrid,
|
snapGrid: s.snapGrid,
|
||||||
nodes: s.nodes,
|
|
||||||
updateNodePosDiff: s.updateNodePosDiff,
|
updateNodePosDiff: s.updateNodePosDiff,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -34,37 +32,13 @@ export default ({
|
|||||||
onSelectionDragStop,
|
onSelectionDragStop,
|
||||||
onSelectionContextMenu,
|
onSelectionContextMenu,
|
||||||
}: NodesSelectionProps) => {
|
}: NodesSelectionProps) => {
|
||||||
const {
|
const { transform, selectedNodesBbox, selectionActive, selectedNodes, snapToGrid, snapGrid, updateNodePosDiff } =
|
||||||
transform,
|
useStore(selector);
|
||||||
selectedNodesBbox,
|
|
||||||
selectionActive,
|
|
||||||
selectedElements,
|
|
||||||
snapToGrid,
|
|
||||||
snapGrid,
|
|
||||||
nodes,
|
|
||||||
updateNodePosDiff,
|
|
||||||
} = useStore(selector);
|
|
||||||
const [tX, tY, tScale] = transform;
|
const [tX, tY, tScale] = transform;
|
||||||
|
|
||||||
const nodeRef = useRef(null);
|
const nodeRef = useRef(null);
|
||||||
|
|
||||||
const grid = useMemo(() => (snapToGrid ? snapGrid : [1, 1])! as [number, number], [snapToGrid, snapGrid]);
|
const grid = useMemo(() => (snapToGrid ? snapGrid : [1, 1])! as [number, number], [snapToGrid, snapGrid]);
|
||||||
|
|
||||||
const selectedNodes = useMemo(
|
|
||||||
() =>
|
|
||||||
selectedElements
|
|
||||||
? selectedElements.filter(isNode).map((selectedNode) => {
|
|
||||||
const matchingNode = nodes.find((node) => node.id === selectedNode.id);
|
|
||||||
|
|
||||||
return {
|
|
||||||
...matchingNode,
|
|
||||||
position: matchingNode?.position,
|
|
||||||
} as Node;
|
|
||||||
})
|
|
||||||
: [],
|
|
||||||
[selectedElements, nodes]
|
|
||||||
);
|
|
||||||
|
|
||||||
const style = useMemo(
|
const style = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
transform: `translate(${tX}px,${tY}px) scale(${tScale})`,
|
transform: `translate(${tX}px,${tY}px) scale(${tScale})`,
|
||||||
@@ -119,16 +93,12 @@ export default ({
|
|||||||
|
|
||||||
const onContextMenu = useCallback(
|
const onContextMenu = useCallback(
|
||||||
(event: MouseEvent) => {
|
(event: MouseEvent) => {
|
||||||
const selectedNodes = selectedElements
|
|
||||||
? selectedElements.filter(isNode).map((selectedNode) => nodes.find((node) => node.id === selectedNode.id)!)
|
|
||||||
: [];
|
|
||||||
|
|
||||||
onSelectionContextMenu?.(event, selectedNodes);
|
onSelectionContextMenu?.(event, selectedNodes);
|
||||||
},
|
},
|
||||||
[onSelectionContextMenu]
|
[onSelectionContextMenu, selectedNodes]
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!selectedElements || selectionActive) {
|
if (!selectedNodes || selectionActive) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
import shallow from 'zustand/shallow';
|
||||||
|
|
||||||
import { Elements, ReactFlowState } from '../../types';
|
import { Elements, ReactFlowState } from '../../types';
|
||||||
import { useStore } from '../../store';
|
import { useStore } from '../../store';
|
||||||
@@ -7,12 +8,15 @@ interface SelectionListenerProps {
|
|||||||
onSelectionChange: (elements: Elements | null) => void;
|
onSelectionChange: (elements: Elements | null) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectedElementsSelector = (s: ReactFlowState) => s.selectedElements;
|
const selectedElementsSelector = (s: ReactFlowState) => [
|
||||||
|
...s.nodes.filter((n) => n.selected),
|
||||||
|
...s.edges.filter((e) => e.selected),
|
||||||
|
];
|
||||||
|
|
||||||
// This is just a helper component for calling the onSelectionChange listener.
|
// This is just a helper component for calling the onSelectionChange listener.
|
||||||
|
|
||||||
export default ({ onSelectionChange }: SelectionListenerProps) => {
|
export default ({ onSelectionChange }: SelectionListenerProps) => {
|
||||||
const selectedElements = useStore(selectedElementsSelector);
|
const selectedElements = useStore(selectedElementsSelector, shallow);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
onSelectionChange(selectedElements);
|
onSelectionChange(selectedElements);
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
import React, { memo, CSSProperties, useCallback } from 'react';
|
import React, { memo, CSSProperties, useCallback } from 'react';
|
||||||
|
import shallow from 'zustand/shallow';
|
||||||
|
|
||||||
import { useStore } from '../../store';
|
import { useStore } from '../../store';
|
||||||
import ConnectionLine from '../../components/ConnectionLine/index';
|
import ConnectionLine from '../../components/ConnectionLine/index';
|
||||||
import { isEdge } from '../../utils/graph';
|
|
||||||
import MarkerDefinitions from './MarkerDefinitions';
|
import MarkerDefinitions from './MarkerDefinitions';
|
||||||
import { getEdgePositions, getHandle } from './utils';
|
import { getEdgePositions, getHandle } from './utils';
|
||||||
import {
|
import {
|
||||||
Position,
|
Position,
|
||||||
Edge,
|
Edge,
|
||||||
Node,
|
Node,
|
||||||
Elements,
|
|
||||||
Connection,
|
Connection,
|
||||||
ConnectionLineType,
|
ConnectionLineType,
|
||||||
ConnectionLineComponent,
|
ConnectionLineComponent,
|
||||||
@@ -55,7 +54,6 @@ interface EdgeWrapperProps {
|
|||||||
onEdgeUpdate?: OnEdgeUpdateFunc;
|
onEdgeUpdate?: OnEdgeUpdateFunc;
|
||||||
targetNode?: Node;
|
targetNode?: Node;
|
||||||
sourceNode?: Node;
|
sourceNode?: Node;
|
||||||
selectedElements: Elements | null;
|
|
||||||
elementsSelectable: boolean;
|
elementsSelectable: boolean;
|
||||||
connectionMode?: ConnectionMode;
|
connectionMode?: ConnectionMode;
|
||||||
}
|
}
|
||||||
@@ -77,7 +75,6 @@ const Edge = memo(
|
|||||||
onEdgeUpdate,
|
onEdgeUpdate,
|
||||||
targetNode,
|
targetNode,
|
||||||
sourceNode,
|
sourceNode,
|
||||||
selectedElements,
|
|
||||||
elementsSelectable,
|
elementsSelectable,
|
||||||
connectionMode,
|
connectionMode,
|
||||||
}: EdgeWrapperProps) => {
|
}: EdgeWrapperProps) => {
|
||||||
@@ -152,8 +149,6 @@ const Edge = memo(
|
|||||||
// return null;
|
// return null;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
const isSelected = selectedElements?.some((elm) => isEdge(elm) && elm.id === edge.id) || false;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EdgeComponent
|
<EdgeComponent
|
||||||
key={edge.id}
|
key={edge.id}
|
||||||
@@ -162,7 +157,7 @@ const Edge = memo(
|
|||||||
type={edge.type}
|
type={edge.type}
|
||||||
data={edge.data}
|
data={edge.data}
|
||||||
onClick={onElementClick}
|
onClick={onElementClick}
|
||||||
selected={isSelected}
|
selected={!!edge.selected}
|
||||||
animated={edge.animated}
|
animated={edge.animated}
|
||||||
label={edge.label}
|
label={edge.label}
|
||||||
labelStyle={edge.labelStyle}
|
labelStyle={edge.labelStyle}
|
||||||
@@ -207,7 +202,6 @@ const selector = (s: ReactFlowState) => ({
|
|||||||
connectionHandleId: s.connectionHandleId,
|
connectionHandleId: s.connectionHandleId,
|
||||||
connectionHandleType: s.connectionHandleType,
|
connectionHandleType: s.connectionHandleType,
|
||||||
connectionPosition: s.connectionPosition,
|
connectionPosition: s.connectionPosition,
|
||||||
selectedElements: s.selectedElements,
|
|
||||||
nodesConnectable: s.nodesConnectable,
|
nodesConnectable: s.nodesConnectable,
|
||||||
elementsSelectable: s.elementsSelectable,
|
elementsSelectable: s.elementsSelectable,
|
||||||
width: s.width,
|
width: s.width,
|
||||||
@@ -222,12 +216,11 @@ const EdgeRenderer = (props: EdgeRendererProps) => {
|
|||||||
connectionHandleId,
|
connectionHandleId,
|
||||||
connectionHandleType,
|
connectionHandleType,
|
||||||
connectionPosition,
|
connectionPosition,
|
||||||
selectedElements,
|
|
||||||
nodesConnectable,
|
nodesConnectable,
|
||||||
elementsSelectable,
|
elementsSelectable,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
} = useStore(selector);
|
} = useStore(selector, shallow);
|
||||||
|
|
||||||
if (!width) {
|
if (!width) {
|
||||||
return null;
|
return null;
|
||||||
@@ -247,7 +240,6 @@ const EdgeRenderer = (props: EdgeRendererProps) => {
|
|||||||
edge={edge}
|
edge={edge}
|
||||||
sourceNode={edge.sourceNode}
|
sourceNode={edge.sourceNode}
|
||||||
targetNode={edge.targetNode}
|
targetNode={edge.targetNode}
|
||||||
selectedElements={selectedElements}
|
|
||||||
elementsSelectable={elementsSelectable}
|
elementsSelectable={elementsSelectable}
|
||||||
markerEndId={props.markerEndId}
|
markerEndId={props.markerEndId}
|
||||||
onEdgeContextMenu={props.onEdgeContextMenu}
|
onEdgeContextMenu={props.onEdgeContextMenu}
|
||||||
|
|||||||
@@ -169,3 +169,16 @@ export const getSourceTargetNodes = (edge: Edge, nodes: Node[]): SourceTargetNod
|
|||||||
{ sourceNode: null, targetNode: null } as SourceTargetNode
|
{ sourceNode: null, targetNode: null } as SourceTargetNode
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const extendEdgeWithSourceAndTarget = (edge: Edge, nodes: Node[]): Edge => {
|
||||||
|
const { sourceNode, targetNode } = getSourceTargetNodes(edge, nodes);
|
||||||
|
|
||||||
|
if (sourceNode) {
|
||||||
|
edge.sourceNode = sourceNode;
|
||||||
|
}
|
||||||
|
if (targetNode) {
|
||||||
|
edge.targetNode = targetNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
return edge;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, { useCallback, memo, ReactNode, WheelEvent, MouseEvent } from 'react';
|
import React, { useCallback, memo, ReactNode, WheelEvent, MouseEvent } from 'react';
|
||||||
|
import shallow from 'zustand/shallow';
|
||||||
|
|
||||||
import { useStore } from '../../store';
|
import { useStore } from '../../store';
|
||||||
import useGlobalKeyHandler from '../../hooks/useGlobalKeyHandler';
|
import useGlobalKeyHandler from '../../hooks/useGlobalKeyHandler';
|
||||||
@@ -60,7 +61,7 @@ const FlowRenderer = ({
|
|||||||
onSelectionDragStop,
|
onSelectionDragStop,
|
||||||
onSelectionContextMenu,
|
onSelectionContextMenu,
|
||||||
}: FlowRendererProps) => {
|
}: FlowRendererProps) => {
|
||||||
const { unsetNodesSelection, resetSelectedElements, nodesSelectionActive } = useStore(selector);
|
const { unsetNodesSelection, resetSelectedElements, nodesSelectionActive } = useStore(selector, shallow);
|
||||||
|
|
||||||
const selectionKeyPressed = useKeyPress(selectionKeyCode);
|
const selectionKeyPressed = useKeyPress(selectionKeyCode);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, { useEffect, useRef, memo } from 'react';
|
import React, { useEffect, useRef, memo } from 'react';
|
||||||
|
import shallow from 'zustand/shallow';
|
||||||
|
|
||||||
import { useStore, useStoreApi } from '../../store';
|
import { useStore, useStoreApi } from '../../store';
|
||||||
import FlowRenderer from '../FlowRenderer';
|
import FlowRenderer from '../FlowRenderer';
|
||||||
@@ -136,7 +137,7 @@ const GraphView = ({
|
|||||||
setConnectionMode,
|
setConnectionMode,
|
||||||
setOnNodesChange,
|
setOnNodesChange,
|
||||||
setOnEdgesChange,
|
setOnEdgesChange,
|
||||||
} = useStore(selector);
|
} = useStore(selector, shallow);
|
||||||
|
|
||||||
const { zoomIn, zoomOut, zoomTo, transform, fitView, initialized } = useZoomPanHelper();
|
const { zoomIn, zoomOut, zoomTo, transform, fitView, initialized } = useZoomPanHelper();
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, { memo, useMemo, ComponentType, MouseEvent } from 'react';
|
import React, { memo, useMemo, ComponentType, MouseEvent } from 'react';
|
||||||
|
import shallow from 'zustand/shallow';
|
||||||
|
|
||||||
import { useStore } from '../../store';
|
import { useStore } from '../../store';
|
||||||
import { Node, NodeTypesType, ReactFlowState, Edge, WrapNodeProps } from '../../types';
|
import { Node, NodeTypesType, ReactFlowState, Edge, WrapNodeProps } from '../../types';
|
||||||
@@ -21,7 +22,6 @@ interface NodeRendererProps {
|
|||||||
|
|
||||||
const selector = (s: ReactFlowState) => ({
|
const selector = (s: ReactFlowState) => ({
|
||||||
transform: s.transform,
|
transform: s.transform,
|
||||||
selectedElements: s.selectedElements,
|
|
||||||
nodesDraggable: s.nodesDraggable,
|
nodesDraggable: s.nodesDraggable,
|
||||||
nodesConnectable: s.nodesConnectable,
|
nodesConnectable: s.nodesConnectable,
|
||||||
elementsSelectable: s.elementsSelectable,
|
elementsSelectable: s.elementsSelectable,
|
||||||
@@ -30,15 +30,10 @@ const selector = (s: ReactFlowState) => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const NodeRenderer = (props: NodeRendererProps) => {
|
const NodeRenderer = (props: NodeRendererProps) => {
|
||||||
const {
|
const { transform, nodesDraggable, nodesConnectable, elementsSelectable, nodes, updateNodeDimensions } = useStore(
|
||||||
transform,
|
selector,
|
||||||
selectedElements,
|
shallow
|
||||||
nodesDraggable,
|
);
|
||||||
nodesConnectable,
|
|
||||||
elementsSelectable,
|
|
||||||
nodes,
|
|
||||||
updateNodeDimensions,
|
|
||||||
} = useStore(selector);
|
|
||||||
|
|
||||||
// const visibleNodes = props.onlyRenderVisibleElements
|
// const visibleNodes = props.onlyRenderVisibleElements
|
||||||
// ? getNodesInside(nodes, { x: 0, y: 0, width, height }, transform, true)
|
// ? getNodesInside(nodes, { x: 0, y: 0, width, height }, transform, true)
|
||||||
@@ -108,7 +103,7 @@ const NodeRenderer = (props: NodeRendererProps) => {
|
|||||||
onNodeDrag={props.onNodeDrag}
|
onNodeDrag={props.onNodeDrag}
|
||||||
onNodeDragStop={props.onNodeDragStop}
|
onNodeDragStop={props.onNodeDragStop}
|
||||||
scale={transform[2]}
|
scale={transform[2]}
|
||||||
selected={selectedElements?.some(({ id }) => id === node.id) || false}
|
selected={!!node.selected}
|
||||||
isDraggable={isDraggable}
|
isDraggable={isDraggable}
|
||||||
isSelectable={isSelectable}
|
isSelectable={isSelectable}
|
||||||
isConnectable={isConnectable}
|
isConnectable={isConnectable}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React, { useEffect, useRef, ReactNode } from 'react';
|
import React, { useEffect, useRef, ReactNode } from 'react';
|
||||||
import { zoom, zoomIdentity } from 'd3-zoom';
|
import { zoom, zoomIdentity } from 'd3-zoom';
|
||||||
import { select, pointer } from 'd3-selection';
|
import { select, pointer } from 'd3-selection';
|
||||||
|
import shallow from 'zustand/shallow';
|
||||||
|
|
||||||
import { clamp } from '../../utils';
|
import { clamp } from '../../utils';
|
||||||
import useKeyPress from '../../hooks/useKeyPress';
|
import useKeyPress from '../../hooks/useKeyPress';
|
||||||
@@ -74,7 +75,7 @@ const ZoomPane = ({
|
|||||||
const store = useStoreApi();
|
const store = useStoreApi();
|
||||||
const zoomPane = useRef<HTMLDivElement>(null);
|
const zoomPane = useRef<HTMLDivElement>(null);
|
||||||
const prevTransform = useRef<FlowTransform>({ x: 0, y: 0, zoom: 0 });
|
const prevTransform = useRef<FlowTransform>({ x: 0, y: 0, zoom: 0 });
|
||||||
const { d3Zoom, d3Selection, d3ZoomHandler, initD3Zoom, updateTransform } = useStore(selector);
|
const { d3Zoom, d3Selection, d3ZoomHandler, initD3Zoom, updateTransform } = useStore(selector, shallow);
|
||||||
const zoomActivationKeyPressed = useKeyPress(zoomActivationKeyCode);
|
const zoomActivationKeyPressed = useKeyPress(zoomActivationKeyCode);
|
||||||
|
|
||||||
useResizeHandler(zoomPane);
|
useResizeHandler(zoomPane);
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
import shallow from 'zustand/shallow';
|
||||||
|
|
||||||
import { useStore, useStoreApi } from '../store';
|
import { useStore, useStoreApi } from '../store';
|
||||||
import useKeyPress from './useKeyPress';
|
import useKeyPress from './useKeyPress';
|
||||||
import { isNode, isEdge, getConnectedEdges } from '../utils/graph';
|
import { getConnectedEdges } from '../utils/graph';
|
||||||
import { KeyCode, ReactFlowState } from '../types';
|
import { KeyCode, ReactFlowState } from '../types';
|
||||||
|
|
||||||
interface HookParams {
|
interface HookParams {
|
||||||
@@ -21,17 +22,17 @@ const selector = (s: ReactFlowState) => ({
|
|||||||
export default ({ deleteKeyCode, multiSelectionKeyCode }: HookParams): void => {
|
export default ({ deleteKeyCode, multiSelectionKeyCode }: HookParams): void => {
|
||||||
const store = useStoreApi();
|
const store = useStoreApi();
|
||||||
const { unsetNodesSelection, setMultiSelectionActive, resetSelectedElements, onNodesChange, onEdgesChange } =
|
const { unsetNodesSelection, setMultiSelectionActive, resetSelectedElements, onNodesChange, onEdgesChange } =
|
||||||
useStore(selector);
|
useStore(selector, shallow);
|
||||||
|
|
||||||
const deleteKeyPressed = useKeyPress(deleteKeyCode);
|
const deleteKeyPressed = useKeyPress(deleteKeyCode);
|
||||||
const multiSelectionKeyPressed = useKeyPress(multiSelectionKeyCode);
|
const multiSelectionKeyPressed = useKeyPress(multiSelectionKeyCode);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { edges, selectedElements } = store.getState();
|
const { nodes, edges } = store.getState();
|
||||||
|
const selectedNodes = nodes.filter((n) => n.selected);
|
||||||
|
const selectedEdges = edges.filter((e) => e.selected);
|
||||||
|
|
||||||
if (deleteKeyPressed && selectedElements) {
|
if (deleteKeyPressed && (selectedNodes || selectedEdges)) {
|
||||||
const selectedNodes = selectedElements.filter(isNode);
|
|
||||||
const selectedEdges = selectedElements.filter(isEdge);
|
|
||||||
const connectedEdges = getConnectedEdges(selectedNodes, edges);
|
const connectedEdges = getConnectedEdges(selectedNodes, edges);
|
||||||
|
|
||||||
const nodeChanges = selectedNodes.map((n) => ({ id: n.id, delete: true }));
|
const nodeChanges = selectedNodes.map((n) => ({ id: n.id, delete: true }));
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { zoomIdentity } from 'd3-zoom';
|
import { zoomIdentity } from 'd3-zoom';
|
||||||
|
import shallow from 'zustand/shallow';
|
||||||
|
|
||||||
import { useStoreApi, useStore } from '../store';
|
import { useStoreApi, useStore } from '../store';
|
||||||
import { getRectOfNodes, pointToRendererPoint, getTransformForBounds } from '../utils/graph';
|
import { getRectOfNodes, pointToRendererPoint, getTransformForBounds } from '../utils/graph';
|
||||||
@@ -26,7 +27,7 @@ const selector = (s: ReactFlowState) => ({
|
|||||||
|
|
||||||
const useZoomPanHelper = (): ZoomPanHelperFunctions => {
|
const useZoomPanHelper = (): ZoomPanHelperFunctions => {
|
||||||
const store = useStoreApi();
|
const store = useStoreApi();
|
||||||
const { d3Zoom, d3Selection } = useStore(selector);
|
const { d3Zoom, d3Selection } = useStore(selector, shallow);
|
||||||
|
|
||||||
const zoomPanHelperFunctions = useMemo<ZoomPanHelperFunctions>(() => {
|
const zoomPanHelperFunctions = useMemo<ZoomPanHelperFunctions>(() => {
|
||||||
if (d3Selection && d3Zoom) {
|
if (d3Selection && d3Zoom) {
|
||||||
|
|||||||
+90
-133
@@ -1,6 +1,5 @@
|
|||||||
import create from 'zustand';
|
import create from 'zustand';
|
||||||
import createContext from 'zustand/context';
|
import createContext from 'zustand/context';
|
||||||
import isEqual from 'fast-deep-equal';
|
|
||||||
|
|
||||||
import { clampPosition, getDimensions } from '../utils';
|
import { clampPosition, getDimensions } from '../utils';
|
||||||
import {
|
import {
|
||||||
@@ -26,8 +25,16 @@ import {
|
|||||||
SnapGrid,
|
SnapGrid,
|
||||||
OnElementsChange,
|
OnElementsChange,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import { parseNode, parseEdge, isNode, getRectOfNodes, getNodesInside, getConnectedEdges } from '../utils/graph';
|
import {
|
||||||
import { getSourceTargetNodes } from '../container/EdgeRenderer/utils';
|
parseNode,
|
||||||
|
parseEdge,
|
||||||
|
isNode,
|
||||||
|
isEdge,
|
||||||
|
getRectOfNodes,
|
||||||
|
getNodesInside,
|
||||||
|
getConnectedEdges,
|
||||||
|
} from '../utils/graph';
|
||||||
|
import { extendEdgeWithSourceAndTarget } from '../container/EdgeRenderer/utils';
|
||||||
import { getHandleBounds } from '../components/Nodes/utils';
|
import { getHandleBounds } from '../components/Nodes/utils';
|
||||||
|
|
||||||
const { Provider, useStore, useStoreApi } = createContext<ReactFlowState>();
|
const { Provider, useStore, useStoreApi } = createContext<ReactFlowState>();
|
||||||
@@ -42,7 +49,6 @@ const createStore = () =>
|
|||||||
onNodesChange: null,
|
onNodesChange: null,
|
||||||
onEdgesChange: null,
|
onEdgesChange: null,
|
||||||
|
|
||||||
selectedElements: null,
|
|
||||||
selectedNodesBbox: { x: 0, y: 0, width: 0, height: 0 },
|
selectedNodesBbox: { x: 0, y: 0, width: 0, height: 0 },
|
||||||
|
|
||||||
d3Zoom: null,
|
d3Zoom: null,
|
||||||
@@ -110,18 +116,7 @@ const createStore = () =>
|
|||||||
return parseNode(propNode, nodeExtent);
|
return parseNode(propNode, nodeExtent);
|
||||||
});
|
});
|
||||||
|
|
||||||
const updatedEdges = edges.map((edge) => {
|
const updatedEdges = edges.map((edge) => extendEdgeWithSourceAndTarget(edge, nextNodes));
|
||||||
const { sourceNode, targetNode } = getSourceTargetNodes(edge, nextNodes);
|
|
||||||
|
|
||||||
if (sourceNode) {
|
|
||||||
edge.sourceNode = sourceNode;
|
|
||||||
}
|
|
||||||
if (targetNode) {
|
|
||||||
edge.targetNode = targetNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
return edge;
|
|
||||||
});
|
|
||||||
|
|
||||||
set({
|
set({
|
||||||
nodes: nextNodes,
|
nodes: nextNodes,
|
||||||
@@ -137,17 +132,7 @@ const createStore = () =>
|
|||||||
if (storeEdge) {
|
if (storeEdge) {
|
||||||
return parseEdge(propEdge);
|
return parseEdge(propEdge);
|
||||||
} else {
|
} else {
|
||||||
const parsedEdge = parseEdge(propEdge);
|
return extendEdgeWithSourceAndTarget(parseEdge(propEdge), nodes);
|
||||||
const { sourceNode, targetNode } = getSourceTargetNodes(parsedEdge, nodes);
|
|
||||||
|
|
||||||
if (sourceNode) {
|
|
||||||
parsedEdge.sourceNode = sourceNode;
|
|
||||||
}
|
|
||||||
if (targetNode) {
|
|
||||||
parsedEdge.targetNode = targetNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
return parsedEdge;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -190,23 +175,21 @@ const createStore = () =>
|
|||||||
updateNodePosDiff: ({ id, diff, isDragging }: NodeDiffUpdate) => {
|
updateNodePosDiff: ({ id, diff, isDragging }: NodeDiffUpdate) => {
|
||||||
const { onNodesChange, nodes } = get();
|
const { onNodesChange, nodes } = get();
|
||||||
|
|
||||||
if (onNodesChange && id && diff) {
|
if (onNodesChange && diff) {
|
||||||
const matchingNode = nodes.find((n) => n.id === id);
|
const matchingNodes = nodes.filter((n) => n.id === id || n.selected);
|
||||||
|
|
||||||
if (matchingNode) {
|
if (matchingNodes?.length) {
|
||||||
requestAnimationFrame(() =>
|
onNodesChange(
|
||||||
onNodesChange([
|
matchingNodes.map((n) => ({
|
||||||
{
|
id: n.id,
|
||||||
id,
|
change: {
|
||||||
change: {
|
position: {
|
||||||
position: {
|
x: n.position.x + diff.x,
|
||||||
x: matchingNode.position.x + diff.x,
|
y: n.position.y + diff.y,
|
||||||
y: matchingNode.position.y + diff.y,
|
isDragging,
|
||||||
isDragging,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
])
|
}))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -226,7 +209,7 @@ const createStore = () =>
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
updateUserSelection: (mousePos: XYPosition) => {
|
updateUserSelection: (mousePos: XYPosition) => {
|
||||||
const { userSelectionRect, nodes, edges, transform, selectedElements } = get();
|
const { userSelectionRect, nodes, edges, transform, onNodesChange, onEdgesChange } = get();
|
||||||
const startX = userSelectionRect.startX ?? 0;
|
const startX = userSelectionRect.startX ?? 0;
|
||||||
const startY = userSelectionRect.startY ?? 0;
|
const startY = userSelectionRect.startY ?? 0;
|
||||||
|
|
||||||
@@ -241,23 +224,21 @@ const createStore = () =>
|
|||||||
const selectedNodes = getNodesInside(nodes, nextUserSelectRect, transform, false, true);
|
const selectedNodes = getNodesInside(nodes, nextUserSelectRect, transform, false, true);
|
||||||
const selectedEdges = getConnectedEdges(selectedNodes, edges);
|
const selectedEdges = getConnectedEdges(selectedNodes, edges);
|
||||||
|
|
||||||
const nextSelectedElements = [...selectedNodes, ...selectedEdges];
|
if (selectedNodes?.length) {
|
||||||
const selectedElementsChanged = !isEqual(nextSelectedElements, selectedElements);
|
onNodesChange?.(selectedNodes.map((n) => ({ id: n.id, change: { selected: true } })));
|
||||||
|
|
||||||
if (selectedElementsChanged) {
|
|
||||||
set({
|
|
||||||
selectedElements: nextSelectedElements.length > 0 ? nextSelectedElements : null,
|
|
||||||
userSelectionRect: nextUserSelectRect,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
set({
|
|
||||||
userSelectionRect: nextUserSelectRect,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (selectedEdges?.length) {
|
||||||
|
onEdgesChange?.(selectedEdges.map((n) => ({ id: n.id, change: { selected: true } })));
|
||||||
|
}
|
||||||
|
|
||||||
|
set({
|
||||||
|
userSelectionRect: nextUserSelectRect,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
unsetUserSelection: () => {
|
unsetUserSelection: () => {
|
||||||
const { selectedElements, userSelectionRect } = get();
|
const { userSelectionRect, nodes } = get();
|
||||||
const selectedNodes = selectedElements?.filter((node) => isNode(node) && node.position) as Node[];
|
const selectedNodes = nodes.filter((node) => node.selected);
|
||||||
|
|
||||||
const stateUpdate = {
|
const stateUpdate = {
|
||||||
selectionActive: false,
|
selectionActive: false,
|
||||||
@@ -265,7 +246,6 @@ const createStore = () =>
|
|||||||
...userSelectionRect,
|
...userSelectionRect,
|
||||||
draw: false,
|
draw: false,
|
||||||
},
|
},
|
||||||
selectedElements: null,
|
|
||||||
selectedNodesBbox: { x: 0, y: 0, width: 0, height: 0 },
|
selectedNodesBbox: { x: 0, y: 0, width: 0, height: 0 },
|
||||||
nodesSelectionActive: false,
|
nodesSelectionActive: false,
|
||||||
};
|
};
|
||||||
@@ -278,28 +258,29 @@ const createStore = () =>
|
|||||||
|
|
||||||
set(stateUpdate);
|
set(stateUpdate);
|
||||||
},
|
},
|
||||||
setSelectedElements: (elements: Elements) => {
|
|
||||||
const { selectedElements } = get();
|
|
||||||
const selectedElementsArr = Array.isArray(elements) ? elements : [elements];
|
|
||||||
const selectedElementsUpdated = !isEqual(selectedElementsArr, selectedElements);
|
|
||||||
|
|
||||||
set({
|
|
||||||
selectedElements: selectedElementsUpdated ? selectedElementsArr : selectedElements,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
addSelectedElements: (elements: Elements) => {
|
addSelectedElements: (elements: Elements) => {
|
||||||
const { multiSelectionActive, selectedElements } = get();
|
const { multiSelectionActive, onNodesChange, onEdgesChange, nodes, edges } = get();
|
||||||
const selectedElementsArr = Array.isArray(elements) ? elements : [elements];
|
const selectedElementsArr = Array.isArray(elements) ? elements : [elements];
|
||||||
|
|
||||||
let nextElements = selectedElementsArr;
|
let selectedNodes;
|
||||||
|
let selectedEdges;
|
||||||
|
|
||||||
if (multiSelectionActive) {
|
if (multiSelectionActive) {
|
||||||
nextElements = selectedElements ? [...selectedElements, ...selectedElementsArr] : selectedElementsArr;
|
selectedNodes = selectedElementsArr.filter(isNode).map((node) => ({ id: node.id, change: { selected: true } }));
|
||||||
|
selectedEdges = selectedElementsArr.filter(isEdge).map((edge) => ({ id: edge.id, change: { selected: true } }));
|
||||||
|
} else {
|
||||||
|
selectedNodes = nodes.map((node) => ({
|
||||||
|
id: node.id,
|
||||||
|
change: { selected: selectedElementsArr.some((e) => e.id === node.id) },
|
||||||
|
}));
|
||||||
|
selectedEdges = edges.map((edge) => ({
|
||||||
|
id: edge.id,
|
||||||
|
change: { selected: selectedElementsArr.some((e) => e.id === edge.id) },
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectedElementsUpdated = !isEqual(nextElements, selectedElements);
|
onNodesChange?.(selectedNodes);
|
||||||
|
onEdgesChange?.(selectedEdges);
|
||||||
set({ selectedElements: selectedElementsUpdated ? nextElements : selectedElements });
|
|
||||||
},
|
},
|
||||||
initD3Zoom: ({ d3Zoom, d3Selection, d3ZoomHandler, transform }: InitD3ZoomPayload) => {
|
initD3Zoom: ({ d3Zoom, d3Selection, d3ZoomHandler, transform }: InitD3ZoomPayload) => {
|
||||||
set({
|
set({
|
||||||
@@ -334,77 +315,53 @@ const createStore = () =>
|
|||||||
return {
|
return {
|
||||||
...node,
|
...node,
|
||||||
position: clampPosition(node.position, nodeExtent),
|
position: clampPosition(node.position, nodeExtent),
|
||||||
__rf: {
|
|
||||||
...node.__rf,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
unsetNodesSelection: () => {
|
|
||||||
set({ nodesSelectionActive: false });
|
|
||||||
},
|
|
||||||
resetSelectedElements: () => {
|
resetSelectedElements: () => {
|
||||||
set({ selectedElements: null });
|
const { nodes, edges, onNodesChange, onEdgesChange } = get();
|
||||||
|
const selectedNodes = nodes
|
||||||
|
.filter((n) => n.selected)
|
||||||
|
.map((n) => ({
|
||||||
|
id: n.id,
|
||||||
|
change: { selected: false },
|
||||||
|
}));
|
||||||
|
|
||||||
|
const selectedEdges = edges
|
||||||
|
.filter((e) => e.selected)
|
||||||
|
.map((e) => ({
|
||||||
|
id: e.id,
|
||||||
|
change: { selected: false },
|
||||||
|
}));
|
||||||
|
|
||||||
|
onNodesChange?.(selectedNodes);
|
||||||
|
onEdgesChange?.(selectedEdges);
|
||||||
},
|
},
|
||||||
updateTransform: (transform: Transform) => {
|
unsetNodesSelection: () => set({ nodesSelectionActive: false }),
|
||||||
set({ transform });
|
updateTransform: (transform: Transform) => set({ transform }),
|
||||||
},
|
updateSize: (size: Dimensions) => set({ width: size.width || 500, height: size.height || 500 }),
|
||||||
updateSize: (size: Dimensions) => {
|
setOnConnect: (onConnect: OnConnectFunc) => set({ onConnect }),
|
||||||
set({ width: size.width || 500, height: size.height || 500 });
|
setOnConnectStart: (onConnectStart: OnConnectStartFunc) => set({ onConnectStart }),
|
||||||
},
|
setOnConnectStop: (onConnectStop: OnConnectStopFunc) => set({ onConnectStop }),
|
||||||
setOnConnect: (onConnect: OnConnectFunc) => {
|
setOnConnectEnd: (onConnectEnd: OnConnectEndFunc) => set({ onConnectEnd }),
|
||||||
set({ onConnect });
|
setConnectionPosition: (connectionPosition: XYPosition) => set({ connectionPosition }),
|
||||||
},
|
setConnectionNodeId: (params: SetConnectionId) => set({ ...params }),
|
||||||
setOnConnectStart: (onConnectStart: OnConnectStartFunc) => {
|
setSnapToGrid: (snapToGrid: boolean) => set({ snapToGrid }),
|
||||||
set({ onConnectStart });
|
setSnapGrid: (snapGrid: SnapGrid) => set({ snapGrid }),
|
||||||
},
|
setInteractive: (isInteractive: boolean) =>
|
||||||
setOnConnectStop: (onConnectStop: OnConnectStopFunc) => {
|
|
||||||
set({ onConnectStop });
|
|
||||||
},
|
|
||||||
setOnConnectEnd: (onConnectEnd: OnConnectEndFunc) => {
|
|
||||||
set({ onConnectEnd });
|
|
||||||
},
|
|
||||||
setConnectionPosition: (connectionPosition: XYPosition) => {
|
|
||||||
set({ connectionPosition });
|
|
||||||
},
|
|
||||||
setConnectionNodeId: (params: SetConnectionId) => {
|
|
||||||
set({ ...params });
|
|
||||||
},
|
|
||||||
setSnapToGrid: (snapToGrid: boolean) => {
|
|
||||||
set({ snapToGrid });
|
|
||||||
},
|
|
||||||
setSnapGrid: (snapGrid: SnapGrid) => {
|
|
||||||
set({ snapGrid });
|
|
||||||
},
|
|
||||||
setInteractive: (isInteractive: boolean) => {
|
|
||||||
set({
|
set({
|
||||||
nodesDraggable: isInteractive,
|
nodesDraggable: isInteractive,
|
||||||
nodesConnectable: isInteractive,
|
nodesConnectable: isInteractive,
|
||||||
elementsSelectable: isInteractive,
|
elementsSelectable: isInteractive,
|
||||||
});
|
}),
|
||||||
},
|
setNodesDraggable: (nodesDraggable: boolean) => set({ nodesDraggable }),
|
||||||
setNodesDraggable: (nodesDraggable: boolean) => {
|
setNodesConnectable: (nodesConnectable: boolean) => set({ nodesConnectable }),
|
||||||
set({ nodesDraggable });
|
setElementsSelectable: (elementsSelectable: boolean) => set({ elementsSelectable }),
|
||||||
},
|
setMultiSelectionActive: (multiSelectionActive: boolean) => set({ multiSelectionActive }),
|
||||||
setNodesConnectable: (nodesConnectable: boolean) => {
|
setConnectionMode: (connectionMode: ConnectionMode) => set({ connectionMode }),
|
||||||
set({ nodesConnectable });
|
setOnNodesChange: (onNodesChange: OnElementsChange) => set({ onNodesChange }),
|
||||||
},
|
setOnEdgesChange: (onEdgesChange: OnElementsChange) => set({ onEdgesChange }),
|
||||||
setElementsSelectable: (elementsSelectable: boolean) => {
|
|
||||||
set({ elementsSelectable });
|
|
||||||
},
|
|
||||||
setMultiSelectionActive: (multiSelectionActive: boolean) => {
|
|
||||||
set({ multiSelectionActive });
|
|
||||||
},
|
|
||||||
setConnectionMode: (connectionMode: ConnectionMode) => {
|
|
||||||
set({ connectionMode });
|
|
||||||
},
|
|
||||||
setOnNodesChange: (onNodesChange: OnElementsChange) => {
|
|
||||||
set({ onNodesChange });
|
|
||||||
},
|
|
||||||
setOnEdgesChange: (onEdgesChange: OnElementsChange) => {
|
|
||||||
set({ onEdgesChange });
|
|
||||||
},
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export { Provider, useStore, createStore, useStoreApi };
|
export { Provider, useStore, createStore, useStoreApi };
|
||||||
|
|||||||
+2
-2
@@ -60,6 +60,7 @@ export interface Node<T = any> {
|
|||||||
width?: number | null;
|
width?: number | null;
|
||||||
height?: number | null;
|
height?: number | null;
|
||||||
handleBounds?: any;
|
handleBounds?: any;
|
||||||
|
selected?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ArrowHeadType {
|
export enum ArrowHeadType {
|
||||||
@@ -88,6 +89,7 @@ export interface Edge<T = any> {
|
|||||||
className?: string;
|
className?: string;
|
||||||
sourceNode?: Node;
|
sourceNode?: Node;
|
||||||
targetNode?: Node;
|
targetNode?: Node;
|
||||||
|
selected?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum BackgroundVariant {
|
export enum BackgroundVariant {
|
||||||
@@ -418,7 +420,6 @@ export interface ReactFlowState {
|
|||||||
transform: Transform;
|
transform: Transform;
|
||||||
nodes: Node[];
|
nodes: Node[];
|
||||||
edges: Edge[];
|
edges: Edge[];
|
||||||
selectedElements: Elements | null;
|
|
||||||
selectedNodesBbox: Rect;
|
selectedNodesBbox: Rect;
|
||||||
onNodesChange: OnElementsChange | null;
|
onNodesChange: OnElementsChange | null;
|
||||||
onEdgesChange: OnElementsChange | null;
|
onEdgesChange: OnElementsChange | null;
|
||||||
@@ -462,7 +463,6 @@ export interface ReactFlowState {
|
|||||||
unsetUserSelection: () => void;
|
unsetUserSelection: () => void;
|
||||||
unsetNodesSelection: () => void;
|
unsetNodesSelection: () => void;
|
||||||
resetSelectedElements: () => void;
|
resetSelectedElements: () => void;
|
||||||
setSelectedElements: (elements: Elements) => void;
|
|
||||||
addSelectedElements: (elements: Elements) => void;
|
addSelectedElements: (elements: Elements) => void;
|
||||||
updateTransform: (transform: Transform) => void;
|
updateTransform: (transform: Transform) => void;
|
||||||
updateSize: (size: Dimensions) => void;
|
updateSize: (size: Dimensions) => void;
|
||||||
|
|||||||
Reference in New Issue
Block a user