From e02e3703c1ebf8a444cdf091b090f2f72777bb81 Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 28 Aug 2024 16:17:03 +0200 Subject: [PATCH 1/4] fix(setNodes): use correct index when using setNodes for inserting #4455 --- .../src/examples/ReconnectEdge/CustomNode.tsx | 14 ++++++++++++++ packages/react/src/utils/changes.ts | 13 ++++++++++--- packages/system/src/types/changes.ts | 2 ++ 3 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 examples/react/src/examples/ReconnectEdge/CustomNode.tsx diff --git a/examples/react/src/examples/ReconnectEdge/CustomNode.tsx b/examples/react/src/examples/ReconnectEdge/CustomNode.tsx new file mode 100644 index 00000000..24e8b03c --- /dev/null +++ b/examples/react/src/examples/ReconnectEdge/CustomNode.tsx @@ -0,0 +1,14 @@ +import { memo } from 'react'; +import { Handle, Position } from '@xyflow/react'; + +const styles = { padding: '10px', background: 'green' }; + +const CustomNode = ({ data }) => ( + <> +
{data.label}
+ + + +); + +export default memo(CustomNode); diff --git a/packages/react/src/utils/changes.ts b/packages/react/src/utils/changes.ts index df215340..f00fa7b3 100644 --- a/packages/react/src/utils/changes.ts +++ b/packages/react/src/utils/changes.ts @@ -19,10 +19,11 @@ function applyChanges(changes: any[], elements: any[]): any[] { // By storing a map of changes for each element, we can a quick lookup as we // iterate over the elements array! const changesMap = new Map(); + const newItems: any[] = []; for (const change of changes) { if (change.type === 'add') { - updatedElements.push(change.item); + newItems.push(change); continue; } else if (change.type === 'remove' || change.type === 'replace') { // For a 'remove' change we can safely ignore any other changes queued for @@ -73,6 +74,12 @@ function applyChanges(changes: any[], elements: any[]): any[] { updatedElements.push(updatedElement); } + if (newItems.length) { + newItems.forEach((item) => { + updatedElements.splice(item.index, 0, { ...item.item }); + }); + } + return updatedElements; } @@ -237,7 +244,7 @@ export function getElementsDiffChanges({ const changes: any[] = []; const itemsLookup = new Map(items.map((item) => [item.id, item])); - for (const item of items) { + for (const [index, item] of items.entries()) { const lookupItem = lookup.get(item.id); const storeItem = lookupItem?.internals?.userNode ?? lookupItem; @@ -246,7 +253,7 @@ export function getElementsDiffChanges({ } if (storeItem === undefined) { - changes.push({ item: item, type: 'add' }); + changes.push({ item: item, type: 'add', index }); } } diff --git a/packages/system/src/types/changes.ts b/packages/system/src/types/changes.ts index 5db0b6de..9b232733 100644 --- a/packages/system/src/types/changes.ts +++ b/packages/system/src/types/changes.ts @@ -32,6 +32,7 @@ export type NodeRemoveChange = { export type NodeAddChange = { item: NodeType; type: 'add'; + index?: number; }; export type NodeReplaceChange = { @@ -57,6 +58,7 @@ export type EdgeRemoveChange = NodeRemoveChange; export type EdgeAddChange = { item: EdgeType; type: 'add'; + index?: number; }; export type EdgeReplaceChange = { From 5c85404209195f30d765f39dc2ca509fb9dfe3d1 Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 28 Aug 2024 16:18:05 +0200 Subject: [PATCH 2/4] chore(examples): cleanup --- .../src/examples/ReconnectEdge/CustomNode.tsx | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 examples/react/src/examples/ReconnectEdge/CustomNode.tsx diff --git a/examples/react/src/examples/ReconnectEdge/CustomNode.tsx b/examples/react/src/examples/ReconnectEdge/CustomNode.tsx deleted file mode 100644 index 24e8b03c..00000000 --- a/examples/react/src/examples/ReconnectEdge/CustomNode.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { memo } from 'react'; -import { Handle, Position } from '@xyflow/react'; - -const styles = { padding: '10px', background: 'green' }; - -const CustomNode = ({ data }) => ( - <> -
{data.label}
- - - -); - -export default memo(CustomNode); From 12dbe125755fad7d2f6dff19100872dd823d1012 Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 28 Aug 2024 16:18:40 +0200 Subject: [PATCH 3/4] chore(changeset): add --- .changeset/stale-bananas-argue.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/stale-bananas-argue.md diff --git a/.changeset/stale-bananas-argue.md b/.changeset/stale-bananas-argue.md new file mode 100644 index 00000000..c5c30810 --- /dev/null +++ b/.changeset/stale-bananas-argue.md @@ -0,0 +1,6 @@ +--- +'@xyflow/react': patch +'@xyflow/system': patch +--- + +use correct index when using setNodes for inserting From e3890f7e388f64d3abd05846dc5c182d5cbdcad2 Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 28 Aug 2024 16:21:38 +0200 Subject: [PATCH 4/4] chore(applyChanges): cleanup --- packages/react/src/utils/changes.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/react/src/utils/changes.ts b/packages/react/src/utils/changes.ts index f00fa7b3..6de98e3a 100644 --- a/packages/react/src/utils/changes.ts +++ b/packages/react/src/utils/changes.ts @@ -19,11 +19,11 @@ function applyChanges(changes: any[], elements: any[]): any[] { // By storing a map of changes for each element, we can a quick lookup as we // iterate over the elements array! const changesMap = new Map(); - const newItems: any[] = []; + const addItemChanges: any[] = []; for (const change of changes) { if (change.type === 'add') { - newItems.push(change); + addItemChanges.push(change); continue; } else if (change.type === 'remove' || change.type === 'replace') { // For a 'remove' change we can safely ignore any other changes queued for @@ -74,9 +74,15 @@ function applyChanges(changes: any[], elements: any[]): any[] { updatedElements.push(updatedElement); } - if (newItems.length) { - newItems.forEach((item) => { - updatedElements.splice(item.index, 0, { ...item.item }); + // we need to wait for all changes to be applied before adding new items + // to be able to add them at the correct index + if (addItemChanges.length) { + addItemChanges.forEach((change) => { + if (change.index !== undefined) { + updatedElements.splice(change.index, 0, { ...change.item }); + } else { + updatedElements.push({ ...change.item }); + } }); }