refactor(easy-peasy): return single values from useStoreState
This commit is contained in:
@@ -25,11 +25,9 @@ const defaultColors = {
|
|||||||
|
|
||||||
const Background = memo(
|
const Background = memo(
|
||||||
({ variant = BackgroundVariant.Dots, gap = 24, size = 0.5, color, style = {}, className = '' }: BackgroundProps) => {
|
({ variant = BackgroundVariant.Dots, gap = 24, size = 0.5, color, style = {}, className = '' }: BackgroundProps) => {
|
||||||
const {
|
const width = useStoreState((s) => s.width);
|
||||||
width,
|
const height = useStoreState((s) => s.height);
|
||||||
height,
|
const [x, y, scale] = useStoreState((s) => s.transform);
|
||||||
transform: [x, y, scale],
|
|
||||||
} = useStoreState((s) => s);
|
|
||||||
|
|
||||||
const bgClasses = classnames('react-flow__background', className);
|
const bgClasses = classnames('react-flow__background', className);
|
||||||
const bgColor = color ? color : defaultColors[variant];
|
const bgColor = color ? color : defaultColors[variant];
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ interface ControlProps extends React.HTMLAttributes<HTMLDivElement> {
|
|||||||
|
|
||||||
const Controls = ({ style, showZoom = true, showFitView = true, showInteractive = true, className }: ControlProps) => {
|
const Controls = ({ style, showZoom = true, showFitView = true, showInteractive = true, className }: ControlProps) => {
|
||||||
const setInteractive = useStoreActions((actions) => actions.setInteractive);
|
const setInteractive = useStoreActions((actions) => actions.setInteractive);
|
||||||
const { isInteractive } = useStoreState(({ isInteractive }) => ({ isInteractive }));
|
const isInteractive = useStoreState((s) => s.isInteractive);
|
||||||
const mapClasses: string = classnames('react-flow__controls', className);
|
const mapClasses: string = classnames('react-flow__controls', className);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -30,27 +30,23 @@ const MiniMap = ({
|
|||||||
nodeBorderRadius = 5,
|
nodeBorderRadius = 5,
|
||||||
maskColor = 'rgba(10, 10, 10, .25)',
|
maskColor = 'rgba(10, 10, 10, .25)',
|
||||||
}: MiniMapProps) => {
|
}: MiniMapProps) => {
|
||||||
const state = useStoreState(({ width, height, nodes, transform: [tX, tY, tScale] }) => ({
|
const containerWidth = useStoreState((s) => s.width);
|
||||||
width,
|
const containerHeight = useStoreState((s) => s.height);
|
||||||
height,
|
const [tX, tY, tScale] = useStoreState((s) => s.transform);
|
||||||
nodes,
|
const nodes = useStoreState((s) => s.nodes);
|
||||||
tX,
|
|
||||||
tY,
|
|
||||||
tScale,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const mapClasses = classnames('react-flow__minimap', className);
|
const mapClasses = classnames('react-flow__minimap', className);
|
||||||
const elementWidth = (style.width || baseStyle.width)! as number;
|
const elementWidth = (style.width || baseStyle.width)! as number;
|
||||||
const elementHeight = (style.height || baseStyle.height)! as number;
|
const elementHeight = (style.height || baseStyle.height)! as number;
|
||||||
const nodeColorFunc = (nodeColor instanceof Function ? nodeColor : () => nodeColor) as StringFunc;
|
const nodeColorFunc = (nodeColor instanceof Function ? nodeColor : () => nodeColor) as StringFunc;
|
||||||
const hasNodes = state.nodes && state.nodes.length;
|
const hasNodes = nodes && nodes.length;
|
||||||
|
|
||||||
const bb = getRectOfNodes(state.nodes);
|
const bb = getRectOfNodes(nodes);
|
||||||
const viewBB: Rect = {
|
const viewBB: Rect = {
|
||||||
x: -state.tX / state.tScale,
|
x: -tX / tScale,
|
||||||
y: -state.tY / state.tScale,
|
y: -tY / tScale,
|
||||||
width: state.width / state.tScale,
|
width: containerWidth / tScale,
|
||||||
height: state.height / state.tScale,
|
height: containerHeight / tScale,
|
||||||
};
|
};
|
||||||
|
|
||||||
const boundingRect = hasNodes ? getBoundsofRects(bb, viewBB) : viewBB;
|
const boundingRect = hasNodes ? getBoundsofRects(bb, viewBB) : viewBB;
|
||||||
@@ -79,7 +75,7 @@ const MiniMap = ({
|
|||||||
}}
|
}}
|
||||||
className={mapClasses}
|
className={mapClasses}
|
||||||
>
|
>
|
||||||
{state.nodes.map((node) => (
|
{nodes.map((node) => (
|
||||||
<MiniMapNode key={node.id} node={node} color={nodeColorFunc(node)} borderRadius={nodeBorderRadius} />
|
<MiniMapNode key={node.id} node={node} color={nodeColorFunc(node)} borderRadius={nodeBorderRadius} />
|
||||||
))}
|
))}
|
||||||
<path
|
<path
|
||||||
|
|||||||
@@ -30,30 +30,28 @@ function getStartPositions(nodes: Node[]): StartPositions {
|
|||||||
export default memo(() => {
|
export default memo(() => {
|
||||||
const [offset, setOffset] = useState<XYPosition>({ x: 0, y: 0 });
|
const [offset, setOffset] = useState<XYPosition>({ x: 0, y: 0 });
|
||||||
const [startPositions, setStartPositions] = useState<StartPositions>({});
|
const [startPositions, setStartPositions] = useState<StartPositions>({});
|
||||||
const state = useStoreState((s) => ({
|
const [tX, tY, tScale] = useStoreState((s) => s.transform);
|
||||||
transform: s.transform,
|
const selectedNodesBbox = useStoreState((s) => s.selectedNodesBbox);
|
||||||
selectedNodesBbox: s.selectedNodesBbox,
|
const selectedElements = useStoreState((s) => s.selectedElements);
|
||||||
selectedElements: s.selectedElements,
|
const snapToGrid = useStoreState((s) => s.snapToGrid);
|
||||||
snapToGrid: s.snapToGrid,
|
const snapGrid = useStoreState((s) => s.snapGrid);
|
||||||
snapGrid: s.snapGrid,
|
const nodes = useStoreState((s) => s.nodes);
|
||||||
nodes: s.nodes,
|
|
||||||
}));
|
|
||||||
const updateNodePos = useStoreActions((a) => a.updateNodePos);
|
const updateNodePos = useStoreActions((a) => a.updateNodePos);
|
||||||
const [tx, ty, tScale] = state.transform;
|
const position = selectedNodesBbox;
|
||||||
const position = state.selectedNodesBbox;
|
const grid = (snapToGrid ? snapGrid : [1, 1])! as [number, number];
|
||||||
const grid = (state.snapToGrid ? state.snapGrid : [1, 1])! as [number, number];
|
|
||||||
|
|
||||||
const onStart = (evt: MouseEvent) => {
|
const onStart = (evt: MouseEvent) => {
|
||||||
const scaledClient: XYPosition = {
|
const scaledClient: XYPosition = {
|
||||||
x: evt.clientX / tScale,
|
x: evt.clientX / tScale,
|
||||||
y: evt.clientY / tScale,
|
y: evt.clientY / tScale,
|
||||||
};
|
};
|
||||||
const offsetX: number = scaledClient.x - position.x - tx;
|
const offsetX: number = scaledClient.x - position.x - tX;
|
||||||
const offsetY: number = scaledClient.y - position.y - ty;
|
const offsetY: number = scaledClient.y - position.y - tY;
|
||||||
const selectedNodes = state.selectedElements
|
const selectedNodes = selectedElements
|
||||||
? (state.selectedElements.filter(isNode) as Node[]).map(
|
? selectedElements
|
||||||
(selectedNode) => state.nodes.find((node) => node.id === selectedNode.id)! as Node
|
.filter(isNode)
|
||||||
)
|
.map((selectedNode) => nodes.find((node) => node.id === selectedNode.id)! as Node)
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
const nextStartPositions = getStartPositions(selectedNodes);
|
const nextStartPositions = getStartPositions(selectedNodes);
|
||||||
@@ -70,11 +68,11 @@ export default memo(() => {
|
|||||||
y: evt.clientY / tScale,
|
y: evt.clientY / tScale,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (state.selectedElements) {
|
if (selectedElements) {
|
||||||
(state.selectedElements.filter(isNode) as Node[]).forEach((node) => {
|
selectedElements.filter(isNode).forEach((node) => {
|
||||||
const pos: XYPosition = {
|
const pos: XYPosition = {
|
||||||
x: startPositions[node.id].x + scaledClient.x - position.x - offset.x - tx,
|
x: startPositions[node.id].x + scaledClient.x - position.x - offset.x - tX,
|
||||||
y: startPositions[node.id].y + scaledClient.y - position.y - offset.y - ty,
|
y: startPositions[node.id].y + scaledClient.y - position.y - offset.y - tY,
|
||||||
};
|
};
|
||||||
|
|
||||||
updateNodePos({ id: node.id, pos });
|
updateNodePos({ id: node.id, pos });
|
||||||
@@ -86,7 +84,7 @@ export default memo(() => {
|
|||||||
<div
|
<div
|
||||||
className="react-flow__nodesselection"
|
className="react-flow__nodesselection"
|
||||||
style={{
|
style={{
|
||||||
transform: `translate(${tx}px,${ty}px) scale(${tScale})`,
|
transform: `translate(${tX}px,${tY}px) scale(${tScale})`,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ReactDraggable
|
<ReactDraggable
|
||||||
@@ -98,10 +96,10 @@ export default memo(() => {
|
|||||||
<div
|
<div
|
||||||
className="react-flow__nodesselection-rect"
|
className="react-flow__nodesselection-rect"
|
||||||
style={{
|
style={{
|
||||||
width: state.selectedNodesBbox.width,
|
width: selectedNodesBbox.width,
|
||||||
height: state.selectedNodesBbox.height,
|
height: selectedNodesBbox.height,
|
||||||
top: state.selectedNodesBbox.y,
|
top: selectedNodesBbox.y,
|
||||||
left: state.selectedNodesBbox.x,
|
left: selectedNodesBbox.x,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</ReactDraggable>
|
</ReactDraggable>
|
||||||
|
|||||||
@@ -187,23 +187,13 @@ function renderEdge(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const EdgeRenderer = memo((props: EdgeRendererProps) => {
|
const EdgeRenderer = memo((props: EdgeRendererProps) => {
|
||||||
const {
|
const [tX, tY, tScale] = useStoreState((s) => s.transform);
|
||||||
transform,
|
const edges = useStoreState((s) => s.edges);
|
||||||
edges,
|
const nodes = useStoreState((s) => s.nodes);
|
||||||
nodes,
|
const connectionSourceId = useStoreState((s) => s.connectionSourceId);
|
||||||
connectionSourceId,
|
const connectionPosition = useStoreState((s) => s.connectionPosition);
|
||||||
connectionPosition: { x, y },
|
const selectedElements = useStoreState((s) => s.selectedElements);
|
||||||
selectedElements,
|
const isInteractive = useStoreState((s) => s.isInteractive);
|
||||||
isInteractive,
|
|
||||||
} = useStoreState((s) => ({
|
|
||||||
transform: s.transform,
|
|
||||||
edges: s.edges,
|
|
||||||
nodes: s.nodes,
|
|
||||||
connectionSourceId: s.connectionSourceId,
|
|
||||||
connectionPosition: s.connectionPosition,
|
|
||||||
selectedElements: s.selectedElements,
|
|
||||||
isInteractive: s.isInteractive,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const { width, height, connectionLineStyle, connectionLineType } = props;
|
const { width, height, connectionLineStyle, connectionLineType } = props;
|
||||||
|
|
||||||
@@ -211,8 +201,7 @@ const EdgeRenderer = memo((props: EdgeRendererProps) => {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [tx, ty, tScale] = transform;
|
const transformStyle = `translate(${tX},${tY}) scale(${tScale})`;
|
||||||
const transformStyle = `translate(${tx},${ty}) scale(${tScale})`;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<svg width={width} height={height} className="react-flow__edges">
|
<svg width={width} height={height} className="react-flow__edges">
|
||||||
@@ -222,9 +211,9 @@ const EdgeRenderer = memo((props: EdgeRendererProps) => {
|
|||||||
<ConnectionLine
|
<ConnectionLine
|
||||||
nodes={nodes}
|
nodes={nodes}
|
||||||
connectionSourceId={connectionSourceId}
|
connectionSourceId={connectionSourceId}
|
||||||
connectionPositionX={x}
|
connectionPositionX={connectionPosition.x}
|
||||||
connectionPositionY={y}
|
connectionPositionY={connectionPosition.y}
|
||||||
transform={transform}
|
transform={[tX, tY, tScale]}
|
||||||
connectionLineStyle={connectionLineStyle}
|
connectionLineStyle={connectionLineStyle}
|
||||||
connectionLineType={connectionLineType}
|
connectionLineType={connectionLineType}
|
||||||
isInteractive={isInteractive}
|
isInteractive={isInteractive}
|
||||||
|
|||||||
@@ -58,14 +58,11 @@ const GraphView = memo(
|
|||||||
}: GraphViewProps) => {
|
}: GraphViewProps) => {
|
||||||
const zoomPane = useRef<HTMLDivElement>(null);
|
const zoomPane = useRef<HTMLDivElement>(null);
|
||||||
const rendererNode = useRef<HTMLDivElement>(null);
|
const rendererNode = useRef<HTMLDivElement>(null);
|
||||||
const state = useStoreState((s) => ({
|
const width = useStoreState((s) => s.width);
|
||||||
width: s.width,
|
const height = useStoreState((s) => s.height);
|
||||||
height: s.height,
|
const d3Initialised = useStoreState((s) => s.d3Initialised);
|
||||||
nodes: s.nodes,
|
const nodesSelectionActive = useStoreState((s) => s.nodesSelectionActive);
|
||||||
edges: s.edges,
|
|
||||||
d3Initialised: s.d3Initialised,
|
|
||||||
nodesSelectionActive: s.nodesSelectionActive,
|
|
||||||
}));
|
|
||||||
const updateSize = useStoreActions((actions) => actions.updateSize);
|
const updateSize = useStoreActions((actions) => actions.updateSize);
|
||||||
const setNodesSelection = useStoreActions((actions) => actions.setNodesSelection);
|
const setNodesSelection = useStoreActions((actions) => actions.setNodesSelection);
|
||||||
const setOnConnect = useStoreActions((a) => a.setOnConnect);
|
const setOnConnect = useStoreActions((a) => a.setOnConnect);
|
||||||
@@ -106,7 +103,7 @@ const GraphView = memo(
|
|||||||
useD3Zoom({ zoomPane, onMove, selectionKeyPressed });
|
useD3Zoom({ zoomPane, onMove, selectionKeyPressed });
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (state.d3Initialised && onLoad) {
|
if (d3Initialised && onLoad) {
|
||||||
onLoad({
|
onLoad({
|
||||||
fitView,
|
fitView,
|
||||||
zoomIn,
|
zoomIn,
|
||||||
@@ -114,7 +111,7 @@ const GraphView = memo(
|
|||||||
project,
|
project,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [state.d3Initialised, onLoad]);
|
}, [d3Initialised, onLoad]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSnapGrid({ snapToGrid, snapGrid });
|
setSnapGrid({ snapToGrid, snapGrid });
|
||||||
@@ -137,15 +134,15 @@ const GraphView = memo(
|
|||||||
onlyRenderVisibleNodes={onlyRenderVisibleNodes}
|
onlyRenderVisibleNodes={onlyRenderVisibleNodes}
|
||||||
/>
|
/>
|
||||||
<EdgeRenderer
|
<EdgeRenderer
|
||||||
width={state.width}
|
width={width}
|
||||||
height={state.height}
|
height={height}
|
||||||
edgeTypes={edgeTypes}
|
edgeTypes={edgeTypes}
|
||||||
onElementClick={onElementClick}
|
onElementClick={onElementClick}
|
||||||
connectionLineType={connectionLineType}
|
connectionLineType={connectionLineType}
|
||||||
connectionLineStyle={connectionLineStyle}
|
connectionLineStyle={connectionLineStyle}
|
||||||
/>
|
/>
|
||||||
{selectionKeyPressed && <UserSelection isInteractive={isInteractive} />}
|
{selectionKeyPressed && <UserSelection isInteractive={isInteractive} />}
|
||||||
{state.nodesSelectionActive && <NodesSelection />}
|
{nodesSelectionActive && <NodesSelection />}
|
||||||
<div className="react-flow__zoompane" onClick={onZoomPaneClick} ref={zoomPane} />
|
<div className="react-flow__zoompane" onClick={onZoomPaneClick} ref={zoomPane} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -49,18 +49,15 @@ function renderNode(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const NodeRenderer = memo(({ onlyRenderVisibleNodes = true, ...props }: NodeRendererProps) => {
|
const NodeRenderer = memo(({ onlyRenderVisibleNodes = true, ...props }: NodeRendererProps) => {
|
||||||
const { nodes, transform, selectedElements, width, height, isInteractive } = useStoreState((s) => ({
|
const nodes = useStoreState((s) => s.nodes);
|
||||||
nodes: s.nodes,
|
const transform = useStoreState((s) => s.transform);
|
||||||
transform: s.transform,
|
const selectedElements = useStoreState((s) => s.selectedElements);
|
||||||
selectedElements: s.selectedElements,
|
const width = useStoreState((s) => s.width);
|
||||||
width: s.width,
|
const height = useStoreState((s) => s.height);
|
||||||
height: s.height,
|
const isInteractive = useStoreState((s) => s.isInteractive);
|
||||||
isInteractive: s.isInteractive,
|
const [tX, tY, tScale] = transform;
|
||||||
}));
|
|
||||||
|
|
||||||
const [tx, ty, tScale] = transform;
|
|
||||||
const transformStyle = {
|
const transformStyle = {
|
||||||
transform: `translate(${tx}px,${ty}px) scale(${tScale})`,
|
transform: `translate(${tX}px,${tY}px) scale(${tScale})`,
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderNodes = onlyRenderVisibleNodes
|
const renderNodes = onlyRenderVisibleNodes
|
||||||
|
|||||||
+8
-14
@@ -1,5 +1,5 @@
|
|||||||
import { useEffect, MutableRefObject } from 'react';
|
import { useEffect, MutableRefObject } from 'react';
|
||||||
import * as d3Zoom from 'd3-zoom';
|
import { zoom, zoomIdentity } from 'd3-zoom';
|
||||||
import { select, event } from 'd3-selection';
|
import { select, event } from 'd3-selection';
|
||||||
|
|
||||||
import { useStoreState, useStoreActions } from '../store/hooks';
|
import { useStoreState, useStoreActions } from '../store/hooks';
|
||||||
@@ -10,17 +10,14 @@ interface UseD3ZoomParams {
|
|||||||
onMove?: () => void;
|
onMove?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const d3ZoomInstance = d3Zoom
|
const d3ZoomInstance = zoom()
|
||||||
.zoom()
|
|
||||||
.scaleExtent([0.5, 2])
|
.scaleExtent([0.5, 2])
|
||||||
.filter(() => !event.button);
|
.filter(() => !event.button);
|
||||||
|
|
||||||
export default ({ zoomPane, onMove, selectionKeyPressed }: UseD3ZoomParams): void => {
|
export default ({ zoomPane, onMove, selectionKeyPressed }: UseD3ZoomParams): void => {
|
||||||
const state = useStoreState((s) => ({
|
const transform = useStoreState((s) => s.transform);
|
||||||
transform: s.transform,
|
const d3Selection = useStoreState((s) => s.d3Selection);
|
||||||
d3Selection: s.d3Selection,
|
const d3Zoom = useStoreState((s) => s.d3Zoom);
|
||||||
d3Zoom: s.d3Zoom,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const initD3 = useStoreActions((actions) => actions.initD3);
|
const initD3 = useStoreActions((actions) => actions.initD3);
|
||||||
const updateTransform = useStoreActions((actions) => actions.updateTransform);
|
const updateTransform = useStoreActions((actions) => actions.updateTransform);
|
||||||
@@ -48,13 +45,10 @@ export default ({ zoomPane, onMove, selectionKeyPressed }: UseD3ZoomParams): voi
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (state.d3Selection && state.d3Zoom) {
|
if (d3Selection && d3Zoom) {
|
||||||
// we need to restore the graph transform otherwise d3 zoom transform and graph transform are not synced
|
// we need to restore the graph transform otherwise d3 zoom transform and graph transform are not synced
|
||||||
const graphTransform = d3Zoom.zoomIdentity
|
const graphTransform = zoomIdentity.translate(transform[0], transform[1]).scale(transform[2]);
|
||||||
.translate(state.transform[0], state.transform[1])
|
d3Selection.call(d3Zoom.transform, graphTransform);
|
||||||
.scale(state.transform[2]);
|
|
||||||
|
|
||||||
state.d3Selection.call(state.d3Zoom.transform, graphTransform);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,13 +6,8 @@ import { parseElement, isNode, isEdge } from '../utils/graph';
|
|||||||
import { Elements, Node, Edge } from '../types';
|
import { Elements, Node, Edge } from '../types';
|
||||||
|
|
||||||
const useElementUpdater = (elements: Elements): void => {
|
const useElementUpdater = (elements: Elements): void => {
|
||||||
const state = useStoreState((s) => ({
|
const stateNodes = useStoreState((s) => s.nodes);
|
||||||
nodes: s.nodes,
|
const stateEdges = useStoreState((s) => s.edges);
|
||||||
edges: s.edges,
|
|
||||||
transform: s.transform,
|
|
||||||
snapToGrid: s.snapToGrid,
|
|
||||||
snapGrid: s.snapGrid,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const setNodes = useStoreActions((a) => a.setNodes);
|
const setNodes = useStoreActions((a) => a.setNodes);
|
||||||
const setEdges = useStoreActions((a) => a.setEdges);
|
const setEdges = useStoreActions((a) => a.setEdges);
|
||||||
@@ -22,7 +17,7 @@ const useElementUpdater = (elements: Elements): void => {
|
|||||||
const edges: Edge[] = elements.filter(isEdge).map((e) => parseElement(e) as Edge);
|
const edges: Edge[] = elements.filter(isEdge).map((e) => parseElement(e) as Edge);
|
||||||
|
|
||||||
const nextNodes: Node[] = nodes.map((propNode) => {
|
const nextNodes: Node[] = nodes.map((propNode) => {
|
||||||
const existingNode = state.nodes.find((n) => n.id === propNode.id);
|
const existingNode = stateNodes.find((n) => n.id === propNode.id);
|
||||||
|
|
||||||
if (existingNode) {
|
if (existingNode) {
|
||||||
const data = !isEqual(existingNode.data, propNode.data)
|
const data = !isEqual(existingNode.data, propNode.data)
|
||||||
@@ -59,8 +54,8 @@ const useElementUpdater = (elements: Elements): void => {
|
|||||||
return parseElement(propNode) as Node;
|
return parseElement(propNode) as Node;
|
||||||
});
|
});
|
||||||
|
|
||||||
const nodesChanged: boolean = !isEqual(state.nodes, nextNodes);
|
const nodesChanged: boolean = !isEqual(stateNodes, nextNodes);
|
||||||
const edgesChanged: boolean = !isEqual(state.edges, edges);
|
const edgesChanged: boolean = !isEqual(stateEdges, edges);
|
||||||
|
|
||||||
if (nodesChanged) {
|
if (nodesChanged) {
|
||||||
setNodes(nextNodes);
|
setNodes(nextNodes);
|
||||||
@@ -69,7 +64,7 @@ const useElementUpdater = (elements: Elements): void => {
|
|||||||
if (edgesChanged) {
|
if (edgesChanged) {
|
||||||
setEdges(edges);
|
setEdges(edges);
|
||||||
}
|
}
|
||||||
}, [elements, state.nodes, state.edges]);
|
}, [elements, stateNodes, stateEdges]);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useElementUpdater;
|
export default useElementUpdater;
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import { useEffect } from 'react';
|
|||||||
|
|
||||||
import { useStoreState, useStoreActions } from '../store/hooks';
|
import { useStoreState, useStoreActions } from '../store/hooks';
|
||||||
import useKeyPress from './useKeyPress';
|
import useKeyPress from './useKeyPress';
|
||||||
import { isEdge, getConnectedEdges } from '../utils/graph';
|
import { isNode, getConnectedEdges } from '../utils/graph';
|
||||||
import { Elements, Node } from '../types';
|
import { Elements } from '../types';
|
||||||
|
|
||||||
interface HookParams {
|
interface HookParams {
|
||||||
deleteKeyCode: number;
|
deleteKeyCode: number;
|
||||||
@@ -11,22 +11,21 @@ interface HookParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default ({ deleteKeyCode, onElementsRemove }: HookParams): void => {
|
export default ({ deleteKeyCode, onElementsRemove }: HookParams): void => {
|
||||||
const state = useStoreState((s) => ({
|
const selectedElements = useStoreState((s) => s.selectedElements);
|
||||||
selectedElements: s.selectedElements,
|
const edges = useStoreState((s) => s.edges);
|
||||||
edges: s.edges,
|
|
||||||
}));
|
|
||||||
const setNodesSelection = useStoreActions((a) => a.setNodesSelection);
|
const setNodesSelection = useStoreActions((a) => a.setNodesSelection);
|
||||||
const deleteKeyPressed = useKeyPress(deleteKeyCode);
|
const deleteKeyPressed = useKeyPress(deleteKeyCode);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (onElementsRemove && deleteKeyPressed && state.selectedElements) {
|
if (onElementsRemove && deleteKeyPressed && selectedElements) {
|
||||||
let elementsToRemove = state.selectedElements;
|
let elementsToRemove = selectedElements;
|
||||||
|
|
||||||
// we also want to remove the edges if only one node is selected
|
// we also want to remove the edges if only one node is selected
|
||||||
if (state.selectedElements.length === 1 && !isEdge(state.selectedElements[0])) {
|
if (selectedElements.length === 1 && isNode(selectedElements[0])) {
|
||||||
const node = (state.selectedElements[0] as unknown) as Node;
|
const node = selectedElements[0];
|
||||||
const connectedEdges = getConnectedEdges([node], state.edges);
|
const connectedEdges = getConnectedEdges([node], edges);
|
||||||
elementsToRemove = [...state.selectedElements, ...connectedEdges];
|
elementsToRemove = [...selectedElements, ...connectedEdges];
|
||||||
}
|
}
|
||||||
|
|
||||||
onElementsRemove(elementsToRemove);
|
onElementsRemove(elementsToRemove);
|
||||||
|
|||||||
Reference in New Issue
Block a user