feature(deleteElements): add deleteElements method

This commit is contained in:
chang_su
2022-10-24 23:37:46 +08:00
parent dc4c3217cb
commit f39936e508
5 changed files with 111 additions and 7 deletions
@@ -78,10 +78,6 @@ const BasicFlow = () => {
); );
}; };
const deleteElements = () => {
instance.deleteSelectedElements()
}
return ( return (
<ReactFlow <ReactFlow
defaultNodes={initialNodes} defaultNodes={initialNodes}
@@ -111,7 +107,6 @@ const BasicFlow = () => {
toggle classnames toggle classnames
</button> </button>
<button onClick={logToObject} style={{ marginRight: 5 }}>toObject</button> <button onClick={logToObject} style={{ marginRight: 5 }}>toObject</button>
<button onClick={deleteElements}>delete selected elements</button>
</div> </div>
</ReactFlow> </ReactFlow>
); );
@@ -43,6 +43,7 @@ const initialNodes: Node[] = [
const initialEdges: Edge[] = [ const initialEdges: Edge[] = [
{ id: 'e1-2', source: '1', target: '2', animated: true }, { id: 'e1-2', source: '1', target: '2', animated: true },
{ id: 'e1-3', source: '1', target: '3' }, { id: 'e1-3', source: '1', target: '3' },
// { id: 'e3-4', source: '3', target: '4' }
]; ];
let id = 5; let id = 5;
@@ -64,6 +65,8 @@ const UseZoomPanHelperFlow = () => {
addEdges, addEdges,
getNodes, getNodes,
getEdges, getEdges,
deleteSelectedElements,
deleteElements
} = useReactFlow(); } = useReactFlow();
const onPaneClick = useCallback( const onPaneClick = useCallback(
@@ -111,7 +114,22 @@ const UseZoomPanHelperFlow = () => {
console.log('edges', getEdges()); console.log('edges', getEdges());
}, [getNodes, getEdges]); }, [getNodes, getEdges]);
const deleteSelectedElements1 = useCallback(() => {
const selectedNodes = nodes.filter(node => node.selected).map(node => node.id);
const selectedEdges = edges.filter(edge => edge.selected).map(edge => edge.id);
deleteElements(selectedNodes, selectedEdges);
}, [deleteElements, nodes, edges])
const deleteSelectedElements2 = useCallback(() => {
deleteSelectedElements();
}, [deleteSelectedElements])
const deleteSomeElements = useCallback(() => {
deleteElements(['2'],['e1-3'])
}, [])
useEffect(() => { useEffect(() => {
// called twice in strict mode of development mode
addEdges({ id: 'e3-4', source: '3', target: '4' }); addEdges({ id: 'e3-4', source: '3', target: '4' });
}, [addEdges]); }, [addEdges]);
@@ -137,6 +155,9 @@ const UseZoomPanHelperFlow = () => {
<button onClick={onAddNode}>add node</button> <button onClick={onAddNode}>add node</button>
<button onClick={onResetNodes}>reset nodes</button> <button onClick={onResetNodes}>reset nodes</button>
<button onClick={logNodes}>useNodes</button> <button onClick={logNodes}>useNodes</button>
<button onClick={deleteSelectedElements1}>deleteSelectedElements1</button>
<button onClick={deleteSelectedElements2}>deleteSelectedElements2</button>
<button onClick={deleteSomeElements}>deleteSomeElements</button>
</div> </div>
<Background /> <Background />
<MiniMap /> <MiniMap />
+11 -2
View File
@@ -12,14 +12,23 @@ interface HookParams {
export default ({ deleteKeyCode, multiSelectionKeyCode }: HookParams): void => { export default ({ deleteKeyCode, multiSelectionKeyCode }: HookParams): void => {
const store = useStoreApi(); const store = useStoreApi();
const { deleteSelectedElements } = useReactFlow(); const { deleteElements } = useReactFlow();
// const { deleteSelectedElements } = useReactFlow();
const deleteKeyPressed = useKeyPress(deleteKeyCode); const deleteKeyPressed = useKeyPress(deleteKeyCode);
const multiSelectionKeyPressed = useKeyPress(multiSelectionKeyCode); const multiSelectionKeyPressed = useKeyPress(multiSelectionKeyCode);
useEffect(() => { useEffect(() => {
if (deleteKeyPressed) { if (deleteKeyPressed) {
deleteSelectedElements(); const {
nodeInternals,
edges,
} = store.getState();
const nodes = Array.from(nodeInternals.values());
const nodeIds = nodes.filter(node => node.selected).map(node => node.id);
const edgeIds = edges.filter(edge => edge.selected).map(edge => edge.id);
deleteElements(nodeIds, edgeIds);
store.setState({ nodesSelectionActive: false });
} }
}, [deleteKeyPressed]); }, [deleteKeyPressed]);
+77
View File
@@ -192,6 +192,81 @@ export default function useReactFlow<NodeData = any, EdgeData = any>(): ReactFlo
} }
}, []); }, []);
const deleteElements = useCallback<Instance.DeleteElements>((nodeIds, edgeIds) => {
const {
nodeInternals,
edges,
hasDefaultNodes,
hasDefaultEdges,
onNodesDelete,
onEdgesDelete,
onNodesChange,
onEdgesChange,
} = store.getState();
const nodes = Array.from(nodeInternals.values());
const nodesToRemove = nodes.reduce<Node[]>((res, node) => {
const parentHit = !nodeIds.includes(node.id) && node.parentNode && res.find((n) => n.id === node.parentNode);
const deletable = typeof node.deletable === 'boolean' ? node.deletable : true;
if (deletable && (nodeIds.includes(node.id) || parentHit)) {
res.push(node);
}
return res;
}, []);
const deletableEdges = edges.filter((e) => (typeof e.deletable === 'boolean' ? e.deletable : true));
const initialHitEdges = deletableEdges.filter((e) => edgeIds.includes(e.id));
if (nodesToRemove || initialHitEdges) {
const connectedEdges = getConnectedEdges(nodesToRemove, deletableEdges);
const edgesToRemove = [...initialHitEdges, ...connectedEdges];
const edgeIdsToRemove = edgesToRemove.reduce<string[]>((res, edge) => {
if (!res.includes(edge.id)) {
res.push(edge.id);
}
return res;
}, []);
if (hasDefaultEdges || hasDefaultNodes) {
if (hasDefaultEdges) {
store.setState({
edges: edges.filter((e) => !edgeIdsToRemove.includes(e.id)),
});
}
if (hasDefaultNodes) {
nodesToRemove.forEach((node) => {
nodeInternals.delete(node.id);
});
store.setState({
nodeInternals: new Map(nodeInternals),
});
}
}
if (edgeIdsToRemove.length > 0) {
onEdgesDelete?.(edgesToRemove);
if (onEdgesChange) {
onEdgesChange(
edgeIdsToRemove.map((id) => ({
id,
type: 'remove',
}))
);
}
}
if (nodesToRemove.length > 0) {
onNodesDelete?.(nodesToRemove);
if (onNodesChange) {
const nodeChanges: NodeChange[] = nodesToRemove.map((n) => ({ id: n.id, type: 'remove' }));
onNodesChange(nodeChanges);
}
}
}
}, []);
return useMemo(() => { return useMemo(() => {
return { return {
...viewportHelper, ...viewportHelper,
@@ -205,6 +280,7 @@ export default function useReactFlow<NodeData = any, EdgeData = any>(): ReactFlo
addEdges, addEdges,
toObject, toObject,
deleteSelectedElements, deleteSelectedElements,
deleteElements,
}; };
}, [ }, [
viewportHelper, viewportHelper,
@@ -218,5 +294,6 @@ export default function useReactFlow<NodeData = any, EdgeData = any>(): ReactFlo
addEdges, addEdges,
toObject, toObject,
deleteSelectedElements, deleteSelectedElements,
deleteElements,
]); ]);
} }
+2
View File
@@ -25,6 +25,7 @@ export namespace Instance {
export type AddEdges<EdgeData> = (payload: Edge<EdgeData>[] | Edge<EdgeData>) => void; export type AddEdges<EdgeData> = (payload: Edge<EdgeData>[] | Edge<EdgeData>) => void;
export type ToObject<NodeData = any, EdgeData = any> = () => ReactFlowJsonObject<NodeData, EdgeData>; export type ToObject<NodeData = any, EdgeData = any> = () => ReactFlowJsonObject<NodeData, EdgeData>;
export type DeleteSelectedElements = () => void; export type DeleteSelectedElements = () => void;
export type DeleteElements = (nodeIds: string[], edgeIds: string[]) => void
} }
export type ReactFlowInstance<NodeData = any, EdgeData = any> = { export type ReactFlowInstance<NodeData = any, EdgeData = any> = {
@@ -37,6 +38,7 @@ export type ReactFlowInstance<NodeData = any, EdgeData = any> = {
addEdges: Instance.AddEdges<EdgeData>; addEdges: Instance.AddEdges<EdgeData>;
getEdge: Instance.GetEdge<EdgeData>; getEdge: Instance.GetEdge<EdgeData>;
toObject: Instance.ToObject<NodeData, EdgeData>; toObject: Instance.ToObject<NodeData, EdgeData>;
deleteElements: Instance.DeleteElements;
deleteSelectedElements: Instance.DeleteSelectedElements; deleteSelectedElements: Instance.DeleteSelectedElements;
viewportInitialized: boolean; viewportInitialized: boolean;
} & Omit<ViewportHelperFunctions, 'initialized'>; } & Omit<ViewportHelperFunctions, 'initialized'>;