) => JSX.Element {
diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md
index 0a0e8306..b590226d 100644
--- a/packages/svelte/CHANGELOG.md
+++ b/packages/svelte/CHANGELOG.md
@@ -1,5 +1,60 @@
# @xyflow/svelte
+## 0.1.35
+
+### Patch Changes
+
+- [#5158](https://github.com/xyflow/xyflow/pull/5158) [`06696060`](https://github.com/xyflow/xyflow/commit/0669606050bb2138a44a1591176ac8e16afeb0f1) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Fix typo in TSDoc comments `React Flow` -> `Svelte Flow`
+
+- Updated dependencies [[`02a3b746`](https://github.com/xyflow/xyflow/commit/02a3b74645799a3f0ce670b69365fa86ecb0616e), [`cbe305e1`](https://github.com/xyflow/xyflow/commit/cbe305e15a5c5d3b92583e0ec12364b2509f49bd), [`1f671bd4`](https://github.com/xyflow/xyflow/commit/1f671bd48f06230da841fdd1d7a312413ef16d03), [`aaebc462`](https://github.com/xyflow/xyflow/commit/aaebc462951ded8e91374c3e084d77af5ed7380a), [`6ec942fc`](https://github.com/xyflow/xyflow/commit/6ec942fc6501f81009c278cc995764bef3e8d03b)]:
+ - @xyflow/system@0.0.55
+
+## 0.1.34
+
+### Patch Changes
+
+- [#5139](https://github.com/xyflow/xyflow/pull/5139) [`89de9ca8`](https://github.com/xyflow/xyflow/commit/89de9ca83fbf9263a687a0f5f915efb2beb31654) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Use `rgba` for colors with opacity instead of `rgb` for `MiniMap` mask color
+
+- Updated dependencies [[`f819005b`](https://github.com/xyflow/xyflow/commit/f819005be362d044b16ce4c0b85432f3f300a13a), [`24a1bc89`](https://github.com/xyflow/xyflow/commit/24a1bc89348817ed9b5c87f74bf2519c705143be), [`36657cd6`](https://github.com/xyflow/xyflow/commit/36657cd66322c911e87eb37275c584a80025adfe), [`89de9ca8`](https://github.com/xyflow/xyflow/commit/89de9ca83fbf9263a687a0f5f915efb2beb31654), [`2ac6e155`](https://github.com/xyflow/xyflow/commit/2ac6e155e35256ca436281df16344366e7d05761), [`f0f378e5`](https://github.com/xyflow/xyflow/commit/f0f378e5b6918c2c30d9dc1e32587063cb942d4e)]:
+ - @xyflow/system@0.0.54
+
+## 0.1.33
+
+### Patch Changes
+
+- [#5124](https://github.com/xyflow/xyflow/pull/5124) [`b76f7f9e`](https://github.com/xyflow/xyflow/commit/b76f7f9eb4841f139b1468b8eda0430ddd19a1ae) Thanks [@bjornosal](https://github.com/bjornosal)! - Export NodeConnection type
+
+## 0.1.32
+
+### Patch Changes
+
+- [#5059](https://github.com/xyflow/xyflow/pull/5059) [`065ff89d`](https://github.com/xyflow/xyflow/commit/065ff89d10488f9c76c56870511e45eaed299778) Thanks [@bcakmakoglu](https://github.com/bcakmakoglu)! - Prevent onPaneClick when connection is in progress. Closes [#5057](https://github.com/xyflow/xyflow/issues/5057)
+
+- [#5067](https://github.com/xyflow/xyflow/pull/5067) [`cb685281`](https://github.com/xyflow/xyflow/commit/cb685281d0eaf03e9833271c31f92b1d143af2fe) Thanks [@peterkogo](https://github.com/peterkogo)! - Fix fitView not working immediately after adding new nodes
+
+- [#5093](https://github.com/xyflow/xyflow/pull/5093) [`65825e89`](https://github.com/xyflow/xyflow/commit/65825e89a6e2e7591087eb41ac89da4da7095f8f) Thanks [@moklick](https://github.com/moklick)! - Hidden nodes are not displayed in the mini map anymore
+
+- Updated dependencies [[`5d15b01b`](https://github.com/xyflow/xyflow/commit/5d15b01ba8cb349d6397a6ed8162848b4dfec293), [`cb685281`](https://github.com/xyflow/xyflow/commit/cb685281d0eaf03e9833271c31f92b1d143af2fe), [`a79f30b3`](https://github.com/xyflow/xyflow/commit/a79f30b3dd7c8ff6400c8d22214b2c2282e5bac1)]:
+ - @xyflow/system@0.0.53
+
+## 0.1.31
+
+### Patch Changes
+
+- [#5019](https://github.com/xyflow/xyflow/pull/5019) [`3e80317c`](https://github.com/xyflow/xyflow/commit/3e80317cf6da0e9fdc111c3ade88f2a88a10dbd6) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Add `"./package.json" to the `exports` field so that users can import it
+
+- Updated dependencies [[`99dd7d35`](https://github.com/xyflow/xyflow/commit/99dd7d3549e7423e7d103b2c956c8b37f5747b90)]:
+ - @xyflow/system@0.0.52
+
+## 0.1.30
+
+### Patch Changes
+
+- [#5010](https://github.com/xyflow/xyflow/pull/5010) [`6c121d42`](https://github.com/xyflow/xyflow/commit/6c121d427fea9a11e86a85f95d2c12ba8af34919) Thanks [@moklick](https://github.com/moklick)! - Add more TSDocs to components, hooks, utils funcs and types
+
+- Updated dependencies [[`6c121d42`](https://github.com/xyflow/xyflow/commit/6c121d427fea9a11e86a85f95d2c12ba8af34919), [`4947029c`](https://github.com/xyflow/xyflow/commit/4947029cd6cda0f695e1fb4815e4030adb232234), [`e8e0d684`](https://github.com/xyflow/xyflow/commit/e8e0d684957b95d53a6cc11598c8755ff02117c7)]:
+ - @xyflow/system@0.0.51
+
## 0.1.29
### Patch Changes
diff --git a/packages/svelte/package.json b/packages/svelte/package.json
index a7bc432a..46a28f7f 100644
--- a/packages/svelte/package.json
+++ b/packages/svelte/package.json
@@ -34,6 +34,7 @@
"type": "module",
"module": "./dist/lib/index.js",
"exports": {
+ "./package.json": "./package.json",
".": {
"types": "./dist/lib/index.d.ts",
"svelte": "./dist/lib/index.js",
@@ -54,32 +55,32 @@
"@xyflow/system": "workspace:*"
},
"devDependencies": {
- "@sveltejs/adapter-auto": "^4.0.0",
- "@sveltejs/kit": "^2.16.1",
- "@sveltejs/package": "^2.3.9",
+ "@sveltejs/adapter-auto": "^6.0.0",
+ "@sveltejs/kit": "^2.20.4",
+ "@sveltejs/package": "^2.3.10",
"@sveltejs/vite-plugin-svelte": "^5.0.3",
- "@typescript-eslint/eslint-plugin": "^8.22.0",
- "@typescript-eslint/parser": "^8.22.0",
- "autoprefixer": "^10.4.20",
+ "@typescript-eslint/eslint-plugin": "^8.29.1",
+ "@typescript-eslint/parser": "^8.29.1",
+ "autoprefixer": "^10.4.21",
"cssnano": "^7.0.6",
"dotenv": "^16.4.7",
- "eslint": "^8.57.0",
- "eslint-config-prettier": "^9.1.0",
- "eslint-plugin-svelte": "^2.46.1",
- "postcss": "^8.5.1",
- "postcss-cli": "^11.0.0",
+ "eslint": "^9.24.0",
+ "eslint-config-prettier": "^10.1.1",
+ "eslint-plugin-svelte": "^3.5.1",
+ "postcss": "^8.5.3",
+ "postcss-cli": "^11.0.1",
"postcss-combine-duplicated-selectors": "^10.0.3",
"postcss-import": "^16.1.0",
"postcss-nested": "^7.0.2",
"postcss-rename": "^0.6.1",
- "prettier": "^3.4.2",
+ "prettier": "^3.5.3",
"prettier-plugin-svelte": "^3.3.3",
- "svelte": "^5.19.5",
- "svelte-check": "^4.1.4",
- "svelte-eslint-parser": "^0.43.0",
+ "svelte": "^5.25.8",
+ "svelte-check": "^4.1.5",
+ "svelte-eslint-parser": "^1.1.2",
"svelte-preprocess": "^6.0.3",
"tslib": "^2.8.1",
- "typescript": "^5.7.3"
+ "typescript": "^5.8.3"
},
"peerDependencies": {
"svelte": "^5.16.0"
diff --git a/packages/svelte/src/lib/container/Pane/Pane.svelte b/packages/svelte/src/lib/container/Pane/Pane.svelte
index cd9c0653..0d33557c 100644
--- a/packages/svelte/src/lib/container/Pane/Pane.svelte
+++ b/packages/svelte/src/lib/container/Pane/Pane.svelte
@@ -75,7 +75,8 @@
function onClick(event: MouseEvent) {
// We prevent click events when the user let go of the selectionKey during a selection
- if (selectionInProgress) {
+ // We also prevent click events when a connection is in progress
+ if (selectionInProgress || store.connection.inProgress) {
selectionInProgress = false;
return;
}
diff --git a/packages/svelte/src/lib/container/Zoom/Zoom.svelte b/packages/svelte/src/lib/container/Zoom/Zoom.svelte
index e950b7f5..310f0842 100644
--- a/packages/svelte/src/lib/container/Zoom/Zoom.svelte
+++ b/packages/svelte/src/lib/container/Zoom/Zoom.svelte
@@ -1,5 +1,4 @@
{
+ store.viewport = { x: transform[0], y: transform[1], zoom: transform[2] };
+ }
}}
>
{@render children()}
diff --git a/packages/svelte/src/lib/index.ts b/packages/svelte/src/lib/index.ts
index 6ce24219..96c5126f 100644
--- a/packages/svelte/src/lib/index.ts
+++ b/packages/svelte/src/lib/index.ts
@@ -107,7 +107,8 @@ export {
type ResizeParams,
type ResizeParamsWithDirection,
type ResizeDragEvent,
- type IsValidConnection
+ type IsValidConnection,
+ type NodeConnection
} from '@xyflow/system';
// system utils
diff --git a/packages/svelte/src/lib/plugins/Minimap/Minimap.svelte b/packages/svelte/src/lib/plugins/Minimap/Minimap.svelte
index 08aa963e..7aac953c 100644
--- a/packages/svelte/src/lib/plugins/Minimap/Minimap.svelte
+++ b/packages/svelte/src/lib/plugins/Minimap/Minimap.svelte
@@ -63,7 +63,10 @@
});
let boundingRect = $derived(
store.nodeLookup.size > 0
- ? getBoundsOfRects(getInternalNodesBounds(store.nodeLookup), viewBB)
+ ? getBoundsOfRects(
+ getInternalNodesBounds(store.nodeLookup, { filter: (n) => !n.hidden }),
+ viewBB
+ )
: viewBB
);
let scaledWidth = $derived(boundingRect.width / width);
diff --git a/packages/svelte/src/lib/store/index.ts b/packages/svelte/src/lib/store/index.ts
index f31c479e..e689d6e1 100644
--- a/packages/svelte/src/lib/store/index.ts
+++ b/packages/svelte/src/lib/store/index.ts
@@ -1,5 +1,4 @@
import {
- fitView as fitViewSystem,
panBy as panBySystem,
updateNodeInternals as updateNodeInternalsSystem,
addEdge as addEdgeUtil,
@@ -13,9 +12,7 @@ import {
type CoordinateExtent,
type UpdateConnection,
type ConnectionState,
- getFitViewNodes,
- updateAbsolutePositions,
- getDimensions
+ updateAbsolutePositions
} from '@xyflow/system';
import type { EdgeTypes, NodeTypes, Node, Edge, FitViewOptions } from '$lib/types';
@@ -72,14 +69,8 @@ export function createStore(signals: StoreSignals): SvelteFlowStore {
nodeExtent: store.nodeExtent
});
- if (!store.fitViewOnInitDone && store.fitViewOnInit) {
- const fitViewOnInitDone = fitViewSync({
- ...store.fitViewOptions,
- nodes: store.fitViewOptions?.nodes
- });
- if (fitViewOnInitDone) {
- store.fitViewOnInitDone = fitViewOnInitDone;
- }
+ if (store.fitViewQueued) {
+ store.resolveFitView();
}
const newNodes = new Map();
@@ -120,52 +111,41 @@ export function createStore(signals: StoreSignals): SvelteFlowStore {
}
function fitView(options?: FitViewOptions) {
- const panZoom = store.panZoom;
- const domNode = store.domNode;
+ // const panZoom = store.panZoom;
+ // const domNode = store.domNode;
- if (!panZoom || !domNode) {
- return Promise.resolve(false);
- }
+ // if (!panZoom || !domNode) {
+ // return Promise.resolve(false);
+ // }
- const { width, height } = getDimensions(domNode);
+ // const { width, height } = getDimensions(domNode);
- const fitViewNodes = getFitViewNodes(store.nodeLookup, options);
+ // const fitViewNodes = getFitViewNodes(store.nodeLookup, options);
- return fitViewSystem(
- {
- nodes: fitViewNodes,
- width,
- height,
- minZoom: store.minZoom,
- maxZoom: store.maxZoom,
- panZoom
- },
- options
- );
- }
+ // return fitViewSystem(
+ // {
+ // nodes: fitViewNodes,
+ // width,
+ // height,
+ // minZoom: store.minZoom,
+ // maxZoom: store.maxZoom,
+ // panZoom
+ // },
+ // options
+ // );e3
+ // We either create a new Promise or reuse the existing one
+ // Even if fitView is called multiple times in a row, we only end up with a single Promise
+ const fitViewResolver = store.fitViewResolver ?? Promise.withResolvers();
- function fitViewSync(options?: FitViewOptions) {
- const panZoom = store.panZoom;
+ // We schedule a fitView by setting fitViewQueued and triggering a setNodes
+ store.fitViewQueued = true;
+ store.fitViewOptions = options;
+ store.fitViewResolver = fitViewResolver;
- if (!panZoom) {
- return false;
- }
+ // We need to update the nodes so that adoptUserNodes is triggered
+ store.nodes = [...store.nodes];
- const fitViewNodes = getFitViewNodes(store.nodeLookup, options);
-
- fitViewSystem(
- {
- nodes: fitViewNodes,
- width: store.width,
- height: store.height,
- minZoom: store.minZoom,
- maxZoom: store.maxZoom,
- panZoom
- },
- options
- );
-
- return fitViewNodes.size > 0;
+ return fitViewResolver.promise;
}
function zoomBy(factor: number, options?: ViewportHelperFunctionOptions) {
@@ -350,10 +330,11 @@ export function createStore(signals: StoreSignals): SvelteFlowStore {
}
function reset() {
- store.fitViewOnInitDone = false;
store.selectionRect = null;
store.selectionRectMode = null;
+ store.resetStoreValues();
+
unselectNodesAndEdges();
cancelConnection();
}
@@ -366,7 +347,7 @@ export function createStore(signals: StoreSignals): SvelteFlowStore {
updateNodeInternals,
zoomIn,
zoomOut,
- fitView: (options?: FitViewOptions) => fitView(options),
+ fitView,
setMinZoom,
setMaxZoom,
setTranslateExtent,
diff --git a/packages/svelte/src/lib/store/initial-store.svelte.ts b/packages/svelte/src/lib/store/initial-store.svelte.ts
index 03cdba63..8278658d 100644
--- a/packages/svelte/src/lib/store/initial-store.svelte.ts
+++ b/packages/svelte/src/lib/store/initial-store.svelte.ts
@@ -27,7 +27,8 @@ import {
type ParentLookup,
pointToRendererPoint,
type ColorModeClass,
- type Transform
+ type Transform,
+ fitViewport
} from '@xyflow/system';
import DefaultNode from '$lib/components/nodes/DefaultNode.svelte';
@@ -51,7 +52,6 @@ import type {
OnBeforeDelete,
IsValidConnection,
Edge,
- Node,
EdgeLayouted,
InternalNode
} from '$lib/types';
@@ -78,14 +78,54 @@ export const getInitialStore = (signals: StoreSignals) => {
// We use a class here, because Svelte adds getters & setter for us.
// Inline classes have some performance implications but we just call it once (max twice).
class SvelteFlowStore {
- _nodes: Node[] = $derived.by(() => {
- adoptUserNodes(signals.nodes, this.nodeLookup, this.parentLookup, {
+ flowId: string = $derived(signals.props.id ?? '1');
+ domNode = $state(null);
+ panZoom: PanZoomInstance | null = $state(null);
+ width = $state(signals.width ?? 0);
+ height = $state(signals.height ?? 0);
+
+ nodesInitialized: boolean = $derived.by(() => {
+ const nodesInitialized = adoptUserNodes(signals.nodes, this.nodeLookup, this.parentLookup, {
nodeExtent: this.nodeExtent,
nodeOrigin: this.nodeOrigin,
elevateNodesOnSelect: signals.props.elevateNodesOnSelect ?? true,
checkEquality: true
});
- return signals.nodes;
+
+ if (this.fitViewQueued && nodesInitialized) {
+ if (this.fitViewOptions?.duration) {
+ this.resolveFitView();
+ } else {
+ /**
+ * When no duration is set, viewport is set immediately which prevents an update
+ * I do not understand why, however we are setting state in a derived which is a no-go
+ */
+ queueMicrotask(() => {
+ this.resolveFitView();
+ });
+ }
+ }
+
+ return nodesInitialized;
+ });
+ edgesInitialized: boolean = $state(false);
+ viewportInitialized: boolean = $derived(this.panZoom !== null);
+
+ // TODO: Figure out initialized
+ _initialNodesLength: number = signals.nodes?.length ?? 0;
+ _initialEdgesLength: number = signals.edges?.length ?? 0;
+ initialized: boolean = $derived.by(() => {
+ let initialized = false;
+ // if it hasn't been initialised check if it's now
+ if (this._initialNodesLength === 0) {
+ initialized = this.viewportInitialized;
+ } else if (this._initialEdgesLength === 0) {
+ initialized = this.viewportInitialized && this.nodesInitialized;
+ } else {
+ initialized = this.viewportInitialized && this.nodesInitialized && this.edgesInitialized;
+ }
+
+ return initialized;
});
_edges: Edge[] = $derived.by(() => {
@@ -94,7 +134,9 @@ export const getInitialStore = (signals: StoreSignals) => {
});
get nodes() {
- return this._nodes;
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
+ this.nodesInitialized;
+ return signals.nodes;
}
set nodes(nodes) {
signals.nodes = nodes;
@@ -116,7 +158,7 @@ export const getInitialStore = (signals: StoreSignals) => {
const {
// We need to access this._nodes to trigger on changes
// eslint-disable-next-line @typescript-eslint/no-unused-vars
- _nodes,
+ nodes,
_edges: edges,
_prevVisibleEdges: previousEdges,
nodeLookup,
@@ -174,11 +216,6 @@ export const getInitialStore = (signals: StoreSignals) => {
signals.elementsSelectable = value;
}
- domNode = $state