Merge pull request #4219 from xyflow/fix/defaultnode-updates
fix(react): default node updates closes #4202
This commit is contained in:
@@ -11,6 +11,8 @@ import {
|
|||||||
useEdgesState,
|
useEdgesState,
|
||||||
OnConnect,
|
OnConnect,
|
||||||
useNodesInitialized,
|
useNodesInitialized,
|
||||||
|
Panel,
|
||||||
|
useReactFlow,
|
||||||
} from '@xyflow/react';
|
} from '@xyflow/react';
|
||||||
|
|
||||||
const initialNodes: Node[] = [
|
const initialNodes: Node[] = [
|
||||||
@@ -49,6 +51,7 @@ const initialEdges: Edge[] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const UseZoomPanHelperFlow = () => {
|
const UseZoomPanHelperFlow = () => {
|
||||||
|
const { addNodes } = useReactFlow();
|
||||||
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
|
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
||||||
|
|
||||||
@@ -59,6 +62,13 @@ const UseZoomPanHelperFlow = () => {
|
|||||||
console.log('initialized', initialized);
|
console.log('initialized', initialized);
|
||||||
}, [initialized]);
|
}, [initialized]);
|
||||||
|
|
||||||
|
const addNode = () =>
|
||||||
|
addNodes({
|
||||||
|
id: `${Math.random()}`,
|
||||||
|
data: { label: 'new node' },
|
||||||
|
position: { x: Math.random() * 400, y: Math.random() * 400 },
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
nodes={nodes}
|
nodes={nodes}
|
||||||
@@ -71,6 +81,9 @@ const UseZoomPanHelperFlow = () => {
|
|||||||
>
|
>
|
||||||
<Background />
|
<Background />
|
||||||
<MiniMap />
|
<MiniMap />
|
||||||
|
<Panel>
|
||||||
|
<button onClick={addNode}>add node</button>
|
||||||
|
</Panel>
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import {
|
import {
|
||||||
|
EdgeRemoveChange,
|
||||||
evaluateAbsolutePosition,
|
evaluateAbsolutePosition,
|
||||||
getElementsToRemove,
|
getElementsToRemove,
|
||||||
getOverlappingArea,
|
getOverlappingArea,
|
||||||
isRectObject,
|
isRectObject,
|
||||||
|
NodeRemoveChange,
|
||||||
nodeToRect,
|
nodeToRect,
|
||||||
type Rect,
|
type Rect,
|
||||||
} from '@xyflow/system';
|
} from '@xyflow/system';
|
||||||
@@ -11,7 +13,7 @@ import {
|
|||||||
import useViewportHelper from './useViewportHelper';
|
import useViewportHelper from './useViewportHelper';
|
||||||
import { useStoreApi } from './useStore';
|
import { useStoreApi } from './useStore';
|
||||||
import { useBatchContext } from '../components/BatchProvider';
|
import { useBatchContext } from '../components/BatchProvider';
|
||||||
import { isNode } from '../utils';
|
import { elementToRemoveChange, isNode } from '../utils';
|
||||||
import type { ReactFlowInstance, Instance, Node, Edge, InternalNode } from '../types';
|
import type { ReactFlowInstance, Instance, Node, Edge, InternalNode } from '../types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -87,12 +89,10 @@ export function useReactFlow<NodeType extends Node = Node, EdgeType extends Edge
|
|||||||
const {
|
const {
|
||||||
nodes,
|
nodes,
|
||||||
edges,
|
edges,
|
||||||
hasDefaultNodes,
|
|
||||||
hasDefaultEdges,
|
|
||||||
onNodesDelete,
|
onNodesDelete,
|
||||||
onEdgesDelete,
|
onEdgesDelete,
|
||||||
onNodesChange,
|
triggerNodeChanges,
|
||||||
onEdgesChange,
|
triggerEdgeChanges,
|
||||||
onDelete,
|
onDelete,
|
||||||
onBeforeDelete,
|
onBeforeDelete,
|
||||||
} = store.getState();
|
} = store.getState();
|
||||||
@@ -108,28 +108,17 @@ export function useReactFlow<NodeType extends Node = Node, EdgeType extends Edge
|
|||||||
const hasMatchingNodes = matchingNodes.length > 0;
|
const hasMatchingNodes = matchingNodes.length > 0;
|
||||||
|
|
||||||
if (hasMatchingEdges) {
|
if (hasMatchingEdges) {
|
||||||
if (hasDefaultEdges) {
|
const edgeChanges: EdgeRemoveChange[] = matchingEdges.map(elementToRemoveChange);
|
||||||
const nextEdges = edges.filter((e) => !matchingEdges.some((mE) => mE.id === e.id));
|
|
||||||
store.getState().setEdges(nextEdges);
|
|
||||||
}
|
|
||||||
|
|
||||||
onEdgesDelete?.(matchingEdges);
|
onEdgesDelete?.(matchingEdges);
|
||||||
onEdgesChange?.(
|
triggerEdgeChanges(edgeChanges);
|
||||||
matchingEdges.map((edge) => ({
|
|
||||||
id: edge.id,
|
|
||||||
type: 'remove',
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasMatchingNodes) {
|
if (hasMatchingNodes) {
|
||||||
if (hasDefaultNodes) {
|
const nodeChanges: NodeRemoveChange[] = matchingNodes.map(elementToRemoveChange);
|
||||||
const nextNodes = nodes.filter((n) => !matchingNodes.some((mN) => mN.id === n.id));
|
|
||||||
store.getState().setNodes(nextNodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
onNodesDelete?.(matchingNodes);
|
onNodesDelete?.(matchingNodes);
|
||||||
onNodesChange?.(matchingNodes.map((node) => ({ id: node.id, type: 'remove' })));
|
triggerNodeChanges(nodeChanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasMatchingNodes || hasMatchingEdges) {
|
if (hasMatchingNodes || hasMatchingEdges) {
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ const createStore = ({
|
|||||||
// new dimensions and update the nodes.
|
// new dimensions and update the nodes.
|
||||||
updateNodeInternals: (updates) => {
|
updateNodeInternals: (updates) => {
|
||||||
const {
|
const {
|
||||||
onNodesChange,
|
triggerNodeChanges,
|
||||||
fitView,
|
fitView,
|
||||||
nodeLookup,
|
nodeLookup,
|
||||||
parentLookup,
|
parentLookup,
|
||||||
@@ -120,7 +120,7 @@ const createStore = ({
|
|||||||
if (debug) {
|
if (debug) {
|
||||||
console.log('React Flow: trigger node changes', changes);
|
console.log('React Flow: trigger node changes', changes);
|
||||||
}
|
}
|
||||||
onNodesChange?.(changes);
|
triggerNodeChanges?.(changes);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updateNodePositions: (nodeDragItems, dragging = false) => {
|
updateNodePositions: (nodeDragItems, dragging = false) => {
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import {
|
|||||||
NodeChange,
|
NodeChange,
|
||||||
NodeSelectionChange,
|
NodeSelectionChange,
|
||||||
EdgeSelectionChange,
|
EdgeSelectionChange,
|
||||||
|
NodeRemoveChange,
|
||||||
|
EdgeRemoveChange,
|
||||||
} from '@xyflow/system';
|
} from '@xyflow/system';
|
||||||
import type { Node, Edge, InternalNode } from '../types';
|
import type { Node, Edge, InternalNode } from '../types';
|
||||||
|
|
||||||
@@ -258,3 +260,10 @@ export function getElementsDiffChanges({
|
|||||||
|
|
||||||
return changes;
|
return changes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function elementToRemoveChange<T extends Node | Edge>(item: T): NodeRemoveChange | EdgeRemoveChange {
|
||||||
|
return {
|
||||||
|
id: item.id,
|
||||||
|
type: 'remove',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@@ -395,7 +395,7 @@ export async function getElementsToRemove<NodeType extends NodeBase = NodeBase,
|
|||||||
nodes: NodeType[];
|
nodes: NodeType[];
|
||||||
edges: EdgeType[];
|
edges: EdgeType[];
|
||||||
}> {
|
}> {
|
||||||
const nodeIds = nodesToRemove.map((node) => node.id);
|
const nodeIds = new Set(nodesToRemove.map((node) => node.id));
|
||||||
const matchingNodes: NodeType[] = [];
|
const matchingNodes: NodeType[] = [];
|
||||||
|
|
||||||
for (const node of nodes) {
|
for (const node of nodes) {
|
||||||
@@ -403,7 +403,7 @@ export async function getElementsToRemove<NodeType extends NodeBase = NodeBase,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isIncluded = nodeIds.includes(node.id);
|
const isIncluded = nodeIds.has(node.id);
|
||||||
const parentHit = !isIncluded && node.parentId && matchingNodes.find((n) => n.id === node.parentId);
|
const parentHit = !isIncluded && node.parentId && matchingNodes.find((n) => n.id === node.parentId);
|
||||||
|
|
||||||
if (isIncluded || parentHit) {
|
if (isIncluded || parentHit) {
|
||||||
@@ -411,13 +411,13 @@ export async function getElementsToRemove<NodeType extends NodeBase = NodeBase,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const edgeIds = edgesToRemove.map((edge) => edge.id);
|
const edgeIds = new Set(edgesToRemove.map((edge) => edge.id));
|
||||||
const deletableEdges = edges.filter((edge) => edge.deletable !== false);
|
const deletableEdges = edges.filter((edge) => edge.deletable !== false);
|
||||||
const connectedEdges = getConnectedEdges(matchingNodes, deletableEdges);
|
const connectedEdges = getConnectedEdges(matchingNodes, deletableEdges);
|
||||||
const matchingEdges: EdgeType[] = connectedEdges;
|
const matchingEdges: EdgeType[] = connectedEdges;
|
||||||
|
|
||||||
for (const edge of deletableEdges) {
|
for (const edge of deletableEdges) {
|
||||||
const isIncluded = edgeIds.includes(edge.id);
|
const isIncluded = edgeIds.has(edge.id);
|
||||||
|
|
||||||
if (isIncluded && !matchingEdges.find((e) => e.id === edge.id)) {
|
if (isIncluded && !matchingEdges.find((e) => e.id === edge.id)) {
|
||||||
matchingEdges.push(edge);
|
matchingEdges.push(edge);
|
||||||
|
|||||||
Reference in New Issue
Block a user