From 3f98f91692aadb55ef026e0421979672ffeaf908 Mon Sep 17 00:00:00 2001 From: peterkogo Date: Wed, 15 Oct 2025 14:08:05 +0200 Subject: [PATCH 1/7] add rootNodeIndex to internals & implement sorting of group nodes --- examples/react/src/examples/Subflow/index.tsx | 22 +++++++++---------- packages/system/src/types/nodes.ts | 1 + packages/system/src/utils/store.ts | 19 ++++++++++++++-- 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/examples/react/src/examples/Subflow/index.tsx b/examples/react/src/examples/Subflow/index.tsx index 82d0d413..ac806c59 100644 --- a/examples/react/src/examples/Subflow/index.tsx +++ b/examples/react/src/examples/Subflow/index.tsx @@ -27,15 +27,15 @@ const onEdgeClick = (_: MouseEvent, edge: Edge) => console.log('click', edge); const defaultViewport = { x: 0, y: 0, zoom: 1.5 }; const initialNodes: Node[] = [ - { - id: 'extent', - position: { x: 0, y: 0 }, - width: 1000, - height: 1000, - data: { label: 'Extent' }, - origin: [0, 0], - zIndex: -1, - }, + // { + // id: 'extent', + // position: { x: 0, y: 0 }, + // width: 1000, + // height: 1000, + // data: { label: 'Extent' }, + // origin: [0, 0], + // zIndex: -1, + // }, { id: '1', type: 'input', @@ -96,12 +96,12 @@ const initialNodes: Node[] = [ }, { id: '5', - type: 'group', + // type: 'group', data: { label: 'Node 5' }, position: { x: 650, y: 250 }, className: 'light', style: { width: 100, height: 100 }, - zIndex: 1000, + // zIndex: 1000, }, { id: '5a', diff --git a/packages/system/src/types/nodes.ts b/packages/system/src/types/nodes.ts index 37293e61..24400db1 100644 --- a/packages/system/src/types/nodes.ts +++ b/packages/system/src/types/nodes.ts @@ -95,6 +95,7 @@ export type InternalNodeBase = Omit( ): boolean { const _options = mergeObjects(adoptUserNodesDefaultOptions, options); + let rootParentIndex = { i: -1 }; let nodesInitialized = nodes.length > 0; const tmpLookup = new Map(nodeLookup); const selectedNodeZ: number = _options?.elevateNodesOnSelect ? 1000 : 0; @@ -166,7 +167,7 @@ export function adoptUserNodes( } if (userNode.parentId) { - updateChildNode(internalNode, nodeLookup, parentLookup, options); + updateChildNode(internalNode, nodeLookup, parentLookup, options, rootParentIndex); } } @@ -197,7 +198,8 @@ function updateChildNode( node: InternalNodeBase, nodeLookup: NodeLookup>, parentLookup: ParentLookup>, - options?: UpdateNodesOptions + options?: UpdateNodesOptions, + rootParentIndex?: { i: number } ) { const { elevateNodesOnSelect, nodeOrigin, nodeExtent } = mergeObjects(defaultOptions, options); const parentId = node.parentId!; @@ -212,6 +214,17 @@ function updateChildNode( updateParentLookup(node, parentLookup); + // We just want to set the rootParentIndex for the first child + if (rootParentIndex && !parentNode.parentId && parentNode.internals.rootParentIndex === undefined) { + parentNode.internals.rootParentIndex = ++rootParentIndex.i; + parentNode.internals.z = parentNode.internals.z + rootParentIndex.i * 10; + } + + // But we need to update rootParentIndex.i also when parent has not been updated + if (rootParentIndex && parentNode.internals.rootParentIndex !== undefined) { + rootParentIndex.i = parentNode.internals.rootParentIndex; + } + const selectedNodeZ = elevateNodesOnSelect ? 1000 : 0; const { x, y, z } = calculateChildXYZ(node, parentNode, nodeOrigin, nodeExtent, selectedNodeZ); const { positionAbsolute } = node.internals; @@ -261,6 +274,8 @@ function calculateChildXYZ( const childZ = calculateZ(childNode, selectedNodeZ); const parentZ = parentNode.internals.z ?? 0; + console.log(parentNode.id, parentZ, childZ); + return { x: absolutePosition.x, y: absolutePosition.y, From 6ffb9f7901c32f5b335aee2517f41bf87f274f32 Mon Sep 17 00:00:00 2001 From: peterkogo Date: Wed, 15 Oct 2025 14:10:15 +0200 Subject: [PATCH 2/7] chore(changeset) --- .changeset/eighty-wolves-cheat.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/eighty-wolves-cheat.md diff --git a/.changeset/eighty-wolves-cheat.md b/.changeset/eighty-wolves-cheat.md new file mode 100644 index 00000000..51dfcdda --- /dev/null +++ b/.changeset/eighty-wolves-cheat.md @@ -0,0 +1,7 @@ +--- +'@xyflow/system': minor +'@xyflow/react': minor +'@xyflow/svelte': minor +--- + +Prevent child nodes of different parents from overlapping From f7845a212b356ccc298c8e847f1a8040968e15e0 Mon Sep 17 00:00:00 2001 From: peterkogo Date: Wed, 15 Oct 2025 14:11:51 +0200 Subject: [PATCH 3/7] remove console.log --- packages/system/src/utils/store.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/system/src/utils/store.ts b/packages/system/src/utils/store.ts index 19aa833b..73b4e619 100644 --- a/packages/system/src/utils/store.ts +++ b/packages/system/src/utils/store.ts @@ -274,8 +274,6 @@ function calculateChildXYZ( const childZ = calculateZ(childNode, selectedNodeZ); const parentZ = parentNode.internals.z ?? 0; - console.log(parentNode.id, parentZ, childZ); - return { x: absolutePosition.x, y: absolutePosition.y, From 98a5c36172d9e94796325066a8112b7254ff142d Mon Sep 17 00:00:00 2001 From: peterkogo Date: Wed, 15 Oct 2025 14:12:47 +0200 Subject: [PATCH 4/7] change incrementation --- packages/system/src/utils/store.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/system/src/utils/store.ts b/packages/system/src/utils/store.ts index 73b4e619..a56b5d4f 100644 --- a/packages/system/src/utils/store.ts +++ b/packages/system/src/utils/store.ts @@ -120,7 +120,7 @@ export function adoptUserNodes( ): boolean { const _options = mergeObjects(adoptUserNodesDefaultOptions, options); - let rootParentIndex = { i: -1 }; + let rootParentIndex = { i: 0 }; let nodesInitialized = nodes.length > 0; const tmpLookup = new Map(nodeLookup); const selectedNodeZ: number = _options?.elevateNodesOnSelect ? 1000 : 0; @@ -216,7 +216,7 @@ function updateChildNode( // We just want to set the rootParentIndex for the first child if (rootParentIndex && !parentNode.parentId && parentNode.internals.rootParentIndex === undefined) { - parentNode.internals.rootParentIndex = ++rootParentIndex.i; + parentNode.internals.rootParentIndex = rootParentIndex.i++; parentNode.internals.z = parentNode.internals.z + rootParentIndex.i * 10; } From fb94327c10077fbcca9c7b40a7954009a1a91743 Mon Sep 17 00:00:00 2001 From: peterkogo Date: Wed, 15 Oct 2025 14:14:05 +0200 Subject: [PATCH 5/7] revert incrementation --- packages/system/src/utils/store.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/system/src/utils/store.ts b/packages/system/src/utils/store.ts index a56b5d4f..73b4e619 100644 --- a/packages/system/src/utils/store.ts +++ b/packages/system/src/utils/store.ts @@ -120,7 +120,7 @@ export function adoptUserNodes( ): boolean { const _options = mergeObjects(adoptUserNodesDefaultOptions, options); - let rootParentIndex = { i: 0 }; + let rootParentIndex = { i: -1 }; let nodesInitialized = nodes.length > 0; const tmpLookup = new Map(nodeLookup); const selectedNodeZ: number = _options?.elevateNodesOnSelect ? 1000 : 0; @@ -216,7 +216,7 @@ function updateChildNode( // We just want to set the rootParentIndex for the first child if (rootParentIndex && !parentNode.parentId && parentNode.internals.rootParentIndex === undefined) { - parentNode.internals.rootParentIndex = rootParentIndex.i++; + parentNode.internals.rootParentIndex = ++rootParentIndex.i; parentNode.internals.z = parentNode.internals.z + rootParentIndex.i * 10; } From 5f9013bb67a669571638fe55517ed494a2e8cb61 Mon Sep 17 00:00:00 2001 From: peterkogo Date: Thu, 16 Oct 2025 15:12:36 +0200 Subject: [PATCH 6/7] extract magic numbers --- packages/system/src/utils/store.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/system/src/utils/store.ts b/packages/system/src/utils/store.ts index 73b4e619..88f4bb79 100644 --- a/packages/system/src/utils/store.ts +++ b/packages/system/src/utils/store.ts @@ -30,6 +30,9 @@ import { import { getNodePositionWithOrigin } from './graph'; import { ParentExpandChild } from './types'; +const SELECTED_NODE_Z = 1000; +const ROOT_PARENT_Z_INCREMENT = 10; + const defaultOptions = { nodeOrigin: [0, 0] as NodeOrigin, nodeExtent: infiniteExtent, @@ -123,7 +126,7 @@ export function adoptUserNodes( let rootParentIndex = { i: -1 }; let nodesInitialized = nodes.length > 0; const tmpLookup = new Map(nodeLookup); - const selectedNodeZ: number = _options?.elevateNodesOnSelect ? 1000 : 0; + const selectedNodeZ: number = _options?.elevateNodesOnSelect ? SELECTED_NODE_Z : 0; nodeLookup.clear(); parentLookup.clear(); @@ -217,7 +220,7 @@ function updateChildNode( // We just want to set the rootParentIndex for the first child if (rootParentIndex && !parentNode.parentId && parentNode.internals.rootParentIndex === undefined) { parentNode.internals.rootParentIndex = ++rootParentIndex.i; - parentNode.internals.z = parentNode.internals.z + rootParentIndex.i * 10; + parentNode.internals.z = parentNode.internals.z + rootParentIndex.i * ROOT_PARENT_Z_INCREMENT; } // But we need to update rootParentIndex.i also when parent has not been updated @@ -225,7 +228,7 @@ function updateChildNode( rootParentIndex.i = parentNode.internals.rootParentIndex; } - const selectedNodeZ = elevateNodesOnSelect ? 1000 : 0; + const selectedNodeZ = elevateNodesOnSelect ? SELECTED_NODE_Z : 0; const { x, y, z } = calculateChildXYZ(node, parentNode, nodeOrigin, nodeExtent, selectedNodeZ); const { positionAbsolute } = node.internals; const positionChanged = x !== positionAbsolute.x || y !== positionAbsolute.y; From b6e68e8432cf49bb984a75c3061679013db3b3c0 Mon Sep 17 00:00:00 2001 From: Moritz Klack Date: Thu, 16 Oct 2025 21:29:12 +0200 Subject: [PATCH 7/7] Update eighty-wolves-cheat.md --- .changeset/eighty-wolves-cheat.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/eighty-wolves-cheat.md b/.changeset/eighty-wolves-cheat.md index 51dfcdda..312765ad 100644 --- a/.changeset/eighty-wolves-cheat.md +++ b/.changeset/eighty-wolves-cheat.md @@ -1,5 +1,5 @@ --- -'@xyflow/system': minor +'@xyflow/system': patch '@xyflow/react': minor '@xyflow/svelte': minor ---