From 7501eace795ef8531f6c61586b2f17d8b1215ac1 Mon Sep 17 00:00:00 2001 From: moklick Date: Mon, 29 Apr 2024 13:35:58 +0200 Subject: [PATCH] fix(react): default node updates closes #4202 --- .../react/src/examples/UseNodesInit/index.tsx | 13 +++++++++ packages/react/src/hooks/useReactFlow.ts | 29 ++++++------------- packages/react/src/store/index.ts | 4 +-- packages/react/src/utils/changes.ts | 9 ++++++ packages/system/src/utils/graph.ts | 8 ++--- 5 files changed, 37 insertions(+), 26 deletions(-) diff --git a/examples/react/src/examples/UseNodesInit/index.tsx b/examples/react/src/examples/UseNodesInit/index.tsx index 549315ca..d4932ae1 100644 --- a/examples/react/src/examples/UseNodesInit/index.tsx +++ b/examples/react/src/examples/UseNodesInit/index.tsx @@ -11,6 +11,8 @@ import { useEdgesState, OnConnect, useNodesInitialized, + Panel, + useReactFlow, } from '@xyflow/react'; const initialNodes: Node[] = [ @@ -49,6 +51,7 @@ const initialEdges: Edge[] = [ ]; const UseZoomPanHelperFlow = () => { + const { addNodes } = useReactFlow(); const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes); const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges); @@ -59,6 +62,13 @@ const UseZoomPanHelperFlow = () => { console.log('initialized', initialized); }, [initialized]); + const addNode = () => + addNodes({ + id: `${Math.random()}`, + data: { label: 'new node' }, + position: { x: Math.random() * 400, y: Math.random() * 400 }, + }); + return ( { > + + + ); }; diff --git a/packages/react/src/hooks/useReactFlow.ts b/packages/react/src/hooks/useReactFlow.ts index 4ac0e50c..a61d4907 100644 --- a/packages/react/src/hooks/useReactFlow.ts +++ b/packages/react/src/hooks/useReactFlow.ts @@ -1,9 +1,11 @@ import { useCallback, useMemo } from 'react'; import { + EdgeRemoveChange, evaluateAbsolutePosition, getElementsToRemove, getOverlappingArea, isRectObject, + NodeRemoveChange, nodeToRect, type Rect, } from '@xyflow/system'; @@ -11,7 +13,7 @@ import { import useViewportHelper from './useViewportHelper'; import { useStoreApi } from './useStore'; import { useBatchContext } from '../components/BatchProvider'; -import { isNode } from '../utils'; +import { elementToRemoveChange, isNode } from '../utils'; import type { ReactFlowInstance, Instance, Node, Edge, InternalNode } from '../types'; /** @@ -87,12 +89,10 @@ export function useReactFlow 0; if (hasMatchingEdges) { - if (hasDefaultEdges) { - const nextEdges = edges.filter((e) => !matchingEdges.some((mE) => mE.id === e.id)); - store.getState().setEdges(nextEdges); - } + const edgeChanges: EdgeRemoveChange[] = matchingEdges.map(elementToRemoveChange); onEdgesDelete?.(matchingEdges); - onEdgesChange?.( - matchingEdges.map((edge) => ({ - id: edge.id, - type: 'remove', - })) - ); + triggerEdgeChanges(edgeChanges); } if (hasMatchingNodes) { - if (hasDefaultNodes) { - const nextNodes = nodes.filter((n) => !matchingNodes.some((mN) => mN.id === n.id)); - store.getState().setNodes(nextNodes); - } + const nodeChanges: NodeRemoveChange[] = matchingNodes.map(elementToRemoveChange); onNodesDelete?.(matchingNodes); - onNodesChange?.(matchingNodes.map((node) => ({ id: node.id, type: 'remove' }))); + triggerNodeChanges(nodeChanges); } if (hasMatchingNodes || hasMatchingEdges) { diff --git a/packages/react/src/store/index.ts b/packages/react/src/store/index.ts index 5d7f521b..29f99999 100644 --- a/packages/react/src/store/index.ts +++ b/packages/react/src/store/index.ts @@ -74,7 +74,7 @@ const createStore = ({ // new dimensions and update the nodes. updateNodeInternals: (updates) => { const { - onNodesChange, + triggerNodeChanges, fitView, nodeLookup, parentLookup, @@ -120,7 +120,7 @@ const createStore = ({ if (debug) { console.log('React Flow: trigger node changes', changes); } - onNodesChange?.(changes); + triggerNodeChanges?.(changes); } }, updateNodePositions: (nodeDragItems, dragging = false) => { diff --git a/packages/react/src/utils/changes.ts b/packages/react/src/utils/changes.ts index cdc83088..df215340 100644 --- a/packages/react/src/utils/changes.ts +++ b/packages/react/src/utils/changes.ts @@ -6,6 +6,8 @@ import { NodeChange, NodeSelectionChange, EdgeSelectionChange, + NodeRemoveChange, + EdgeRemoveChange, } from '@xyflow/system'; import type { Node, Edge, InternalNode } from '../types'; @@ -258,3 +260,10 @@ export function getElementsDiffChanges({ return changes; } + +export function elementToRemoveChange(item: T): NodeRemoveChange | EdgeRemoveChange { + return { + id: item.id, + type: 'remove', + }; +} diff --git a/packages/system/src/utils/graph.ts b/packages/system/src/utils/graph.ts index 53592609..6a4715b8 100644 --- a/packages/system/src/utils/graph.ts +++ b/packages/system/src/utils/graph.ts @@ -395,7 +395,7 @@ export async function getElementsToRemove { - const nodeIds = nodesToRemove.map((node) => node.id); + const nodeIds = new Set(nodesToRemove.map((node) => node.id)); const matchingNodes: NodeType[] = []; for (const node of nodes) { @@ -403,7 +403,7 @@ export async function getElementsToRemove n.id === node.parentId); if (isIncluded || parentHit) { @@ -411,13 +411,13 @@ export async function getElementsToRemove edge.id); + const edgeIds = new Set(edgesToRemove.map((edge) => edge.id)); const deletableEdges = edges.filter((edge) => edge.deletable !== false); const connectedEdges = getConnectedEdges(matchingNodes, deletableEdges); const matchingEdges: EdgeType[] = connectedEdges; 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)) { matchingEdges.push(edge);