chore(svelte-examples): pull out of lib package (#3363)
* chore(svelte-examples): pull out of lib package * chore(svelte-examples): cleanup * chore(examples): add readme files
This commit is contained in:
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
// See https://kit.svelte.dev/docs/types#app
|
||||
// for information about these interfaces
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface Platform {}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
@@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<style>
|
||||
html,
|
||||
body,
|
||||
#root {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
</style>
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body>
|
||||
<div id="root">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,46 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/stores';
|
||||
|
||||
const routes = [
|
||||
'customnode',
|
||||
'drag-n-drop',
|
||||
'edges',
|
||||
'figma',
|
||||
'interaction',
|
||||
'overview',
|
||||
'stress',
|
||||
'subflows',
|
||||
'usesvelteflow',
|
||||
'validation'
|
||||
];
|
||||
|
||||
const onChange = (event: Event) => {
|
||||
const route = (event.target as HTMLSelectElement).value;
|
||||
goto(route);
|
||||
};
|
||||
</script>
|
||||
|
||||
<header>
|
||||
<div class="logo">Svelte Flow</div>
|
||||
<select on:change={onChange} value={$page.route.id}>
|
||||
{#each routes as route}
|
||||
<option value={`/${route}`}>{route}</option>
|
||||
{/each}
|
||||
</select>
|
||||
</header>
|
||||
|
||||
<style>
|
||||
header {
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid #eee;
|
||||
display: flex;
|
||||
font-weight: 700;
|
||||
align-items: center;
|
||||
color: #111;
|
||||
}
|
||||
|
||||
.logo {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1 @@
|
||||
export { default as Header } from './Header.svelte';
|
||||
@@ -0,0 +1,8 @@
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
|
||||
/** @type {import('./$types').LayoutServerLoad} */
|
||||
export function load({ route }) {
|
||||
if (route.id === '/') {
|
||||
throw redirect(307, '/overview');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<script lang="ts">
|
||||
import { Header } from '../components/Header';
|
||||
</script>
|
||||
|
||||
<div class="app">
|
||||
<Header />
|
||||
<div class="flow">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.app {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.flow {
|
||||
flex: 1;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1 @@
|
||||
<div>this redirects to /overview</div>
|
||||
@@ -0,0 +1,131 @@
|
||||
<script lang="ts">
|
||||
import type { ChangeEventHandler } from 'svelte/elements';
|
||||
import { writable } from 'svelte/store';
|
||||
import {
|
||||
SvelteFlow,
|
||||
Controls,
|
||||
Background,
|
||||
BackgroundVariant,
|
||||
MiniMap,
|
||||
Position,
|
||||
type Node,
|
||||
type NodeTypes,
|
||||
type Edge,
|
||||
type Connection
|
||||
} from '@xyflow/svelte';
|
||||
import CustomNode from './CustomNode.svelte';
|
||||
|
||||
import '@xyflow/svelte/dist/style.css';
|
||||
|
||||
const nodeTypes: NodeTypes = {
|
||||
colorNode: CustomNode
|
||||
};
|
||||
|
||||
const bgColor = writable('#1A192B');
|
||||
|
||||
const onChange: ChangeEventHandler<HTMLInputElement> = (event) => {
|
||||
nodes.update((nds) =>
|
||||
nds.map((node) => {
|
||||
if (node.type !== 'colorNode') {
|
||||
return node;
|
||||
}
|
||||
|
||||
const color = (event.target as HTMLInputElement)?.value;
|
||||
|
||||
bgColor.set(color);
|
||||
|
||||
return {
|
||||
...node,
|
||||
data: {
|
||||
...node.data,
|
||||
color
|
||||
}
|
||||
};
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const nodes = writable<Node[]>([
|
||||
{
|
||||
id: '1',
|
||||
type: 'input',
|
||||
data: { label: 'An input node' },
|
||||
position: { x: 0, y: 50 },
|
||||
sourcePosition: Position.Right
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'colorNode',
|
||||
data: { onChange: onChange, color: $bgColor },
|
||||
style: 'border: 1px solid #777; padding: 10px',
|
||||
position: { x: 250, y: 50 }
|
||||
},
|
||||
{
|
||||
id: '2a',
|
||||
type: 'colorNode',
|
||||
data: { onChange: onChange, color: $bgColor },
|
||||
style: 'border: 1px solid #777; padding: 10px',
|
||||
position: { x: 250, y: 520 }
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
type: 'output',
|
||||
data: { label: 'Output A' },
|
||||
position: { x: 650, y: 25 },
|
||||
targetPosition: Position.Left
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
type: 'output',
|
||||
data: { label: 'Output B' },
|
||||
position: { x: 650, y: 120 },
|
||||
targetPosition: Position.Left
|
||||
}
|
||||
]);
|
||||
|
||||
const edges = writable<Edge[]>([
|
||||
{
|
||||
id: 'e1-2',
|
||||
source: '1',
|
||||
target: '2',
|
||||
animated: true
|
||||
},
|
||||
{
|
||||
id: 'e2a-3',
|
||||
source: '2',
|
||||
sourceHandle: 'a',
|
||||
target: '3',
|
||||
animated: true
|
||||
},
|
||||
{
|
||||
id: 'e2b-4',
|
||||
source: '2',
|
||||
sourceHandle: 'b',
|
||||
target: '4',
|
||||
animated: true
|
||||
}
|
||||
]);
|
||||
|
||||
const onConnect = (connection: Connection) => {
|
||||
console.log('on connect', connection);
|
||||
};
|
||||
</script>
|
||||
|
||||
<SvelteFlow
|
||||
{nodes}
|
||||
{edges}
|
||||
{nodeTypes}
|
||||
style="--bgcolor: {$bgColor}"
|
||||
fitView
|
||||
on:connect={onConnect}
|
||||
>
|
||||
<Controls />
|
||||
<Background variant={BackgroundVariant.Dots} />
|
||||
<MiniMap />
|
||||
</SvelteFlow>
|
||||
|
||||
<style>
|
||||
:global(.svelte-flow) {
|
||||
background: var(--bgcolor);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script lang="ts">
|
||||
import { Handle, Position, type NodeProps } from '@xyflow/svelte';
|
||||
|
||||
type $$Props = NodeProps;
|
||||
|
||||
export let data: { color: string; onChange: () => void } = { color: '#111', onChange: () => {} };
|
||||
</script>
|
||||
|
||||
<Handle type="target" position={Position.Left} on:connect />
|
||||
<div>
|
||||
Custom Color Picker Node: <strong>{data.color}</strong>
|
||||
</div>
|
||||
<input class="nodrag" type="color" on:input={data.onChange} value={data.color} />
|
||||
<Handle type="source" position={Position.Right} id="a" style="top: 10px;" on:connect />
|
||||
<Handle
|
||||
type="source"
|
||||
position={Position.Right}
|
||||
id="b"
|
||||
style="top: auto; bottom: 10px;"
|
||||
on:connect
|
||||
/>
|
||||
@@ -0,0 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { SvelteFlowProvider } from '@xyflow/svelte';
|
||||
|
||||
import Flow from './Flow.svelte';
|
||||
</script>
|
||||
|
||||
<SvelteFlowProvider>
|
||||
<Flow />
|
||||
</SvelteFlowProvider>
|
||||
@@ -0,0 +1,106 @@
|
||||
<script lang="ts">
|
||||
import { writable } from 'svelte/store';
|
||||
import {
|
||||
SvelteFlow,
|
||||
Controls,
|
||||
Background,
|
||||
BackgroundVariant,
|
||||
MiniMap,
|
||||
useSvelteFlow,
|
||||
type Node
|
||||
} from '@xyflow/svelte';
|
||||
import Sidebar from './Sidebar.svelte';
|
||||
|
||||
import '@xyflow/svelte/dist/style.css';
|
||||
|
||||
const nodes = writable([
|
||||
{
|
||||
id: '1',
|
||||
type: 'input',
|
||||
data: { label: 'Input Node' },
|
||||
position: { x: 150, y: 5 }
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'default',
|
||||
data: { label: 'Node' },
|
||||
position: { x: 0, y: 150 }
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
type: 'output',
|
||||
data: { label: 'Output Node' },
|
||||
position: { x: 300, y: 150 }
|
||||
}
|
||||
]);
|
||||
|
||||
const edges = writable([
|
||||
{
|
||||
id: '1-2',
|
||||
type: 'default',
|
||||
source: '1',
|
||||
target: '2',
|
||||
label: 'Edge Text'
|
||||
},
|
||||
{
|
||||
id: '1-3',
|
||||
type: 'smoothstep',
|
||||
source: '1',
|
||||
target: '3'
|
||||
}
|
||||
]);
|
||||
|
||||
const svelteFlow = useSvelteFlow();
|
||||
|
||||
const onDragOver = (event: DragEvent) => {
|
||||
event.preventDefault();
|
||||
|
||||
console.log(event);
|
||||
|
||||
if (event.dataTransfer) {
|
||||
event.dataTransfer.dropEffect = 'move';
|
||||
}
|
||||
};
|
||||
|
||||
const onDrop = (event: DragEvent) => {
|
||||
event.preventDefault();
|
||||
|
||||
if (!event.dataTransfer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const type = event.dataTransfer.getData('application/svelteflow');
|
||||
const position = svelteFlow.project({
|
||||
x: event.clientX,
|
||||
y: event.clientY - 40
|
||||
});
|
||||
const newNode: Node = {
|
||||
id: `${Math.random()}`,
|
||||
type,
|
||||
position,
|
||||
data: { label: `${type} node` }
|
||||
};
|
||||
|
||||
svelteFlow.nodes.update((nds) => nds.concat(newNode));
|
||||
};
|
||||
|
||||
$: {
|
||||
console.log($nodes);
|
||||
}
|
||||
</script>
|
||||
|
||||
<main>
|
||||
<SvelteFlow {nodes} {edges} fitView on:dragover={onDragOver} on:drop={onDrop}>
|
||||
<Controls />
|
||||
<Background variant={BackgroundVariant.Dots} />
|
||||
<MiniMap />
|
||||
</SvelteFlow>
|
||||
<Sidebar />
|
||||
</main>
|
||||
|
||||
<style>
|
||||
main {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,61 @@
|
||||
<script lang="ts">
|
||||
import { useSvelteFlow } from '@xyflow/svelte';
|
||||
|
||||
const onDragStart = (event: DragEvent, nodeType: string) => {
|
||||
if (!event.dataTransfer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
event.dataTransfer.setData('application/svelteflow', nodeType);
|
||||
event.dataTransfer.effectAllowed = 'move';
|
||||
};
|
||||
|
||||
const { zoomIn, zoomOut, fitView, viewport, nodes } = useSvelteFlow();
|
||||
</script>
|
||||
|
||||
<aside>
|
||||
<div class="label">You can drag these nodes to the pane on the left.</div>
|
||||
<div
|
||||
class="input-node node"
|
||||
on:dragstart={(event) => onDragStart(event, 'input')}
|
||||
draggable={true}
|
||||
>
|
||||
Input Node
|
||||
</div>
|
||||
<div
|
||||
class="default-node node"
|
||||
on:dragstart={(event) => onDragStart(event, 'default')}
|
||||
draggable={true}
|
||||
>
|
||||
Default Node
|
||||
</div>
|
||||
<div
|
||||
class="output-node node"
|
||||
on:dragstart={(event) => onDragStart(event, 'output')}
|
||||
draggable={true}
|
||||
>
|
||||
Output Node
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<style>
|
||||
.label {
|
||||
margin: 0.5rem 0 0.25rem 0;
|
||||
}
|
||||
|
||||
aside {
|
||||
width: 20vw;
|
||||
background: #f4f4f4;
|
||||
padding: 0.4rem 0.8rem;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.node {
|
||||
margin-bottom: 0.5rem;
|
||||
border: 1px solid #111;
|
||||
padding: 0.5rem 1rem;
|
||||
font-weight: 700;
|
||||
border-radius: 3px;
|
||||
cursor: grab;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,152 @@
|
||||
<script lang="ts">
|
||||
import { writable } from 'svelte/store';
|
||||
import {
|
||||
SvelteFlow,
|
||||
Controls,
|
||||
Background,
|
||||
BackgroundVariant,
|
||||
MiniMap,
|
||||
MarkerType
|
||||
} from '@xyflow/svelte';
|
||||
|
||||
import '@xyflow/svelte/dist/style.css';
|
||||
|
||||
const nodes = writable([
|
||||
{
|
||||
id: '1',
|
||||
type: 'input',
|
||||
data: { label: 'Input 1' },
|
||||
position: { x: 250, y: 0 }
|
||||
},
|
||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 150, y: 100 } },
|
||||
{ id: '2a', data: { label: 'Node 2a' }, position: { x: 0, y: 180 } },
|
||||
{ id: '2b', data: { label: 'Node 2b' }, position: { x: -40, y: 300 } },
|
||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 250, y: 200 } },
|
||||
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 300 } },
|
||||
{ id: '3a', data: { label: 'Node 3a' }, position: { x: 150, y: 300 } },
|
||||
{ id: '5', data: { label: 'Node 5' }, position: { x: 250, y: 400 } },
|
||||
{
|
||||
id: '6',
|
||||
type: 'output',
|
||||
data: { label: 'Output 6' },
|
||||
position: { x: 50, y: 550 }
|
||||
},
|
||||
{
|
||||
id: '7',
|
||||
type: 'output',
|
||||
data: { label: 'Output 7' },
|
||||
position: { x: 250, y: 550 }
|
||||
},
|
||||
{
|
||||
id: '8',
|
||||
type: 'output',
|
||||
data: { label: 'Output 8' },
|
||||
position: { x: 525, y: 600 }
|
||||
},
|
||||
{
|
||||
id: '9',
|
||||
type: 'output',
|
||||
data: { label: 'Output 9' },
|
||||
position: { x: 675, y: 500 }
|
||||
}
|
||||
]);
|
||||
|
||||
const edges = writable([
|
||||
{
|
||||
id: 'e1-2',
|
||||
source: '1',
|
||||
target: '2',
|
||||
label: 'bezier edge (default)'
|
||||
},
|
||||
{
|
||||
id: 'e2-2a',
|
||||
source: '2',
|
||||
target: '2a',
|
||||
type: 'smoothstep',
|
||||
label: 'smoothstep edge'
|
||||
},
|
||||
{
|
||||
id: 'e2a-2b',
|
||||
source: '2a',
|
||||
target: '2b',
|
||||
type: 'simplebezier',
|
||||
label: 'simple bezier edge'
|
||||
},
|
||||
{ id: 'e2-3', source: '2', target: '3', type: 'step', label: 'step edge' },
|
||||
{
|
||||
id: 'e3-4',
|
||||
source: '3',
|
||||
target: '4',
|
||||
type: 'straight',
|
||||
label: 'straight edge'
|
||||
},
|
||||
{
|
||||
id: 'e3-3a',
|
||||
source: '3',
|
||||
target: '3a',
|
||||
type: 'straight',
|
||||
label: 'label only edge',
|
||||
style: 'stroke: none'
|
||||
},
|
||||
{
|
||||
id: 'e3-5',
|
||||
source: '4',
|
||||
target: '5',
|
||||
animated: true,
|
||||
label: 'animated styled edge',
|
||||
style: 'stroke: red'
|
||||
},
|
||||
{
|
||||
id: 'e5-7',
|
||||
source: '5',
|
||||
target: '7',
|
||||
label: 'label with styled bg',
|
||||
labelStyle: 'background: #FFCC00; color: #fff; opacity: 0.7',
|
||||
markerEnd: {
|
||||
type: MarkerType.ArrowClosed
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'e5-8',
|
||||
source: '5',
|
||||
target: '8',
|
||||
data: { text: 'custom edge' }
|
||||
},
|
||||
{
|
||||
id: 'e5-9',
|
||||
source: '5',
|
||||
target: '9',
|
||||
data: { text: 'custom edge 2' }
|
||||
},
|
||||
{
|
||||
id: 'e5-6',
|
||||
source: '5',
|
||||
target: '6',
|
||||
label: 'hi',
|
||||
labelStyle: 'background: red; font-weight: 700; padding: 5px;',
|
||||
style: 'stroke: #ffcc0',
|
||||
markerEnd: {
|
||||
type: MarkerType.Arrow,
|
||||
color: '#FFCC00',
|
||||
markerUnits: 'userSpaceOnUse',
|
||||
width: 20,
|
||||
height: 20,
|
||||
strokeWidth: 2
|
||||
},
|
||||
markerStart: {
|
||||
type: MarkerType.ArrowClosed,
|
||||
color: '#FFCC00',
|
||||
orient: 'auto-start-reverse',
|
||||
markerUnits: 'userSpaceOnUse',
|
||||
width: 20,
|
||||
height: 20
|
||||
}
|
||||
}
|
||||
]);
|
||||
</script>
|
||||
|
||||
<SvelteFlow {nodes} {edges} fitView>
|
||||
<Controls />
|
||||
<Background variant={BackgroundVariant.Dots} />
|
||||
<MiniMap />
|
||||
</SvelteFlow>
|
||||
@@ -0,0 +1,56 @@
|
||||
<script lang="ts">
|
||||
import { writable } from 'svelte/store';
|
||||
import {
|
||||
SvelteFlow,
|
||||
Controls,
|
||||
Background,
|
||||
BackgroundVariant,
|
||||
SelectionMode
|
||||
} from '@xyflow/svelte';
|
||||
|
||||
import '@xyflow/svelte/dist/style.css';
|
||||
|
||||
const onPaneContextMenu = (e: any) => {
|
||||
e.preventDefault();
|
||||
console.log('context menu');
|
||||
};
|
||||
|
||||
const panOnDrag = [1, 2];
|
||||
|
||||
const onMoveStart = (e: any) => console.log('move start', e);
|
||||
const onMove = (e: any) => console.log('move', e);
|
||||
const onMoveEnd = (e: any) => console.log('move end', e);
|
||||
|
||||
const nodes = writable([
|
||||
{
|
||||
id: '1',
|
||||
type: 'input',
|
||||
data: { label: 'Node 1' },
|
||||
position: { x: 250, y: 5 },
|
||||
className: 'light'
|
||||
},
|
||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 }, className: 'light' },
|
||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 }, className: 'light' },
|
||||
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 }, className: 'light' }
|
||||
]);
|
||||
|
||||
const edges = writable([
|
||||
{ id: 'e1-2', source: '1', target: '2', animated: true },
|
||||
{ id: 'e1-3', source: '1', target: '3' }
|
||||
]);
|
||||
</script>
|
||||
|
||||
<SvelteFlow
|
||||
{nodes}
|
||||
{edges}
|
||||
fitView
|
||||
selectionMode={SelectionMode.Partial}
|
||||
panOnScroll
|
||||
{panOnDrag}
|
||||
{onMoveStart}
|
||||
{onMove}
|
||||
{onMoveEnd}
|
||||
>
|
||||
<Controls />
|
||||
<Background variant={BackgroundVariant.Dots} />
|
||||
</SvelteFlow>
|
||||
@@ -0,0 +1,213 @@
|
||||
<script lang="ts">
|
||||
import { writable } from 'svelte/store';
|
||||
import {
|
||||
SvelteFlow,
|
||||
Controls,
|
||||
Panel,
|
||||
PanOnScrollMode,
|
||||
MiniMap,
|
||||
type OnMoveEnd,
|
||||
type Node,
|
||||
type Edge
|
||||
} from '@xyflow/svelte';
|
||||
|
||||
import '@xyflow/svelte/dist/style.css';
|
||||
|
||||
const nodes = writable([
|
||||
{
|
||||
id: '1',
|
||||
type: 'input',
|
||||
data: { label: 'Node 1' },
|
||||
position: { x: 250, y: 5 }
|
||||
},
|
||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 } },
|
||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 } },
|
||||
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 } }
|
||||
]);
|
||||
|
||||
const edges = writable([
|
||||
{ id: 'e1-2', source: '1', target: '2', animated: true },
|
||||
{ id: 'e1-3', source: '1', target: '3' }
|
||||
]);
|
||||
|
||||
const onNodeDragStart = (_: MouseEvent, node: Node) => console.log('drag start', node);
|
||||
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
|
||||
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
|
||||
const onEdgeClick = (_: MouseEvent, edge: Edge) => console.log('click', edge);
|
||||
const onPaneClick = (event: MouseEvent) => console.log('onPaneClick', event);
|
||||
const onPaneScroll = (event?: WheelEvent) => console.log('onPaneScroll', event);
|
||||
const onPaneContextMenu = (event: MouseEvent) => console.log('onPaneContextMenu', event);
|
||||
const onMoveEnd: OnMoveEnd = (_, viewport) => console.log('onMoveEnd', viewport);
|
||||
|
||||
let isSelectable = false;
|
||||
let isDraggable = false;
|
||||
let isConnectable = false;
|
||||
let zoomOnScroll = false;
|
||||
let zoomOnPinch = false;
|
||||
let panOnScroll = false;
|
||||
let panOnScrollMode = PanOnScrollMode.Free;
|
||||
let zoomOnDoubleClick = false;
|
||||
let panOnDrag = true;
|
||||
let captureZoomClick = false;
|
||||
let captureZoomScroll = false;
|
||||
let captureElementClick = false;
|
||||
</script>
|
||||
|
||||
<SvelteFlow
|
||||
{nodes}
|
||||
{edges}
|
||||
elementsSelectable={isSelectable}
|
||||
nodesConnectable={isConnectable}
|
||||
nodesDraggable={isDraggable}
|
||||
{zoomOnScroll}
|
||||
{zoomOnPinch}
|
||||
{panOnScroll}
|
||||
{panOnScrollMode}
|
||||
{zoomOnDoubleClick}
|
||||
{panOnDrag}
|
||||
{onMoveEnd}
|
||||
>
|
||||
<MiniMap />
|
||||
<Controls />
|
||||
|
||||
<Panel position="top-right">
|
||||
<div>
|
||||
<label for="draggable">
|
||||
nodesDraggable
|
||||
<input
|
||||
id="draggable"
|
||||
type="checkbox"
|
||||
bind:checked={isDraggable}
|
||||
class="svelte-flow__draggable"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="connectable">
|
||||
nodesConnectable
|
||||
<input
|
||||
id="connectable"
|
||||
type="checkbox"
|
||||
bind:checked={isConnectable}
|
||||
class="svelte-flow__connectable"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="selectable">
|
||||
elementsSelectable
|
||||
<input
|
||||
id="selectable"
|
||||
type="checkbox"
|
||||
bind:checked={isSelectable}
|
||||
class="svelte-flow__selectable"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="zoomonscroll">
|
||||
zoomOnScroll
|
||||
<input
|
||||
id="zoomonscroll"
|
||||
type="checkbox"
|
||||
bind:checked={zoomOnScroll}
|
||||
class="svelte-flow__zoomonscroll"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="zoomonpinch">
|
||||
zoomOnPinch
|
||||
<input
|
||||
id="zoomonpinch"
|
||||
type="checkbox"
|
||||
bind:checked={zoomOnPinch}
|
||||
class="svelte-flow__zoomonpinch"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="panonscroll">
|
||||
panOnScroll
|
||||
<input
|
||||
id="panonscroll"
|
||||
type="checkbox"
|
||||
bind:checked={panOnScroll}
|
||||
class="svelte-flow__panonscroll"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="panonscrollmode">
|
||||
panOnScrollMode
|
||||
<select
|
||||
id="panonscrollmode"
|
||||
bind:value={panOnScrollMode}
|
||||
on:change={(event) => {
|
||||
panOnScrollMode = PanOnScrollMode.Free;
|
||||
}}
|
||||
class="svelte-flow__panonscrollmode"
|
||||
>
|
||||
<option value="free">free</option>
|
||||
<option value="horizontal">horizontal</option>
|
||||
<option value="vertical">vertical</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="zoomondbl">
|
||||
zoomOnDoubleClick
|
||||
<input
|
||||
id="zoomondbl"
|
||||
type="checkbox"
|
||||
bind:checked={zoomOnDoubleClick}
|
||||
class="svelte-flow__zoomondbl"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="panondrag">
|
||||
panOnDrag
|
||||
<input
|
||||
id="panondrag"
|
||||
type="checkbox"
|
||||
bind:checked={panOnDrag}
|
||||
class="svelte-flow__panondrag"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="capturezoompaneclick">
|
||||
capture onPaneClick
|
||||
<input
|
||||
id="capturezoompaneclick"
|
||||
type="checkbox"
|
||||
bind:checked={captureZoomClick}
|
||||
class="svelte-flow__capturezoompaneclick"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="capturezoompanescroll">
|
||||
capture onPaneScroll
|
||||
<input
|
||||
id="capturezoompanescroll"
|
||||
type="checkbox"
|
||||
bind:checked={captureZoomScroll}
|
||||
class="svelte-flow__capturezoompanescroll"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="captureelementclick">
|
||||
capture onElementClick
|
||||
<input
|
||||
id="captureelementclick"
|
||||
type="checkbox"
|
||||
bind:checked={captureElementClick}
|
||||
class="svelte-flow__captureelementclick"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</Panel>
|
||||
</SvelteFlow>
|
||||
@@ -0,0 +1,169 @@
|
||||
<script lang="ts">
|
||||
import { writable } from 'svelte/store';
|
||||
import {
|
||||
SvelteFlow,
|
||||
Controls,
|
||||
Background,
|
||||
BackgroundVariant,
|
||||
MiniMap,
|
||||
Panel,
|
||||
SelectionMode,
|
||||
type NodeTypes,
|
||||
type EdgeTypes
|
||||
} from '@xyflow/svelte';
|
||||
|
||||
import CustomNode from './CustomNode.svelte';
|
||||
import CustomEdge from './CustomEdge.svelte';
|
||||
|
||||
import '@xyflow/svelte/dist/style.css';
|
||||
|
||||
const nodeTypes: NodeTypes = {
|
||||
custom: CustomNode
|
||||
};
|
||||
|
||||
const edgeTypes: EdgeTypes = {
|
||||
custom: CustomEdge
|
||||
};
|
||||
|
||||
const nodes = writable([
|
||||
{
|
||||
id: '1',
|
||||
type: 'input',
|
||||
data: { label: 'Input Node' },
|
||||
position: { x: 150, y: 5 }
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'default',
|
||||
data: { label: 'Node' },
|
||||
position: { x: 0, y: 150 },
|
||||
selectable: false
|
||||
},
|
||||
{
|
||||
id: 'A',
|
||||
type: 'default',
|
||||
data: { label: 'Styled with class' },
|
||||
class: 'custom-style',
|
||||
position: { x: 150, y: 150 }
|
||||
},
|
||||
{
|
||||
id: 'D',
|
||||
type: 'default',
|
||||
data: { label: 'Not draggable' },
|
||||
position: { x: 150, y: 200 },
|
||||
draggable: false
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
type: 'output',
|
||||
data: { label: 'Output Node' },
|
||||
position: { x: 300, y: 150 }
|
||||
},
|
||||
{
|
||||
id: 'B',
|
||||
type: 'default',
|
||||
data: { label: 'Styled with style' },
|
||||
style: 'border: 2px solid #ff5050;',
|
||||
position: { x: 450, y: 150 }
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
type: 'custom',
|
||||
data: { label: 'Custom Node' },
|
||||
position: { x: 150, y: 300 }
|
||||
}
|
||||
]);
|
||||
|
||||
const edges = writable([
|
||||
{
|
||||
id: '1-2',
|
||||
type: 'default',
|
||||
source: '1',
|
||||
target: '2',
|
||||
label: 'Edge Text'
|
||||
},
|
||||
{
|
||||
id: '1-3',
|
||||
type: 'smoothstep',
|
||||
source: '1',
|
||||
target: '3',
|
||||
selectable: false
|
||||
},
|
||||
{
|
||||
id: '2-4',
|
||||
type: 'custom',
|
||||
source: '2',
|
||||
target: '4',
|
||||
animated: true
|
||||
}
|
||||
]);
|
||||
|
||||
function updateNode() {
|
||||
nodes.update((nds) =>
|
||||
nds.map((n) => {
|
||||
if (n.id === '1') {
|
||||
return {
|
||||
...n,
|
||||
position: { x: n.position.x + 20, y: n.position.y }
|
||||
};
|
||||
}
|
||||
|
||||
return n;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
$: {
|
||||
console.log('nodes changed', $nodes);
|
||||
}
|
||||
</script>
|
||||
|
||||
<SvelteFlow
|
||||
{nodes}
|
||||
{edges}
|
||||
{nodeTypes}
|
||||
{edgeTypes}
|
||||
fitView
|
||||
minZoom={0.1}
|
||||
maxZoom={2.5}
|
||||
selectionMode={SelectionMode.Full}
|
||||
initialViewport={{ x: 100, y: 100, zoom: 2 }}
|
||||
snapGrid={[25, 25]}
|
||||
on:nodeclick={(event) => console.log('on node click', event)}
|
||||
on:nodemouseenter={(event) => console.log('on node enter', event)}
|
||||
on:nodemouseleave={(event) => console.log('on node leave', event)}
|
||||
on:edgeclick={(event) => console.log('edge click', event)}
|
||||
on:connectstart={(event) => console.log('on connect start', event)}
|
||||
on:connect={(event) => console.log('on connect', event)}
|
||||
on:connectend={(event) => console.log('on connect end', event)}
|
||||
on:paneclick={(event) => console.log('on pane click', event)}
|
||||
on:panecontextmenu={(event) => {
|
||||
event.preventDefault();
|
||||
console.log('on pane contextmenu', event);
|
||||
}}
|
||||
>
|
||||
<Controls />
|
||||
<Background variant={BackgroundVariant.Dots} />
|
||||
<MiniMap />
|
||||
<Panel position="top-right">
|
||||
<button on:click={updateNode}>update node pos</button>
|
||||
</Panel>
|
||||
</SvelteFlow>
|
||||
|
||||
<style>
|
||||
:global(.svelte-flow .custom-style) {
|
||||
background: #ff5050;
|
||||
color: white;
|
||||
}
|
||||
|
||||
:root {
|
||||
--background-color: #ffffdd;
|
||||
--background-pattern-color: #5050ff;
|
||||
|
||||
--minimap-background-color: #f5f6f7;
|
||||
--minimap-mask-color: rgb(255, 255, 240, 0.6);
|
||||
|
||||
--controls-button-background-color: #ddd;
|
||||
--controls-button-background-color-hover: #ccc;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,59 @@
|
||||
<script lang="ts">
|
||||
import {
|
||||
BaseEdge,
|
||||
EdgeLabelRenderer,
|
||||
useSvelteFlow,
|
||||
type EdgeProps,
|
||||
getBezierPath
|
||||
} from '@xyflow/svelte';
|
||||
|
||||
type $$Props = EdgeProps;
|
||||
|
||||
$: [path, labelX, labelY] = getBezierPath({
|
||||
sourceX: $$props.sourceX,
|
||||
sourceY: $$props.sourceY,
|
||||
targetX: $$props.targetX,
|
||||
targetY: $$props.targetY,
|
||||
sourcePosition: $$props.sourcePosition,
|
||||
targetPosition: $$props.targetPosition
|
||||
});
|
||||
|
||||
const svelteFlow = useSvelteFlow();
|
||||
|
||||
function onClick() {
|
||||
svelteFlow.edges.update((eds) => eds.filter((e) => e.id !== $$props.id));
|
||||
}
|
||||
</script>
|
||||
|
||||
<BaseEdge {path} {labelX} {labelY} {...$$props} />
|
||||
|
||||
<EdgeLabelRenderer>
|
||||
<button
|
||||
style:transform={`translate(-50%,-50%) translate(${labelX}px,${labelY}px)`}
|
||||
class="edge-button"
|
||||
on:click={onClick}
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
</EdgeLabelRenderer>
|
||||
|
||||
<style>
|
||||
.edge-button {
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
border: none;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 8px;
|
||||
pointer-events: all;
|
||||
cursor: pointer;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.edge-button:hover {
|
||||
box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,27 @@
|
||||
<script lang="ts">
|
||||
import { Handle, Position, type NodeProps } from '@xyflow/svelte';
|
||||
|
||||
type $$Props = NodeProps;
|
||||
|
||||
export let data: { label: string } = { label: 'Node' };
|
||||
export let xPos: number = 0;
|
||||
export let yPos: number = 0;
|
||||
</script>
|
||||
|
||||
<div class="custom">
|
||||
<div>{data.label}</div>
|
||||
<div>{~~xPos}, {~~yPos}</div>
|
||||
|
||||
<Handle type="target" position={Position.Top} />
|
||||
|
||||
<Handle type="source" position={Position.Bottom} style="left: 10%;" id="a" />
|
||||
<Handle type="source" position={Position.Bottom} id="b" />
|
||||
<Handle type="source" position={Position.Bottom} style="left: 90%;" id="c" />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.custom {
|
||||
background: #ffcc00;
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,57 @@
|
||||
<script lang="ts">
|
||||
import { writable } from 'svelte/store';
|
||||
import {
|
||||
SvelteFlow,
|
||||
Controls,
|
||||
Background,
|
||||
BackgroundVariant,
|
||||
MiniMap,
|
||||
type Node,
|
||||
type Edge
|
||||
} from '@xyflow/svelte';
|
||||
|
||||
import '@xyflow/svelte/dist/style.css';
|
||||
|
||||
const yNodes = 25;
|
||||
const xNodes = 25;
|
||||
|
||||
const nodeItems: Node[] = [];
|
||||
const edgeItems: Edge[] = [];
|
||||
|
||||
let source = null;
|
||||
|
||||
for (let y = 0; y < yNodes; y++) {
|
||||
for (let x = 0; x < xNodes; x++) {
|
||||
const position = { x: x * 100, y: y * 50 };
|
||||
const id = `${x}-${y}`;
|
||||
const data = { label: `Node ${id}` };
|
||||
const node = {
|
||||
id,
|
||||
data,
|
||||
position,
|
||||
type: 'default'
|
||||
};
|
||||
nodeItems.push(node);
|
||||
|
||||
if (source) {
|
||||
const edge = {
|
||||
id: `${source.id}-${id}`,
|
||||
source: source.id,
|
||||
target: id
|
||||
};
|
||||
edgeItems.push(edge);
|
||||
}
|
||||
|
||||
source = node;
|
||||
}
|
||||
}
|
||||
|
||||
const nodes = writable(nodeItems);
|
||||
const edges = writable(edgeItems);
|
||||
</script>
|
||||
|
||||
<SvelteFlow {nodes} {edges} fitView minZoom={0.2}>
|
||||
<Controls />
|
||||
<Background variant={BackgroundVariant.Dots} />
|
||||
<MiniMap />
|
||||
</SvelteFlow>
|
||||
@@ -0,0 +1,134 @@
|
||||
<script lang="ts">
|
||||
import { writable } from 'svelte/store';
|
||||
import {
|
||||
SvelteFlow,
|
||||
Controls,
|
||||
Background,
|
||||
BackgroundVariant,
|
||||
MiniMap,
|
||||
type NodeTypes,
|
||||
type Node
|
||||
} from '@xyflow/svelte';
|
||||
|
||||
import '@xyflow/svelte/dist/style.css';
|
||||
|
||||
import DebugNode from './DebugNode.svelte';
|
||||
|
||||
const nodeTypes: NodeTypes = {
|
||||
default: DebugNode
|
||||
};
|
||||
|
||||
const nodes = writable<Node[]>([
|
||||
{
|
||||
id: '1',
|
||||
type: 'input',
|
||||
data: { label: 'Node 1' },
|
||||
position: { x: 250, y: 5 },
|
||||
origin: [0.5, 0.5]
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
data: { label: 'Node 4' },
|
||||
position: { x: 100, y: 200 },
|
||||
style: 'width:500px; height:300px;'
|
||||
},
|
||||
{
|
||||
id: '4a',
|
||||
data: { label: 'Node 4a' },
|
||||
position: { x: 15, y: 15 },
|
||||
parentNode: '4',
|
||||
extent: [
|
||||
[0, 0],
|
||||
[100, 100]
|
||||
]
|
||||
},
|
||||
{
|
||||
id: '4b',
|
||||
data: { label: 'Node 4b' },
|
||||
position: { x: 100, y: 60 },
|
||||
style: 'width: 300px; height: 200px;',
|
||||
parentNode: '4'
|
||||
},
|
||||
{
|
||||
id: '4b1',
|
||||
data: { label: 'Node 4b1' },
|
||||
position: { x: 40, y: 20 },
|
||||
parentNode: '4b'
|
||||
},
|
||||
{
|
||||
id: '4b2',
|
||||
data: { label: 'Node 4b2' },
|
||||
position: { x: 20, y: 100 },
|
||||
parentNode: '4b'
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
type: 'group',
|
||||
data: { label: 'Node 5' },
|
||||
position: { x: 650, y: 250 },
|
||||
style: 'width: 400px; height: 150px',
|
||||
zIndex: 1000
|
||||
},
|
||||
{
|
||||
id: '5a',
|
||||
data: { label: 'Node 5a' },
|
||||
position: { x: 0, y: 0 },
|
||||
parentNode: '5',
|
||||
extent: 'parent'
|
||||
},
|
||||
{
|
||||
id: '5b',
|
||||
data: { label: 'Node 5b' },
|
||||
position: { x: 225, y: 50 },
|
||||
parentNode: '5',
|
||||
expandParent: true
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
data: { label: 'Node 2' },
|
||||
position: { x: 100, y: 100 }
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
data: { label: 'Node 3' },
|
||||
position: { x: 400, y: 100 }
|
||||
}
|
||||
]);
|
||||
|
||||
const edges = writable([
|
||||
{
|
||||
id: 'e1-2',
|
||||
source: '1',
|
||||
target: '2'
|
||||
// markerEnd: {
|
||||
// type: MarkerType.Arrow,
|
||||
// strokeWidth: 2,
|
||||
// width: 15,
|
||||
// height: 15,
|
||||
// color: '#f00',
|
||||
// },
|
||||
},
|
||||
{ id: 'e1-3', source: '1', target: '3' },
|
||||
{ id: 'e3-4', source: '3', target: '4' },
|
||||
{ id: 'e3-4b', source: '3', target: '4b', zIndex: 100 },
|
||||
{ id: 'e4a-4b1', source: '4a', target: '4b1' },
|
||||
{ id: 'e4a-4b2', source: '4a', target: '4b2', zIndex: 100 },
|
||||
{ id: 'e4b1-4b2', source: '4b1', target: '4b2' }
|
||||
]);
|
||||
|
||||
$: {
|
||||
console.log($nodes);
|
||||
}
|
||||
</script>
|
||||
|
||||
<SvelteFlow {nodes} {edges} {nodeTypes} fitView minZoom={0.1} maxZoom={2.5}>
|
||||
<Controls />
|
||||
<Background variant={BackgroundVariant.Dots} />
|
||||
<MiniMap />
|
||||
</SvelteFlow>
|
||||
|
||||
<style>
|
||||
:global(.svelte-flow .svelte-flow__node.parent) {
|
||||
background-color: rgba(220, 220, 255, 0.4);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,24 @@
|
||||
<script lang="ts">
|
||||
import { Handle, Position, type NodeProps } from '@xyflow/svelte';
|
||||
|
||||
type $$Props = NodeProps;
|
||||
|
||||
export let id: string;
|
||||
export let xPos: number = 0;
|
||||
export let yPos: number = 0;
|
||||
export let zIndex: number = 0;
|
||||
</script>
|
||||
|
||||
<Handle type="target" position={Position.Top} />
|
||||
<div>{id}</div>
|
||||
<div>
|
||||
x:{Math.round(xPos || 0)} y:{Math.round(yPos || 0)} z:{zIndex}
|
||||
</div>
|
||||
<Handle type="source" position={Position.Bottom} />
|
||||
|
||||
<style>
|
||||
.custom {
|
||||
background: #ffcc00;
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { SvelteFlowProvider } from '@xyflow/svelte';
|
||||
|
||||
import Flow from './Flow.svelte';
|
||||
</script>
|
||||
|
||||
<SvelteFlowProvider>
|
||||
<Flow />
|
||||
</SvelteFlowProvider>
|
||||
@@ -0,0 +1,61 @@
|
||||
<script lang="ts">
|
||||
import { writable } from 'svelte/store';
|
||||
import { SvelteFlow, Controls, Background, BackgroundVariant, MiniMap } from '@xyflow/svelte';
|
||||
|
||||
import Sidebar from './Sidebar.svelte';
|
||||
|
||||
import '@xyflow/svelte/dist/style.css';
|
||||
|
||||
const nodes = writable([
|
||||
{
|
||||
id: '1',
|
||||
type: 'input',
|
||||
data: { label: 'Input Node' },
|
||||
position: { x: 150, y: 5 }
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'default',
|
||||
data: { label: 'Node' },
|
||||
position: { x: 0, y: 150 }
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
type: 'output',
|
||||
data: { label: 'Output Node' },
|
||||
position: { x: 300, y: 150 }
|
||||
}
|
||||
]);
|
||||
|
||||
const edges = writable([
|
||||
{
|
||||
id: '1-2',
|
||||
type: 'default',
|
||||
source: '1',
|
||||
target: '2',
|
||||
label: 'Edge Text'
|
||||
},
|
||||
{
|
||||
id: '1-3',
|
||||
type: 'smoothstep',
|
||||
source: '1',
|
||||
target: '3'
|
||||
}
|
||||
]);
|
||||
</script>
|
||||
|
||||
<main>
|
||||
<SvelteFlow {nodes} {edges} fitView>
|
||||
<Controls />
|
||||
<Background variant={BackgroundVariant.Dots} />
|
||||
<MiniMap />
|
||||
</SvelteFlow>
|
||||
<Sidebar />
|
||||
</main>
|
||||
|
||||
<style>
|
||||
main {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,56 @@
|
||||
<script lang="ts">
|
||||
import { useSvelteFlow } from '@xyflow/svelte';
|
||||
|
||||
const {
|
||||
zoomIn,
|
||||
zoomOut,
|
||||
setZoom,
|
||||
fitView,
|
||||
setCenter,
|
||||
setViewport,
|
||||
getViewport,
|
||||
viewport,
|
||||
nodes
|
||||
} = useSvelteFlow();
|
||||
</script>
|
||||
|
||||
<aside>
|
||||
<div class="label">Functions:</div>
|
||||
<button on:click={() => zoomIn()}>zoom in</button>
|
||||
<button on:click={() => zoomOut({ duration: 1000 })}>zoom out transition</button>
|
||||
<button on:click={() => setZoom(2)}>set zoom</button>
|
||||
<button on:click={() => fitView()}>fitView</button>
|
||||
<button on:click={() => setCenter(0, 0)}>setCenter 0, 0</button>
|
||||
<button on:click={() => setViewport({ x: 100, y: 100, zoom: 2 })}>setViewport</button>
|
||||
<button on:click={() => console.log(getViewport())}>getViewport</button>
|
||||
|
||||
<div class="label">Nodes:</div>
|
||||
{#each $nodes as node (node.id)}
|
||||
<div>id: {node.id} | x: {node.position.x.toFixed(1)} y: {node.position.y.toFixed(1)}</div>
|
||||
{/each}
|
||||
|
||||
<div class="label">Viewport:</div>
|
||||
<div>
|
||||
x: {$viewport.x.toFixed(1)} y: {$viewport.y.toFixed(1)} zoom: {$viewport.zoom.toFixed(1)}
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<style>
|
||||
.label {
|
||||
font-weight: 700;
|
||||
margin: 0.5rem 0 0.25rem 0;
|
||||
}
|
||||
|
||||
aside {
|
||||
width: 20vw;
|
||||
background: #f4f4f4;
|
||||
padding: 0.4rem 0.8rem;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
button {
|
||||
display: block;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,40 @@
|
||||
<script lang="ts">
|
||||
import { writable } from 'svelte/store';
|
||||
import {
|
||||
SvelteFlow,
|
||||
Controls,
|
||||
Background,
|
||||
BackgroundVariant,
|
||||
type IsValidConnection,
|
||||
Position
|
||||
} from '@xyflow/svelte';
|
||||
|
||||
import '@xyflow/svelte/dist/style.css';
|
||||
import './style.css';
|
||||
|
||||
const nodeDefaults = {
|
||||
sourcePosition: Position.Right,
|
||||
targetPosition: Position.Left
|
||||
};
|
||||
|
||||
const nodes = writable([
|
||||
{
|
||||
id: '0',
|
||||
position: { x: 0, y: 150 },
|
||||
data: { label: 'only connectable with B' },
|
||||
...nodeDefaults
|
||||
},
|
||||
{ id: 'A', position: { x: 250, y: 0 }, data: { label: 'A' }, ...nodeDefaults },
|
||||
{ id: 'B', position: { x: 250, y: 150 }, data: { label: 'B' }, ...nodeDefaults },
|
||||
{ id: 'C', position: { x: 250, y: 300 }, data: { label: 'C' }, ...nodeDefaults }
|
||||
]);
|
||||
|
||||
const edges = writable([]);
|
||||
|
||||
const isValidConnection: IsValidConnection = (connection) => connection.target === 'B';
|
||||
</script>
|
||||
|
||||
<SvelteFlow {nodes} {edges} fitView minZoom={0.1} maxZoom={2.5} {isValidConnection}>
|
||||
<Controls />
|
||||
<Background variant={BackgroundVariant.Dots} />
|
||||
</SvelteFlow>
|
||||
@@ -0,0 +1,7 @@
|
||||
.svelte-flow__handle.connecting {
|
||||
background: #ff6060;
|
||||
}
|
||||
|
||||
.svelte-flow__handle.valid {
|
||||
background: #55dd99;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/* 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';
|
||||
|
||||
.svelte-flow__edge-label {
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/* this gets exported as style.css and can be used for the default theming */
|
||||
@import '../../../system/src/styles/init.css';
|
||||
@import '../../../system/src/styles/style.css';
|
||||
|
||||
.svelte-flow__edge-label {
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
}
|
||||
Reference in New Issue
Block a user