refactor(svelte): use custom stores for nodes and edges

This commit is contained in:
moklick
2023-03-07 17:16:33 +01:00
parent 33b9a801fe
commit 1153486ae2
9 changed files with 163 additions and 142 deletions
@@ -87,7 +87,6 @@ export default function drag(
const dragHandler = d3Drag()
.on('start', (event: UseDragEvent) => {
const pointerPos = getPointerPosition(event);
console.log(pointerPos);
lastPos = pointerPos;
dragItems = getDragItems(get(nodes), pointerPos, nodeId);
})
@@ -1,5 +1,5 @@
<script lang="ts">
import { setContext, onMount, createEventDispatcher } from 'svelte';
import { setContext, onMount } from 'svelte';
import cc from 'classcat';
import { key, createStore } from '$lib/store';
@@ -18,8 +18,8 @@
type $$Events = SvelteFlowEvents;
export let id: $$Props['id'] = '1';
export let nodes: $$Props['nodes'] = [];
export let edges: $$Props['edges'] = [];
export let nodes: $$Props['nodes'];
export let edges: $$Props['edges'];
export let fitView: $$Props['fitView'] = undefined;
export let minZoom: $$Props['minZoom'] = undefined;
export let maxZoom: $$Props['maxZoom'] = undefined;
@@ -28,7 +28,6 @@
export let edgeTypes: $$Props['edgeTypes'] = undefined;
export let selectionKey: $$Props['selectionKey'] = undefined;
export let deleteKey: $$Props['deleteKey'] = undefined;
export let defaultEdgeOptions: $$Props['defaultEdgeOptions'] = undefined;
export let connectionRadius: $$Props['connectionRadius'] = undefined;
export let connectionLineType: $$Props['connectionLineType'] = undefined
export let style: $$Props['style'] = undefined;
@@ -38,6 +37,8 @@
let domNode: HTMLDivElement;
const store = createStore({
nodes,
edges,
fitView,
nodeTypes
});
@@ -51,15 +52,6 @@
store.width.set(width);
store.height.set(height);
store.domNode.set(domNode);
// @todo: is this a svelte way for two way binding?
store.nodes.subscribe((ns) => {
nodes = ns;
});
store.edges.subscribe((es) => {
edges = es;
});
});
$: {
@@ -67,7 +59,6 @@
id,
connectionLineType,
connectionRadius,
defaultEdgeOptions
};
Object.keys(updatableProps).forEach(prop => {
@@ -79,14 +70,6 @@
})
}
$: {
store.setNodes(nodes);
}
$: {
store.setEdges(edges);
}
$: {
if (nodeTypes !== undefined) {
store.setNodeTypes(nodeTypes);
@@ -14,10 +14,12 @@ import type {
EdgeTypes,
DefaultEdgeOptions
} from '$lib/types';
import type { Writable } from 'svelte/store';
import type { createNodes } from '$lib/utils';
export type SvelteFlowProps = {
nodes: Node[];
edges: Edge[];
nodes: ReturnType<typeof createNodes>;
edges: Writable<Edge[]>;
id?: string;
nodeTypes?: NodeTypes;
+12 -32
View File
@@ -30,10 +30,13 @@ import {
initialStoreState
} from './initial-store';
import type { SvelteFlowStore } from './types';
import type { SvelteFlowProps } from '$lib/container/SvelteFlow/types';
export const key = Symbol();
type CreateStoreProps = {
nodes: SvelteFlowProps['nodes'];
edges: SvelteFlowProps['edges'];
fitView?: boolean;
nodeOrigin?: NodeOrigin;
transform?: Transform;
@@ -42,9 +45,15 @@ type CreateStoreProps = {
id?: string;
};
export function createStore({ fitView: fitViewOnInit = false }: CreateStoreProps): SvelteFlowStore {
export function createStore({
fitView: fitViewOnInit = false,
nodes,
edges
}: CreateStoreProps): SvelteFlowStore {
const store = {
...initialStoreState
...initialStoreState,
nodes,
edges
};
let fitViewOnInitDone = false;
@@ -63,36 +72,9 @@ export function createStore({ fitView: fitViewOnInit = false }: CreateStoreProps
});
}
function setEdges(edges: Edge[]) {
const defaultEdgeOptions = get(store.defaultEdgeOptions);
const nextEdges = defaultEdgeOptions
? edges.map((e) => ({ ...defaultEdgeOptions, ...e }))
: edges;
store.edges.set(nextEdges);
}
function addEdge(edgeParams: Edge | Connection) {
const edges = get(store.edges);
setEdges(addEdgeUtil(edgeParams, edges));
}
function setNodes(nodes: Node[]) {
const defaultNodeOptions = get(store.defaultNodeOptions) || {};
store.nodes.update((currentNodes) => {
const nextNodes = nodes.map((n) => {
const currentNode = currentNodes.find((cn) => cn.id === n.id) || {};
return {
...defaultNodeOptions,
...currentNode,
...n,
positionAbsolute: n.position
};
});
return nextNodes;
});
store.edges.set(addEdgeUtil(edgeParams, edges));
}
function updateNodePositions(nodeDragItems: NodeDragItem[], dragging = false) {
@@ -332,8 +314,6 @@ export function createStore({ fitView: fitViewOnInit = false }: CreateStoreProps
connectionPath: getConnectionPath(store),
// actions
setNodes,
setEdges,
setNodeTypes,
setEdgeTypes,
addEdge,
+1 -14
View File
@@ -16,16 +16,7 @@ import OutputNode from '$lib/components/nodes/OutputNode.svelte';
import BezierEdge from '$lib/components/edges/BezierEdge.svelte';
import StraightEdge from '$lib/components/edges/StraightEdge.svelte';
import SmoothStepEdge from '$lib/components/edges/SmoothStepEdge.svelte';
import type {
Node,
Edge,
ConnectionData,
NodeTypes,
EdgeTypes,
EdgeLayouted,
DefaultEdgeOptions,
DefaultNodeOptions
} from '$lib/types';
import type { ConnectionData, NodeTypes, EdgeTypes, EdgeLayouted } from '$lib/types';
export const initConnectionData = {
nodeId: null,
@@ -49,8 +40,6 @@ export const initialEdgeTypes = {
export const initialStoreState = {
id: writable<string | null>(null),
nodes: writable<Node[]>([]),
edges: writable<Edge[]>([]),
edgesLayouted: readable<EdgeLayouted[]>([]),
height: writable<number>(500),
width: writable<number>(500),
@@ -61,8 +50,6 @@ export const initialStoreState = {
zoom: null,
selection: null
}),
defaultNodeOptions: writable<DefaultNodeOptions | null>(null),
defaultEdgeOptions: writable<DefaultEdgeOptions | null>(null),
dragging: writable<boolean>(false),
selectionRect: writable<SelectionRect | null>(null),
selectionKeyPressed: writable<boolean>(false),
+5 -3
View File
@@ -8,10 +8,9 @@ import type {
import type { initialStoreState } from './initial-store';
import type { Node, Edge, ConnectionData, NodeTypes, EdgeTypes } from '$lib/types';
import type { Writable } from 'svelte/store';
export type SvelteFlowStoreActions = {
setNodes: (nodes: Node[]) => void;
setEdges: (edges: Edge[]) => void;
setNodeTypes: (nodeTypes: NodeTypes) => void;
setEdgeTypes: (edgeTypes: EdgeTypes) => void;
addEdge: (edge: Edge | Connection) => void;
@@ -33,6 +32,9 @@ export type SvelteFlowStoreActions = {
cancelConnection: () => void;
};
export type SvelteFlowStoreState = typeof initialStoreState;
export type SvelteFlowStoreState = typeof initialStoreState & {
nodes: Writable<Node[]>;
edges: Writable<Edge[]>;
};
export type SvelteFlowStore = SvelteFlowStoreState & SvelteFlowStoreActions;
+66 -1
View File
@@ -9,7 +9,8 @@ import {
getConnectedEdgesBase,
getDimensions
} from '@reactflow/utils';
import type { Edge, Node } from '$lib/types';
import type { DefaultEdgeOptions, DefaultNodeOptions, Edge, Node } from '$lib/types';
import { writable, type Writable } from 'svelte/store';
export const isNode = isNodeBase<Node, Edge>;
export const isEdge = isEdgeBase<Node, Edge>;
@@ -45,3 +46,67 @@ export const getHandleBounds = (
};
});
};
export const createNodes = (
nodes: Node[],
defaultOptions?: DefaultNodeOptions
): Writable<Node[]> & { setDefaultOptions: (opts: DefaultNodeOptions) => void } => {
const { subscribe, set, update } = writable<Node[]>([]);
let value = nodes;
let defaults = defaultOptions || {};
const _set: typeof set = (nds: Node[]) => {
const nextNodes = defaults ? nds.map((node) => ({ ...defaults, ...node })) : nds;
// @todo calculate absolute position based on parent / child relation
const nextNodesLayouted = nextNodes.map((n) => ({ ...n, positionAbsolute: n.position }));
value = nextNodesLayouted;
set(value);
};
const _update: typeof update = (fn: (nds: Node[]) => Node[]) => _set(fn(value));
const setDefaultOptions = (options: DefaultNodeOptions) => {
defaults = options;
};
_set(value);
return {
subscribe,
set: _set,
update: _update,
setDefaultOptions
};
};
export const createEdges = (
edges: Edge[],
defaultOptions?: DefaultEdgeOptions
): Writable<Edge[]> & { setDefaultOptions: (opts: DefaultEdgeOptions) => void } => {
const { subscribe, set, update } = writable<Edge[]>([]);
let value = edges;
let defaults = defaultOptions || {};
const _set: typeof set = (eds: Edge[]) => {
const nextEdges = defaults ? eds.map((edge) => ({ ...defaults, ...edge })) : eds;
value = nextEdges;
set(value);
};
const _update: typeof update = (fn: (eds: Edge[]) => Edge[]) => _set(fn(value));
const setDefaultOptions = (options: DefaultEdgeOptions) => {
defaults = options;
};
_set(value);
return {
subscribe,
set: _set,
update: _update,
setDefaultOptions
};
};
+22 -13
View File
@@ -5,7 +5,9 @@
BackgroundVariant,
Minimap,
Panel,
type Node, type Edge, type NodeTypes
createNodes,
createEdges,
type NodeTypes
} from '../lib/index';
import CustomNode from '../customnodes/Custom.svelte';
@@ -47,7 +49,7 @@
// }
// }
let nodes: Node<{ label: string }>[] = [
let nodes = createNodes([
{
id: '1',
type: 'input',
@@ -93,9 +95,9 @@
data: { label: 'Custom Node' },
position: { x: 150, y: 300 }
}
];
]);
let edges: Edge[] = [
let edges = createEdges([
{
id: '1-2',
type: 'default',
@@ -114,28 +116,35 @@
type: 'default',
source: '2',
target: '4',
animated: true
}
];
], { animated: true });
function updateNode() {
nodes[0].position = { x: nodes[0].position.x + 20, y: nodes[0].position.y };
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)
// }
$: {
console.log('nodes changed', $nodes)
}
</script>
<SvelteFlow
bind:nodes
bind:edges
{nodes}
{edges}
{nodeTypes}
fitView
minZoom={0.1}
maxZoom={2.5}
initialViewport={{ x: 100, y: 100, zoom: 2 }}
defaultEdgeOptions={{ animated: true }}
on:node:click={(event) => console.log('on node click', event)}
on:node:mouseenter={(event) => console.log('on node enter', event)}
on:node:mouseleave={(event) => console.log('on node leave', event)}