From 423f45e0c92ae44bc73516edeebaf7cc1055b3c0 Mon Sep 17 00:00:00 2001 From: pengfu Date: Sat, 17 Sep 2022 21:35:22 +0800 Subject: [PATCH 1/4] feature(deleteSelectedElements): add `deleteSelectedElements` method --- example/src/Basic/index.tsx | 7 ++- src/hooks/useGlobalKeyHandler.ts | 81 +++----------------------- src/hooks/useReactFlow.ts | 97 +++++++++++++++++++++++++++++++- src/types/instance.ts | 2 + 4 files changed, 110 insertions(+), 77 deletions(-) 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; From f39936e5084a8b87933cd8e7aff91016d3fe0b55 Mon Sep 17 00:00:00 2001 From: chang_su Date: Mon, 24 Oct 2022 23:37:46 +0800 Subject: [PATCH 2/4] feature(deleteElements): add deleteElements method --- .../vite-app/src/examples/Basic/index.tsx | 5 -- .../src/examples/UseReactFlow/index.tsx | 21 +++++ .../core/src/hooks/useGlobalKeyHandler.ts | 13 +++- packages/core/src/hooks/useReactFlow.ts | 77 +++++++++++++++++++ packages/core/src/types/instance.ts | 2 + 5 files changed, 111 insertions(+), 7 deletions(-) diff --git a/examples/vite-app/src/examples/Basic/index.tsx b/examples/vite-app/src/examples/Basic/index.tsx index f3f74dda..c157ce23 100644 --- a/examples/vite-app/src/examples/Basic/index.tsx +++ b/examples/vite-app/src/examples/Basic/index.tsx @@ -78,10 +78,6 @@ const BasicFlow = () => { ); }; - const deleteElements = () => { - instance.deleteSelectedElements() - } - return ( { toggle classnames - ); diff --git a/examples/vite-app/src/examples/UseReactFlow/index.tsx b/examples/vite-app/src/examples/UseReactFlow/index.tsx index 7133cec9..87a610b5 100644 --- a/examples/vite-app/src/examples/UseReactFlow/index.tsx +++ b/examples/vite-app/src/examples/UseReactFlow/index.tsx @@ -43,6 +43,7 @@ const initialNodes: Node[] = [ const initialEdges: Edge[] = [ { id: 'e1-2', source: '1', target: '2', animated: true }, { id: 'e1-3', source: '1', target: '3' }, + // { id: 'e3-4', source: '3', target: '4' } ]; let id = 5; @@ -64,6 +65,8 @@ const UseZoomPanHelperFlow = () => { addEdges, getNodes, getEdges, + deleteSelectedElements, + deleteElements } = useReactFlow(); const onPaneClick = useCallback( @@ -111,7 +114,22 @@ const UseZoomPanHelperFlow = () => { console.log('edges', 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(() => { + // called twice in strict mode of development mode addEdges({ id: 'e3-4', source: '3', target: '4' }); }, [addEdges]); @@ -137,6 +155,9 @@ const UseZoomPanHelperFlow = () => { + + + diff --git a/packages/core/src/hooks/useGlobalKeyHandler.ts b/packages/core/src/hooks/useGlobalKeyHandler.ts index 3d563941..52d918dc 100644 --- a/packages/core/src/hooks/useGlobalKeyHandler.ts +++ b/packages/core/src/hooks/useGlobalKeyHandler.ts @@ -12,14 +12,23 @@ interface HookParams { export default ({ deleteKeyCode, multiSelectionKeyCode }: HookParams): void => { const store = useStoreApi(); - const { deleteSelectedElements } = useReactFlow(); + const { deleteElements } = useReactFlow(); + // const { deleteSelectedElements } = useReactFlow(); const deleteKeyPressed = useKeyPress(deleteKeyCode); const multiSelectionKeyPressed = useKeyPress(multiSelectionKeyCode); useEffect(() => { 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]); diff --git a/packages/core/src/hooks/useReactFlow.ts b/packages/core/src/hooks/useReactFlow.ts index 76043a2e..0e1ed6bb 100644 --- a/packages/core/src/hooks/useReactFlow.ts +++ b/packages/core/src/hooks/useReactFlow.ts @@ -192,6 +192,81 @@ export default function useReactFlow(): ReactFlo } }, []); + const deleteElements = useCallback((nodeIds, edgeIds) => { + const { + nodeInternals, + edges, + hasDefaultNodes, + hasDefaultEdges, + onNodesDelete, + onEdgesDelete, + onNodesChange, + onEdgesChange, + } = store.getState(); + const nodes = Array.from(nodeInternals.values()); + const nodesToRemove = nodes.reduce((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((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 { ...viewportHelper, @@ -205,6 +280,7 @@ export default function useReactFlow(): ReactFlo addEdges, toObject, deleteSelectedElements, + deleteElements, }; }, [ viewportHelper, @@ -218,5 +294,6 @@ export default function useReactFlow(): ReactFlo addEdges, toObject, deleteSelectedElements, + deleteElements, ]); } diff --git a/packages/core/src/types/instance.ts b/packages/core/src/types/instance.ts index 058da326..deffc86c 100644 --- a/packages/core/src/types/instance.ts +++ b/packages/core/src/types/instance.ts @@ -25,6 +25,7 @@ export namespace Instance { export type AddEdges = (payload: Edge[] | Edge) => void; export type ToObject = () => ReactFlowJsonObject; export type DeleteSelectedElements = () => void; + export type DeleteElements = (nodeIds: string[], edgeIds: string[]) => void } export type ReactFlowInstance = { @@ -37,6 +38,7 @@ export type ReactFlowInstance = { addEdges: Instance.AddEdges; getEdge: Instance.GetEdge; toObject: Instance.ToObject; + deleteElements: Instance.DeleteElements; deleteSelectedElements: Instance.DeleteSelectedElements; viewportInitialized: boolean; } & Omit; From b6ec8b70b20154a79c161462d80bd3d856a238da Mon Sep 17 00:00:00 2001 From: chang_su Date: Tue, 25 Oct 2022 14:43:44 +0800 Subject: [PATCH 3/4] chore: remove deleteSelectedElements method --- .../src/examples/UseReactFlow/index.tsx | 5 -- .../core/src/hooks/useGlobalKeyHandler.ts | 1 - packages/core/src/hooks/useReactFlow.ts | 80 ------------------- packages/core/src/types/instance.ts | 2 - 4 files changed, 88 deletions(-) diff --git a/examples/vite-app/src/examples/UseReactFlow/index.tsx b/examples/vite-app/src/examples/UseReactFlow/index.tsx index 87a610b5..eb83a88e 100644 --- a/examples/vite-app/src/examples/UseReactFlow/index.tsx +++ b/examples/vite-app/src/examples/UseReactFlow/index.tsx @@ -65,7 +65,6 @@ const UseZoomPanHelperFlow = () => { addEdges, getNodes, getEdges, - deleteSelectedElements, deleteElements } = useReactFlow(); @@ -120,10 +119,6 @@ const UseZoomPanHelperFlow = () => { deleteElements(selectedNodes, selectedEdges); }, [deleteElements, nodes, edges]) - const deleteSelectedElements2 = useCallback(() => { - deleteSelectedElements(); - }, [deleteSelectedElements]) - const deleteSomeElements = useCallback(() => { deleteElements(['2'],['e1-3']) }, []) diff --git a/packages/core/src/hooks/useGlobalKeyHandler.ts b/packages/core/src/hooks/useGlobalKeyHandler.ts index 52d918dc..345864a0 100644 --- a/packages/core/src/hooks/useGlobalKeyHandler.ts +++ b/packages/core/src/hooks/useGlobalKeyHandler.ts @@ -13,7 +13,6 @@ interface HookParams { export default ({ deleteKeyCode, multiSelectionKeyCode }: HookParams): void => { const store = useStoreApi(); const { deleteElements } = useReactFlow(); - // const { deleteSelectedElements } = useReactFlow(); const deleteKeyPressed = useKeyPress(deleteKeyCode); const multiSelectionKeyPressed = useKeyPress(multiSelectionKeyCode); diff --git a/packages/core/src/hooks/useReactFlow.ts b/packages/core/src/hooks/useReactFlow.ts index 0e1ed6bb..92480da2 100644 --- a/packages/core/src/hooks/useReactFlow.ts +++ b/packages/core/src/hooks/useReactFlow.ts @@ -114,84 +114,6 @@ 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 }); - } - }, []); - const deleteElements = useCallback((nodeIds, edgeIds) => { const { nodeInternals, @@ -279,7 +201,6 @@ export default function useReactFlow(): ReactFlo addNodes, addEdges, toObject, - deleteSelectedElements, deleteElements, }; }, [ @@ -293,7 +214,6 @@ export default function useReactFlow(): ReactFlo addNodes, addEdges, toObject, - deleteSelectedElements, deleteElements, ]); } diff --git a/packages/core/src/types/instance.ts b/packages/core/src/types/instance.ts index deffc86c..733b5392 100644 --- a/packages/core/src/types/instance.ts +++ b/packages/core/src/types/instance.ts @@ -24,7 +24,6 @@ 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 DeleteElements = (nodeIds: string[], edgeIds: string[]) => void } @@ -39,6 +38,5 @@ export type ReactFlowInstance = { getEdge: Instance.GetEdge; toObject: Instance.ToObject; deleteElements: Instance.DeleteElements; - deleteSelectedElements: Instance.DeleteSelectedElements; viewportInitialized: boolean; } & Omit; From a22229eb14a01e909c2c5f7fa9d8653d738f0ad9 Mon Sep 17 00:00:00 2001 From: chang_su Date: Tue, 25 Oct 2022 16:17:16 +0800 Subject: [PATCH 4/4] chore: update deleteElements param --- .../vite-app/src/examples/UseReactFlow/index.tsx | 14 ++++++-------- packages/core/src/hooks/useGlobalKeyHandler.ts | 6 +++--- packages/core/src/hooks/useReactFlow.ts | 4 +++- packages/core/src/types/instance.ts | 6 +++++- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/examples/vite-app/src/examples/UseReactFlow/index.tsx b/examples/vite-app/src/examples/UseReactFlow/index.tsx index eb83a88e..6fca9627 100644 --- a/examples/vite-app/src/examples/UseReactFlow/index.tsx +++ b/examples/vite-app/src/examples/UseReactFlow/index.tsx @@ -113,18 +113,17 @@ const UseZoomPanHelperFlow = () => { console.log('edges', 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); + const deleteSelectedElements = useCallback(() => { + const selectedNodes = nodes.filter(node => node.selected); + const selectedEdges = edges.filter(edge => edge.selected); + deleteElements({ nodes: selectedNodes, edges: selectedEdges }); }, [deleteElements, nodes, edges]) const deleteSomeElements = useCallback(() => { - deleteElements(['2'],['e1-3']) + deleteElements({ nodes: [{ id: '2' }], edges: [{ id: 'e1-3' }] }) }, []) useEffect(() => { - // called twice in strict mode of development mode addEdges({ id: 'e3-4', source: '3', target: '4' }); }, [addEdges]); @@ -150,8 +149,7 @@ const UseZoomPanHelperFlow = () => { - - + diff --git a/packages/core/src/hooks/useGlobalKeyHandler.ts b/packages/core/src/hooks/useGlobalKeyHandler.ts index 2827d9cb..f2b206e7 100644 --- a/packages/core/src/hooks/useGlobalKeyHandler.ts +++ b/packages/core/src/hooks/useGlobalKeyHandler.ts @@ -20,9 +20,9 @@ export default ({ deleteKeyCode, multiSelectionKeyCode }: HookParams): void => { if (deleteKeyPressed) { 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); + const selectedNodes = nodes.filter((node) => node.selected); + const selectedEdges = edges.filter((edge) => edge.selected); + deleteElements({nodes: selectedNodes, edges: selectedEdges}); store.setState({ nodesSelectionActive: false }); } }, [deleteKeyPressed]); diff --git a/packages/core/src/hooks/useReactFlow.ts b/packages/core/src/hooks/useReactFlow.ts index 32f4ee86..77415b9b 100644 --- a/packages/core/src/hooks/useReactFlow.ts +++ b/packages/core/src/hooks/useReactFlow.ts @@ -114,7 +114,7 @@ export default function useReactFlow(): ReactFlo }; }, []); - const deleteElements = useCallback((nodeIds, edgeIds) => { + const deleteElements = useCallback(({ nodes: nodesDeleted, edges: edgesDeleted }) => { const { nodeInternals, edges, @@ -126,6 +126,8 @@ export default function useReactFlow(): ReactFlo onEdgesChange, } = store.getState(); const nodes = Array.from(nodeInternals.values()); + const nodeIds = (nodesDeleted || []).map((node) => node.id); + const edgeIds = (edgesDeleted || []).map((edge) => edge.id); const nodesToRemove = nodes.reduce((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; diff --git a/packages/core/src/types/instance.ts b/packages/core/src/types/instance.ts index 8548c9f3..0c7200d2 100644 --- a/packages/core/src/types/instance.ts +++ b/packages/core/src/types/instance.ts @@ -8,6 +8,10 @@ export type ReactFlowJsonObject = { viewport: Viewport; }; +export type DeleteElementsOptions = { + nodes?: (Partial & { id: Node['id'] })[], + edges?: (Partial & { id: Edge['id'] })[] +}; export namespace Instance { export type GetNodes = () => Node[]; export type SetNodes = ( @@ -22,7 +26,7 @@ export namespace Instance { export type GetEdge = (id: string) => Edge | undefined; export type AddEdges = (payload: Edge[] | Edge) => void; export type ToObject = () => ReactFlowJsonObject; - export type DeleteElements = (nodeIds: string[], edgeIds: string[]) => void + export type DeleteElements = ({ nodes, edges }: DeleteElementsOptions) => void; } export type ReactFlowInstance = {