feat(deletion): add onBeforeDelete handler
This commit is contained in:
@@ -64,6 +64,7 @@ const reactFlowFieldsToTrack = [
|
||||
'isValidConnection',
|
||||
'selectNodesOnDrag',
|
||||
'nodeDragThreshold',
|
||||
'onBeforeDelete',
|
||||
] as const;
|
||||
|
||||
type ReactFlowFieldsToTrack = (typeof reactFlowFieldsToTrack)[number];
|
||||
|
||||
@@ -70,6 +70,7 @@ const ReactFlow = forwardRef<ReactFlowRefType, ReactFlowProps>(
|
||||
onSelectionContextMenu,
|
||||
onSelectionStart,
|
||||
onSelectionEnd,
|
||||
onBeforeDelete,
|
||||
connectionMode,
|
||||
connectionLineType = ConnectionLineType.Bezier,
|
||||
connectionLineStyle,
|
||||
@@ -284,6 +285,7 @@ const ReactFlow = forwardRef<ReactFlowRefType, ReactFlowProps>(
|
||||
isValidConnection={isValidConnection}
|
||||
selectNodesOnDrag={selectNodesOnDrag}
|
||||
nodeDragThreshold={nodeDragThreshold}
|
||||
onBeforeDelete={onBeforeDelete}
|
||||
/>
|
||||
<SelectionListener onSelectionChange={onSelectionChange} />
|
||||
{children}
|
||||
|
||||
@@ -30,8 +30,8 @@ export default ({
|
||||
|
||||
useEffect(() => {
|
||||
if (deleteKeyPressed) {
|
||||
const { edges, nodes } = store.getState();
|
||||
deleteElements({ nodes: nodes.filter(selected), edges: edges.filter(selected) });
|
||||
const { edges, nodes, onBeforeDelete } = store.getState();
|
||||
deleteElements({ nodes: nodes.filter(selected), edges: edges.filter(selected), onBeforeDelete });
|
||||
store.setState({ nodesSelectionActive: false });
|
||||
}
|
||||
}, [deleteKeyPressed]);
|
||||
|
||||
@@ -12,7 +12,6 @@ import type {
|
||||
EdgeResetChange,
|
||||
NodeRemoveChange,
|
||||
EdgeRemoveChange,
|
||||
NodeChange,
|
||||
Node,
|
||||
Edge,
|
||||
} from '../types';
|
||||
@@ -118,67 +117,65 @@ export default function useReactFlow<NodeType extends Node = Node, EdgeType exte
|
||||
};
|
||||
}, []);
|
||||
|
||||
const deleteElements = useCallback<Instance.DeleteElements>(({ nodes: nodesDeleted, edges: edgesDeleted }) => {
|
||||
const {
|
||||
nodes,
|
||||
edges,
|
||||
hasDefaultNodes,
|
||||
hasDefaultEdges,
|
||||
onNodesDelete,
|
||||
onEdgesDelete,
|
||||
onNodesChange,
|
||||
onEdgesChange,
|
||||
onDelete,
|
||||
} = store.getState();
|
||||
const { matchingNodes, matchingEdges } = getElementsToRemove<Node, Edge>({
|
||||
nodesToRemove: nodesDeleted || [],
|
||||
edgesToRemove: edgesDeleted || [],
|
||||
nodes,
|
||||
edges,
|
||||
});
|
||||
const deleteElements = useCallback<Instance.DeleteElements>(
|
||||
({ nodes: nodesToRemove = [], edges: edgesToRemove = [], onBeforeDelete }) => {
|
||||
const {
|
||||
nodes,
|
||||
edges,
|
||||
hasDefaultNodes,
|
||||
hasDefaultEdges,
|
||||
onNodesDelete,
|
||||
onEdgesDelete,
|
||||
onNodesChange,
|
||||
onEdgesChange,
|
||||
onDelete,
|
||||
} = store.getState();
|
||||
const { nodes: matchingNodes, edges: matchingEdges } = getElementsToRemove({
|
||||
nodesToRemove,
|
||||
edgesToRemove,
|
||||
nodes,
|
||||
edges,
|
||||
onBeforeDelete,
|
||||
});
|
||||
|
||||
if (matchingNodes.length || matchingEdges.length) {
|
||||
if (hasDefaultEdges || hasDefaultNodes) {
|
||||
const hasMatchingEdges = matchingEdges.length > 0;
|
||||
const hasMatchingNodes = matchingNodes.length > 0;
|
||||
|
||||
if (hasMatchingEdges) {
|
||||
if (hasDefaultEdges) {
|
||||
store.setState({
|
||||
edges: edges.filter((e) => !matchingEdges.some((mE) => mE.id === e.id)),
|
||||
});
|
||||
}
|
||||
|
||||
onEdgesDelete?.(matchingEdges);
|
||||
onEdgesChange?.(
|
||||
matchingEdges.map((edge) => ({
|
||||
id: edge.id,
|
||||
type: 'remove',
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
if (hasMatchingNodes) {
|
||||
if (hasDefaultNodes) {
|
||||
store.setState({
|
||||
nodes: nodes.filter((n) => !matchingNodes.some((mN) => mN.id === n.id)),
|
||||
});
|
||||
}
|
||||
|
||||
onNodesDelete?.(matchingNodes);
|
||||
onNodesChange?.(matchingNodes.map((node) => ({ id: node.id, type: 'remove' })));
|
||||
}
|
||||
|
||||
if (matchingEdges.length > 0) {
|
||||
onEdgesDelete?.(matchingEdges);
|
||||
|
||||
if (onEdgesChange) {
|
||||
onEdgesChange(
|
||||
matchingEdges.map((edge) => ({
|
||||
id: edge.id,
|
||||
type: 'remove',
|
||||
}))
|
||||
);
|
||||
}
|
||||
if (hasMatchingNodes || hasMatchingEdges) {
|
||||
onDelete?.({ nodes: matchingNodes, edges: matchingEdges });
|
||||
}
|
||||
|
||||
if (matchingNodes.length > 0) {
|
||||
onNodesDelete?.(matchingNodes as Node[]);
|
||||
|
||||
if (onNodesChange) {
|
||||
const nodeChanges: NodeChange[] = matchingNodes.map((node) => ({ id: node.id, type: 'remove' }));
|
||||
onNodesChange(nodeChanges);
|
||||
}
|
||||
}
|
||||
|
||||
onDelete?.({ nodes: matchingNodes, edges: matchingEdges });
|
||||
}
|
||||
|
||||
return { deletedNodes: matchingNodes, deletedEdges: matchingEdges };
|
||||
}, []);
|
||||
return { deletedNodes: matchingNodes, deletedEdges: matchingEdges };
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const getNodeRect = useCallback(
|
||||
(nodeOrRect: NodeType | { id: Node['id'] } | Rect): [Rect | null, NodeType | null | undefined, boolean] => {
|
||||
|
||||
@@ -79,6 +79,7 @@ export {
|
||||
type ColorMode,
|
||||
type ColorModeClass,
|
||||
type HandleType,
|
||||
type OnBeforeDelete,
|
||||
} from '@xyflow/system';
|
||||
|
||||
// system utils
|
||||
|
||||
@@ -21,6 +21,7 @@ import type {
|
||||
IsValidConnection,
|
||||
ColorMode,
|
||||
SnapGrid,
|
||||
OnBeforeDelete,
|
||||
} from '@xyflow/system';
|
||||
|
||||
import type {
|
||||
@@ -100,6 +101,7 @@ export type ReactFlowProps = Omit<HTMLAttributes<HTMLDivElement>, 'onError'> & {
|
||||
onPaneMouseEnter?: (event: ReactMouseEvent) => void;
|
||||
onPaneMouseMove?: (event: ReactMouseEvent) => void;
|
||||
onPaneMouseLeave?: (event: ReactMouseEvent) => void;
|
||||
onBeforeDelete?: OnBeforeDelete;
|
||||
nodeTypes?: NodeTypes;
|
||||
edgeTypes?: EdgeTypes;
|
||||
connectionLineType?: ConnectionLineType;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-namespace */
|
||||
import type { Rect, Viewport } from '@xyflow/system';
|
||||
import type { OnBeforeDelete, Rect, Viewport } from '@xyflow/system';
|
||||
import type { Node, Edge, ViewportHelperFunctions } from '.';
|
||||
|
||||
export type ReactFlowJsonObject<NodeType extends Node = Node, EdgeType extends Edge = Edge> = {
|
||||
@@ -12,6 +12,7 @@ export type ReactFlowJsonObject<NodeType extends Node = Node, EdgeType extends E
|
||||
export type DeleteElementsOptions = {
|
||||
nodes?: (Node | { id: Node['id'] })[];
|
||||
edges?: (Edge | { id: Edge['id'] })[];
|
||||
onBeforeDelete?: OnBeforeDelete;
|
||||
};
|
||||
|
||||
export namespace Instance {
|
||||
@@ -31,7 +32,7 @@ export namespace Instance {
|
||||
NodeType,
|
||||
EdgeType
|
||||
>;
|
||||
export type DeleteElements = ({ nodes, edges }: DeleteElementsOptions) => {
|
||||
export type DeleteElements = (params: DeleteElementsOptions) => {
|
||||
deletedNodes: Node[];
|
||||
deletedEdges: Edge[];
|
||||
};
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
type EdgeLookup,
|
||||
type ConnectionLookup,
|
||||
type NodeLookup,
|
||||
OnBeforeDelete,
|
||||
} from '@xyflow/system';
|
||||
|
||||
import type {
|
||||
@@ -132,6 +133,7 @@ export type ReactFlowStore = {
|
||||
onViewportChangeStart?: OnViewportChange;
|
||||
onViewportChange?: OnViewportChange;
|
||||
onViewportChangeEnd?: OnViewportChange;
|
||||
onBeforeDelete?: OnBeforeDelete;
|
||||
|
||||
onSelectionChangeHandlers: OnSelectionChangeFunc[];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user