From 7cb9a8686ddf932c7fdbc36e919a78e25dee649b Mon Sep 17 00:00:00 2001 From: peterkogo Date: Tue, 21 Jan 2025 15:45:08 +0100 Subject: [PATCH 1/3] Make internal nodes immutable --- packages/system/src/utils/store.ts | 105 ++++++++++++++++------------- 1 file changed, 60 insertions(+), 45 deletions(-) diff --git a/packages/system/src/utils/store.ts b/packages/system/src/utils/store.ts index 7eb7ccdb..77c5b369 100644 --- a/packages/system/src/utils/store.ts +++ b/packages/system/src/utils/store.ts @@ -87,6 +87,7 @@ export function adoptUserNodes( options?: UpdateNodesOptions ) { const _options = mergeObjects(adoptUserNodesDefaultOptions, options); + const tmpLookup = new Map(nodeLookup); const selectedNodeZ: number = _options?.elevateNodesOnSelect ? 1000 : 0; @@ -173,11 +174,15 @@ function updateChildNode( const positionChanged = x !== positionAbsolute.x || y !== positionAbsolute.y; if (positionChanged || z !== node.internals.z) { - node.internals = { - ...node.internals, - positionAbsolute: positionChanged ? { x, y } : positionAbsolute, - z, - }; + // we create a new object to mark the node as updated + nodeLookup.set(node.id, { + ...node, + internals: { + ...node.internals, + positionAbsolute: positionChanged ? { x, y } : positionAbsolute, + z, + }, + }); } } @@ -333,60 +338,70 @@ export function updateNodeInternals( } if (node.hidden) { - node.internals = { - ...node.internals, - handleBounds: undefined, - }; + nodeLookup.set(node.id, { + ...node, + internals: { + ...node.internals, + handleBounds: undefined, + }, + }); updatedInternals = true; - } else { - const dimensions = getDimensions(update.nodeElement); - const dimensionChanged = node.measured.width !== dimensions.width || node.measured.height !== dimensions.height; - const doUpdate = !!( - dimensions.width && - dimensions.height && - (dimensionChanged || !node.internals.handleBounds || update.force) - ); + continue; + } - if (doUpdate) { - const nodeBounds = update.nodeElement.getBoundingClientRect(); - const extent = isCoordinateExtent(node.extent) ? node.extent : nodeExtent; - let { positionAbsolute } = node.internals; + const dimensions = getDimensions(update.nodeElement); + const dimensionChanged = node.measured.width !== dimensions.width || node.measured.height !== dimensions.height; + const doUpdate = !!( + dimensions.width && + dimensions.height && + (dimensionChanged || !node.internals.handleBounds || update.force) + ); - if (node.parentId && node.extent === 'parent') { - positionAbsolute = clampPositionToParent(positionAbsolute, dimensions, nodeLookup.get(node.parentId)!); - } else if (extent) { - positionAbsolute = clampPosition(positionAbsolute, extent, dimensions); - } + if (doUpdate) { + const nodeBounds = update.nodeElement.getBoundingClientRect(); + const extent = isCoordinateExtent(node.extent) ? node.extent : nodeExtent; + let { positionAbsolute } = node.internals; - node.measured = dimensions; - node.internals = { + if (node.parentId && node.extent === 'parent') { + positionAbsolute = clampPositionToParent(positionAbsolute, dimensions, nodeLookup.get(node.parentId)!); + } else if (extent) { + positionAbsolute = clampPosition(positionAbsolute, extent, dimensions); + } + + const newNode = { + ...node, + measured: dimensions, + internals: { ...node.internals, positionAbsolute, handleBounds: { source: getHandleBounds('source', update.nodeElement, nodeBounds, zoom, node.id), target: getHandleBounds('target', update.nodeElement, nodeBounds, zoom, node.id), }, - }; - if (node.parentId) { - updateChildNode(node, nodeLookup, parentLookup, { nodeOrigin }); - } + }, + }; - updatedInternals = true; + nodeLookup.set(node.id, newNode); - if (dimensionChanged) { - changes.push({ + if (node.parentId) { + updateChildNode(newNode, nodeLookup, parentLookup, { nodeOrigin }); + } + + updatedInternals = true; + + if (dimensionChanged) { + changes.push({ + id: node.id, + type: 'dimensions', + dimensions, + }); + + if (node.expandParent && node.parentId) { + parentExpandChildren.push({ id: node.id, - type: 'dimensions', - dimensions, + parentId: node.parentId, + rect: nodeToRect(newNode, nodeOrigin), }); - - if (node.expandParent && node.parentId) { - parentExpandChildren.push({ - id: node.id, - parentId: node.parentId, - rect: nodeToRect(node, nodeOrigin), - }); - } } } } From c12fa5c178d7df55e54676a739995d48ffe9b911 Mon Sep 17 00:00:00 2001 From: peterkogo Date: Tue, 21 Jan 2025 15:45:35 +0100 Subject: [PATCH 2/3] Allow handle id to be null --- packages/system/src/types/handles.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/system/src/types/handles.ts b/packages/system/src/types/handles.ts index f9828dd5..9cf2a1dd 100644 --- a/packages/system/src/types/handles.ts +++ b/packages/system/src/types/handles.ts @@ -36,5 +36,5 @@ export type HandleProps = { /** Id of the handle * @remarks optional if there is only one handle of this type */ - id?: string; + id?: string | null; }; From e73ef09fbc8d872b46cf52c9d6a32dbb388c220b Mon Sep 17 00:00:00 2001 From: peterkogo Date: Tue, 21 Jan 2025 15:46:28 +0100 Subject: [PATCH 3/3] chore(changeset) add --- .changeset/spotty-pots-rest.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/spotty-pots-rest.md diff --git a/.changeset/spotty-pots-rest.md b/.changeset/spotty-pots-rest.md new file mode 100644 index 00000000..42344e2f --- /dev/null +++ b/.changeset/spotty-pots-rest.md @@ -0,0 +1,5 @@ +--- +'@xyflow/system': patch +--- + +Make internal nodes immutable