Compare commits

...

17 Commits

Author SHA1 Message Date
c6b585403e init commit
Some checks failed
Playwright Tests / Playwright Tests (push) Has been cancelled
2026-03-17 16:30:30 +03:30
Moritz Klack
6ec8214cf3 Merge pull request #5691 from xyflow/changeset-release/main
Release packages
2026-02-19 12:52:21 +01:00
github-actions[bot]
81a284a27c chore(packages): bump 2026-02-18 20:15:08 +00:00
Moritz Klack
ac89f9fa63 Merge pull request #5684 from ysds/fix/nodes-selection-drag-after-programmatic-selection
fix: ensure drag handlers update when nodes selection changes programmatically
2026-02-18 21:13:47 +01:00
Moritz Klack
d66689691d Merge pull request #5704 from xyflow/fix/old-callback-reference
Fix old callback references passed to XYHandle
2026-02-18 21:04:47 +01:00
Moritz Klack
e3c1f42e9a Update connection status during ongoing connection 2026-02-18 11:15:02 +01:00
peterkogo
c91d3d022f chore(changeset) 2026-02-18 10:49:43 +01:00
Moritz Klack
48eed6f105 Merge pull request #5703 from xyflow/fix/use-nodes-data-type
Improve return type of useNodesData
2026-02-16 20:57:22 +01:00
peterkogo
45a4a977c5 Always use latest version of onConnectEnd & isValidConnection in Handle/ReconnectAnchors 2026-02-10 16:02:43 +01:00
peterkogo
ce6c869df4 Improve return type of useNodesdata 2026-02-10 10:58:51 +01:00
Moritz Klack
7813d07345 Merge pull request #5698 from xyflow/fix/svelte-subflow-minimap
Fix/svelte subflow minimap
2026-02-09 22:39:02 +01:00
peterkogo
cb41f444eb simplify code & useEffect instead of uselayoutEffect 2026-02-09 07:57:41 +01:00
peterkogo
ee53f8baf7 add reproduction of the bug 2026-02-06 19:41:24 +01:00
peterkogo
7eeebc9c04 chore(changeset) 2026-02-04 14:18:34 +01:00
peterkogo
5166e1df83 fix child nodes not updating in Minimap 2026-02-04 14:17:31 +01:00
ysds
382c654c31 chore(changeset): add changeset for drag handler fix 2026-01-24 03:01:29 +09:00
ysds
03b8e1ef19 fix: ensure drag handlers update when nodes selection changes programmatically
Fixes #4841

When nodes were programmatically selected (e.g., adding a new node with `selected: true`),
the nodes selection rectangle would appear but dragging it would not work.

Changes:
- Consolidated duplicate effect hooks in useDrag into a single useIsomorphicLayoutEffect
- Added `disabled` parameter to useDrag to allow external control
- NodesSelection now passes `disabled: !shouldRender` to useDrag
- Improved condition clarity with `shouldRender` variable

This ensures drag handlers are properly set up when nodeRef.current becomes available,
even when the selection state changes after the initial render.
2026-01-24 02:29:02 +09:00
28 changed files with 17286 additions and 5604 deletions

View File

@@ -1,5 +0,0 @@
---
'@xyflow/react': patch
---
Optimize zooming performance when panOnScroll mode is enabled

View File

@@ -1,5 +0,0 @@
---
'@xyflow/react': patch
---
Prevent unnecessary updates when selectNodesOnDrag = false

View File

@@ -1,5 +0,0 @@
---
'@xyflow/react': patch
---
Handle undefined node in mini map

14166
_pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -62,6 +62,7 @@ import MovingHandles from '../examples/MovingHandles';
import DetachedHandle from '../examples/DetachedHandle'; import DetachedHandle from '../examples/DetachedHandle';
import ZIndexMode from '../examples/ZIndexMode'; import ZIndexMode from '../examples/ZIndexMode';
import Middlewares from '../examples/Middlewares'; import Middlewares from '../examples/Middlewares';
import NodeSelectionBug from '../examples/NodeSelectionBug';
export interface IRoute { export interface IRoute {
name: string; name: string;
@@ -390,6 +391,11 @@ const routes: IRoute[] = [
path: 'z-index-mode', path: 'z-index-mode',
component: ZIndexMode, component: ZIndexMode,
}, },
{
name: 'Node Selection Bug',
path: 'node-selection-bug',
component: NodeSelectionBug,
},
]; ];
export default routes; export default routes;

View File

@@ -0,0 +1,41 @@
import { Node, ReactFlow, useNodesState } from '@xyflow/react';
import '@xyflow/react/dist/style.css';
import { useRef } from 'react';
export default function App() {
const [nodes, setNodes, onNodesChange] = useNodesState<Node>([
{
id: '0',
position: { x: 0, y: 0 },
data: { label: 'Rectangle Select Me First' },
},
]);
const id = useRef(0);
return (
<>
<button
onClick={() =>
setNodes((nodes) => [
...nodes.map((node) => ({ ...node, selected: false })),
{
id: (++id.current).toString(),
position: { x: -100, y: 100 * Math.floor((id.current + 1) / 2) },
data: { label: `Button Node ${id.current}` },
selected: true,
},
{
id: (++id.current).toString(),
position: { x: 100, y: (100 * id.current) / 2 },
data: { label: `Button Node ${id.current}` },
selected: true,
},
])
}
>
Click me to add nodes that are already selected.
</button>
<ReactFlow nodes={nodes} onNodesChange={onNodesChange} fitView></ReactFlow>
</>
);
}

View File

@@ -1,7 +1,8 @@
import { memo, useState } from 'react'; import { memo, useState } from 'react';
import { Position, NodeProps, Handle, useReactFlow } from '@xyflow/react'; import { Position, NodeProps, Handle, useReactFlow } from '@xyflow/react';
import type { TextNode } from '.';
function TextNode({ id, data }: NodeProps) { function TextNode({ id, data }: NodeProps<TextNode>) {
const { updateNodeData } = useReactFlow(); const { updateNodeData } = useReactFlow();
const [text, setText] = useState(data.text); const [text, setText] = useState(data.text);
const updateText = (text: string) => { const updateText = (text: string) => {

View File

@@ -1,18 +1,18 @@
import { memo, useEffect } from 'react'; import { memo, useEffect } from 'react';
import { Position, NodeProps, useReactFlow, Handle, useNodeConnections, useNodesData } from '@xyflow/react'; import { Position, NodeProps, useReactFlow, Handle, useNodeConnections, useNodesData } from '@xyflow/react';
import { isTextNode, type TextNode, type MyNode } from '.'; import { isTextNode, type TextNode, type MyNode, type UppercaseNode } from '.';
function UppercaseNode({ id }: NodeProps) { function UppercaseNode({ id }: NodeProps<UppercaseNode>) {
const { updateNodeData } = useReactFlow(); const { updateNodeData } = useReactFlow();
const connections = useNodeConnections({ const connections = useNodeConnections({
handleType: 'target', handleType: 'target',
}); });
const nodesData = useNodesData<MyNode>(connections[0]?.source); const nodesData = useNodesData<MyNode>(connections[0]?.source);
const textNode = isTextNode(nodesData) ? nodesData : null;
useEffect(() => { useEffect(() => {
updateNodeData(id, { text: textNode?.data.text.toUpperCase() }); const text = nodesData?.type === 'text' ? nodesData?.data.text.toUpperCase() : undefined;
}, [textNode]); updateNodeData(id, { text });
}, [nodesData]);
return ( return (
<div style={{ background: '#eee', color: '#222', padding: 10, fontSize: 12, borderRadius: 10 }}> <div style={{ background: '#eee', color: '#222', padding: 10, fontSize: 12, borderRadius: 10 }}>

View File

@@ -8,22 +8,21 @@
type Node, type Node,
type NodeProps type NodeProps
} from '@xyflow/svelte'; } from '@xyflow/svelte';
import { isTextNode, type MyNode } from './+page.svelte'; import { type MyNode } from './+page.svelte';
let { id }: NodeProps<Node<{ text: string }>> = $props(); let { id }: NodeProps<Node<{ text: string }>> = $props();
const { updateNodeData } = useSvelteFlow(); const { updateNodeData } = useSvelteFlow();
const connections = useNodeConnections({ const connections = useNodeConnections({
id: id,
handleType: 'target' handleType: 'target'
}); });
let nodeData = $derived(useNodesData<MyNode>(connections.current[0]?.source)); let nodesData = $derived(useNodesData<MyNode>(connections.current[0]?.source));
let textNodeData = $derived(isTextNode(nodeData.current) ? nodeData.current.data.text : null);
$effect.pre(() => { $effect.pre(() => {
const input = textNodeData?.toUpperCase() ?? ''; const text =
updateNodeData(id, { text: input }); nodesData.current?.type === 'text' ? nodesData.current?.data.text.toUpperCase() : undefined;
updateNodeData(id, { text });
}); });
</script> </script>

View File

@@ -1,5 +1,24 @@
# @xyflow/react # @xyflow/react
## 12.10.1
### Patch Changes
- [#5704](https://github.com/xyflow/xyflow/pull/5704) [`c91d3d022`](https://github.com/xyflow/xyflow/commit/c91d3d022f4517f4403a898cd02ee891b7e1f2d2) Thanks [@peterkogo](https://github.com/peterkogo)! - Keep `onConnectEnd` and `isValidConnection` up to date in an ongoing connection
- [#5687](https://github.com/xyflow/xyflow/pull/5687) [`2624479ad`](https://github.com/xyflow/xyflow/commit/2624479ad3d0b06fcb690242b2372ff2a7e16f54) Thanks [@vkrol](https://github.com/vkrol)! - Optimize zooming performance when panOnScroll mode is enabled
- [#5682](https://github.com/xyflow/xyflow/pull/5682) [`7b6e46ce1`](https://github.com/xyflow/xyflow/commit/7b6e46ce17f49e759f614a8f933f7dc729635b48) Thanks [@artemtam](https://github.com/artemtam)! - Prevent unnecessary updates when selectNodesOnDrag = false
- [#5703](https://github.com/xyflow/xyflow/pull/5703) [`ce6c869df`](https://github.com/xyflow/xyflow/commit/ce6c869df40b2b013484808c742ca508da4a591f) Thanks [@peterkogo](https://github.com/peterkogo)! - Improve return type of useNodesData. Now you can narrow down the data type by checking the node type.
- [#5692](https://github.com/xyflow/xyflow/pull/5692) [`49646858f`](https://github.com/xyflow/xyflow/commit/49646858f951455921aedbb83725b4225dbdef9d) Thanks [@moklick](https://github.com/moklick)! - Handle undefined node in mini map
- [#5684](https://github.com/xyflow/xyflow/pull/5684) [`382c654c3`](https://github.com/xyflow/xyflow/commit/382c654c315accca2005e39d477eed6649f12e40) Thanks [@ysds](https://github.com/ysds)! - Consolidate drag handler effects in useDrag to fix programmatic selection issues
- Updated dependencies [[`ce6c869df`](https://github.com/xyflow/xyflow/commit/ce6c869df40b2b013484808c742ca508da4a591f)]:
- @xyflow/system@0.0.75
## 12.10.0 ## 12.10.0
### Minor Changes ### Minor Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@xyflow/react", "name": "@xyflow/react",
"version": "12.10.0", "version": "12.10.1",
"description": "React Flow - A highly customizable React library for building node-based editors and interactive flow charts.", "description": "React Flow - A highly customizable React library for building node-based editors and interactive flow charts.",
"keywords": [ "keywords": [
"react", "react",

View File

@@ -53,12 +53,10 @@ export function EdgeUpdateAnchors<EdgeType extends Edge = Edge>({
const { const {
autoPanOnConnect, autoPanOnConnect,
domNode, domNode,
isValidConnection,
connectionMode, connectionMode,
connectionRadius, connectionRadius,
lib, lib,
onConnectStart, onConnectStart,
onConnectEnd,
cancelConnection, cancelConnection,
nodeLookup, nodeLookup,
rfId: flowId, rfId: flowId,
@@ -93,10 +91,10 @@ export function EdgeUpdateAnchors<EdgeType extends Edge = Edge>({
flowId, flowId,
cancelConnection, cancelConnection,
panBy, panBy,
isValidConnection, isValidConnection: (...args) => store.getState().isValidConnection?.(...args) ?? true,
onConnect: onConnectEdge, onConnect: onConnectEdge,
onConnectStart: _onConnectStart, onConnectStart: _onConnectStart,
onConnectEnd, onConnectEnd: (...args) => store.getState().onConnectEnd?.(...args),
onReconnectEnd: _onReconnectEnd, onReconnectEnd: _onReconnectEnd,
updateConnection, updateConnection,
getTransform: () => store.getState().transform, getTransform: () => store.getState().transform,

View File

@@ -142,10 +142,10 @@ function HandleComponent(
panBy: currentStore.panBy, panBy: currentStore.panBy,
cancelConnection: currentStore.cancelConnection, cancelConnection: currentStore.cancelConnection,
onConnectStart: currentStore.onConnectStart, onConnectStart: currentStore.onConnectStart,
onConnectEnd: currentStore.onConnectEnd, onConnectEnd: (...args) => store.getState().onConnectEnd?.(...args),
updateConnection: currentStore.updateConnection, updateConnection: currentStore.updateConnection,
onConnect: onConnectExtended, onConnect: onConnectExtended,
isValidConnection: isValidConnection || currentStore.isValidConnection, isValidConnection: isValidConnection || ((...args) => store.getState().isValidConnection?.(...args) ?? true),
getTransform: () => store.getState().transform, getTransform: () => store.getState().transform,
getFromHandle: () => store.getState().connection.fromHandle, getFromHandle: () => store.getState().connection.fromHandle,
autoPanSpeed: currentStore.autoPanSpeed, autoPanSpeed: currentStore.autoPanSpeed,

View File

@@ -51,11 +51,14 @@ export function NodesSelection<NodeType extends Node>({
} }
}, [disableKeyboardA11y]); }, [disableKeyboardA11y]);
const shouldRender = !userSelectionActive && width !== null && height !== null;
useDrag({ useDrag({
nodeRef, nodeRef,
disabled: !shouldRender,
}); });
if (userSelectionActive || !width || !height) { if (!shouldRender) {
return null; return null;
} }

View File

@@ -52,22 +52,23 @@ export function useDrag({
}, []); }, []);
useEffect(() => { useEffect(() => {
if (disabled) { if (disabled || !nodeRef.current || !xyDrag.current) {
xyDrag.current?.destroy(); return;
} else if (nodeRef.current) {
xyDrag.current?.update({
noDragClassName,
handleSelector,
domNode: nodeRef.current,
isSelectable,
nodeId,
nodeClickDistance,
});
return () => {
xyDrag.current?.destroy();
};
} }
}, [noDragClassName, handleSelector, disabled, isSelectable, nodeRef, nodeId]);
xyDrag.current.update({
noDragClassName,
handleSelector,
domNode: nodeRef.current,
isSelectable,
nodeId,
nodeClickDistance,
});
return () => {
xyDrag.current?.destroy();
};
}, [noDragClassName, handleSelector, disabled, isSelectable, nodeRef, nodeId, nodeClickDistance]);
return dragging; return dragging;
} }

View File

@@ -1,5 +1,5 @@
import { useCallback } from 'react'; import { useCallback } from 'react';
import { shallowNodeData } from '@xyflow/system'; import { DistributivePick, shallowNodeData } from '@xyflow/system';
import { useStore } from '../hooks/useStore'; import { useStore } from '../hooks/useStore';
import type { Node } from '../types'; import type { Node } from '../types';
@@ -25,11 +25,11 @@ import type { Node } from '../types';
export function useNodesData<NodeType extends Node = Node>( export function useNodesData<NodeType extends Node = Node>(
/** The id of the node to get the data from. */ /** The id of the node to get the data from. */
nodeId: string nodeId: string
): Pick<NodeType, 'id' | 'type' | 'data'> | null; ): DistributivePick<NodeType, 'id' | 'type' | 'data'> | null;
export function useNodesData<NodeType extends Node = Node>( export function useNodesData<NodeType extends Node = Node>(
/** The ids of the nodes to get the data from. */ /** The ids of the nodes to get the data from. */
nodeIds: string[] nodeIds: string[]
): Pick<NodeType, 'id' | 'type' | 'data'>[]; ): DistributivePick<NodeType, 'id' | 'type' | 'data'>[];
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
export function useNodesData(nodeIds: any): any { export function useNodesData(nodeIds: any): any {
const nodesData = useStore( const nodesData = useStore(

View File

@@ -1,5 +1,18 @@
# @xyflow/svelte # @xyflow/svelte
## 1.5.1
### Patch Changes
- [#5704](https://github.com/xyflow/xyflow/pull/5704) [`c91d3d022`](https://github.com/xyflow/xyflow/commit/c91d3d022f4517f4403a898cd02ee891b7e1f2d2) Thanks [@peterkogo](https://github.com/peterkogo)! - Keep `onConnectEnd` and `isValidConnection` up to date in an ongoing connection
- [#5703](https://github.com/xyflow/xyflow/pull/5703) [`ce6c869df`](https://github.com/xyflow/xyflow/commit/ce6c869df40b2b013484808c742ca508da4a591f) Thanks [@peterkogo](https://github.com/peterkogo)! - Improve return type of useNodesData. Now you can narrow down the data type by checking the node type.
- [#5698](https://github.com/xyflow/xyflow/pull/5698) [`7eeebc9c0`](https://github.com/xyflow/xyflow/commit/7eeebc9c04ce88f821363e3ea83e4dae36e04c45) Thanks [@peterkogo](https://github.com/peterkogo)! - Fix child nodes not updating on the Minimap when parent is dragged
- Updated dependencies [[`ce6c869df`](https://github.com/xyflow/xyflow/commit/ce6c869df40b2b013484808c742ca508da4a591f)]:
- @xyflow/system@0.0.75
## 1.5.0 ## 1.5.0
### Minor Changes ### Minor Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@xyflow/svelte", "name": "@xyflow/svelte",
"version": "1.5.0", "version": "1.5.1",
"description": "Svelte Flow - A highly customizable Svelte library for building node-based editors, workflow systems, diagrams and more.", "description": "Svelte Flow - A highly customizable Svelte library for building node-based editors, workflow systems, diagrams and more.",
"keywords": [ "keywords": [
"svelte", "svelte",

View File

@@ -79,9 +79,9 @@
flowId, flowId,
cancelConnection, cancelConnection,
panBy, panBy,
isValidConnection, isValidConnection: (...args) => store.isValidConnection?.(...args) ?? true,
onConnectStart: _onConnectStart, onConnectStart: _onConnectStart,
onConnectEnd: onconnectend, onConnectEnd: (...args) => store.onconnectend?.(...args),
onConnect: (connection) => { onConnect: (connection) => {
const reconnectedEdge = { ...edge, ...connection }; const reconnectedEdge = { ...edge, ...connection };
const newEdge = onbeforereconnect const newEdge = onbeforereconnect

View File

@@ -125,21 +125,14 @@
autoPanOnConnect: store.autoPanOnConnect, autoPanOnConnect: store.autoPanOnConnect,
autoPanSpeed: store.autoPanSpeed, autoPanSpeed: store.autoPanSpeed,
flowId: store.flowId, flowId: store.flowId,
isValidConnection: isValidConnection ?? store.isValidConnection, isValidConnection:
isValidConnection || ((...args) => store.isValidConnection?.(...args) ?? true),
updateConnection: store.updateConnection, updateConnection: store.updateConnection,
cancelConnection: store.cancelConnection, cancelConnection: store.cancelConnection,
panBy: store.panBy, panBy: store.panBy,
onConnect: onConnectExtended, onConnect: onConnectExtended,
onConnectStart: (event, startParams) => { onConnectStart: store.onconnectstart,
store.onconnectstart?.(event, { onConnectEnd: (...args) => store.onconnectend?.(...args),
nodeId: startParams.nodeId,
handleId: startParams.handleId,
handleType: startParams.handleType
});
},
onConnectEnd: (event, connectionState) => {
store.onconnectend?.(event, connectionState);
},
getTransform: () => [store.viewport.x, store.viewport.y, store.viewport.zoom], getTransform: () => [store.viewport.x, store.viewport.y, store.viewport.zoom],
getFromHandle: () => store.connection.fromHandle, getFromHandle: () => store.connection.fromHandle,
dragThreshold: store.connectionDragThreshold, dragThreshold: store.connectionDragThreshold,

View File

@@ -1,4 +1,4 @@
import { shallowNodeData } from '@xyflow/system'; import { shallowNodeData, type DistributivePick } from '@xyflow/system';
import type { Node } from '$lib/types'; import type { Node } from '$lib/types';
import { useStore } from '$lib/store'; import { useStore } from '$lib/store';
@@ -12,10 +12,10 @@ import { useStore } from '$lib/store';
*/ */
export function useNodesData<NodeType extends Node = Node>( export function useNodesData<NodeType extends Node = Node>(
nodeId: string nodeId: string
): { current: Pick<NodeType, 'id' | 'data' | 'type'> | null }; ): { current: DistributivePick<NodeType, 'id' | 'data' | 'type'> | null };
export function useNodesData<NodeType extends Node = Node>( export function useNodesData<NodeType extends Node = Node>(
nodeIds: string[] nodeIds: string[]
): { current: Pick<NodeType, 'id' | 'data' | 'type'>[] }; ): { current: DistributivePick<NodeType, 'id' | 'data' | 'type'>[] };
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
export function useNodesData(nodeIds: any): any { export function useNodesData(nodeIds: any): any {
const { nodes, nodeLookup } = $derived(useStore()); const { nodes, nodeLookup } = $derived(useStore());

View File

@@ -6,12 +6,7 @@
</script> </script>
<script lang="ts"> <script lang="ts">
import { import { getBoundsOfRects, getInternalNodesBounds, nodeHasDimensions } from '@xyflow/system';
getBoundsOfRects,
getInternalNodesBounds,
getNodeDimensions,
nodeHasDimensions
} from '@xyflow/system';
import { useStore } from '$lib/store'; import { useStore } from '$lib/store';
import { Panel } from '$lib/container/Panel'; import { Panel } from '$lib/container/Panel';
@@ -45,9 +40,6 @@
let store = $derived(useStore()); let store = $derived(useStore());
let ariaLabelConfig = $derived(store.ariaLabelConfig); let ariaLabelConfig = $derived(store.ariaLabelConfig);
const nodeColorFunc = nodeColor === undefined ? undefined : getAttrFunction(nodeColor);
const nodeStrokeColorFunc = getAttrFunction(nodeStrokeColor);
const nodeClassFunc = getAttrFunction(nodeClass);
const shapeRendering = const shapeRendering =
// @ts-expect-error - TS doesn't know about chrome // @ts-expect-error - TS doesn't know about chrome
typeof window === 'undefined' || !!window.chrome ? 'crispEdges' : 'geometricPrecision'; typeof window === 'undefined' || !!window.chrome ? 'crispEdges' : 'geometricPrecision';
@@ -119,20 +111,16 @@
{#each store.nodes as userNode (userNode.id)} {#each store.nodes as userNode (userNode.id)}
{@const node = store.nodeLookup.get(userNode.id)} {@const node = store.nodeLookup.get(userNode.id)}
{#if node && nodeHasDimensions(node) && !node.hidden} {#if node && nodeHasDimensions(node) && !node.hidden}
{@const nodeDimesions = getNodeDimensions(node)}
<MinimapNode <MinimapNode
id={node.id} id={node.id}
x={node.internals.positionAbsolute.x}
y={node.internals.positionAbsolute.y}
{...nodeDimesions}
selected={node.selected} selected={node.selected}
{nodeComponent} {nodeComponent}
color={nodeColorFunc?.(node)} color={nodeColor === undefined ? undefined : getAttrFunction(nodeColor)(userNode)}
borderRadius={nodeBorderRadius} borderRadius={nodeBorderRadius}
strokeColor={nodeStrokeColorFunc(node)} strokeColor={getAttrFunction(nodeStrokeColor)(userNode)}
strokeWidth={nodeStrokeWidth} strokeWidth={nodeStrokeWidth}
{shapeRendering} {shapeRendering}
class={nodeClassFunc(node)} class={getAttrFunction(nodeClass)(userNode)}
/> />
{/if} {/if}
{/each} {/each}

View File

@@ -1,14 +1,15 @@
<script lang="ts"> <script lang="ts">
import type { ClassValue } from 'svelte/elements';
import type { Component } from 'svelte'; import type { Component } from 'svelte';
import type { MiniMapNodeProps } from './types'; import type { MiniMapNodeProps } from './types';
import { useInternalNode } from '$lib/hooks/useInternalNode.svelte';
import { getNodeDimensions } from '@xyflow/system';
let { let {
id, id,
x, x: xProp,
y, y: yProp,
width, width: widthProp,
height, height: heightProp,
borderRadius = 5, borderRadius = 5,
color, color,
shapeRendering, shapeRendering,
@@ -17,21 +18,26 @@
selected, selected,
class: className, class: className,
nodeComponent nodeComponent
}: { }: MiniMapNodeProps & {
id: string;
x: number;
y: number;
width: number;
height: number;
borderRadius?: number;
color?: string;
shapeRendering: string;
strokeColor?: string;
strokeWidth?: number;
selected?: boolean;
class?: ClassValue;
nodeComponent?: Component<MiniMapNodeProps>; nodeComponent?: Component<MiniMapNodeProps>;
} = $props(); } = $props();
let internalNode = $derived(useInternalNode(id));
let { width, height, x, y } = $derived.by(() => {
if (!internalNode.current) {
return { width: 0, height: 0, x: 0, y: 0 };
}
const { width, height } = getNodeDimensions(internalNode.current);
return {
width: widthProp ?? width,
height: heightProp ?? height,
x: xProp ?? internalNode.current.internals.positionAbsolute.x,
y: yProp ?? internalNode.current.internals.positionAbsolute.y
};
});
</script> </script>
{#if nodeComponent} {#if nodeComponent}

View File

@@ -12,10 +12,10 @@ export type GetMiniMapNodeAttribute = (node: Node) => string;
*/ */
export type MiniMapNodeProps = { export type MiniMapNodeProps = {
id: string; id: string;
x: number; x?: number;
y: number; y?: number;
width: number; width?: number;
height: number; height?: number;
borderRadius?: number; borderRadius?: number;
class?: ClassValue; class?: ClassValue;
color?: string; color?: string;

View File

@@ -1,5 +1,11 @@
# @xyflow/system # @xyflow/system
## 0.0.75
### Patch Changes
- [#5703](https://github.com/xyflow/xyflow/pull/5703) [`ce6c869df`](https://github.com/xyflow/xyflow/commit/ce6c869df40b2b013484808c742ca508da4a591f) Thanks [@peterkogo](https://github.com/peterkogo)! - Improve return type of useNodesData. Now you can narrow down the data type by checking the node type.
## 0.0.74 ## 0.0.74
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@xyflow/system", "name": "@xyflow/system",
"version": "0.0.74", "version": "0.0.75",
"description": "xyflow core system that powers React Flow and Svelte Flow.", "description": "xyflow core system that powers React Flow and Svelte Flow.",
"keywords": [ "keywords": [
"node-based UI", "node-based UI",

View File

@@ -56,3 +56,10 @@ export type Transform = [number, number, number];
* to represent an unbounded extent. * to represent an unbounded extent.
*/ */
export type CoordinateExtent = [[number, number], [number, number]]; export type CoordinateExtent = [[number, number], [number, number]];
/**
* Using Pick with a union type (e.g. `NodeType`) will merge every property type along all union members.
* See https://github.com/microsoft/TypeScript/issues/28339#issuecomment-463577347
* Note: Currently you are able to Pick properties that are not in the type without error.
*/
export type DistributivePick<T, K extends string> = T extends unknown ? { [P in Extract<keyof T, K>]: T[P] } : never;

8440
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff