From 4f77447ab5c6192f1743668e137cf6efe4b551b5 Mon Sep 17 00:00:00 2001 From: Alessandro Date: Tue, 14 Oct 2025 10:22:30 +0200 Subject: [PATCH 01/10] Fix svelte minimap if all nodes are hidden --- packages/svelte/src/lib/plugins/Minimap/Minimap.svelte | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/svelte/src/lib/plugins/Minimap/Minimap.svelte b/packages/svelte/src/lib/plugins/Minimap/Minimap.svelte index 33209dcb..04bb982a 100644 --- a/packages/svelte/src/lib/plugins/Minimap/Minimap.svelte +++ b/packages/svelte/src/lib/plugins/Minimap/Minimap.svelte @@ -60,8 +60,11 @@ width: store.width / store.viewport.zoom, height: store.height / store.viewport.zoom }); + + const hasVisibleNodes = $derived(store.nodeLookup.size > 0 && store.nodes.some((n) => !n.hidden)); + let boundingRect = $derived( - store.nodeLookup.size > 0 + hasVisibleNodes ? getBoundsOfRects( getInternalNodesBounds(store.nodeLookup, { filter: (n) => !n.hidden }), viewBB From a67f2992b1c5cbeaca5f5d79d623390f4fbc1057 Mon Sep 17 00:00:00 2001 From: Alessandro Date: Tue, 14 Oct 2025 11:33:10 +0200 Subject: [PATCH 02/10] Update getInternalNodesBounds and examples --- .../src/examples/CustomMiniMapNode/index.tsx | 29 ++++++++------ .../src/components/Header/Header.svelte | 1 + .../examples/custom-minimap/+page.svelte | 39 +++++++++++-------- .../src/lib/plugins/Minimap/Minimap.svelte | 19 +++++---- packages/system/src/utils/graph.ts | 9 ++++- 5 files changed, 60 insertions(+), 37 deletions(-) diff --git a/examples/react/src/examples/CustomMiniMapNode/index.tsx b/examples/react/src/examples/CustomMiniMapNode/index.tsx index 21b1d073..1bb0f39b 100644 --- a/examples/react/src/examples/CustomMiniMapNode/index.tsx +++ b/examples/react/src/examples/CustomMiniMapNode/index.tsx @@ -1,4 +1,4 @@ -import { MouseEvent, CSSProperties, useCallback } from 'react'; +import { MouseEvent, CSSProperties, useCallback, useState } from 'react'; import { ReactFlow, @@ -14,19 +14,13 @@ import { ReactFlowInstance, useEdgesState, useNodesState, + Panel, } from '@xyflow/react'; const onInit = (reactFlowInstance: ReactFlowInstance) => console.log('flow loaded:', reactFlowInstance); const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node); const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node); -const buttonStyle: CSSProperties = { - position: 'absolute', - left: 10, - top: 10, - zIndex: 4, -}; - const CustomMiniMapNode = ({ x, y, width, height }: MiniMapNodeProps) => { return ; }; @@ -34,6 +28,7 @@ const CustomMiniMapNode = ({ x, y, width, height }: MiniMapNodeProps) => { const CustomMiniMapNodeFlow = () => { const [nodes, setNodes, onNodesChange] = useNodesState([]); const [edges, setEdges, onEdgesChange] = useEdgesState([]); + const [hideAllNodes, setHideAllNodes] = useState(false); const onConnect = useCallback((params: Connection | Edge) => setEdges((els) => addEdge(params, els)), [setEdges]); const addRandomNode = () => { @@ -45,10 +40,17 @@ const CustomMiniMapNodeFlow = () => { x: Math.random() * window.innerWidth, y: Math.random() * window.innerHeight, }, + hidden: hideAllNodes, }; setNodes((nds) => nds.concat(newNode)); }; + const toggleHideAllNodes = () => { + setHideAllNodes(!hideAllNodes); + setNodes((nds) => nds.map((n) => ({ ...n, hidden: hideAllNodes }))); + setEdges((eds) => eds.map((e) => ({ ...e, hidden: hideAllNodes }))); + }; + return ( { - + + + + ); }; diff --git a/examples/svelte/src/components/Header/Header.svelte b/examples/svelte/src/components/Header/Header.svelte index 0ebe84e9..c03eef13 100644 --- a/examples/svelte/src/components/Header/Header.svelte +++ b/examples/svelte/src/components/Header/Header.svelte @@ -17,6 +17,7 @@ 'handle-connect', 'interaction', 'intersections', + 'minimap-bug', 'node-toolbar', 'node-resizer', 'overview', diff --git a/examples/svelte/src/routes/examples/custom-minimap/+page.svelte b/examples/svelte/src/routes/examples/custom-minimap/+page.svelte index 1e9c96ca..0a0c734c 100644 --- a/examples/svelte/src/routes/examples/custom-minimap/+page.svelte +++ b/examples/svelte/src/routes/examples/custom-minimap/+page.svelte @@ -4,15 +4,17 @@ Background, Controls, MiniMap, + Panel, type Node, - type Edge, + type Edge } from '@xyflow/svelte'; - + import '@xyflow/svelte/dist/style.css'; import CustomMiniMapNode from './CustomMiniMapNode.svelte'; let nodes = $state.raw([]); let edges = $state.raw([]); + let hideAllNodes = $state(false); function addRandomNode() { const nodeId = (nodes.length + 1).toString(); @@ -21,28 +23,33 @@ data: { label: `Node: ${nodeId}` }, position: { x: Math.random() * (typeof window !== 'undefined' ? window.innerWidth : 800), - y: Math.random() * (typeof window !== 'undefined' ? window.innerHeight : 600), + y: Math.random() * (typeof window !== 'undefined' ? window.innerHeight : 600) }, - type: 'default' + type: 'default', + hidden: hideAllNodes }; nodes = [...nodes, newNode]; } + + function toggleHideAllNodes() { + hideAllNodes = !hideAllNodes; + nodes = nodes.map((node) => ({ + ...node, + hidden: hideAllNodes + })); + } - + - + + + + + diff --git a/packages/svelte/src/lib/plugins/Minimap/Minimap.svelte b/packages/svelte/src/lib/plugins/Minimap/Minimap.svelte index 04bb982a..6748dc47 100644 --- a/packages/svelte/src/lib/plugins/Minimap/Minimap.svelte +++ b/packages/svelte/src/lib/plugins/Minimap/Minimap.svelte @@ -61,16 +61,19 @@ height: store.height / store.viewport.zoom }); - const hasVisibleNodes = $derived(store.nodeLookup.size > 0 && store.nodes.some((n) => !n.hidden)); + // let boundingRect = $derived( + // store.nodeLookup.size > 0 && store.nodes.some((n) => !n.hidden) + // ? getBoundsOfRects( + // getInternalNodesBounds(store.nodeLookup, { filter: (n) => !n.hidden }), + // viewBB + // ) + // : viewBB + // ); let boundingRect = $derived( - hasVisibleNodes - ? getBoundsOfRects( - getInternalNodesBounds(store.nodeLookup, { filter: (n) => !n.hidden }), - viewBB - ) - : viewBB + getBoundsOfRects(getInternalNodesBounds(store.nodeLookup, { filter: (n) => !n.hidden }), viewBB) ); + let scaledWidth = $derived(boundingRect.width / width); let scaledHeight = $derived(boundingRect.height / height); let viewScale = $derived(Math.max(scaledWidth, scaledHeight)); @@ -124,7 +127,7 @@ {#each store.nodes as userNode (userNode.id)} {@const node = store.nodeLookup.get(userNode.id)} - {#if node && nodeHasDimensions(node)} + {#if node && nodeHasDimensions(node) && !node.hidden} {@const nodeDimesions = getNodeDimensions(node)} , params: GetInternalNodesBoundsParams = {} ): Rect => { + const emptyRect = { x: 0, y: 0, width: 0, height: 0 }; + if (nodeLookup.size === 0) { - return { x: 0, y: 0, width: 0, height: 0 }; + return emptyRect; } let box = { x: Infinity, y: Infinity, x2: -Infinity, y2: -Infinity }; + let hasVisibleNodes = false; + nodeLookup.forEach((node) => { if (params.filter === undefined || params.filter(node)) { + hasVisibleNodes = true; const nodeBox = nodeToBox(node as InternalNodeBase); box = getBoundsOfBoxes(box, nodeBox); } }); - return boxToRect(box); + return hasVisibleNodes ? boxToRect(box) : emptyRect; }; export const getNodesInside = ( From 8be0307688d29d1f4ba52b7b7f9e5bd2cadbb24d Mon Sep 17 00:00:00 2001 From: Alessandro Date: Tue, 14 Oct 2025 12:09:39 +0200 Subject: [PATCH 03/10] remove comments --- packages/svelte/src/lib/plugins/Minimap/Minimap.svelte | 9 --------- 1 file changed, 9 deletions(-) diff --git a/packages/svelte/src/lib/plugins/Minimap/Minimap.svelte b/packages/svelte/src/lib/plugins/Minimap/Minimap.svelte index 6748dc47..90c6abb4 100644 --- a/packages/svelte/src/lib/plugins/Minimap/Minimap.svelte +++ b/packages/svelte/src/lib/plugins/Minimap/Minimap.svelte @@ -61,15 +61,6 @@ height: store.height / store.viewport.zoom }); - // let boundingRect = $derived( - // store.nodeLookup.size > 0 && store.nodes.some((n) => !n.hidden) - // ? getBoundsOfRects( - // getInternalNodesBounds(store.nodeLookup, { filter: (n) => !n.hidden }), - // viewBB - // ) - // : viewBB - // ); - let boundingRect = $derived( getBoundsOfRects(getInternalNodesBounds(store.nodeLookup, { filter: (n) => !n.hidden }), viewBB) ); From 34c9b7491495688733aa87828359be16f61def51 Mon Sep 17 00:00:00 2001 From: Alessandro Cheli <17289614+0x0f0f0f@users.noreply.github.com> Date: Tue, 14 Oct 2025 12:09:53 +0200 Subject: [PATCH 04/10] Update examples/react/src/examples/CustomMiniMapNode/index.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- examples/react/src/examples/CustomMiniMapNode/index.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/react/src/examples/CustomMiniMapNode/index.tsx b/examples/react/src/examples/CustomMiniMapNode/index.tsx index 1bb0f39b..5766d109 100644 --- a/examples/react/src/examples/CustomMiniMapNode/index.tsx +++ b/examples/react/src/examples/CustomMiniMapNode/index.tsx @@ -46,9 +46,12 @@ const CustomMiniMapNodeFlow = () => { }; const toggleHideAllNodes = () => { - setHideAllNodes(!hideAllNodes); - setNodes((nds) => nds.map((n) => ({ ...n, hidden: hideAllNodes }))); - setEdges((eds) => eds.map((e) => ({ ...e, hidden: hideAllNodes }))); + setHideAllNodes(prev => { + const next = !prev; + setNodes(nds => nds.map(n => ({ ...n, hidden: next }))); + setEdges(eds => eds.map(e => ({ ...e, hidden: next }))); + return next; + }); }; return ( From 0fbc99e5293ccb7411135aa8bb732b523d137892 Mon Sep 17 00:00:00 2001 From: Alessandro Date: Tue, 14 Oct 2025 12:46:47 +0200 Subject: [PATCH 05/10] remove example --- examples/svelte/src/components/Header/Header.svelte | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/svelte/src/components/Header/Header.svelte b/examples/svelte/src/components/Header/Header.svelte index c03eef13..0ebe84e9 100644 --- a/examples/svelte/src/components/Header/Header.svelte +++ b/examples/svelte/src/components/Header/Header.svelte @@ -17,7 +17,6 @@ 'handle-connect', 'interaction', 'intersections', - 'minimap-bug', 'node-toolbar', 'node-resizer', 'overview', From 8a9ee2d836776da42b867c6ba90d302fbbc79b37 Mon Sep 17 00:00:00 2001 From: Alessandro Date: Tue, 14 Oct 2025 13:20:10 +0200 Subject: [PATCH 06/10] Add changeset --- .changeset/giant-foxes-roll.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/giant-foxes-roll.md diff --git a/.changeset/giant-foxes-roll.md b/.changeset/giant-foxes-roll.md new file mode 100644 index 00000000..2cc1b82a --- /dev/null +++ b/.changeset/giant-foxes-roll.md @@ -0,0 +1,6 @@ +--- +'@xyflow/svelte': patch +'@xyflow/system': patch +--- + +Fix Minimap if all nodes are hidden in a flow and refactor getInternalNodesBounds From 3057dcd8cbef80fbf8b89f8408afdbbe087aede3 Mon Sep 17 00:00:00 2001 From: Alessandro Date: Tue, 14 Oct 2025 13:20:38 +0200 Subject: [PATCH 07/10] simplify getInternalNodesBounds --- packages/system/src/utils/graph.ts | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/packages/system/src/utils/graph.ts b/packages/system/src/utils/graph.ts index 1b7d27d1..ab68ae72 100644 --- a/packages/system/src/utils/graph.ts +++ b/packages/system/src/utils/graph.ts @@ -241,25 +241,16 @@ export const getInternalNodesBounds = , params: GetInternalNodesBoundsParams = {} ): Rect => { - const emptyRect = { x: 0, y: 0, width: 0, height: 0 }; - - if (nodeLookup.size === 0) { - return emptyRect; - } - - let box = { x: Infinity, y: Infinity, x2: -Infinity, y2: -Infinity }; - - let hasVisibleNodes = false; + let box = { x: 0, y: 0, x2: 0, y2: 0 }; nodeLookup.forEach((node) => { if (params.filter === undefined || params.filter(node)) { - hasVisibleNodes = true; const nodeBox = nodeToBox(node as InternalNodeBase); box = getBoundsOfBoxes(box, nodeBox); } }); - return hasVisibleNodes ? boxToRect(box) : emptyRect; + return boxToRect(box); }; export const getNodesInside = ( From 43e06954161d275bdf905c7dac07a66eef8180e6 Mon Sep 17 00:00:00 2001 From: Alessandro Date: Tue, 14 Oct 2025 13:33:58 +0200 Subject: [PATCH 08/10] restore version with infinity --- packages/system/src/utils/graph.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/system/src/utils/graph.ts b/packages/system/src/utils/graph.ts index ab68ae72..1b7d27d1 100644 --- a/packages/system/src/utils/graph.ts +++ b/packages/system/src/utils/graph.ts @@ -241,16 +241,25 @@ export const getInternalNodesBounds = , params: GetInternalNodesBoundsParams = {} ): Rect => { - let box = { x: 0, y: 0, x2: 0, y2: 0 }; + const emptyRect = { x: 0, y: 0, width: 0, height: 0 }; + + if (nodeLookup.size === 0) { + return emptyRect; + } + + let box = { x: Infinity, y: Infinity, x2: -Infinity, y2: -Infinity }; + + let hasVisibleNodes = false; nodeLookup.forEach((node) => { if (params.filter === undefined || params.filter(node)) { + hasVisibleNodes = true; const nodeBox = nodeToBox(node as InternalNodeBase); box = getBoundsOfBoxes(box, nodeBox); } }); - return boxToRect(box); + return hasVisibleNodes ? boxToRect(box) : emptyRect; }; export const getNodesInside = ( From b5287b8808acf0f81288d27a553d8fbe5c8c4d79 Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 14 Oct 2025 16:00:01 +0200 Subject: [PATCH 09/10] chore(getInternalNodesBounds): cleanup --- packages/system/src/utils/graph.ts | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/packages/system/src/utils/graph.ts b/packages/system/src/utils/graph.ts index 1b7d27d1..df32a165 100644 --- a/packages/system/src/utils/graph.ts +++ b/packages/system/src/utils/graph.ts @@ -241,25 +241,17 @@ export const getInternalNodesBounds = , params: GetInternalNodesBoundsParams = {} ): Rect => { - const emptyRect = { x: 0, y: 0, width: 0, height: 0 }; - - if (nodeLookup.size === 0) { - return emptyRect; - } - let box = { x: Infinity, y: Infinity, x2: -Infinity, y2: -Infinity }; - let hasVisibleNodes = false; nodeLookup.forEach((node) => { if (params.filter === undefined || params.filter(node)) { + box = getBoundsOfBoxes(box, nodeToBox(node as InternalNodeBase)); hasVisibleNodes = true; - const nodeBox = nodeToBox(node as InternalNodeBase); - box = getBoundsOfBoxes(box, nodeBox); } }); - return hasVisibleNodes ? boxToRect(box) : emptyRect; + return hasVisibleNodes ? boxToRect(box) : { x: 0, y: 0, width: 0, height: 0 }; }; export const getNodesInside = ( From 15831900dec006043e8459ac25c44ae0762bb87a Mon Sep 17 00:00:00 2001 From: Moritz Klack Date: Tue, 14 Oct 2025 16:05:31 +0200 Subject: [PATCH 10/10] Do not crash minimap if all nodes are hidden Refactor getInternalNodesBounds for improved stability. --- .changeset/giant-foxes-roll.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/giant-foxes-roll.md b/.changeset/giant-foxes-roll.md index 2cc1b82a..14d73c64 100644 --- a/.changeset/giant-foxes-roll.md +++ b/.changeset/giant-foxes-roll.md @@ -3,4 +3,4 @@ '@xyflow/system': patch --- -Fix Minimap if all nodes are hidden in a flow and refactor getInternalNodesBounds +Do not crash minimap if all nodes are hidden