Merge pull request #5327 from xyflow/fix/svelte-ssr-portals
Fix SSR and portals in Svelte Flow & update Astro Example
This commit is contained in:
5
.changeset/blue-gorillas-help.md
Normal file
5
.changeset/blue-gorillas-help.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'@xyflow/svelte': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Prevent selecting of edges when spacebar is pressed
|
||||||
5
.changeset/funny-mayflies-grin.md
Normal file
5
.changeset/funny-mayflies-grin.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'@xyflow/svelte': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix initial fitView for SSR
|
||||||
5
.changeset/sour-flowers-love.md
Normal file
5
.changeset/sour-flowers-love.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'@xyflow/svelte': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix `ViewportPortal` not working when used outside of `SvelteFlow` component
|
||||||
5
.changeset/twenty-panthers-report.md
Normal file
5
.changeset/twenty-panthers-report.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'@xyflow/svelte': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Display nodes correctly in SSR output
|
||||||
@@ -11,15 +11,15 @@
|
|||||||
"astro": "astro"
|
"astro": "astro"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/react": "^3.0.2",
|
"@astrojs/react": "^4.3.0",
|
||||||
"@astrojs/svelte": "^4.0.2",
|
"@astrojs/svelte": "^7.1.0",
|
||||||
"@types/react": "^18.2.24",
|
"@types/react": "^18.2.24",
|
||||||
"@types/react-dom": "^18.2.8",
|
"@types/react-dom": "^18.2.8",
|
||||||
"@xyflow/react": "workspace:^",
|
"@xyflow/react": "workspace:^",
|
||||||
"@xyflow/svelte": "workspace:^",
|
"@xyflow/svelte": "workspace:^",
|
||||||
"astro": "^3.2.2",
|
"astro": "^5.9.2",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"svelte": "^4.2.1"
|
"svelte": "^5.33.18"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,18 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { writable } from 'svelte/store';
|
import {
|
||||||
import { SvelteFlow, Controls, Background, BackgroundVariant, Position, type Node, type Edge } from '@xyflow/svelte';
|
SvelteFlow,
|
||||||
|
Controls,
|
||||||
|
Background,
|
||||||
|
BackgroundVariant,
|
||||||
|
Position,
|
||||||
|
ViewportPortal,
|
||||||
|
type Node,
|
||||||
|
type Edge,
|
||||||
|
} from '@xyflow/svelte';
|
||||||
|
|
||||||
import '@xyflow/svelte/dist/style.css';
|
import '@xyflow/svelte/dist/style.css';
|
||||||
|
|
||||||
const nodes = writable<Node[]>([
|
let nodes = $state.raw<Node[]>([
|
||||||
{
|
{
|
||||||
id: '0',
|
id: '0',
|
||||||
position: { x: 0, y: 150 },
|
position: { x: 0, y: 150 },
|
||||||
@@ -59,7 +67,7 @@
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const edges = writable<Edge[]>([
|
let edges = $state.raw<Edge[]>([
|
||||||
{ id: '0A', source: '0', target: 'A', animated: true },
|
{ id: '0A', source: '0', target: 'A', animated: true },
|
||||||
{ id: '0B', source: '0', target: 'B', animated: true },
|
{ id: '0B', source: '0', target: 'B', animated: true },
|
||||||
{ id: '0C', source: '0', target: 'C', animated: true },
|
{ id: '0C', source: '0', target: 'C', animated: true },
|
||||||
@@ -71,8 +79,11 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div style="height: 400px; width: 700px;">
|
<div style="height: 400px; width: 700px;">
|
||||||
<SvelteFlow {nodes} {edges} fitView {defaultEdgeOptions} width={700} height={400}>
|
<SvelteFlow bind:nodes bind:edges fitView {defaultEdgeOptions} width={700} height={400}>
|
||||||
<Controls />
|
<Controls />
|
||||||
<Background variant={BackgroundVariant.Dots} />
|
<Background variant={BackgroundVariant.Dots} />
|
||||||
|
<ViewportPortal target="front">
|
||||||
|
<div style:transform="translate(100px, 100px)" style:position="absolute">[100, 100] inside the flow.</div>
|
||||||
|
</ViewportPortal>
|
||||||
</SvelteFlow>
|
</SvelteFlow>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { writable } from 'svelte/store';
|
|
||||||
import { SvelteFlow, Controls, Background, BackgroundVariant, type Node, type Edge } from '@xyflow/svelte';
|
import { SvelteFlow, Controls, Background, BackgroundVariant, type Node, type Edge } from '@xyflow/svelte';
|
||||||
|
|
||||||
import '@xyflow/svelte/dist/style.css';
|
import '@xyflow/svelte/dist/style.css';
|
||||||
import CustomNode from './CustomNode.svelte';
|
import CustomNode from './CustomNode.svelte';
|
||||||
|
|
||||||
const nodes = writable<Node[]>([
|
let nodes = $state.raw<Node[]>([
|
||||||
{
|
{
|
||||||
id: '1',
|
id: '1',
|
||||||
position: { x: 0, y: 0 },
|
position: { x: 0, y: 0 },
|
||||||
@@ -24,7 +23,7 @@
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const edges = writable<Edge[]>([{ id: '1-2', source: '1', target: '2' }]);
|
let edges = $state.raw<Edge[]>([{ id: '1-2', source: '1', target: '2' }]);
|
||||||
|
|
||||||
const nodeTypes = {
|
const nodeTypes = {
|
||||||
'input-node': CustomNode,
|
'input-node': CustomNode,
|
||||||
@@ -32,7 +31,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div style="height: 400px; width: 700px;">
|
<div style="height: 400px; width: 700px;">
|
||||||
<SvelteFlow {nodes} {edges} {nodeTypes} fitView width={700} height={400}>
|
<SvelteFlow bind:nodes bind:edges {nodeTypes} fitView width={700} height={400}>
|
||||||
<Controls />
|
<Controls />
|
||||||
<Background variant={BackgroundVariant.Dots} />
|
<Background variant={BackgroundVariant.Dots} />
|
||||||
</SvelteFlow>
|
</SvelteFlow>
|
||||||
|
|||||||
@@ -6,38 +6,38 @@ import SvelteFlowInitialApp from '../components/SvelteFlowInitialExample/index.s
|
|||||||
---
|
---
|
||||||
|
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width" />
|
<meta name="viewport" content="width=device-width" />
|
||||||
<meta name="generator" content={Astro.generator} />
|
<meta name="generator" content={Astro.generator} />
|
||||||
<title>Astro example for React Flow and Svelte Flow</title>
|
<title>Astro example for React Flow and Svelte Flow</title>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
html, body {
|
html,
|
||||||
margin:0;
|
body {
|
||||||
font-family: sans-serif;
|
margin: 0;
|
||||||
}
|
font-family: sans-serif;
|
||||||
</style>
|
}
|
||||||
</head>
|
</style>
|
||||||
<body>
|
</head>
|
||||||
<h2>React Flow</h2>
|
<body>
|
||||||
<p>no client hydration</p>
|
<h2>React Flow</h2>
|
||||||
<ReactFlowApp />
|
<p>no client hydration</p>
|
||||||
|
<ReactFlowApp />
|
||||||
|
|
||||||
<p>client hydration on load (client:load)</p>
|
<p>client hydration on load (client:load)</p>
|
||||||
<ReactFlowApp client:load />
|
<ReactFlowApp client:load />
|
||||||
|
|
||||||
<p>client hydration on load (client:load) and initialWidth / initialHeight</p>
|
<p>client hydration on load (client:load) and initialWidth / initialHeight</p>
|
||||||
<ReactFlowInitialApp client:load />
|
<ReactFlowInitialApp client:load />
|
||||||
|
|
||||||
<h2>Svelte Flow</h2>
|
<h2>Svelte Flow</h2>
|
||||||
<SvelteFlowApp />
|
<SvelteFlowApp />
|
||||||
|
|
||||||
<p>client hydration on load (client:load)</p>
|
<p>client hydration on load (client:load)</p>
|
||||||
<SvelteFlowApp client:load />
|
<SvelteFlowApp client:load />
|
||||||
|
|
||||||
<p>client hydration on load (client:load) and initialWidth / initialHeight</p>
|
<p>client hydration on load (client:load) and initialWidth / initialHeight</p>
|
||||||
<SvelteFlowInitialApp client:load />
|
<SvelteFlowInitialApp client:load />
|
||||||
|
</body>
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
export { portal } from './portal.svelte';
|
export { portal } from './portal.svelte';
|
||||||
|
export { hideOnSSR } from './utils.svelte';
|
||||||
|
|||||||
@@ -15,25 +15,32 @@ function tryToMount(node: Element, domNode: Element | null, target: Portal | und
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function portal(node: Element, target: Portal | undefined) {
|
export function portal(node: Element, target: Portal | undefined) {
|
||||||
// TODO: does this work if called outside of SvelteFlow
|
const { domNode } = $derived(useStore());
|
||||||
const store = useStore();
|
|
||||||
|
|
||||||
let previousTarget: Portal | undefined = target;
|
let destroyEffect: (() => void) | undefined;
|
||||||
|
// svelte-ignore state_referenced_locally
|
||||||
tryToMount(node, store.domNode, target);
|
if (domNode) {
|
||||||
|
// if the domNode is already mounted, we can directly try to mount the node
|
||||||
|
tryToMount(node, domNode, target);
|
||||||
|
} else {
|
||||||
|
// if the domNode is not mounted yet, we need to wait for it to be ready
|
||||||
|
destroyEffect = $effect.root(() => {
|
||||||
|
$effect(() => {
|
||||||
|
tryToMount(node, domNode, target);
|
||||||
|
destroyEffect?.();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
async update(target: Portal) {
|
async update(target: Portal | undefined) {
|
||||||
if (target !== previousTarget) {
|
tryToMount(node, domNode, target);
|
||||||
node.parentNode?.removeChild(node);
|
|
||||||
previousTarget = target;
|
|
||||||
}
|
|
||||||
tryToMount(node, store.domNode, target);
|
|
||||||
},
|
},
|
||||||
destroy() {
|
destroy() {
|
||||||
if (node.parentNode) {
|
if (node.parentNode) {
|
||||||
node.parentNode.removeChild(node);
|
node.parentNode.removeChild(node);
|
||||||
}
|
}
|
||||||
|
destroyEffect?.();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
17
packages/svelte/src/lib/actions/portal/utils.svelte.ts
Normal file
17
packages/svelte/src/lib/actions/portal/utils.svelte.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
export function hideOnSSR(): { value: boolean } {
|
||||||
|
let hide = $state(typeof window === 'undefined');
|
||||||
|
if (hide) {
|
||||||
|
const destroyEffect = $effect.root(() => {
|
||||||
|
$effect(() => {
|
||||||
|
hide = false;
|
||||||
|
destroyEffect?.();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
get value() {
|
||||||
|
return hide;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { getContext } from 'svelte';
|
import { getContext } from 'svelte';
|
||||||
import { portal } from '$lib/actions/portal';
|
import { hideOnSSR, portal } from '$lib/actions/portal';
|
||||||
|
|
||||||
import { useStore } from '$lib/store';
|
import { useStore } from '$lib/store';
|
||||||
import type { EdgeLabelProps } from './types';
|
import type { EdgeLabelProps } from './types';
|
||||||
@@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
use:portal={'edge-labels'}
|
use:portal={'edge-labels'}
|
||||||
|
style:display={hideOnSSR().value ? 'none' : undefined}
|
||||||
class={['svelte-flow__edge-label', { transparent }, className]}
|
class={['svelte-flow__edge-label', { transparent }, className]}
|
||||||
style:cursor={selectEdgeOnClick ? 'pointer' : undefined}
|
style:cursor={selectEdgeOnClick ? 'pointer' : undefined}
|
||||||
style:transform="translate(-50%, -50%) translate({x}px,{y}px)"
|
style:transform="translate(-50%, -50%) translate({x}px,{y}px)"
|
||||||
|
|||||||
@@ -89,8 +89,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onkeydown = (event: KeyboardEvent) => {
|
function onkeydown(event: KeyboardEvent) {
|
||||||
// TODO: Possible Svelte Bug? onkeydown is always firing for the last edge
|
|
||||||
if (!store.disableKeyboardA11y && elementSelectionKeys.includes(event.key) && selectable) {
|
if (!store.disableKeyboardA11y && elementSelectionKeys.includes(event.key) && selectable) {
|
||||||
const { unselectNodesAndEdges, addSelectedEdges } = store;
|
const { unselectNodesAndEdges, addSelectedEdges } = store;
|
||||||
const unselect = event.key === 'Escape';
|
const unselect = event.key === 'Escape';
|
||||||
@@ -102,7 +101,7 @@
|
|||||||
addSelectedEdges([id]);
|
addSelectedEdges([id]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
||||||
|
|||||||
@@ -46,7 +46,6 @@
|
|||||||
let store = useStore();
|
let store = useStore();
|
||||||
let ariaLabelConfig = $derived(store.ariaLabelConfig);
|
let ariaLabelConfig = $derived(store.ariaLabelConfig);
|
||||||
|
|
||||||
|
|
||||||
let prevConnections: Map<string, HandleConnection> | null = null;
|
let prevConnections: Map<string, HandleConnection> | null = null;
|
||||||
$effect.pre(() => {
|
$effect.pre(() => {
|
||||||
if (onconnect || ondisconnect) {
|
if (onconnect || ondisconnect) {
|
||||||
|
|||||||
@@ -66,7 +66,9 @@
|
|||||||
let draggable = $derived(_draggable ?? store.nodesDraggable);
|
let draggable = $derived(_draggable ?? store.nodesDraggable);
|
||||||
let selectable = $derived(_selectable ?? store.elementsSelectable);
|
let selectable = $derived(_selectable ?? store.elementsSelectable);
|
||||||
let connectable = $derived(_connectable ?? store.nodesConnectable);
|
let connectable = $derived(_connectable ?? store.nodesConnectable);
|
||||||
let initialized = $derived(nodeHasDimensions(node) && !!node.internals.handleBounds);
|
let hasDimensions = $derived(nodeHasDimensions(node));
|
||||||
|
let hasHandleBounds = $derived(!!node.internals.handleBounds);
|
||||||
|
let isInitialized = $derived(hasDimensions && hasHandleBounds);
|
||||||
let focusable = $derived(_focusable ?? store.nodesFocusable);
|
let focusable = $derived(_focusable ?? store.nodesFocusable);
|
||||||
|
|
||||||
function isInParentLookup(id: string) {
|
function isInParentLookup(id: string) {
|
||||||
@@ -150,7 +152,7 @@
|
|||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
/* eslint-disable @typescript-eslint/no-unused-expressions */
|
/* eslint-disable @typescript-eslint/no-unused-expressions */
|
||||||
if (resizeObserver && (!initialized || nodeRef !== prevNodeRef)) {
|
if (resizeObserver && (!isInitialized || nodeRef !== prevNodeRef)) {
|
||||||
prevNodeRef && resizeObserver.unobserve(prevNodeRef);
|
prevNodeRef && resizeObserver.unobserve(prevNodeRef);
|
||||||
nodeRef && resizeObserver.observe(nodeRef);
|
nodeRef && resizeObserver.observe(nodeRef);
|
||||||
prevNodeRef = nodeRef;
|
prevNodeRef = nodeRef;
|
||||||
@@ -265,7 +267,7 @@
|
|||||||
class:parent={isParent}
|
class:parent={isParent}
|
||||||
style:z-index={zIndex}
|
style:z-index={zIndex}
|
||||||
style:transform="translate({positionX}px, {positionY}px)"
|
style:transform="translate({positionX}px, {positionY}px)"
|
||||||
style:visibility={initialized ? 'visible' : 'hidden'}
|
style:visibility={hasDimensions ? 'visible' : 'hidden'}
|
||||||
style={nodeStyle}
|
style={nodeStyle}
|
||||||
onclick={onSelectNodeHandler}
|
onclick={onSelectNodeHandler}
|
||||||
onpointerenter={onnodepointerenter
|
onpointerenter={onnodepointerenter
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { portal } from '$lib/actions/portal';
|
import { hideOnSSR, portal } from '$lib/actions/portal';
|
||||||
import type { ViewportPortalProps } from './types';
|
import type { ViewportPortalProps } from './types';
|
||||||
|
|
||||||
let { target = 'front', children, ...rest }: ViewportPortalProps = $props();
|
let { target = 'front', children, ...rest }: ViewportPortalProps = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div use:portal={`viewport-${target}`} {...rest}>
|
<div
|
||||||
|
use:portal={`viewport-${target}`}
|
||||||
|
style:display={hideOnSSR().value ? 'none' : undefined}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
{@render children?.()}
|
{@render children?.()}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import { getContext } from 'svelte';
|
import { getContext } from 'svelte';
|
||||||
import { Position, getNodeToolbarTransform } from '@xyflow/system';
|
import { Position, getNodeToolbarTransform } from '@xyflow/system';
|
||||||
|
|
||||||
import { portal } from '$lib/actions/portal';
|
import { hideOnSSR, portal } from '$lib/actions/portal';
|
||||||
import { useStore } from '$lib/store';
|
import { useStore } from '$lib/store';
|
||||||
import { useSvelteFlow } from '$lib/hooks/useSvelteFlow.svelte';
|
import { useSvelteFlow } from '$lib/hooks/useSvelteFlow.svelte';
|
||||||
|
|
||||||
@@ -68,6 +68,7 @@
|
|||||||
{#if store.domNode && isActive && toolbarNodes}
|
{#if store.domNode && isActive && toolbarNodes}
|
||||||
<div
|
<div
|
||||||
use:portal={'root'}
|
use:portal={'root'}
|
||||||
|
style:display={hideOnSSR().value ? 'none' : undefined}
|
||||||
class="svelte-flow__node-toolbar"
|
class="svelte-flow__node-toolbar"
|
||||||
data-id={toolbarNodes.reduce((acc, node) => `${acc}${node.id} `, '').trim()}
|
data-id={toolbarNodes.reduce((acc, node) => `${acc}${node.id} `, '').trim()}
|
||||||
style:position="absolute"
|
style:position="absolute"
|
||||||
|
|||||||
@@ -84,6 +84,25 @@ export const initialEdgeTypes = {
|
|||||||
step: StepEdgeInternal
|
step: StepEdgeInternal
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function getInitialViewport(
|
||||||
|
// This is just used to make sure adoptUserNodes is called before we calculate the viewport
|
||||||
|
_nodesInitialized: boolean,
|
||||||
|
fitView: boolean | undefined,
|
||||||
|
initialViewport: Viewport | undefined,
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
nodeLookup: NodeLookup
|
||||||
|
) {
|
||||||
|
if (fitView && !initialViewport && width && height) {
|
||||||
|
const bounds = getInternalNodesBounds(nodeLookup, {
|
||||||
|
filter: (node) => !!((node.width || node.initialWidth) && (node.height || node.initialHeight))
|
||||||
|
});
|
||||||
|
return getViewportForBounds(bounds, width, height, 0.5, 2, 0.1);
|
||||||
|
} else {
|
||||||
|
return initialViewport ?? { x: 0, y: 0, zoom: 1 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function getInitialStore<NodeType extends Node = Node, EdgeType extends Edge = Edge>(
|
export function getInitialStore<NodeType extends Node = Node, EdgeType extends Edge = Edge>(
|
||||||
signals: StoreSignals<NodeType, EdgeType>
|
signals: StoreSignals<NodeType, EdgeType>
|
||||||
) {
|
) {
|
||||||
@@ -298,7 +317,16 @@ export function getInitialStore<NodeType extends Node = Node, EdgeType extends E
|
|||||||
|
|
||||||
// _viewport is the internal viewport.
|
// _viewport is the internal viewport.
|
||||||
// when binding to viewport, we operate on signals.viewport instead
|
// when binding to viewport, we operate on signals.viewport instead
|
||||||
_viewport: Viewport = $state(signals.props.initialViewport ?? { x: 0, y: 0, zoom: 1 });
|
_viewport: Viewport = $state(
|
||||||
|
getInitialViewport(
|
||||||
|
this.nodesInitialized,
|
||||||
|
signals.props.fitView,
|
||||||
|
signals.props.initialViewport,
|
||||||
|
this.width,
|
||||||
|
this.height,
|
||||||
|
this.nodeLookup
|
||||||
|
)
|
||||||
|
);
|
||||||
get viewport() {
|
get viewport() {
|
||||||
return signals.viewport ?? this._viewport;
|
return signals.viewport ?? this._viewport;
|
||||||
}
|
}
|
||||||
@@ -410,15 +438,6 @@ export function getInitialStore<NodeType extends Node = Node, EdgeType extends E
|
|||||||
);
|
);
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
// Process intial fitView here
|
|
||||||
if (signals.props.fitView && !signals.props.initialViewport && this.width && this.height) {
|
|
||||||
const bounds = getInternalNodesBounds(this.nodeLookup, {
|
|
||||||
filter: (node) =>
|
|
||||||
!!((node.width || node.initialWidth) && (node.height || node.initialHeight))
|
|
||||||
});
|
|
||||||
this.viewport = getViewportForBounds(bounds, this.width, this.height, 0.5, 2, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'development') {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
warnIfDeeplyReactive(signals.nodes, 'nodes');
|
warnIfDeeplyReactive(signals.nodes, 'nodes');
|
||||||
warnIfDeeplyReactive(signals.edges, 'edges');
|
warnIfDeeplyReactive(signals.edges, 'edges');
|
||||||
|
|||||||
3800
pnpm-lock.yaml
generated
3800
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user