diff --git a/examples/vite-app/src/examples/Basic/index.tsx b/examples/vite-app/src/examples/Basic/index.tsx
index 37c5d010..f3f74dda 100644
--- a/examples/vite-app/src/examples/Basic/index.tsx
+++ b/examples/vite-app/src/examples/Basic/index.tsx
@@ -78,6 +78,10 @@ const BasicFlow = () => {
);
};
+ const deleteElements = () => {
+ instance.deleteSelectedElements()
+ }
+
return (
{
-
+
+
);
diff --git a/packages/core/src/hooks/useGlobalKeyHandler.ts b/packages/core/src/hooks/useGlobalKeyHandler.ts
index 151c9786..3d563941 100644
--- a/packages/core/src/hooks/useGlobalKeyHandler.ts
+++ b/packages/core/src/hooks/useGlobalKeyHandler.ts
@@ -2,8 +2,8 @@ import { useEffect } from 'react';
import { useStoreApi } from '../hooks/useStore';
import useKeyPress from './useKeyPress';
-import { getConnectedEdges } from '../utils/graph';
-import { KeyCode, NodeChange, Node } from '../types';
+import { KeyCode } from '../types';
+import useReactFlow from './useReactFlow';
interface HookParams {
deleteKeyCode: KeyCode | null;
@@ -12,88 +12,14 @@ interface HookParams {
export default ({ deleteKeyCode, multiSelectionKeyCode }: HookParams): void => {
const store = useStoreApi();
+ const { deleteSelectedElements } = useReactFlow();
+
const deleteKeyPressed = useKeyPress(deleteKeyCode);
const multiSelectionKeyPressed = useKeyPress(multiSelectionKeyCode);
useEffect(() => {
- if (!deleteKeyPressed) {
- return;
- }
-
- const {
- nodeInternals,
- edges,
- hasDefaultNodes,
- hasDefaultEdges,
- onNodesDelete,
- onEdgesDelete,
- onNodesChange,
- onEdgesChange,
- } = store.getState();
- const nodes = Array.from(nodeInternals.values());
- const nodesToRemove = nodes.reduce((res, node) => {
- const parentSelected = !node.selected && node.parentNode && res.find((n) => n.id === node.parentNode);
- const deletable = typeof node.deletable === 'boolean' ? node.deletable : true;
- if (deletable && (node.selected || parentSelected)) {
- res.push(node);
- }
-
- return res;
- }, []);
- const deletableEdges = edges.filter((e) => (typeof e.deletable === 'boolean' ? e.deletable : true));
- const selectedEdges = deletableEdges.filter((e) => e.selected);
-
- if (nodesToRemove || selectedEdges) {
- const connectedEdges = getConnectedEdges(nodesToRemove, deletableEdges);
- const edgesToRemove = [...selectedEdges, ...connectedEdges];
- const edgeIdsToRemove = edgesToRemove.reduce((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);
- }
- }
-
- store.setState({ nodesSelectionActive: false });
+ if (deleteKeyPressed) {
+ deleteSelectedElements();
}
}, [deleteKeyPressed]);
diff --git a/packages/core/src/hooks/useReactFlow.ts b/packages/core/src/hooks/useReactFlow.ts
index ba826ddf..76043a2e 100644
--- a/packages/core/src/hooks/useReactFlow.ts
+++ b/packages/core/src/hooks/useReactFlow.ts
@@ -11,7 +11,10 @@ import {
EdgeResetChange,
NodeRemoveChange,
EdgeRemoveChange,
+ NodeChange,
+ Node,
} from '../types';
+import { getConnectedEdges } from '../utils/graph';
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
export default function useReactFlow(): ReactFlowInstance {
@@ -111,6 +114,84 @@ export default function useReactFlow(): ReactFlo
};
}, []);
+ const deleteSelectedElements = useCallback(() => {
+ const {
+ nodeInternals,
+ edges,
+ hasDefaultNodes,
+ hasDefaultEdges,
+ onNodesDelete,
+ onEdgesDelete,
+ onNodesChange,
+ onEdgesChange,
+ } = store.getState();
+ const nodes = Array.from(nodeInternals.values());
+ const nodesToRemove = nodes.reduce((res, node) => {
+ const parentSelected = !node.selected && node.parentNode && res.find((n) => n.id === node.parentNode);
+ const deletable = typeof node.deletable === 'boolean' ? node.deletable : true;
+ if (deletable && (node.selected || parentSelected)) {
+ res.push(node);
+ }
+
+ return res;
+ }, []);
+ const deletableEdges = edges.filter((e) => (typeof e.deletable === 'boolean' ? e.deletable : true));
+ const selectedEdges = deletableEdges.filter((e) => e.selected);
+
+ if (nodesToRemove || selectedEdges) {
+ const connectedEdges = getConnectedEdges(nodesToRemove, deletableEdges);
+ const edgesToRemove = [...selectedEdges, ...connectedEdges];
+ const edgeIdsToRemove = edgesToRemove.reduce((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);
+ }
+ }
+
+ store.setState({ nodesSelectionActive: false });
+ }
+ }, []);
+
return useMemo(() => {
return {
...viewportHelper,
@@ -123,6 +204,19 @@ export default function useReactFlow(): ReactFlo
addNodes,
addEdges,
toObject,
+ deleteSelectedElements,
};
- }, [viewportHelper, getNodes, getNode, getEdges, getEdge, setNodes, setEdges, addNodes, addEdges, toObject]);
+ }, [
+ viewportHelper,
+ getNodes,
+ getNode,
+ getEdges,
+ getEdge,
+ setNodes,
+ setEdges,
+ addNodes,
+ addEdges,
+ toObject,
+ deleteSelectedElements,
+ ]);
}
diff --git a/packages/core/src/types/instance.ts b/packages/core/src/types/instance.ts
index f5fe2848..058da326 100644
--- a/packages/core/src/types/instance.ts
+++ b/packages/core/src/types/instance.ts
@@ -24,6 +24,7 @@ export namespace Instance {
export type GetEdge = (id: string) => Edge | undefined;
export type AddEdges = (payload: Edge[] | Edge) => void;
export type ToObject = () => ReactFlowJsonObject;
+ export type DeleteSelectedElements = () => void;
}
export type ReactFlowInstance = {
@@ -36,5 +37,6 @@ export type ReactFlowInstance = {
addEdges: Instance.AddEdges;
getEdge: Instance.GetEdge;
toObject: Instance.ToObject;
+ deleteSelectedElements: Instance.DeleteSelectedElements;
viewportInitialized: boolean;
} & Omit;