implemented new fitView logic
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -3,12 +3,13 @@
|
||||
import type { Snippet } from 'svelte';
|
||||
|
||||
let { store, children }: { store: SvelteFlowStore; children: Snippet } = $props();
|
||||
|
||||
let { x, y, zoom } = $derived(store._viewport);
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="svelte-flow__viewport xyflow__viewport"
|
||||
style="transform: translate({store.viewport.x}px, {store.viewport.y}px) scale({store.viewport
|
||||
.zoom})"
|
||||
style="transform: translate({x}px, {y}px) scale({zoom})"
|
||||
>
|
||||
{@render children()}
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { PanOnScrollMode, type PanZoomInstance, type Transform } from '@xyflow/system';
|
||||
|
||||
import zoom from '$lib/actions/zoom';
|
||||
@@ -24,15 +23,8 @@
|
||||
let panOnDragActive = $derived(store.panActivationKeyPressed || panOnDrag);
|
||||
let panOnScrollActive = $derived(store.panActivationKeyPressed || panOnScroll);
|
||||
|
||||
const onTransformChange = (transform: Transform) =>
|
||||
(store.viewport = { x: transform[0], y: transform[1], zoom: transform[2] });
|
||||
|
||||
// We extract the initial value by destructuring
|
||||
const { viewport: initialViewport } = store;
|
||||
|
||||
onMount(() => {
|
||||
store.viewportInitialized = true;
|
||||
});
|
||||
</script>
|
||||
|
||||
<div
|
||||
@@ -66,7 +58,10 @@
|
||||
translateExtent: store.translateExtent,
|
||||
lib: 'svelte',
|
||||
paneClickDistance,
|
||||
onTransformChange
|
||||
onTransformChange: (transform: Transform) => {
|
||||
performance.mark('svelte-flow-zoom-transform-change');
|
||||
store.viewport = { x: transform[0], y: transform[1], zoom: transform[2] };
|
||||
}
|
||||
}}
|
||||
>
|
||||
{@render children()}
|
||||
|
||||
@@ -107,7 +107,8 @@ export {
|
||||
type ResizeParams,
|
||||
type ResizeParamsWithDirection,
|
||||
type ResizeDragEvent,
|
||||
type IsValidConnection
|
||||
type IsValidConnection,
|
||||
type NodeConnection
|
||||
} from '@xyflow/system';
|
||||
|
||||
// system utils
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<string, Node>();
|
||||
@@ -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<boolean>();
|
||||
|
||||
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,
|
||||
|
||||
@@ -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<HTMLDivElement | null>(null);
|
||||
panZoom: PanZoomInstance | null = $state(null);
|
||||
width = $state<number>(signals.width ?? 0);
|
||||
height = $state<number>(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<HTMLDivElement | null>(null);
|
||||
width = $state<number>(signals.width ?? 0);
|
||||
height = $state<number>(signals.height ?? 0);
|
||||
|
||||
flowId: string = $derived(signals.props.id ?? '1');
|
||||
minZoom: number = $derived(signals.props.minZoom ?? 0.5);
|
||||
maxZoom: number = $derived(signals.props.maxZoom ?? 2);
|
||||
|
||||
@@ -192,11 +229,10 @@ export const getInitialStore = (signals: StoreSignals) => {
|
||||
autoPanOnNodeDrag: boolean = $derived(signals.props.autoPanOnNodeDrag ?? true);
|
||||
autoPanOnConnect: boolean = $derived(signals.props.autoPanOnConnect ?? true);
|
||||
|
||||
fitViewOnInitDone: boolean = $state(false);
|
||||
fitViewOnInit: boolean = $derived(signals.props.fitView ?? false);
|
||||
fitViewOptions: FitViewOptions | undefined = $derived(signals.props.fitViewOptions);
|
||||
fitViewQueued: boolean = signals.props.fitView ?? false;
|
||||
fitViewOptions: FitViewOptions | undefined = signals.props.fitViewOptions;
|
||||
fitViewResolver: PromiseWithResolvers<boolean> | null = null;
|
||||
|
||||
panZoom: PanZoomInstance | null = $state(null);
|
||||
snapGrid: SnapGrid | null = $derived(signals.props.snapGrid ?? null);
|
||||
|
||||
dragging: boolean = $state(false);
|
||||
@@ -215,15 +251,16 @@ export const getInitialStore = (signals: StoreSignals) => {
|
||||
|
||||
// _viewport is the internal viewport.
|
||||
// when binding to viewport, we operate on signals.viewport instead
|
||||
initial: boolean = true;
|
||||
_viewport: Viewport = $state(signals.props.initialViewport ?? { x: 0, y: 0, zoom: 1 });
|
||||
get viewport() {
|
||||
return signals.viewport ?? this._viewport;
|
||||
}
|
||||
set viewport(viewport: Viewport) {
|
||||
set viewport(newViewport: Viewport) {
|
||||
if (signals.viewport) {
|
||||
signals.viewport = viewport;
|
||||
signals.viewport = newViewport;
|
||||
}
|
||||
this._viewport = viewport;
|
||||
this._viewport = newViewport;
|
||||
}
|
||||
|
||||
// _connection is viewport independent and originating from XYHandle
|
||||
@@ -271,25 +308,32 @@ export const getInitialStore = (signals: StoreSignals) => {
|
||||
onconnectend?: OnConnectEnd = $derived(signals.props.onconnectend);
|
||||
onbeforedelete?: OnBeforeDelete = $derived(signals.props.onbeforedelete);
|
||||
|
||||
nodesInitialized: boolean = $state(false);
|
||||
edgesInitialized: boolean = $state(false);
|
||||
viewportInitialized: boolean = $state(false);
|
||||
|
||||
_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;
|
||||
resolveFitView = async () => {
|
||||
if (!this.panZoom) {
|
||||
return;
|
||||
}
|
||||
|
||||
return initialized;
|
||||
});
|
||||
await fitViewport(
|
||||
{
|
||||
nodes: this.nodeLookup,
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
panZoom: this.panZoom,
|
||||
minZoom: this.minZoom,
|
||||
maxZoom: this.maxZoom
|
||||
},
|
||||
this.fitViewOptions
|
||||
);
|
||||
|
||||
this.fitViewResolver?.resolve(true);
|
||||
/**
|
||||
* wait for the fitViewport to resolve before deleting the resolver,
|
||||
* we want to reuse the old resolver if the user calls fitView again in the mean time
|
||||
*/
|
||||
this.fitViewQueued = false;
|
||||
this.fitViewOptions = undefined;
|
||||
this.fitViewResolver = null;
|
||||
};
|
||||
|
||||
_prefersDark = new MediaQuery(
|
||||
'(prefers-color-scheme: dark)',
|
||||
@@ -328,7 +372,6 @@ export const getInitialStore = (signals: StoreSignals) => {
|
||||
|
||||
// Only way to check if an object is a proxy
|
||||
// is to see if is failes to perform a structured clone
|
||||
// TODO: is $state.raw really nessessary?
|
||||
function warnIfDeeplyReactive(array: unknown[] | undefined, name: string) {
|
||||
try {
|
||||
if (array && array.length > 0) {
|
||||
|
||||
@@ -12,7 +12,9 @@ import type { Node } from '$lib/types';
|
||||
import type { ClassValue } from 'svelte/elements';
|
||||
|
||||
/**
|
||||
* The Edge type is mainly used for the `edges` that get passed to the SvelteFlow component.
|
||||
* An `Edge` is the complete description with everything Svelte Flow needs to know in order to
|
||||
* render it.
|
||||
* @public
|
||||
*/
|
||||
export type Edge<
|
||||
EdgeData extends Record<string, unknown> = Record<string, unknown>,
|
||||
|
||||
@@ -3,7 +3,7 @@ import { isNodeBase, isEdgeBase } from '@xyflow/system';
|
||||
import type { Edge, Node } from '$lib/types';
|
||||
|
||||
/**
|
||||
* Test whether an object is useable as a Node
|
||||
* Test whether an object is usable as a Node
|
||||
* @public
|
||||
* @remarks In TypeScript this is a type guard that will narrow the type of whatever you pass in to Node if it returns true
|
||||
* @param element - The element to test
|
||||
@@ -13,7 +13,7 @@ export const isNode = <NodeType extends Node = Node>(element: unknown): element
|
||||
isNodeBase<NodeType>(element);
|
||||
|
||||
/**
|
||||
* Test whether an object is useable as an Edge
|
||||
* Test whether an object is usable as an Edge
|
||||
* @public
|
||||
* @remarks In TypeScript this is a type guard that will narrow the type of whatever you pass in to Edge if it returns true
|
||||
* @param element - The element to test
|
||||
|
||||
Reference in New Issue
Block a user