Skip to content

Commit a9b0521

Browse files
committed
chore(flow): update to SvelteFlow 1.0.0 (#79) (#102)
Closes #79
1 parent fa19a99 commit a9b0521

File tree

7 files changed

+234
-457
lines changed

7 files changed

+234
-457
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
"@tailwindcss/vite": "^4.1",
3939
"@uiw/codemirror-theme-dracula": "^4.23",
4040
"@uiw/codemirror-theme-github": "^4.23",
41-
"@xyflow/svelte": "^0.1.26",
41+
"@xyflow/svelte": "^1.2.1",
4242
"cron-parser": "^5.1.1",
4343
"cronstrue": "^2.59.0",
4444
"dotenv": "^16",

pnpm-lock.yaml

Lines changed: 168 additions & 392 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/lib/components/flow/DisposeButtonEdge.svelte

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,30 @@
11
<script lang="ts">
2-
import { BaseEdge, EdgeLabelRenderer, type EdgeProps, getBezierPath, useEdges } from '@xyflow/svelte';
2+
import { BaseEdge, EdgeLabel, type EdgeProps, getBezierPath, useEdges } from '@xyflow/svelte';
33
import IconX from 'lucide-svelte/icons/x';
44
5-
type $$Props = EdgeProps;
6-
7-
export let id: $$Props['id'];
8-
export let sourceX: $$Props['sourceX'];
9-
export let sourceY: $$Props['sourceY'];
10-
export let sourcePosition: $$Props['sourcePosition'];
11-
export let targetX: $$Props['targetX'];
12-
export let targetY: $$Props['targetY'];
13-
export let targetPosition: $$Props['targetPosition'];
14-
export let markerEnd: $$Props['markerEnd'] = undefined;
15-
export let style: $$Props['style'] = undefined;
16-
export let data: $$Props['data'] = undefined;
17-
18-
$: [edgePath, labelX, labelY] = getBezierPath({
5+
const {
6+
id,
197
sourceX,
208
sourceY,
219
sourcePosition,
2210
targetX,
2311
targetY,
24-
targetPosition
25-
});
12+
targetPosition,
13+
markerEnd,
14+
style,
15+
data,
16+
}: EdgeProps = $props();
17+
18+
let [edgePath, labelX, labelY] = $derived(
19+
getBezierPath({
20+
sourceX,
21+
sourceY,
22+
sourcePosition,
23+
targetX,
24+
targetY,
25+
targetPosition,
26+
}),
27+
);
2628
2729
const edges = useEdges();
2830
@@ -44,19 +46,14 @@
4446
</script>
4547

4648
<BaseEdge path={edgePath} {markerEnd} {style}/>
47-
<EdgeLabelRenderer>
48-
<div
49-
class="edgeButtonContainer nodrag nopan"
50-
style:transform="translate(-50%, -50%) translate({labelX}px,{labelY}px)"
51-
>
52-
<button class="edgeButton border-surface-900-100 bg-surface-100-900 hover:bg-surface-200-800" on:click={onEdgeClick}>
53-
<IconX class="mx-auto"/>
54-
</button>
55-
</div>
56-
</EdgeLabelRenderer>
49+
<EdgeLabel class="edgeButtonContainer" style="background: none!important" x={labelX} y={labelY}>
50+
<button class="edgeButton border-surface-900-100 bg-surface-100-900 hover:bg-surface-200-800" onclick={onEdgeClick}>
51+
<IconX class="mx-auto"/>
52+
</button>
53+
</EdgeLabel>
5754

5855
<style>
59-
.edgeButtonContainer {
56+
:global(.edgeButtonContainer) {
6057
position: absolute;
6158
font-size: 12pt;
6259
/* everything inside EdgeLabelRenderer has no pointer events by default */

src/lib/components/flow/Flow.svelte

Lines changed: 34 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
<script lang="ts">
22
import '@xyflow/svelte/dist/style.css';
3-
import { Background, Controls, type Edge, MarkerType, MiniMap, type Node, SvelteFlow } from "@xyflow/svelte";
4-
import { writable } from "svelte/store";
3+
import {
4+
Background,
5+
Controls,
6+
type Edge,
7+
MarkerType,
8+
MiniMap,
9+
type Node,
10+
SvelteFlow,
11+
useSvelteFlow,
12+
} from "@xyflow/svelte";
513
import { DISPOSE_EDGE, edgeTypes, FLOW_NODE, nodeTypes } from "$lib/model/svelte_flow";
614
import { getLayoutedElements } from "$lib/components/flow/flow_utils";
715
import {
@@ -17,7 +25,6 @@
1725
import type { NodeCreatedHandler } from "$lib/components/add";
1826
import type { WorkflowWithNodes } from "$lib/model/flows";
1927
import FlowMenus from "$lib/components/flow/FlowMenus.svelte";
20-
import { useSvelteFlow } from "@xyflow/svelte";
2128
2229
type Props = {
2330
flow: WorkflowWithNodes
@@ -42,7 +49,9 @@
4249
onsettingschange: (newSettings: NodeSettings) => updateSettings(apiProps, node._id, newSettings),
4350
ondelete: () => {
4451
deleteNode(apiProps, node._id)
45-
.then(() => nodesStore.update(nodes => nodes.filter(n => n.id !== node._id)));
52+
.then(() => {
53+
nodesStore = nodesStore.filter(n => n.id !== node._id);
54+
});
4655
},
4756
heights,
4857
widths,
@@ -59,66 +68,62 @@
5968
id: `${node._id}:${next}`,
6069
source: node._id,
6170
target: next,
62-
animated: true,
6371
data: {
6472
ondisconnect: () => disconnectNodes(apiProps, node._id, next)
6573
}
6674
} as Edge))
6775
);
6876
69-
const nodesStore = writable<Node[]>(initialNodes);
70-
const edgesStore = writable<Edge[]>(initialEdges);
71-
const { fitView } = useSvelteFlow();
77+
let nodesStore = $state.raw<Node[]>(initialNodes);
78+
let edgesStore = $state.raw<Edge[]>(initialEdges);
7279
73-
// never-ending promise while the layout is being calculated
74-
let promise: Promise<void> = $state(new Promise(() => {}));
80+
const { promise, resolve } = Promise.withResolvers()
7581
7682
$effect(() => {
7783
if (Object.keys(widths).length === initialNodes.length && Object.keys(heights).length === initialNodes.length) {
78-
updateLayout();
84+
updateLayout()
85+
.then(() => resolve(null));
7986
}
8087
})
8188
82-
function updateLayout() {
83-
promise = getLayoutedElements(
89+
const svelteFlow = useSvelteFlow()
90+
async function updateLayout() {
91+
const layoutedNodes = (await getLayoutedElements(
8492
initialNodes,
8593
initialEdges,
8694
widths,
8795
heights,
8896
{ 'elk.direction': "RIGHT" }
89-
).then(({ nodes: layoutedNodes }) => {
90-
// most readable TS/JS code
91-
nodesStore.update(_ => layoutedNodes.map(d => ({ ...d, data: { ...d.data, initializing: false }})));
92-
// scuffed way to wait for the nodes to be updated before fitting the view
93-
// this is necessary because an immediate call to `fitView` would slightly offset the view
94-
let unsubscriber: () => void;
95-
unsubscriber = nodesStore.subscribe((_) => {
96-
if (!unsubscriber) return
97-
fitView();
98-
unsubscriber()
99-
});
100-
})
97+
)).nodes
98+
99+
nodesStore = layoutedNodes.map(d => ({ ...d, data: { ...d.data, initializing: false } }));
100+
for (let i = 0; i < 10; i++) {
101+
await svelteFlow.fitView();
102+
}
101103
}
102104
103105
const addNode: NodeCreatedHandler = async (node: StandaloneNode) => {
104106
const newNode = createNodeFromNode(node);
105107
newNode.width = Object.values(widths).reduce((acc, val) => acc + val, 0) / Object.keys(widths).length;
106-
nodesStore.update(nodes => [...nodes, newNode]);
108+
// do not use `.push` because Svelte 5 is totally bugged
109+
nodesStore = [...nodesStore, newNode];
107110
}
108111
</script>
109112

110113
<SvelteFlow proOptions={{hideAttribution: true}}
111114
{nodeTypes}
112115
{edgeTypes}
113-
nodes={nodesStore}
114-
edges={edgesStore}
116+
fitView
117+
bind:nodes={nodesStore}
118+
bind:edges={edgesStore}
115119
defaultEdgeOptions={{
116120
type: DISPOSE_EDGE,
117121
markerEnd: {
118122
type: MarkerType.Arrow,
119123
width: 25,
120124
height: 25
121-
}
125+
},
126+
animated: true,
122127
}}
123128
class="svelte-flow"
124129
onconnect={(event) => connectNodes(apiProps, event.source, event.target)}

src/lib/components/flow/FlowLoading.svelte

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
<script lang="ts">
2-
import { writable } from "svelte/store";
32
import { Background, SvelteFlow } from "@xyflow/svelte";
43
5-
const nodes = writable([]);
6-
const edges = writable([]);
4+
const nodes = $state.raw([]);
5+
const edges = $state.raw([]);
76
</script>
87

98
<SvelteFlow proOptions={{hideAttribution: true}}

src/lib/components/flow/FlowMenus.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
<Panel position="top-left" class="flex flex-row items-center">
5555
<div class="svelte-flow__controls flex-row!">
5656
<ControlButton
57-
on:click={() => toggleOpen(ADD)}
57+
onclick={() => toggleOpen(ADD)}
5858
class="svelte-flow__controls-addnode"
5959
title="add node"
6060
aria-label="add node"
@@ -75,7 +75,7 @@
7575
<FlowTriggerButton apiProps={props.apiProps} flow={props.flow}/>
7676
<div>
7777
<ControlButton
78-
on:click={() => toggleOpen(LOGS)}
78+
onclick={() => toggleOpen(LOGS)}
7979
class="svelte-flow__controls-showlogs no-fill"
8080
title="show logs"
8181
aria-label="show logs"

src/lib/components/node/Node.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
})
6060
6161
const { edges } = useStore()
62-
let hasOutputNode = $derived($edges.some(edge => edge.source === node._id))
62+
let hasOutputNode = $derived(edges.some(edge => edge.source === node._id))
6363
6464
const isHighlighted = page.url.searchParams.get("highlightedNode") === node._id;
6565
</script>
@@ -71,7 +71,7 @@
7171
class={metadata?.position === "START" ? "bg-green-500!" : ""}/>
7272
{/if}
7373
<div class:max-w-3xl={data.initializing === true} class="h-full flex flex-col cursor-auto flow-node p-2 card preset-filled-surface-100-900 border-surface-200-800 divide-surface-200-800 border overflow-hidden">
74-
<NodeResizeControl minWidth={150} minHeight={50}>
74+
<NodeResizeControl minWidth={150} minHeight={50} autoScale={false}>
7575
<IconScaling size="1em" class="absolute -translate-x-2 -translate-y-2"/>
7676
</NodeResizeControl>
7777
{#if metadata}

0 commit comments

Comments
 (0)