From 7d24127e3f5ea4b63a1cab85531eb78d03f96f8c Mon Sep 17 00:00:00 2001 From: peterkogo Date: Thu, 11 Apr 2024 13:03:12 +0200 Subject: [PATCH 01/27] added isValidConnection on Handle component --- packages/svelte/src/lib/components/Handle/Handle.svelte | 7 +++++-- packages/svelte/src/lib/types/general.ts | 4 ++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/svelte/src/lib/components/Handle/Handle.svelte b/packages/svelte/src/lib/components/Handle/Handle.svelte index f93688fc..fdc80c49 100644 --- a/packages/svelte/src/lib/components/Handle/Handle.svelte +++ b/packages/svelte/src/lib/components/Handle/Handle.svelte @@ -22,12 +22,15 @@ export let position: $$Props['position'] = Position.Top; export let style: $$Props['style'] = undefined; export let isConnectable: $$Props['isConnectable'] = undefined; + export let isValidConnection: $$Props['isValidConnection'] = undefined; export let onconnect: $$Props['onconnect'] = undefined; export let ondisconnect: $$Props['ondisconnect'] = undefined; // @todo implement connectablestart, connectableend // export let isConnectableStart: $$Props['isConnectableStart'] = undefined; // export let isConnectableEnd: $$Props['isConnectableEnd'] = undefined; + $: console.log(isValidConnection); + let className: $$Props['class'] = undefined; export { className as class }; @@ -45,7 +48,7 @@ nodeLookup, connectionRadius, viewport, - isValidConnection, + isValidConnection: isValidConnectionStore, lib, addEdge, onedgecreate, @@ -77,7 +80,7 @@ lib: $lib, autoPanOnConnect: $autoPanOnConnect, flowId: $flowId, - isValidConnection: $isValidConnection, + isValidConnection: isValidConnection ?? $isValidConnectionStore, updateConnection, cancelConnection, panBy, diff --git a/packages/svelte/src/lib/types/general.ts b/packages/svelte/src/lib/types/general.ts index fe728fae..71e2047a 100644 --- a/packages/svelte/src/lib/types/general.ts +++ b/packages/svelte/src/lib/types/general.ts @@ -45,6 +45,10 @@ export type HandleComponentProps = { isConnectableStart?: boolean; /** Should you be able to connect to this handle */ isConnectableEnd?: boolean; + /** Function that is called when checking if connection is valid. + * Overrides the isValidConnection on the Flow component. + */ + isValidConnection?: IsValidConnection; onconnect?: (connections: Connection[]) => void; ondisconnect?: (connections: Connection[]) => void; }; From e25c3304d00d5c79f344ab72800346f9653bfa7d Mon Sep 17 00:00:00 2001 From: peterkogo Date: Thu, 11 Apr 2024 13:05:36 +0200 Subject: [PATCH 02/27] removed console.log --- packages/svelte/src/lib/components/Handle/Handle.svelte | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/svelte/src/lib/components/Handle/Handle.svelte b/packages/svelte/src/lib/components/Handle/Handle.svelte index fdc80c49..e004250b 100644 --- a/packages/svelte/src/lib/components/Handle/Handle.svelte +++ b/packages/svelte/src/lib/components/Handle/Handle.svelte @@ -29,8 +29,6 @@ // export let isConnectableStart: $$Props['isConnectableStart'] = undefined; // export let isConnectableEnd: $$Props['isConnectableEnd'] = undefined; - $: console.log(isValidConnection); - let className: $$Props['class'] = undefined; export { className as class }; From a0a046e21f02c813d5205fe4abc4e11e6b8d7012 Mon Sep 17 00:00:00 2001 From: Daniel Darabos Date: Thu, 18 Apr 2024 12:35:13 +0200 Subject: [PATCH 03/27] Do not reset nodes and edges. They are controlled by the user. --- packages/svelte/src/lib/store/index.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/svelte/src/lib/store/index.ts b/packages/svelte/src/lib/store/index.ts index c808d2af..7ab5611a 100644 --- a/packages/svelte/src/lib/store/index.ts +++ b/packages/svelte/src/lib/store/index.ts @@ -349,8 +349,6 @@ export function createStore({ store.selectionRectMode.set(null); store.snapGrid.set(null); store.isValidConnection.set(() => true); - store.nodes.set([]); - store.edges.set([]); unselectNodesAndEdges(); cancelConnection(); From 72582b035fe016cc1b86cc242e0c76457ccffe77 Mon Sep 17 00:00:00 2001 From: RedPhoenixQ Date: Mon, 22 Apr 2024 18:29:07 +0200 Subject: [PATCH 04/27] Move node EventMap to types and use createEventDispatcher from svelte Using createEventDispatcher from another imported function seems to break the svelte types and thus none of the node events where typed. --- .../NodeSelection/NodeSelection.svelte | 20 +++++++++---------- .../components/NodeWrapper/NodeWrapper.svelte | 6 +++--- packages/svelte/src/lib/types/nodes.ts | 11 ++++++++++ packages/svelte/src/lib/utils/index.ts | 13 ------------ 4 files changed, 24 insertions(+), 26 deletions(-) diff --git a/packages/svelte/src/lib/components/NodeSelection/NodeSelection.svelte b/packages/svelte/src/lib/components/NodeSelection/NodeSelection.svelte index e648604a..08a1cd6e 100644 --- a/packages/svelte/src/lib/components/NodeSelection/NodeSelection.svelte +++ b/packages/svelte/src/lib/components/NodeSelection/NodeSelection.svelte @@ -5,17 +5,17 @@ import { useStore } from '$lib/store'; import { Selection } from '$lib/components/Selection'; import drag from '$lib/actions/drag'; - import type { Node } from '$lib/types'; - import { createNodeEventDispatcher } from '$lib'; + import type { Node, NodeEventMap } from '$lib/types'; const store = useStore(); const { selectionRectMode, nodes } = store; - const dispatch = createEventDispatcher<{ - selectioncontextmenu: { nodes: Node[]; event: MouseEvent | TouchEvent }; - selectionclick: { nodes: Node[]; event: MouseEvent | TouchEvent }; - }>(); - const dispatchNodeEvent = createNodeEventDispatcher(); + const dispatch = createEventDispatcher< + NodeEventMap & { + selectioncontextmenu: { nodes: Node[]; event: MouseEvent | TouchEvent }; + selectionclick: { nodes: Node[]; event: MouseEvent | TouchEvent }; + } + >(); $: selectedNodes = $nodes.filter((n) => n.selected); $: bounds = getNodesBounds(selectedNodes); @@ -37,13 +37,13 @@ disabled: false, store, onDrag: (event, _, __, nodes) => { - dispatchNodeEvent('nodedrag', { event, targetNode: null, nodes }); + dispatch('nodedrag', { event, targetNode: null, nodes }); }, onDragStart: (event, _, __, nodes) => { - dispatchNodeEvent('nodedragstart', { event, targetNode: null, nodes }); + dispatch('nodedragstart', { event, targetNode: null, nodes }); }, onDragStop: (event, _, __, nodes) => { - dispatchNodeEvent('nodedragstop', { event, targetNode: null, nodes }); + dispatch('nodedragstop', { event, targetNode: null, nodes }); } }} on:contextmenu={onContextMenu} diff --git a/packages/svelte/src/lib/components/NodeWrapper/NodeWrapper.svelte b/packages/svelte/src/lib/components/NodeWrapper/NodeWrapper.svelte index 74a30a3b..c0966ab9 100644 --- a/packages/svelte/src/lib/components/NodeWrapper/NodeWrapper.svelte +++ b/packages/svelte/src/lib/components/NodeWrapper/NodeWrapper.svelte @@ -1,7 +1,7 @@
-
Node
- - - +
Node
+ + +
diff --git a/examples/svelte/src/routes/examples/customnode/CustomNode.svelte b/examples/svelte/src/routes/examples/customnode/CustomNode.svelte index e22701e3..47a33534 100644 --- a/examples/svelte/src/routes/examples/customnode/CustomNode.svelte +++ b/examples/svelte/src/routes/examples/customnode/CustomNode.svelte @@ -6,6 +6,8 @@ export let data: $$Props['data']; + $$restProps; + const { colorStore } = data; diff --git a/examples/svelte/src/routes/examples/edges/ButtonEdge.svelte b/examples/svelte/src/routes/examples/edges/ButtonEdge.svelte index 235aab98..ee582226 100644 --- a/examples/svelte/src/routes/examples/edges/ButtonEdge.svelte +++ b/examples/svelte/src/routes/examples/edges/ButtonEdge.svelte @@ -4,27 +4,18 @@ type $$Props = EdgeProps; export let id: $$Props['id'] = ''; - export let source: $$Props['source'] = ''; - export let target: $$Props['target'] = ''; - export let animated: $$Props['animated'] = undefined; - export let selected: $$Props['selected'] = undefined; - export let label: $$Props['label'] = undefined; - export let labelStyle: $$Props['labelStyle'] = undefined; - export let data: $$Props['data'] = undefined; export let style: $$Props['style'] = undefined; - export let markerStart: $$Props['markerStart'] = undefined; export let markerEnd: $$Props['markerEnd'] = undefined; - export let interactionWidth: $$Props['interactionWidth'] = undefined; export let sourceX: $$Props['sourceX']; export let sourceY: $$Props['sourceY']; export let sourcePosition: $$Props['sourcePosition']; - export let sourceHandleId: $$Props['sourceHandleId'] = undefined; export let targetX: $$Props['targetX']; export let targetY: $$Props['targetY']; export let targetPosition: $$Props['targetPosition']; - export let targetHandleId: $$Props['targetHandleId'] = undefined; + + $$restProps; $: [edgePath, labelX, labelY] = getBezierPath({ sourceX, @@ -34,18 +25,6 @@ targetY, targetPosition }); - - source; - target; - animated; - selected; - data; - label; - labelStyle; - markerStart; - interactionWidth; - sourceHandleId; - targetHandleId; diff --git a/examples/svelte/src/routes/examples/edges/CustomBezierEdge.svelte b/examples/svelte/src/routes/examples/edges/CustomBezierEdge.svelte index 48d86c3d..960d3e6e 100644 --- a/examples/svelte/src/routes/examples/edges/CustomBezierEdge.svelte +++ b/examples/svelte/src/routes/examples/edges/CustomBezierEdge.svelte @@ -3,14 +3,8 @@ type $$Props = EdgeProps; - export let id: $$Props['id'] = ''; - export let source: $$Props['source'] = ''; - export let target: $$Props['target'] = ''; - export let animated: $$Props['animated'] = undefined; - export let selected: $$Props['selected'] = undefined; export let label: $$Props['label'] = undefined; export let labelStyle: $$Props['labelStyle'] = undefined; - export let data: $$Props['data'] = undefined; export let style: $$Props['style'] = undefined; export let markerStart: $$Props['markerStart'] = undefined; export let markerEnd: $$Props['markerEnd'] = undefined; @@ -19,23 +13,12 @@ export let sourceX: $$Props['sourceX']; export let sourceY: $$Props['sourceY']; export let sourcePosition: $$Props['sourcePosition']; - export let sourceHandleId: $$Props['sourceHandleId'] = undefined; export let targetX: $$Props['targetX']; export let targetY: $$Props['targetY']; export let targetPosition: $$Props['targetPosition']; - export let targetHandleId: $$Props['targetHandleId'] = undefined; - id; - source; - target; - animated; - selected; - data; - sourcePosition; - targetPosition; - sourceHandleId; - targetHandleId; + $$restProps;
diff --git a/examples/svelte/src/routes/examples/handle-connect/SingleHandleNode.svelte b/examples/svelte/src/routes/examples/handle-connect/SingleHandleNode.svelte index 7c1e026d..d2958969 100644 --- a/examples/svelte/src/routes/examples/handle-connect/SingleHandleNode.svelte +++ b/examples/svelte/src/routes/examples/handle-connect/SingleHandleNode.svelte @@ -21,34 +21,7 @@ console.log('disconnect source', connection); } - export let data: $$Props['data']; - export let targetPosition: $$Props['targetPosition'] = Position.Top; - export let sourcePosition: $$Props['sourcePosition'] = Position.Bottom; - export let width: $$Props['width'] = undefined; - export let height: $$Props['height'] = undefined; - export let selected: $$Props['selected'] = undefined; - export let type: $$Props['type'] = undefined; - export let zIndex: $$Props['zIndex'] = undefined; - export let dragging: $$Props['dragging'] = false; - export let dragHandle: $$Props['dragHandle'] = undefined; - export let positionAbsolute: $$Props['positionAbsolute'] = { - x: 0, - y: 0 - }; - export let isConnectable: $$Props['isConnectable'] = undefined; - - data; - targetPosition; - sourcePosition; - width; - height; - selected; - type; - zIndex; - dragging; - dragHandle; - positionAbsolute; - isConnectable; + $$restProps;
diff --git a/examples/svelte/src/routes/examples/node-resizer/+page.svelte b/examples/svelte/src/routes/examples/node-resizer/+page.svelte index 8e08174a..e03acf34 100644 --- a/examples/svelte/src/routes/examples/node-resizer/+page.svelte +++ b/examples/svelte/src/routes/examples/node-resizer/+page.svelte @@ -1,13 +1,14 @@ import { Handle, NodeResizer, Position, type NodeProps } from '@xyflow/svelte'; + import type { ResizeNode } from './types'; - type $$Props = NodeProps; + type $$Props = NodeProps; - export let data: $$Props['data'] = undefined; + export let data: $$Props['data']; export let selected: $$Props['selected'] = undefined; diff --git a/examples/svelte/src/routes/examples/node-resizer/HorizontalResizer.svelte b/examples/svelte/src/routes/examples/node-resizer/HorizontalResizer.svelte index 4942e511..5caea508 100644 --- a/examples/svelte/src/routes/examples/node-resizer/HorizontalResizer.svelte +++ b/examples/svelte/src/routes/examples/node-resizer/HorizontalResizer.svelte @@ -1,9 +1,10 @@ - - - - - - - ); -} - -export default ResizeIcon; diff --git a/examples/svelte/src/routes/examples/node-resizer/VerticalResizer.svelte b/examples/svelte/src/routes/examples/node-resizer/VerticalResizer.svelte index 65ccae15..5e173508 100644 --- a/examples/svelte/src/routes/examples/node-resizer/VerticalResizer.svelte +++ b/examples/svelte/src/routes/examples/node-resizer/VerticalResizer.svelte @@ -1,9 +1,10 @@ ; diff --git a/examples/svelte/src/routes/examples/node-toolbar/CustomNode.svelte b/examples/svelte/src/routes/examples/node-toolbar/CustomNode.svelte index af2dabaa..99b00f7c 100644 --- a/examples/svelte/src/routes/examples/node-toolbar/CustomNode.svelte +++ b/examples/svelte/src/routes/examples/node-toolbar/CustomNode.svelte @@ -2,6 +2,7 @@ import { NodeToolbar, type NodeProps, Handle, Position } from '@xyflow/svelte'; type $$Props = NodeProps; + $$restProps; export let data: $$Props['data']; diff --git a/examples/svelte/src/routes/examples/overview/CustomNode.svelte b/examples/svelte/src/routes/examples/overview/CustomNode.svelte index faf6a2a5..0e991ac2 100644 --- a/examples/svelte/src/routes/examples/overview/CustomNode.svelte +++ b/examples/svelte/src/routes/examples/overview/CustomNode.svelte @@ -1,7 +1,8 @@ diff --git a/examples/svelte/src/routes/examples/subflows/DebugNode.svelte b/examples/svelte/src/routes/examples/subflows/DebugNode.svelte index 9676957e..ecacb06b 100644 --- a/examples/svelte/src/routes/examples/subflows/DebugNode.svelte +++ b/examples/svelte/src/routes/examples/subflows/DebugNode.svelte @@ -1,16 +1,19 @@
{id}
- x:{Math.round(positionAbsolute.x)} y:{Math.round(positionAbsolute.y)} z:{zIndex} + x:{Math.round(positionAbsoluteX)} y:{Math.round(positionAbsoluteY)} z:{zIndex}
diff --git a/examples/svelte/src/routes/examples/useupdatenodeinternals/CustomNode.svelte b/examples/svelte/src/routes/examples/useupdatenodeinternals/CustomNode.svelte index fbe9c8d7..89a73e1c 100644 --- a/examples/svelte/src/routes/examples/useupdatenodeinternals/CustomNode.svelte +++ b/examples/svelte/src/routes/examples/useupdatenodeinternals/CustomNode.svelte @@ -4,6 +4,7 @@ type $$Props = NodeProps; export let id: $$Props['id']; + $$restProps; const updateNodeInternals = useUpdateNodeInternals(); From 00cbf2246c2afaf22e20c6f1dd55893d9775a132 Mon Sep 17 00:00:00 2001 From: moklick Date: Thu, 2 May 2024 15:01:14 +0200 Subject: [PATCH 14/27] fix(svelte): only update node dimension attributes when necessary --- packages/svelte/src/lib/store/index.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/svelte/src/lib/store/index.ts b/packages/svelte/src/lib/store/index.ts index c0360c3c..f37d8e47 100644 --- a/packages/svelte/src/lib/store/index.ts +++ b/packages/svelte/src/lib/store/index.ts @@ -111,8 +111,12 @@ export function createStore({ switch (change.type) { case 'dimensions': { const measured = { ...node.measured, ...change.dimensions }; - node.width = change.dimensions?.width ?? node.width; - node.height = change.dimensions?.height ?? node.height; + + if (change.setAttributes) { + node.width = change.dimensions?.width ?? node.width; + node.height = change.dimensions?.height ?? node.height; + } + node.measured = measured; break; } From 3b940ac5ae38b0c8d929685c64e9858200fd3696 Mon Sep 17 00:00:00 2001 From: moklick Date: Thu, 2 May 2024 15:01:37 +0200 Subject: [PATCH 15/27] fix(svelte): use correct updateNodeInternals API --- .../svelte/src/lib/components/NodeWrapper/NodeWrapper.svelte | 2 +- .../svelte/src/lib/container/NodeRenderer/NodeRenderer.svelte | 2 +- packages/svelte/src/lib/container/Pane/Pane.svelte | 4 ++-- packages/svelte/src/lib/hooks/useUpdateNodeInternals.ts | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/svelte/src/lib/components/NodeWrapper/NodeWrapper.svelte b/packages/svelte/src/lib/components/NodeWrapper/NodeWrapper.svelte index c0966ab9..8f13be9b 100644 --- a/packages/svelte/src/lib/components/NodeWrapper/NodeWrapper.svelte +++ b/packages/svelte/src/lib/components/NodeWrapper/NodeWrapper.svelte @@ -104,7 +104,7 @@ { id, nodeElement: nodeRef, - forceUpdate: true + force: true } ] ]) diff --git a/packages/svelte/src/lib/container/NodeRenderer/NodeRenderer.svelte b/packages/svelte/src/lib/container/NodeRenderer/NodeRenderer.svelte index dc08aee0..9aeb308d 100644 --- a/packages/svelte/src/lib/container/NodeRenderer/NodeRenderer.svelte +++ b/packages/svelte/src/lib/container/NodeRenderer/NodeRenderer.svelte @@ -26,7 +26,7 @@ updates.set(id, { id, nodeElement: entry.target as HTMLDivElement, - forceUpdate: true + force: true }); }); diff --git a/packages/svelte/src/lib/container/Pane/Pane.svelte b/packages/svelte/src/lib/container/Pane/Pane.svelte index 05cbdb41..e616a1b4 100644 --- a/packages/svelte/src/lib/container/Pane/Pane.svelte +++ b/packages/svelte/src/lib/container/Pane/Pane.svelte @@ -35,7 +35,7 @@ } from '@xyflow/system'; import { useStore } from '$lib/store'; - import type { Node, Edge } from '$lib/types'; + import type { Node, Edge, InternalNode } from '$lib/types'; import type { PaneProps } from './types'; type $$Props = PaneProps; @@ -68,7 +68,7 @@ let container: HTMLDivElement; let containerBounds: DOMRect | null = null; - let selectedNodes: Node[] = []; + let selectedNodes: InternalNode[] = []; $: _panOnDrag = $panActivationKeyPressed || panOnDrag; $: isSelecting = diff --git a/packages/svelte/src/lib/hooks/useUpdateNodeInternals.ts b/packages/svelte/src/lib/hooks/useUpdateNodeInternals.ts index cbb240ab..489dec0b 100644 --- a/packages/svelte/src/lib/hooks/useUpdateNodeInternals.ts +++ b/packages/svelte/src/lib/hooks/useUpdateNodeInternals.ts @@ -23,7 +23,7 @@ export function useUpdateNodeInternals(): UpdateNodeInternals { ) as HTMLDivElement; if (nodeElement) { - updates.set(updateId, { id: updateId, nodeElement, forceUpdate: true }); + updates.set(updateId, { id: updateId, nodeElement, force: true }); } }); From f2f2c3cc2ecbc629b46de9e2179637f292fe4bf5 Mon Sep 17 00:00:00 2001 From: moklick Date: Thu, 2 May 2024 15:36:42 +0200 Subject: [PATCH 16/27] feat(svelte): add fitViewOptions for Controls closes #4201 --- .../svelte/src/routes/examples/overview/+page.svelte | 11 ++++++++--- .../svelte/src/lib/plugins/Controls/Controls.svelte | 3 ++- packages/svelte/src/lib/plugins/Controls/types.ts | 3 +++ packages/svelte/src/lib/store/index.ts | 4 ++-- packages/svelte/src/lib/types/general.ts | 2 +- packages/system/src/types/general.ts | 4 ++-- 6 files changed, 18 insertions(+), 9 deletions(-) diff --git a/examples/svelte/src/routes/examples/overview/+page.svelte b/examples/svelte/src/routes/examples/overview/+page.svelte index 301730f6..92a353bb 100644 --- a/examples/svelte/src/routes/examples/overview/+page.svelte +++ b/examples/svelte/src/routes/examples/overview/+page.svelte @@ -13,8 +13,8 @@ type Node, type Edge, ConnectionMode, - useSvelteFlow, - ControlButton + ControlButton, + type FitViewOptions } from '@xyflow/svelte'; import CustomNode from './CustomNode.svelte'; @@ -33,6 +33,11 @@ custom: CustomEdge }; + const fitViewOptions: FitViewOptions = { + padding: 0.2, + nodes: [{ id: '1' }, { id: '2' }] + }; + const nodes = writable([ { id: '1', @@ -191,7 +196,7 @@ attributionPosition={'top-center'} deleteKey={['Backspace', 'd']} > - + xy console.log('control button')} >log { - fitView(); + fitView(fitViewOptions); }; const onToggleInteractivity = () => { diff --git a/packages/svelte/src/lib/plugins/Controls/types.ts b/packages/svelte/src/lib/plugins/Controls/types.ts index 1de8dee9..a4e5f9d7 100644 --- a/packages/svelte/src/lib/plugins/Controls/types.ts +++ b/packages/svelte/src/lib/plugins/Controls/types.ts @@ -1,6 +1,8 @@ import type { HTMLButtonAttributes } from 'svelte/elements'; import type { PanelPosition } from '@xyflow/system'; +import type { FitViewOptions } from '$lib/types'; + export type ControlsProps = { /** Position of the controls on the pane * @example PanelPosition.TopLeft, PanelPosition.TopRight, @@ -21,6 +23,7 @@ export type ControlsProps = { style?: string; class?: string; orientation?: 'horizontal' | 'vertical'; + fitViewOptions?: FitViewOptions; }; export type ControlButtonProps = HTMLButtonAttributes & { diff --git a/packages/svelte/src/lib/store/index.ts b/packages/svelte/src/lib/store/index.ts index f37d8e47..e02573ad 100644 --- a/packages/svelte/src/lib/store/index.ts +++ b/packages/svelte/src/lib/store/index.ts @@ -2,7 +2,7 @@ import { getContext, setContext } from 'svelte'; import { derived, get, writable } from 'svelte/store'; import { createMarkerIds, - fitView as fitViewUtil, + fitView as fitViewSystem, getElementsToRemove, panBy as panBySystem, updateNodeInternals as updateNodeInternalsSystem, @@ -140,7 +140,7 @@ export function createStore({ return false; } - return fitViewUtil( + return fitViewSystem( { nodeLookup: get(store.nodeLookup), width: get(store.width), diff --git a/packages/svelte/src/lib/types/general.ts b/packages/svelte/src/lib/types/general.ts index 71e2047a..8aaa9a0a 100644 --- a/packages/svelte/src/lib/types/general.ts +++ b/packages/svelte/src/lib/types/general.ts @@ -53,7 +53,7 @@ export type HandleComponentProps = { ondisconnect?: (connections: Connection[]) => void; }; -export type FitViewOptions = FitViewOptionsBase; +export type FitViewOptions = FitViewOptionsBase; export type OnDelete = (params: { nodes: Node[]; edges: Edge[] }) => void; export type OnEdgeCreate = (connection: Connection) => Edge | Connection | void; diff --git a/packages/system/src/types/general.ts b/packages/system/src/types/general.ts index 0ab0fa03..6ff1dd45 100644 --- a/packages/system/src/types/general.ts +++ b/packages/system/src/types/general.ts @@ -61,13 +61,13 @@ export type FitViewParamsBase = { nodeOrigin?: NodeOrigin; }; -export type FitViewOptionsBase = { +export type FitViewOptionsBase = { padding?: number; includeHiddenNodes?: boolean; minZoom?: number; maxZoom?: number; duration?: number; - nodes?: (NodeType | { id: NodeType['id'] })[]; + nodes?: (NodeType | { id: string })[]; }; export type Viewport = { From 534db656b4712786aec99b15a755b42d9e1047ed Mon Sep 17 00:00:00 2001 From: moklick Date: Thu, 2 May 2024 16:39:57 +0200 Subject: [PATCH 17/27] feat(svelte): add getInternalNode and useInternalNode --- .../components/NodeWrapper/NodeWrapper.svelte | 2 +- .../src/lib/components/NodeWrapper/types.ts | 4 +-- .../svelte/src/lib/hooks/useInternalNode.ts | 17 +++++++++++++ .../svelte/src/lib/hooks/useSvelteFlow.ts | 25 ++++++++++++++----- 4 files changed, 39 insertions(+), 9 deletions(-) create mode 100644 packages/svelte/src/lib/hooks/useInternalNode.ts diff --git a/packages/svelte/src/lib/components/NodeWrapper/NodeWrapper.svelte b/packages/svelte/src/lib/components/NodeWrapper/NodeWrapper.svelte index 8f13be9b..7ba52792 100644 --- a/packages/svelte/src/lib/components/NodeWrapper/NodeWrapper.svelte +++ b/packages/svelte/src/lib/components/NodeWrapper/NodeWrapper.svelte @@ -141,7 +141,7 @@ handleNodeSelection(id); } - dispatchNodeEvent('nodeclick', { node, event }); + dispatchNodeEvent('nodeclick', { node: node.internals.userNode, event }); } diff --git a/packages/svelte/src/lib/components/NodeWrapper/types.ts b/packages/svelte/src/lib/components/NodeWrapper/types.ts index 7277be5f..842eb70b 100644 --- a/packages/svelte/src/lib/components/NodeWrapper/types.ts +++ b/packages/svelte/src/lib/components/NodeWrapper/types.ts @@ -1,4 +1,4 @@ -import type { Node } from '$lib/types'; +import type { InternalNode, Node } from '$lib/types'; export type NodeWrapperProps = Pick< Node, @@ -32,6 +32,6 @@ export type NodeWrapperProps = Pick< resizeObserver?: ResizeObserver | null; isParent?: boolean; zIndex: number; - node: Node; + node: InternalNode; initialized: boolean; }; diff --git a/packages/svelte/src/lib/hooks/useInternalNode.ts b/packages/svelte/src/lib/hooks/useInternalNode.ts new file mode 100644 index 00000000..16c83960 --- /dev/null +++ b/packages/svelte/src/lib/hooks/useInternalNode.ts @@ -0,0 +1,17 @@ +import { derived, type Readable } from 'svelte/store'; + +import { useStore } from '$lib/store'; +import type { InternalNode } from '$lib/types'; + +/** + * Hook to get an internal node by id. + * + * @public + * @param id - the node id + * @returns a readable with an internal node or undefined + */ +export function useInternalNode(id: string): Readable { + const { nodeLookup, nodes } = useStore(); + + return derived([nodeLookup, nodes], ([nodeLookup]) => nodeLookup.get(id)); +} diff --git a/packages/svelte/src/lib/hooks/useSvelteFlow.ts b/packages/svelte/src/lib/hooks/useSvelteFlow.ts index 6c83418f..be40af64 100644 --- a/packages/svelte/src/lib/hooks/useSvelteFlow.ts +++ b/packages/svelte/src/lib/hooks/useSvelteFlow.ts @@ -18,7 +18,7 @@ import { } from '@xyflow/system'; import { useStore } from '$lib/store'; -import type { Edge, FitViewOptions, Node } from '$lib/types'; +import type { Edge, FitViewOptions, InternalNode, Node } from '$lib/types'; import { isNode } from '$lib/utils'; /** @@ -41,6 +41,13 @@ export function useSvelteFlow(): { * @param options.duration - optional duration. If set, a transition will be applied */ zoomOut: ZoomInOut; + /** + * Returns an internal node by id. + * + * @param id - the node id + * @returns the node or undefined if no node was found + */ + getInternalNode: (id: string) => InternalNode | undefined; /** * Returns a node by id. * @@ -280,10 +287,13 @@ export function useSvelteFlow(): { } }; + const getInternalNode = (id: string) => get(nodeLookup).get(id); + return { zoomIn, zoomOut, - getNode: (id) => get(nodeLookup).get(id), + getInternalNode, + getNode: (id) => getInternalNode(id)?.internals.userNode, getNodes: (ids) => (ids === undefined ? get(nodes) : getElements(get(nodeLookup), ids)), getEdge: (id) => get(edgeLookup).get(id), getEdges: (ids) => (ids === undefined ? get(edges) : getElements(get(edgeLookup), ids)), @@ -474,14 +484,17 @@ export function useSvelteFlow(): { viewport }; } - -function getElements(lookup: Map, ids: string[]) { +function getElements(lookup: Map, ids: string[]): Node[]; +function getElements(lookup: Map, ids: string[]): Edge[]; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function getElements(lookup: Map, ids: string[]): any[] { const result = []; for (const id of ids) { - const element = lookup.get(id); + const item = lookup.get(id); - if (element) { + if (item) { + const element = 'internals' in item ? item.internals?.userNode : item; result.push(element); } } From 9984dd39a2c4a2bf74e257415000e823e99b73d6 Mon Sep 17 00:00:00 2001 From: moklick Date: Thu, 2 May 2024 17:29:31 +0200 Subject: [PATCH 18/27] refactor(svelte): add quotes to edge marker urls --- .../svelte/src/lib/components/EdgeWrapper/EdgeWrapper.svelte | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/svelte/src/lib/components/EdgeWrapper/EdgeWrapper.svelte b/packages/svelte/src/lib/components/EdgeWrapper/EdgeWrapper.svelte index f2166cee..54fdf91f 100644 --- a/packages/svelte/src/lib/components/EdgeWrapper/EdgeWrapper.svelte +++ b/packages/svelte/src/lib/components/EdgeWrapper/EdgeWrapper.svelte @@ -53,8 +53,8 @@ $: edgeType = type || 'default'; $: edgeComponent = $edgeTypes[edgeType] || BezierEdgeInternal; - $: markerStartUrl = markerStart ? `url(#${getMarkerId(markerStart, $flowId)})` : undefined; - $: markerEndUrl = markerEnd ? `url(#${getMarkerId(markerEnd, $flowId)})` : undefined; + $: markerStartUrl = markerStart ? `url('#${getMarkerId(markerStart, $flowId)}')` : undefined; + $: markerEndUrl = markerEnd ? `url('#${getMarkerId(markerEnd, $flowId)}')` : undefined; $: isSelectable = selectable || ($elementsSelectable && typeof selectable === 'undefined'); const handleEdgeSelect = useHandleEdgeSelect(); From e1ef45666abb4bdedbe130808fa3a2d488e4daca Mon Sep 17 00:00:00 2001 From: moklick Date: Thu, 2 May 2024 17:29:53 +0200 Subject: [PATCH 19/27] test(svelte): nodeDragThreshold=0 for node tests --- examples/svelte/src/generic-tests/nodes/general.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/svelte/src/generic-tests/nodes/general.ts b/examples/svelte/src/generic-tests/nodes/general.ts index 4e5abc91..60757953 100644 --- a/examples/svelte/src/generic-tests/nodes/general.ts +++ b/examples/svelte/src/generic-tests/nodes/general.ts @@ -3,6 +3,7 @@ import DragHandleNode from './components/DragHandleNode.svelte'; export default { flowProps: { fitView: true, + nodeDragThreshold: 0, nodeTypes: { DragHandleNode }, From ce9ce1db0badd30913ca7cf10a13f3dc1618cc54 Mon Sep 17 00:00:00 2001 From: moklick Date: Thu, 2 May 2024 17:40:48 +0200 Subject: [PATCH 20/27] fix(system): return user nodes in node drag/click handlers --- .../src/components/NodeWrapper/index.tsx | 22 ++++++++++++++----- packages/system/src/xydrag/utils.ts | 11 +++++----- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/packages/react/src/components/NodeWrapper/index.tsx b/packages/react/src/components/NodeWrapper/index.tsx index dfbb7b93..b509824c 100644 --- a/packages/react/src/components/NodeWrapper/index.tsx +++ b/packages/react/src/components/NodeWrapper/index.tsx @@ -98,11 +98,21 @@ export function NodeWrapper({ }); const hasPointerEvents = isSelectable || isDraggable || onClick || onMouseEnter || onMouseMove || onMouseLeave; - const onMouseEnterHandler = onMouseEnter ? (event: MouseEvent) => onMouseEnter(event, { ...node }) : undefined; - const onMouseMoveHandler = onMouseMove ? (event: MouseEvent) => onMouseMove(event, { ...node }) : undefined; - const onMouseLeaveHandler = onMouseLeave ? (event: MouseEvent) => onMouseLeave(event, { ...node }) : undefined; - const onContextMenuHandler = onContextMenu ? (event: MouseEvent) => onContextMenu(event, { ...node }) : undefined; - const onDoubleClickHandler = onDoubleClick ? (event: MouseEvent) => onDoubleClick(event, { ...node }) : undefined; + const onMouseEnterHandler = onMouseEnter + ? (event: MouseEvent) => onMouseEnter(event, { ...internals.userNode }) + : undefined; + const onMouseMoveHandler = onMouseMove + ? (event: MouseEvent) => onMouseMove(event, { ...internals.userNode }) + : undefined; + const onMouseLeaveHandler = onMouseLeave + ? (event: MouseEvent) => onMouseLeave(event, { ...internals.userNode }) + : undefined; + const onContextMenuHandler = onContextMenu + ? (event: MouseEvent) => onContextMenu(event, { ...internals.userNode }) + : undefined; + const onDoubleClickHandler = onDoubleClick + ? (event: MouseEvent) => onDoubleClick(event, { ...internals.userNode }) + : undefined; const onSelectNodeHandler = (event: MouseEvent) => { const { selectNodesOnDrag, nodeDragThreshold } = store.getState(); @@ -118,7 +128,7 @@ export function NodeWrapper({ } if (onClick) { - onClick(event, { ...node }); + onClick(event, { ...internals.userNode }); } }; diff --git a/packages/system/src/xydrag/utils.ts b/packages/system/src/xydrag/utils.ts index bb836a32..ee8326ff 100644 --- a/packages/system/src/xydrag/utils.ts +++ b/packages/system/src/xydrag/utils.ts @@ -77,7 +77,7 @@ export function getDragItems( // returns two params: // 1. the dragged node (or the first of the list, if we are dragging a node selection) // 2. array of selected nodes (for multi selections) -export function getEventHandlerParams({ +export function getEventHandlerParams({ nodeId, dragItems, nodeLookup, @@ -85,11 +85,11 @@ export function getEventHandlerParams({ nodeId?: string; dragItems: Map; nodeLookup: Map; -}): [NodeType, NodeType[]] { - const nodesFromDragItems: NodeType[] = []; +}): [NodeBase, NodeBase[]] { + const nodesFromDragItems: NodeBase[] = []; for (const [id, dragItem] of dragItems) { - const node = nodeLookup.get(id); + const node = nodeLookup.get(id)?.internals.userNode; if (node) { nodesFromDragItems.push({ @@ -103,7 +103,8 @@ export function getEventHandlerParams({ return [nodesFromDragItems[0], nodesFromDragItems]; } - const node = nodeLookup.get(nodeId)!; + const node = nodeLookup.get(nodeId)!.internals.userNode; + return [ { ...node, From c0de3ad941744cdac6f83a636899483a17f66891 Mon Sep 17 00:00:00 2001 From: moklick Date: Thu, 2 May 2024 17:49:06 +0200 Subject: [PATCH 21/27] chore(libs): export Align type --- packages/react/src/index.ts | 1 + packages/react/src/types/general.ts | 4 ++-- packages/svelte/src/lib/index.ts | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index 5ab91928..f8ba9ea6 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -38,6 +38,7 @@ export * from './types'; // system types export { + type Align, type SmoothStepPathOptions, type BezierPathOptions, ConnectionLineType, diff --git a/packages/react/src/types/general.ts b/packages/react/src/types/general.ts index 6f1105a7..2f518dca 100644 --- a/packages/react/src/types/general.ts +++ b/packages/react/src/types/general.ts @@ -63,8 +63,8 @@ export type OnSelectionChangeParams = { export type OnSelectionChangeFunc = (params: OnSelectionChangeParams) => void; -export type FitViewParams = FitViewParamsBase; -export type FitViewOptions = FitViewOptionsBase; +export type FitViewParams = FitViewParamsBase; +export type FitViewOptions = FitViewOptionsBase; export type FitView = (fitViewOptions?: FitViewOptions) => boolean; export type OnInit = ( reactFlowInstance: ReactFlowInstance diff --git a/packages/svelte/src/lib/index.ts b/packages/svelte/src/lib/index.ts index 72808cda..6a646f80 100644 --- a/packages/svelte/src/lib/index.ts +++ b/packages/svelte/src/lib/index.ts @@ -51,6 +51,7 @@ export type { SvelteFlowStore } from '$lib/store/types'; // system types export { + type Align, type SmoothStepPathOptions, type BezierPathOptions, ConnectionLineType, From ec2592966ecf554e349d69ca496e53343f348363 Mon Sep 17 00:00:00 2001 From: moklick Date: Thu, 2 May 2024 17:49:15 +0200 Subject: [PATCH 22/27] chore(changelogs): update --- packages/react/CHANGELOG.md | 13 +++++++------ packages/svelte/CHANGELOG.md | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index 90119e80..5bbe2a56 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -2,12 +2,13 @@ ## 12.0.0-next.17 -- refactor(react): cleanup `useReactFlow` -- fix(types): export `KeyCode` -- fix(nodes): handle default node updates closes #4202 -- fix(types): add string array to `UpdateNodeInternals` thanks @DenizUgur -- fix(pane): pinch zoom on windows -- fix(pane): drag for touch devices +- fix broken `defaultNodes` +- add string array to `UpdateNodeInternals` thanks @DenizUgur +- pinch zoom on windows +- drag for touch devices +- return user node in node event handlers +- cleanup `useReactFlow` +- export `KeyCode` and `Align` type ## 12.0.0-next.16 diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index d87b7e83..430f2d82 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,27 @@ # @xyflow/svelte +## 0.1.0 + +This is a bigger update for Svelte Flow to keep up with the latest changes we made for React Flow and the Svelte5 rewrite. The biggest change is the separation of user nodes (type `Node`) and internal nodes (type `InternalNode`), which includes a renaming of the `node.computed` attribute to `node.measured`. In the previous versions, we stored internals in `node[internalsSymbol]`. This doesn't exist anymore, but we only add it to our internal nodes in `node.internals.`. + +## ⚠️ Breaking + +- rename `node.computed` to `node.measured` - this attribute only includes `width` and `height` and no `positionAbsolute` anymore. For this we added the helpers `getInternalNode` and `useInternalNode` +- rename `node.parentNode` to `node.parentId` + +### More updates: + +- add `isValidConnection` for `` component +- add `fitViewOptions` for `` component +- add `getInternalNode` to `useSvelteFlow` +- add `useInternalNode` hook +- don't reset nodes and edges when svelte flow unmounts - thanks @darabos +- fix node event types - thanks @RedPhoenixQ +- make handleId and isTarget reactive - thanks @darabos +- fix MiniMap interaction for touch devices +- fix pane: pinch zoom on windows +- fix nodes: return user node in node event handlers + ## 0.0.41 - fix: re-observe nodes when not initialized From ad3a803abbec1fb0bb5d255d0d92b2cec388b403 Mon Sep 17 00:00:00 2001 From: moklick Date: Thu, 2 May 2024 18:02:38 +0200 Subject: [PATCH 23/27] fix(react): dont allow invalid selection rect --- .../react/src/examples/DefaultNodes/index.tsx | 22 +++++++++---------- .../DevTools/DevTools/NodeInspector.tsx | 8 +++---- .../src/components/NodesSelection/index.tsx | 6 ++--- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/examples/react/src/examples/DefaultNodes/index.tsx b/examples/react/src/examples/DefaultNodes/index.tsx index 46ef8e0c..354fa994 100644 --- a/examples/react/src/examples/DefaultNodes/index.tsx +++ b/examples/react/src/examples/DefaultNodes/index.tsx @@ -54,26 +54,24 @@ const DefaultNodes = () => { const updateNodePositions = () => { instance.setNodes((nodes) => - nodes.map((node) => { - node.position = { + nodes.map((node) => ({ + ...node, + position: { x: Math.random() * 400, y: Math.random() * 400, - }; - - return node; - }) + }, + })) ); }; const updateEdgeColors = () => { instance.setEdges((edges) => - edges.map((edge) => { - edge.style = { + edges.map((edge) => ({ + ...edge, + style: { stroke: '#ff5050', - }; - - return edge; - }) + }, + })) ); }; diff --git a/examples/react/src/examples/DevTools/DevTools/NodeInspector.tsx b/examples/react/src/examples/DevTools/DevTools/NodeInspector.tsx index 5d467514..e0897509 100644 --- a/examples/react/src/examples/DevTools/DevTools/NodeInspector.tsx +++ b/examples/react/src/examples/DevTools/DevTools/NodeInspector.tsx @@ -44,10 +44,10 @@ export default function NodeInspector() {
{nodes.map((node) => { - const x = node.computed?.positionAbsolute?.x || 0; - const y = node.computed?.positionAbsolute?.y || 0; - const width = node.computed?.width || 0; - const height = node.computed?.height || 0; + const x = node?.position?.x || 0; + const y = node?.position?.y || 0; + const width = node.measured?.width || 0; + const height = node.measured?.height || 0; return ( { }); return { - width, - height, + width: isNumeric(width) ? width : null, + height: isNumeric(height) ? height : null, userSelectionActive: s.userSelectionActive, transformString: `translate(${s.transform[0]}px,${s.transform[1]}px) scale(${s.transform[2]}) translate(${x}px,${y}px)`, }; From 5f3dbbbade19ed54854ea32683c9d7ddadb0858b Mon Sep 17 00:00:00 2001 From: moklick Date: Thu, 2 May 2024 18:05:38 +0200 Subject: [PATCH 24/27] chore(versions): bump --- packages/react/package.json | 2 +- packages/svelte/package.json | 2 +- packages/system/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/react/package.json b/packages/react/package.json index 3b99d721..1cfc0aec 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/react", - "version": "12.0.0-next.16", + "version": "12.0.0-next.17", "description": "React Flow - A highly customizable React library for building node-based editors and interactive flow charts.", "keywords": [ "react", diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 0277272b..4a8e1bb5 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/svelte", - "version": "0.0.41", + "version": "0.1.0", "description": "Svelte Flow - A highly customizable Svelte library for building node-based editors, workflow systems, diagrams and more.", "keywords": [ "svelte", diff --git a/packages/system/package.json b/packages/system/package.json index 849a01fe..468ee9b7 100644 --- a/packages/system/package.json +++ b/packages/system/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/system", - "version": "0.0.24", + "version": "0.0.25", "description": "xyflow core system that powers React Flow and Svelte Flow.", "keywords": [ "node-based UI", From d562818f4cb91375d95f70f69186b4dd4423c577 Mon Sep 17 00:00:00 2001 From: moklick Date: Mon, 6 May 2024 11:20:10 +0200 Subject: [PATCH 25/27] fix(styles): add node-resizer to base style --- packages/react/src/styles/base.css | 1 + packages/svelte/src/styles/base.css | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/react/src/styles/base.css b/packages/react/src/styles/base.css index d6be5b10..25f3719a 100644 --- a/packages/react/src/styles/base.css +++ b/packages/react/src/styles/base.css @@ -1,3 +1,4 @@ /* this will be exported as base.css and can be used for a basic styling */ @import '../../../system/src/styles/init.css'; @import '../../../system/src/styles/base.css'; +@import '../../../system/src/styles/node-resizer.css'; diff --git a/packages/svelte/src/styles/base.css b/packages/svelte/src/styles/base.css index 80bc953d..a0cf3040 100644 --- a/packages/svelte/src/styles/base.css +++ b/packages/svelte/src/styles/base.css @@ -1,6 +1,7 @@ /* this gets exported as style.css and can be used for the default theming */ @import '../../../system/src/styles/init.css'; @import '../../../system/src/styles/base.css'; +@import '../../../system/src/styles/node-resizer.css'; .svelte-flow__edge-label { text-align: center; From de86c64128a232eb53957bde479c5f6340d4b14c Mon Sep 17 00:00:00 2001 From: moklick Date: Mon, 6 May 2024 11:47:45 +0200 Subject: [PATCH 26/27] fix(svelte): selection for sub flows --- .../NodeSelection/NodeSelection.svelte | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/svelte/src/lib/components/NodeSelection/NodeSelection.svelte b/packages/svelte/src/lib/components/NodeSelection/NodeSelection.svelte index 08a1cd6e..f894d8d9 100644 --- a/packages/svelte/src/lib/components/NodeSelection/NodeSelection.svelte +++ b/packages/svelte/src/lib/components/NodeSelection/NodeSelection.svelte @@ -1,6 +1,6 @@ -{#if selectedNodes && $selectionRectMode === 'nodes'} +{#if $selectionRectMode === 'nodes' && bounds && isNumeric(bounds.x) && isNumeric(bounds.y)}
Date: Mon, 6 May 2024 11:47:57 +0200 Subject: [PATCH 27/27] fix(minimap): sub flow node positions --- .../src/lib/plugins/Minimap/Minimap.svelte | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/packages/svelte/src/lib/plugins/Minimap/Minimap.svelte b/packages/svelte/src/lib/plugins/Minimap/Minimap.svelte index 20b2317d..2e6a7364 100644 --- a/packages/svelte/src/lib/plugins/Minimap/Minimap.svelte +++ b/packages/svelte/src/lib/plugins/Minimap/Minimap.svelte @@ -9,10 +9,11 @@ import cc from 'classcat'; import { getBoundsOfRects, + getInternalNodesBounds, getNodeDimensions, getNodePositionWithOrigin, - getNodesBounds, - nodeHasDimensions + nodeHasDimensions, + type Rect } from '@xyflow/system'; import { useStore } from '$lib/store'; @@ -49,6 +50,7 @@ const defaultHeight = 150; const { nodes, + nodeLookup, viewport, width: containerWidth, height: containerHeight, @@ -71,7 +73,14 @@ width: $containerWidth / $viewport.zoom, height: $containerHeight / $viewport.zoom }; - $: boundingRect = $nodes.length > 0 ? getBoundsOfRects(getNodesBounds($nodes), viewBB) : viewBB; + let boundingRect: Rect = viewBB; + + $: { + boundingRect = + $nodeLookup.size > 0 ? getBoundsOfRects(getInternalNodesBounds($nodeLookup), viewBB) : viewBB; + $nodes; + } + $: elementWidth = width ?? defaultWidth; $: elementHeight = height ?? defaultHeight; $: scaledWidth = boundingRect.width / elementWidth; @@ -122,8 +131,9 @@ > {#if ariaLabel}{ariaLabel}{/if} - {#each $nodes as node (node.id)} - {#if nodeHasDimensions(node)} + {#each $nodes as userNode (userNode.id)} + {@const node = $nodeLookup.get(userNode.id)} + {#if node && nodeHasDimensions(node)} {@const pos = getNodePositionWithOrigin(node).positionAbsolute} {@const nodeDimesions = getNodeDimensions(node)}