diff --git a/example/src/Basic/index.tsx b/example/src/Basic/index.tsx
index 74d0f69b..7db68b3c 100644
--- a/example/src/Basic/index.tsx
+++ b/example/src/Basic/index.tsx
@@ -56,6 +56,10 @@ const BasicFlow = () => {
);
};
+ const deleteElements = () => {
+ instance.deleteSelectedElements()
+ }
+
return (
{
-
+
+
);
diff --git a/src/hooks/useGlobalKeyHandler.ts b/src/hooks/useGlobalKeyHandler.ts
index 8c9cb89d..e9574624 100644
--- a/src/hooks/useGlobalKeyHandler.ts
+++ b/src/hooks/useGlobalKeyHandler.ts
@@ -1,94 +1,27 @@
import { useEffect } from 'react';
-import shallow from 'zustand/shallow';
-import { useStore, useStoreApi } from '../store';
+import { useStoreApi } from '../store';
import useKeyPress from './useKeyPress';
-import { getConnectedEdges } from '../utils/graph';
-import { EdgeChange, KeyCode, NodeChange, Node, ReactFlowState } from '../types';
+import { KeyCode } from '../types';
+import useReactFlow from './useReactFlow';
interface HookParams {
deleteKeyCode: KeyCode | null;
multiSelectionKeyCode: KeyCode | null;
}
-const selector = (s: ReactFlowState) => ({
- onNodesChange: s.onNodesChange,
- onEdgesChange: s.onEdgesChange,
-});
-
export default ({ deleteKeyCode, multiSelectionKeyCode }: HookParams): void => {
const store = useStoreApi();
- const { onNodesChange, onEdgesChange } = useStore(selector, shallow);
+ const { deleteSelectedElements } = useReactFlow();
const deleteKeyPressed = useKeyPress(deleteKeyCode);
const multiSelectionKeyPressed = useKeyPress(multiSelectionKeyCode);
useEffect(() => {
- const { nodeInternals, edges, hasDefaultNodes, hasDefaultEdges, onNodesDelete, onEdgesDelete } = store.getState();
- const nodes = Array.from(nodeInternals.values());
- const nodesToRemove = nodes.reduce((res, node) => {
- if (!node.selected && node.parentNode && res.find((n) => n.id === node.parentNode)) {
- res.push(node);
- } else if (node.selected) {
- res.push(node);
- }
-
- return res;
- }, []);
- const selectedEdges = edges.filter((e) => e.selected);
-
- if (deleteKeyPressed && (nodesToRemove || selectedEdges)) {
- const connectedEdges = getConnectedEdges(nodesToRemove, edges);
- 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) {
- const edgeChanges: EdgeChange[] = edgeIdsToRemove.map((id) => ({
- id,
- type: 'remove',
- }));
- onEdgesChange(edgeChanges);
- }
- }
-
- 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, onNodesChange, onEdgesChange]);
+ }, [deleteKeyPressed]);
useEffect(() => {
store.setState({ multiSelectionActive: multiSelectionKeyPressed });
diff --git a/src/hooks/useReactFlow.ts b/src/hooks/useReactFlow.ts
index 3bffe8fa..ab8bc54e 100644
--- a/src/hooks/useReactFlow.ts
+++ b/src/hooks/useReactFlow.ts
@@ -1,7 +1,7 @@
import { useCallback, useMemo } from 'react';
import useViewportHelper from './useViewportHelper';
-import { useStoreApi } from '../store';
+import { useStore, useStoreApi } from '../store';
import {
ReactFlowInstance,
Instance,
@@ -11,12 +11,25 @@ import {
EdgeResetChange,
NodeRemoveChange,
EdgeRemoveChange,
+ ReactFlowState,
+ EdgeChange,
+ NodeChange,
+ Node,
} from '../types';
+import { getConnectedEdges } from '../utils/graph';
+import shallow from 'zustand/shallow';
+
+const selector = (s: ReactFlowState) => ({
+ onNodesChange: s.onNodesChange,
+ onEdgesChange: s.onEdgesChange,
+});
export default function useReactFlow(): ReactFlowInstance {
const viewportHelper = useViewportHelper();
const store = useStoreApi();
+ const { onNodesChange, onEdgesChange } = useStore(selector, shallow);
+
const getNodes = useCallback>(() => {
const { nodeInternals } = store.getState();
const nodes = Array.from(nodeInternals.values());
@@ -110,6 +123,73 @@ export default function useReactFlow(): ReactFlo
};
}, []);
+ const deleteSelectedElements = useCallback(() => {
+ const { nodeInternals, edges, hasDefaultNodes, hasDefaultEdges, onNodesDelete, onEdgesDelete } = store.getState();
+ const nodes = Array.from(nodeInternals.values());
+ const nodesToRemove = nodes.reduce((res, node) => {
+ if (!node.selected && node.parentNode && res.find((n) => n.id === node.parentNode)) {
+ res.push(node);
+ } else if (node.selected) {
+ res.push(node);
+ }
+
+ return res;
+ }, []);
+ const selectedEdges = edges.filter((e) => e.selected);
+
+ if (nodesToRemove || selectedEdges) {
+ const connectedEdges = getConnectedEdges(nodesToRemove, edges);
+ 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) {
+ const edgeChanges: EdgeChange[] = edgeIdsToRemove.map((id) => ({
+ id,
+ type: 'remove',
+ }));
+ onEdgesChange(edgeChanges);
+ }
+ }
+
+ 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,
@@ -122,6 +202,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/src/types/instance.ts b/src/types/instance.ts
index 14867f00..4d21af37 100644
--- a/src/types/instance.ts
+++ b/src/types/instance.ts
@@ -22,6 +22,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 = {
@@ -34,5 +35,6 @@ export type ReactFlowInstance = {
addEdges: Instance.AddEdges;
getEdge: Instance.GetEdge;
toObject: Instance.ToObject;
+ deleteSelectedElements: Instance.DeleteSelectedElements;
viewportInitialized: boolean;
} & Omit;