cleaning up Svelte 4 leftovers
This commit is contained in:
@@ -124,16 +124,22 @@
|
||||
]);
|
||||
|
||||
function updateNode() {
|
||||
nodes[0].position.x += 20;
|
||||
// nodes = $nodes;
|
||||
// We might as well just use updateNode() here
|
||||
// this is just to show what is required to update a node
|
||||
const newNode = { ...nodes[0] };
|
||||
newNode.position.x += 20;
|
||||
nodes[0] = newNode;
|
||||
nodes = [...nodes];
|
||||
}
|
||||
|
||||
function updateEdge() {
|
||||
edges[0].type = edges[0].type === 'default' ? 'smoothstep' : 'default';
|
||||
// edges = $edges;
|
||||
// We might as well just use updateEdge() here
|
||||
// this is just to show what is required to update an edge
|
||||
const newEdge = { ...edges[0] };
|
||||
newEdge.type = newEdge.type === 'default' ? 'smoothstep' : 'default';
|
||||
edges[0] = newEdge;
|
||||
edges = [...edges];
|
||||
}
|
||||
|
||||
// $inspect(nodes);
|
||||
</script>
|
||||
|
||||
<SvelteFlow
|
||||
@@ -152,38 +158,38 @@
|
||||
initialViewport={{ x: 100, y: 100, zoom: 2 }}
|
||||
snapGrid={[25, 25]}
|
||||
oninit={() => console.log('on init')}
|
||||
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:edgemouseenter={(event) => console.log('edge enter', event)}
|
||||
on:edgemouseleave={(event) => console.log('edge leave', event)}
|
||||
onnodeclick={(event) => console.log('on node click', event)}
|
||||
onnodemouseenter={(event) => console.log('on node enter', event)}
|
||||
onnodemouseleave={(event) => console.log('on node leave', event)}
|
||||
onedgeclick={(event) => console.log('edge click', event)}
|
||||
onedgemouseenter={(event) => console.log('edge enter', event)}
|
||||
onedgemouseleave={(event) => console.log('edge leave', event)}
|
||||
onconnectstart={(event) => console.log('on connect start', event)}
|
||||
onconnect={(event) => console.log('on connect', event)}
|
||||
onconnectend={(event) => console.log('on connect end', event)}
|
||||
on:paneclick={(event) => console.log('on pane click', event)}
|
||||
on:panecontextmenu={(event) => {
|
||||
onpaneclick={(event) => console.log('on pane click', event)}
|
||||
onpanecontextmenu={(event) => {
|
||||
console.log('on pane contextmenu', event);
|
||||
}}
|
||||
on:nodedrag={(event) => {
|
||||
onnodedrag={(event) => {
|
||||
console.log('on node drag', event);
|
||||
}}
|
||||
on:nodedragstart={(event) => {
|
||||
onnodedragstart={(event) => {
|
||||
console.log('on node drag start', event);
|
||||
}}
|
||||
on:nodedragstop={(event) => {
|
||||
onnodedragstop={({ event }) => {
|
||||
console.log('on node drag stop', event);
|
||||
}}
|
||||
on:nodecontextmenu={(event) => {
|
||||
event.detail.event.preventDefault();
|
||||
onnodecontextmenu={({ event }) => {
|
||||
event.preventDefault();
|
||||
console.log('on node contextmenu', event);
|
||||
}}
|
||||
on:edgecontextmenu={({ detail: { event, edge } }) => {
|
||||
onedgecontextmenu={({ event, edge }) => {
|
||||
event.preventDefault();
|
||||
console.log('on edge contextmenu', edge);
|
||||
}}
|
||||
on:selectionclick={(event) => console.log('on selection click', event)}
|
||||
on:selectioncontextmenu={(event) => console.log('on selection contextmenu', event)}
|
||||
onselectionclick={(event) => console.log('on selection click', event)}
|
||||
onselectioncontextmenu={(event) => console.log('on selection contextmenu', event)}
|
||||
onbeforedelete={async ({ nodes, edges }) => {
|
||||
console.log('on before delete', nodes, edges);
|
||||
const deleteElements = confirm('Are you sure you want to delete the selected elements?');
|
||||
@@ -199,8 +205,7 @@
|
||||
{#snippet before()}
|
||||
<ControlButton>xy</ControlButton>
|
||||
{/snippet}
|
||||
<ControlButton aria-label="log" on:click={() => console.log('control button')}
|
||||
>log</ControlButton
|
||||
<ControlButton aria-label="log" onclick={() => console.log('control button')}>log</ControlButton
|
||||
>
|
||||
</Controls>
|
||||
<Background variant={BackgroundVariant.Dots} />
|
||||
|
||||
@@ -5,7 +5,7 @@ import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||
const config = {
|
||||
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
|
||||
// for more information about preprocessors
|
||||
preprocess: vitePreprocess(),
|
||||
preprocess: vitePreprocess({ script: true }),
|
||||
compilerOptions: {
|
||||
runes: true
|
||||
},
|
||||
|
||||
@@ -8,7 +8,10 @@
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"strict": true
|
||||
"strict": true,
|
||||
"target": "ES2022",
|
||||
"verbatimModuleSyntax": true,
|
||||
"isolatedModules": true
|
||||
}
|
||||
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
|
||||
//
|
||||
|
||||
@@ -83,13 +83,13 @@
|
||||
"typescript": "^5.5.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"svelte": "^3.0.0 || ^4.0.0 || ^5.0.0"
|
||||
"svelte": "^5.0.0"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"typesVersions": {
|
||||
">4.0": {
|
||||
">5.0": {
|
||||
"index": [
|
||||
"./dist/lib/index.d.ts"
|
||||
]
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
if (event.target !== container) {
|
||||
return;
|
||||
}
|
||||
|
||||
handler?.(event);
|
||||
};
|
||||
}
|
||||
@@ -17,7 +16,7 @@
|
||||
const isSelected = ids.includes(item.id);
|
||||
|
||||
if (item.selected !== isSelected) {
|
||||
item.selected = isSelected;
|
||||
return { ...item, selected: isSelected };
|
||||
}
|
||||
|
||||
return item;
|
||||
@@ -33,7 +32,6 @@
|
||||
getConnectedEdges
|
||||
} from '@xyflow/system';
|
||||
|
||||
import { useStore } from '$lib/store';
|
||||
import type { Node, Edge, InternalNode } from '$lib/types';
|
||||
import type { PaneProps } from './types';
|
||||
let {
|
||||
@@ -45,8 +43,6 @@
|
||||
children
|
||||
}: PaneProps = $props();
|
||||
|
||||
// const { nodes, edges } = store;
|
||||
|
||||
// svelte-ignore non_reactive_update
|
||||
let container: HTMLDivElement;
|
||||
let containerBounds: DOMRect | null = null;
|
||||
@@ -143,14 +139,14 @@
|
||||
prevSelectedNodeIds.length !== selectedNodeIds.length ||
|
||||
selectedNodeIds.some((id) => !prevSelectedNodeIds.includes(id))
|
||||
) {
|
||||
// store.nodes.update((nodes) => nodes.map(toggleSelected(selectedNodeIds)));
|
||||
store.nodes = store.nodes.map(toggleSelected(selectedNodeIds));
|
||||
}
|
||||
|
||||
if (
|
||||
prevSelectedEdgeIds.length !== selectedEdgeIds.length ||
|
||||
selectedEdgeIds.some((id) => !prevSelectedEdgeIds.includes(id))
|
||||
) {
|
||||
// store.edges.update((edges) => edges.map(toggleSelected(selectedEdgeIds)));
|
||||
store.edges = store.edges.map(toggleSelected(selectedEdgeIds));
|
||||
}
|
||||
|
||||
store.selectionRectMode = 'user';
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
<!-- TODO: why is this neccessary for types to work?? -->
|
||||
<svelte:options runes={true} />
|
||||
|
||||
<script lang="ts">
|
||||
import { getContext, setContext, onDestroy } from 'svelte';
|
||||
import cc from 'classcat';
|
||||
@@ -19,7 +16,7 @@
|
||||
import { key, createStore } from '$lib/store';
|
||||
import type { SvelteFlowProps } from './types';
|
||||
import { useColorModeClass } from '$lib/hooks/useColorModeClass';
|
||||
import { type ProviderContext, type ContainerSignals, type StoreContext } from '$lib/store/types';
|
||||
import { type ProviderContext, type StoreContext } from '$lib/store/types';
|
||||
|
||||
let {
|
||||
style,
|
||||
@@ -62,7 +59,6 @@
|
||||
panOnScroll = false,
|
||||
panOnDrag = true,
|
||||
selectionOnDrag = true,
|
||||
defaultEdgeOptions,
|
||||
connectionLineContainerStyle = '',
|
||||
connectionLineStyle = '',
|
||||
attributionPosition,
|
||||
@@ -101,11 +97,13 @@
|
||||
}
|
||||
});
|
||||
|
||||
// Set store for provider context
|
||||
const providerContext = getContext<ProviderContext>(key);
|
||||
if (providerContext) {
|
||||
providerContext.setStore(store);
|
||||
}
|
||||
|
||||
// Overwrite store context to give children direct access
|
||||
setContext(key, {
|
||||
provider: false,
|
||||
getStore() {
|
||||
|
||||
@@ -31,7 +31,8 @@ import type {
|
||||
OnDelete,
|
||||
OnEdgeCreate,
|
||||
OnBeforeDelete,
|
||||
IsValidConnection
|
||||
IsValidConnection,
|
||||
DefaultNodeOptions
|
||||
} from '$lib/types';
|
||||
import type { Writable } from 'svelte/store';
|
||||
import type { Snippet } from 'svelte';
|
||||
@@ -301,6 +302,22 @@ export type SvelteFlowProps = NodeEvents &
|
||||
* }
|
||||
*/
|
||||
defaultEdgeOptions?: DefaultEdgeOptions;
|
||||
/** Defaults to be applied to all new nodes that are added to the flow.
|
||||
*
|
||||
* Properties on a new nodes will override these defaults if they exist.
|
||||
* @example
|
||||
* const defaultNodeOptions = {
|
||||
* type: 'customNodeType',
|
||||
* position: {x: 0, y: 0}
|
||||
* data: { label: 'custom label' },
|
||||
* hidden: false,
|
||||
* deletable: true,
|
||||
* selected: false,
|
||||
* focusable: true,
|
||||
* zIndex: 12,
|
||||
* }
|
||||
*/
|
||||
defaultNodeOptions?: DefaultNodeOptions;
|
||||
/** Sets a fixed width for the flow */
|
||||
width?: number;
|
||||
/** Sets a fixed height for the flow */
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
import { getContext } from 'svelte';
|
||||
import type { StoreContext, SvelteFlowStore } from './types';
|
||||
|
||||
import { key } from './';
|
||||
|
||||
export function useStore(): SvelteFlowStore {
|
||||
const storeContext = getContext<StoreContext>(key);
|
||||
|
||||
if (!storeContext) {
|
||||
throw new Error(
|
||||
'In order to use useStore you need to wrap your component in a <SvelteFlowProvider />'
|
||||
);
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
if (storeContext.provider && !$effect.tracking()) {
|
||||
console.warn(
|
||||
'Use $derived(useStore()), when not calling inside a child of the <SvelteFlow /> component.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return storeContext.getStore();
|
||||
}
|
||||
@@ -21,14 +21,12 @@ import {
|
||||
import type { EdgeTypes, NodeTypes, Node, Edge, FitViewOptions } from '$lib/types';
|
||||
import { initialEdgeTypes, initialNodeTypes, getInitialStore } from './initial-store.svelte';
|
||||
import { type StoreSignals, type SvelteFlowStore, type SvelteFlowStoreActions } from './types';
|
||||
import { syncNodeStores, syncEdgeStores } from './utils';
|
||||
import drag from '$lib/actions/drag';
|
||||
// import { getVisibleEdges } from './visible-edges';
|
||||
// import { getVisibleNodes } from './visible-nodes';
|
||||
|
||||
export const key = Symbol();
|
||||
|
||||
export { useStore } from './hook.svelte';
|
||||
export { useStore } from '../hooks/useStore';
|
||||
|
||||
export function createStore(signals: StoreSignals): SvelteFlowStore {
|
||||
const store = getInitialStore(signals);
|
||||
@@ -82,8 +80,10 @@ export function createStore(signals: StoreSignals): SvelteFlowStore {
|
||||
...store.fitViewOptions,
|
||||
nodes: store.fitViewOptions?.nodes
|
||||
});
|
||||
if (fitViewOnInitDone) {
|
||||
store.fitViewOnInitDone = fitViewOnInitDone;
|
||||
}
|
||||
}
|
||||
|
||||
const newNodes = new Map<string, Node>();
|
||||
for (const change of changes) {
|
||||
@@ -115,9 +115,7 @@ export function createStore(signals: StoreSignals): SvelteFlowStore {
|
||||
newNodes.set(change.id, node);
|
||||
}
|
||||
|
||||
// store.nodes.update((nds) => nds);
|
||||
store.nodes = store.nodes.map((node) => newNodes.get(node.id) ?? node);
|
||||
// signals.updateNodes((node) => newNodes.get(node.id) ?? node);
|
||||
|
||||
if (!store.nodesInitialized) {
|
||||
store.nodesInitialized = true;
|
||||
@@ -244,24 +242,23 @@ export function createStore(signals: StoreSignals): SvelteFlowStore {
|
||||
const isMultiSelection = store.multiselectionKeyPressed;
|
||||
|
||||
// store.nodes.update((ns) =>
|
||||
store.nodes.forEach((node) => {
|
||||
store.nodes = store.nodes.map((node) => {
|
||||
const nodeWillBeSelected = ids.includes(node.id);
|
||||
const selected = isMultiSelection ? node.selected || nodeWillBeSelected : nodeWillBeSelected;
|
||||
|
||||
if (node.selected !== selected) {
|
||||
// we need to mutate the node here in order to have the correct selected state in the drag handler
|
||||
node.selected = selected;
|
||||
return { ...node };
|
||||
}
|
||||
|
||||
// return node;
|
||||
return node;
|
||||
});
|
||||
// );
|
||||
|
||||
if (!isMultiSelection) {
|
||||
// store.edges.forEach((es) =>
|
||||
store.edges.forEach((edge) => {
|
||||
edge.selected = false;
|
||||
// return edge;
|
||||
store.edges = store.edges.map((edge) => {
|
||||
return edge.selected ? { ...edge, selected: false } : edge;
|
||||
});
|
||||
// );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,7 +316,6 @@ export function createStore(signals: StoreSignals): SvelteFlowStore {
|
||||
});
|
||||
}
|
||||
|
||||
// const _connection = writable<ConnectionState>(initialConnection);
|
||||
const updateConnection: UpdateConnection = (newConnection: ConnectionState) => {
|
||||
store.rawConnection = { ...newConnection };
|
||||
};
|
||||
@@ -338,9 +334,6 @@ export function createStore(signals: StoreSignals): SvelteFlowStore {
|
||||
}
|
||||
|
||||
const storeWithActions = Object.assign(store, {
|
||||
// syncNodeStores: (nodes) => syncNodeStores(store.nodes, nodes),
|
||||
// syncEdgeStores: (edges) => syncEdgeStores(store.edges, edges),
|
||||
// syncViewport: (viewport) => syncViewportStores(store.panZoom, store.viewport, viewport),
|
||||
setNodeTypes,
|
||||
setEdgeTypes,
|
||||
addEdge,
|
||||
|
||||
@@ -49,7 +49,9 @@ import type {
|
||||
OnDelete,
|
||||
OnEdgeCreate,
|
||||
OnBeforeDelete,
|
||||
IsValidConnection
|
||||
IsValidConnection,
|
||||
Edge,
|
||||
Node
|
||||
} from '$lib/types';
|
||||
|
||||
import type { StoreSignals } from './types';
|
||||
@@ -69,6 +71,8 @@ export const initialEdgeTypes = {
|
||||
};
|
||||
|
||||
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.
|
||||
class SvelteFlowStore {
|
||||
get nodes() {
|
||||
return signals.nodes;
|
||||
@@ -86,6 +90,7 @@ export const getInitialStore = (signals: StoreSignals) => {
|
||||
parentLookup: ParentLookup = new Map();
|
||||
connectionLookup: ConnectionLookup = new Map();
|
||||
edgeLookup: EdgeLookup = new Map();
|
||||
|
||||
adoptNodes: true = $derived.by(() => {
|
||||
adoptUserNodes(signals.nodes, this.nodeLookup, this.parentLookup, {
|
||||
nodeExtent: this.nodeExtent,
|
||||
@@ -100,7 +105,7 @@ export const getInitialStore = (signals: StoreSignals) => {
|
||||
return true;
|
||||
});
|
||||
|
||||
domNode: HTMLDivElement | null = $derived(signals.domNode ?? signals.props.domNode ?? null);
|
||||
domNode: HTMLDivElement | null = $derived(signals.domNode ?? signals.domNode ?? null);
|
||||
width: number = $derived(signals.width ?? signals.props.width ?? 0);
|
||||
height: number = $derived(signals.height ?? signals.props.height ?? 0);
|
||||
|
||||
@@ -112,6 +117,9 @@ export const getInitialStore = (signals: StoreSignals) => {
|
||||
nodeExtent: CoordinateExtent = $derived(signals.props.nodeExtent ?? infiniteExtent);
|
||||
translateExtent: CoordinateExtent = $derived(signals.props.translateExtent ?? infiniteExtent);
|
||||
|
||||
defaultEdgeOptions: Partial<Edge> = $derived(signals.props.defaultEdgeOptions ?? {});
|
||||
defaultNodeOptions: Partial<Node> = $derived(signals.props.defaultNodeOptions ?? {});
|
||||
|
||||
nodeDragThreshold: number = $derived(signals.props.nodeDragThreshold ?? 1);
|
||||
autoPanOnNodeDrag: boolean = $derived(signals.props.autoPanOnNodeDrag ?? true);
|
||||
autoPanOnConnect: boolean = $derived(signals.props.autoPanOnConnect ?? true);
|
||||
@@ -207,6 +215,7 @@ export const getInitialStore = (signals: StoreSignals) => {
|
||||
colorMode: ColorMode = $derived(signals.props.colorMode ?? 'light');
|
||||
|
||||
constructor() {
|
||||
// Process intial fitView here
|
||||
if (signals.props.fitView && !signals.props.initialViewport && this.width && this.height) {
|
||||
const bounds = getInternalNodesBounds(this.nodeLookup, {
|
||||
filter: (node) =>
|
||||
@@ -221,95 +230,4 @@ export const getInitialStore = (signals: StoreSignals) => {
|
||||
}
|
||||
}
|
||||
return new SvelteFlowStore();
|
||||
|
||||
// return new Store();
|
||||
// const nodeLookup: NodeLookup = new Map();
|
||||
// const parentLookup = new Map();
|
||||
// const connectionLookup = new Map();
|
||||
// const edgeLookup = new Map();
|
||||
|
||||
// const storeNodeOrigin = nodeOrigin ?? [0, 0];
|
||||
// const storeNodeExtent = nodeExtent ?? infiniteExtent;
|
||||
|
||||
// adoptUserNodes(nodes, nodeLookup, parentLookup, {
|
||||
// nodeExtent: storeNodeExtent,
|
||||
// nodeOrigin: storeNodeOrigin,
|
||||
// elevateNodesOnSelect: false,
|
||||
// checkEquality: false
|
||||
// });
|
||||
|
||||
// updateConnectionLookup(connectionLookup, edgeLookup, edges);
|
||||
|
||||
// let viewport: Viewport = { x: 0, y: 0, zoom: 1 };
|
||||
|
||||
// if (fitView && width && height) {
|
||||
// const bounds = getInternalNodesBounds(nodeLookup, {
|
||||
// filter: (node) => !!((node.width || node.initialWidth) && (node.height || node.initialHeight))
|
||||
// });
|
||||
// viewport = getViewportForBounds(bounds, width, height, 0.5, 2, 0.1);
|
||||
// }
|
||||
|
||||
// return {
|
||||
// flowId: writable<string | null>(null),
|
||||
// nodes: createNodesStore(nodes, nodeLookup, parentLookup, storeNodeOrigin, storeNodeExtent),
|
||||
// nodeLookup: readable<NodeLookup<InternalNode>>(nodeLookup),
|
||||
// parentLookup: readable<ParentLookup<InternalNode>>(parentLookup),
|
||||
// edgeLookup: readable<EdgeLookup<Edge>>(edgeLookup),
|
||||
// visibleNodes: readable<InternalNode[]>([]),
|
||||
// edges: createEdgesStore(edges, connectionLookup, edgeLookup),
|
||||
// visibleEdges: readable<EdgeLayouted[]>([]),
|
||||
// connectionLookup: readable<ConnectionLookup>(connectionLookup),
|
||||
// height: writable<number>(500),
|
||||
// width: writable<number>(500),
|
||||
// minZoom: writable<number>(0.5),
|
||||
// maxZoom: writable<number>(2),
|
||||
// nodeOrigin: writable<NodeOrigin>(storeNodeOrigin),
|
||||
// nodeDragThreshold: writable<number>(1),
|
||||
// nodeExtent: writable<CoordinateExtent>(storeNodeExtent),
|
||||
// translateExtent: writable<CoordinateExtent>(infiniteExtent),
|
||||
// autoPanOnNodeDrag: writable<boolean>(true),
|
||||
// autoPanOnConnect: writable<boolean>(true),
|
||||
// fitViewOnInit: writable<boolean>(false),
|
||||
// fitViewOnInitDone: writable<boolean>(false),
|
||||
// fitViewOptions: writable<FitViewOptions>(undefined),
|
||||
// panZoom: writable<PanZoomInstance | null>(null),
|
||||
// snapGrid: writable<SnapGrid | null>(null),
|
||||
// dragging: writable<boolean>(false),
|
||||
// selectionRect: writable<SelectionRect | null>(null),
|
||||
// selectionKeyPressed: writable<boolean>(false),
|
||||
// multiselectionKeyPressed: writable<boolean>(false),
|
||||
// deleteKeyPressed: writable<boolean>(false),
|
||||
// panActivationKeyPressed: writable<boolean>(false),
|
||||
// zoomActivationKeyPressed: writable<boolean>(false),
|
||||
// selectionRectMode: writable<string | null>(null),
|
||||
// selectionMode: writable<SelectionMode>(SelectionMode.Partial),
|
||||
// nodeTypes: writable<NodeTypes>(initialNodeTypes),
|
||||
// edgeTypes: writable<EdgeTypes>(initialEdgeTypes),
|
||||
// viewport: writable<Viewport>(viewport),
|
||||
// connectionMode: writable<ConnectionMode>(ConnectionMode.Strict),
|
||||
// domNode: writable<HTMLDivElement | null>(null),
|
||||
// connection: readable<ConnectionState>(initialConnection),
|
||||
// connectionLineType: writable<ConnectionLineType>(ConnectionLineType.Bezier),
|
||||
// connectionRadius: writable<number>(20),
|
||||
// isValidConnection: writable<IsValidConnection>(() => true),
|
||||
// nodesDraggable: writable<boolean>(true),
|
||||
// nodesConnectable: writable<boolean>(true),
|
||||
// elementsSelectable: writable<boolean>(true),
|
||||
// selectNodesOnDrag: writable<boolean>(true),
|
||||
// markers: readable<MarkerProps[]>([]),
|
||||
// defaultMarkerColor: writable<string>('#b1b1b7'),
|
||||
// lib: readable<string>('svelte'),
|
||||
// onlyRenderVisibleElements: writable<boolean>(false),
|
||||
// onerror: writable<OnError>(devWarn),
|
||||
// ondelete: writable<OnDelete>(undefined),
|
||||
// onedgecreate: writable<OnEdgeCreate>(undefined),
|
||||
// onconnect: writable<OnConnect>(undefined),
|
||||
// onconnectstart: writable<OnConnectStart>(undefined),
|
||||
// onconnectend: writable<OnConnectEnd>(undefined),
|
||||
// onbeforedelete: writable<OnBeforeDelete>(undefined),
|
||||
// nodesInitialized: writable<boolean>(false),
|
||||
// edgesInitialized: writable<boolean>(false),
|
||||
// viewportInitialized: writable<boolean>(false),
|
||||
// initialized: readable<boolean>(false)
|
||||
// };
|
||||
};
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
import { readable, writable } from 'svelte/store';
|
||||
import {
|
||||
infiniteExtent,
|
||||
SelectionMode,
|
||||
ConnectionMode,
|
||||
ConnectionLineType,
|
||||
devWarn,
|
||||
adoptUserNodes,
|
||||
getViewportForBounds,
|
||||
updateConnectionLookup,
|
||||
initialConnection,
|
||||
type SelectionRect,
|
||||
type SnapGrid,
|
||||
type MarkerProps,
|
||||
type PanZoomInstance,
|
||||
type CoordinateExtent,
|
||||
type NodeOrigin,
|
||||
type OnError,
|
||||
type Viewport,
|
||||
type ConnectionLookup,
|
||||
type OnConnect,
|
||||
type OnConnectStart,
|
||||
type OnConnectEnd,
|
||||
type NodeLookup,
|
||||
type EdgeLookup,
|
||||
type ConnectionState,
|
||||
type ParentLookup,
|
||||
getInternalNodesBounds
|
||||
} from '@xyflow/system';
|
||||
|
||||
import DefaultNode from '$lib/components/nodes/DefaultNode.svelte';
|
||||
import InputNode from '$lib/components/nodes/InputNode.svelte';
|
||||
import OutputNode from '$lib/components/nodes/OutputNode.svelte';
|
||||
import GroupNode from '$lib/components/nodes/GroupNode.svelte';
|
||||
|
||||
import {
|
||||
BezierEdgeInternal,
|
||||
SmoothStepEdgeInternal,
|
||||
StraightEdgeInternal,
|
||||
StepEdgeInternal
|
||||
} from '$lib/components/edges';
|
||||
|
||||
import type {
|
||||
NodeTypes,
|
||||
EdgeTypes,
|
||||
EdgeLayouted,
|
||||
Node,
|
||||
Edge,
|
||||
FitViewOptions,
|
||||
OnDelete,
|
||||
OnEdgeCreate,
|
||||
OnBeforeDelete,
|
||||
IsValidConnection,
|
||||
InternalNode
|
||||
} from '$lib/types';
|
||||
import { createNodesStore, createEdgesStore } from './utils';
|
||||
|
||||
export const initialNodeTypes = {
|
||||
input: InputNode,
|
||||
output: OutputNode,
|
||||
default: DefaultNode,
|
||||
group: GroupNode
|
||||
};
|
||||
|
||||
export const initialEdgeTypes = {
|
||||
straight: StraightEdgeInternal,
|
||||
smoothstep: SmoothStepEdgeInternal,
|
||||
default: BezierEdgeInternal,
|
||||
step: StepEdgeInternal
|
||||
};
|
||||
|
||||
export const getInitialStore = ({
|
||||
nodes = [],
|
||||
edges = [],
|
||||
width,
|
||||
height,
|
||||
fitView,
|
||||
nodeOrigin,
|
||||
nodeExtent
|
||||
}: {
|
||||
nodes?: Node[];
|
||||
edges?: Edge[];
|
||||
width?: number;
|
||||
height?: number;
|
||||
fitView?: boolean;
|
||||
nodeOrigin?: NodeOrigin;
|
||||
nodeExtent?: CoordinateExtent;
|
||||
}) => {
|
||||
const nodeLookup: NodeLookup = new Map();
|
||||
const parentLookup = new Map();
|
||||
const connectionLookup = new Map();
|
||||
const edgeLookup = new Map();
|
||||
|
||||
const storeNodeOrigin = nodeOrigin ?? [0, 0];
|
||||
const storeNodeExtent = nodeExtent ?? infiniteExtent;
|
||||
|
||||
adoptUserNodes(nodes, nodeLookup, parentLookup, {
|
||||
nodeExtent: storeNodeExtent,
|
||||
nodeOrigin: storeNodeOrigin,
|
||||
elevateNodesOnSelect: false,
|
||||
checkEquality: false
|
||||
});
|
||||
|
||||
updateConnectionLookup(connectionLookup, edgeLookup, edges);
|
||||
|
||||
let viewport: Viewport = { x: 0, y: 0, zoom: 1 };
|
||||
|
||||
if (fitView && width && height) {
|
||||
const bounds = getInternalNodesBounds(nodeLookup, {
|
||||
filter: (node) => !!((node.width || node.initialWidth) && (node.height || node.initialHeight))
|
||||
});
|
||||
viewport = getViewportForBounds(bounds, width, height, 0.5, 2, 0.1);
|
||||
}
|
||||
|
||||
return {
|
||||
flowId: writable<string | null>(null),
|
||||
nodes: createNodesStore(nodes, nodeLookup, parentLookup, storeNodeOrigin, storeNodeExtent),
|
||||
nodeLookup: readable<NodeLookup<InternalNode>>(nodeLookup),
|
||||
parentLookup: readable<ParentLookup<InternalNode>>(parentLookup),
|
||||
edgeLookup: readable<EdgeLookup<Edge>>(edgeLookup),
|
||||
visibleNodes: readable<InternalNode[]>([]),
|
||||
edges: createEdgesStore(edges, connectionLookup, edgeLookup),
|
||||
visibleEdges: readable<EdgeLayouted[]>([]),
|
||||
connectionLookup: readable<ConnectionLookup>(connectionLookup),
|
||||
height: writable<number>(500),
|
||||
width: writable<number>(500),
|
||||
minZoom: writable<number>(0.5),
|
||||
maxZoom: writable<number>(2),
|
||||
nodeOrigin: writable<NodeOrigin>(storeNodeOrigin),
|
||||
nodeDragThreshold: writable<number>(1),
|
||||
nodeExtent: writable<CoordinateExtent>(storeNodeExtent),
|
||||
translateExtent: writable<CoordinateExtent>(infiniteExtent),
|
||||
autoPanOnNodeDrag: writable<boolean>(true),
|
||||
autoPanOnConnect: writable<boolean>(true),
|
||||
fitViewOnInit: writable<boolean>(false),
|
||||
fitViewOnInitDone: writable<boolean>(false),
|
||||
fitViewOptions: writable<FitViewOptions>(undefined),
|
||||
panZoom: writable<PanZoomInstance | null>(null),
|
||||
snapGrid: writable<SnapGrid | null>(null),
|
||||
dragging: writable<boolean>(false),
|
||||
selectionRect: writable<SelectionRect | null>(null),
|
||||
selectionKeyPressed: writable<boolean>(false),
|
||||
multiselectionKeyPressed: writable<boolean>(false),
|
||||
deleteKeyPressed: writable<boolean>(false),
|
||||
panActivationKeyPressed: writable<boolean>(false),
|
||||
zoomActivationKeyPressed: writable<boolean>(false),
|
||||
selectionRectMode: writable<string | null>(null),
|
||||
selectionMode: writable<SelectionMode>(SelectionMode.Partial),
|
||||
nodeTypes: writable<NodeTypes>(initialNodeTypes),
|
||||
edgeTypes: writable<EdgeTypes>(initialEdgeTypes),
|
||||
viewport: writable<Viewport>(viewport),
|
||||
connectionMode: writable<ConnectionMode>(ConnectionMode.Strict),
|
||||
domNode: writable<HTMLDivElement | null>(null),
|
||||
connection: readable<ConnectionState>(initialConnection),
|
||||
connectionLineType: writable<ConnectionLineType>(ConnectionLineType.Bezier),
|
||||
connectionRadius: writable<number>(20),
|
||||
isValidConnection: writable<IsValidConnection>(() => true),
|
||||
nodesDraggable: writable<boolean>(true),
|
||||
nodesConnectable: writable<boolean>(true),
|
||||
elementsSelectable: writable<boolean>(true),
|
||||
selectNodesOnDrag: writable<boolean>(true),
|
||||
markers: readable<MarkerProps[]>([]),
|
||||
defaultMarkerColor: writable<string>('#b1b1b7'),
|
||||
lib: readable<string>('svelte'),
|
||||
onlyRenderVisibleElements: writable<boolean>(false),
|
||||
onerror: writable<OnError>(devWarn),
|
||||
ondelete: writable<OnDelete>(undefined),
|
||||
onedgecreate: writable<OnEdgeCreate>(undefined),
|
||||
onconnect: writable<OnConnect>(undefined),
|
||||
onconnectstart: writable<OnConnectStart>(undefined),
|
||||
onconnectend: writable<OnConnectEnd>(undefined),
|
||||
onbeforedelete: writable<OnBeforeDelete>(undefined),
|
||||
nodesInitialized: writable<boolean>(false),
|
||||
edgesInitialized: writable<boolean>(false),
|
||||
viewportInitialized: writable<boolean>(false),
|
||||
initialized: readable<boolean>(false)
|
||||
};
|
||||
};
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { Writable } from 'svelte/store';
|
||||
import type {
|
||||
InternalNodeUpdate,
|
||||
XYPosition,
|
||||
@@ -14,9 +13,6 @@ import type { Node, Edge, NodeTypes, EdgeTypes, FitViewOptions } from '$lib/type
|
||||
import type { SvelteFlowProps } from '$lib/container/SvelteFlow';
|
||||
|
||||
export type SvelteFlowStoreActions = {
|
||||
// syncNodeStores: (nodesStore: Writable<Node[]>) => void;
|
||||
// syncEdgeStores: (edgeStore: Writable<Edge[]>) => void;
|
||||
// syncViewport: (viewportStore?: Writable<Viewport>) => void;
|
||||
setNodeTypes: (nodeTypes: NodeTypes) => void;
|
||||
setEdgeTypes: (edgeTypes: EdgeTypes) => void;
|
||||
addEdge: (edge: Edge | Connection) => void;
|
||||
@@ -39,9 +35,8 @@ export type SvelteFlowStoreActions = {
|
||||
reset(): void;
|
||||
};
|
||||
|
||||
export type ContainerSignals = { domNode?: HTMLDivElement | null; width?: number; height?: number };
|
||||
export type StoreSignals = {
|
||||
props: Partial<SvelteFlowProps> & ContainerSignals;
|
||||
props: Partial<SvelteFlowProps>;
|
||||
domNode?: HTMLDivElement;
|
||||
width?: number;
|
||||
height?: number;
|
||||
|
||||
@@ -1,222 +0,0 @@
|
||||
import {
|
||||
writable,
|
||||
get,
|
||||
type Unsubscriber,
|
||||
type Subscriber,
|
||||
type Updater,
|
||||
type Writable
|
||||
} from 'svelte/store';
|
||||
import {
|
||||
adoptUserNodes,
|
||||
updateConnectionLookup,
|
||||
type Viewport,
|
||||
type PanZoomInstance,
|
||||
type ConnectionLookup,
|
||||
type EdgeLookup,
|
||||
type NodeLookup,
|
||||
type ParentLookup,
|
||||
type NodeOrigin,
|
||||
infiniteExtent,
|
||||
type CoordinateExtent
|
||||
} from '@xyflow/system';
|
||||
|
||||
import type { DefaultEdgeOptions, DefaultNodeOptions, Edge, InternalNode, Node } from '$lib/types';
|
||||
|
||||
// we need to sync the user nodes and the internal nodes so that the user can receive the updates
|
||||
// made by Svelte Flow (like dragging or selecting a node).
|
||||
export function syncNodeStores(
|
||||
nodesStore: ReturnType<typeof createNodesStore>,
|
||||
userNodesStore: Writable<Node[]>
|
||||
) {
|
||||
const nodesStoreSetter = nodesStore.set;
|
||||
const userNodesStoreSetter = userNodesStore.set;
|
||||
const currentNodesStore = get(nodesStore);
|
||||
const currentUserNodesStore = get(userNodesStore);
|
||||
// depending how the user initializes the nodes, we need to decide if we want to use
|
||||
// the user nodes or the internal nodes for initialization. A user can use a SvelteFlowProvider
|
||||
// without providing any nodes, in that case we want to use the nodes passed by the user.
|
||||
// By default we are using the store nodes, because they already have the absolute positions.
|
||||
const initWithUserNodes = currentNodesStore.length === 0 && currentUserNodesStore.length > 0;
|
||||
|
||||
let val = initWithUserNodes ? currentUserNodesStore : currentNodesStore;
|
||||
nodesStore.set(val);
|
||||
|
||||
const _set = (nds: Node[]) => {
|
||||
const updatedNodes = nodesStoreSetter(nds);
|
||||
val = updatedNodes;
|
||||
|
||||
userNodesStoreSetter(val);
|
||||
|
||||
return updatedNodes;
|
||||
};
|
||||
|
||||
nodesStore.set = userNodesStore.set = _set;
|
||||
nodesStore.update = userNodesStore.update = (fn: (nds: Node[]) => Node[]) => _set(fn(val));
|
||||
}
|
||||
|
||||
// same for edges
|
||||
export function syncEdgeStores(
|
||||
edgesStore: ReturnType<typeof createEdgesStore>,
|
||||
userEdgesStore: Writable<Edge[]>
|
||||
) {
|
||||
const nodesStoreSetter = edgesStore.set;
|
||||
const userEdgesStoreSetter = userEdgesStore.set;
|
||||
|
||||
let val = get(userEdgesStore);
|
||||
edgesStore.set(val);
|
||||
|
||||
const _set = (eds: Edge[]) => {
|
||||
nodesStoreSetter(eds);
|
||||
userEdgesStoreSetter(eds);
|
||||
val = eds;
|
||||
};
|
||||
|
||||
edgesStore.set = userEdgesStore.set = _set;
|
||||
edgesStore.update = userEdgesStore.update = (fn: (nds: Edge[]) => Edge[]) => _set(fn(val));
|
||||
}
|
||||
|
||||
// it is possible to pass a viewport store to SvelteFlow for having more control
|
||||
// if that's the case we need to sync the internal viewport with the user viewport
|
||||
export const syncViewportStores = (
|
||||
panZoomStore: PanZoomInstance | null,
|
||||
viewportStore: Writable<Viewport>,
|
||||
userViewportStore?: Writable<Viewport>
|
||||
) => {
|
||||
if (!userViewportStore) {
|
||||
return;
|
||||
}
|
||||
|
||||
const panZoom = panZoomStore;
|
||||
|
||||
const viewportStoreSetter = viewportStore.set;
|
||||
const userViewportStoreSetter = userViewportStore.set;
|
||||
|
||||
let val = userViewportStore ? get(userViewportStore) : { x: 0, y: 0, zoom: 1 };
|
||||
viewportStore.set(val);
|
||||
|
||||
viewportStore.set = (vp: Viewport) => {
|
||||
viewportStoreSetter(vp);
|
||||
userViewportStoreSetter(vp);
|
||||
|
||||
val = vp;
|
||||
|
||||
return vp;
|
||||
};
|
||||
|
||||
userViewportStore.set = (vp: Viewport) => {
|
||||
panZoom?.syncViewport(vp);
|
||||
|
||||
viewportStoreSetter(vp);
|
||||
userViewportStoreSetter(vp);
|
||||
|
||||
val = vp;
|
||||
|
||||
return vp;
|
||||
};
|
||||
|
||||
viewportStore.update = (fn: (vp: Viewport) => Viewport) => {
|
||||
viewportStore.set(fn(val));
|
||||
};
|
||||
|
||||
userViewportStore.update = (fn: (vp: Viewport) => Viewport) => {
|
||||
userViewportStore.set(fn(val));
|
||||
};
|
||||
};
|
||||
|
||||
export type NodeStoreOptions = {
|
||||
elevateNodesOnSelect?: boolean;
|
||||
};
|
||||
|
||||
type Update<T> = Writable<T>['update'];
|
||||
|
||||
// we are creating a custom store for the internals nodes in order to update the zIndex and positionAbsolute.
|
||||
// The user only passes in relative positions, so we need to calculate the absolute positions based on the parent nodes.
|
||||
export const createNodesStore = (
|
||||
nodes: Node[],
|
||||
nodeLookup: NodeLookup<InternalNode>,
|
||||
parentLookup: ParentLookup<InternalNode>,
|
||||
nodeOrigin: NodeOrigin = [0, 0],
|
||||
nodeExtent: CoordinateExtent = infiniteExtent
|
||||
): {
|
||||
subscribe: (this: void, run: Subscriber<Node[]>) => Unsubscriber;
|
||||
update: (this: void, updater: Updater<Node[]>) => void;
|
||||
set: (this: void, value: Node[]) => Node[];
|
||||
setDefaultOptions: (opts: DefaultNodeOptions) => void;
|
||||
setOptions: (opts: NodeStoreOptions) => void;
|
||||
} => {
|
||||
const { subscribe, set } = writable<Node[]>([]);
|
||||
let value = nodes;
|
||||
let defaults = {};
|
||||
let elevateNodesOnSelect = true;
|
||||
|
||||
const _set = (nds: Node[]): Node[] => {
|
||||
adoptUserNodes(nds, nodeLookup, parentLookup, {
|
||||
elevateNodesOnSelect,
|
||||
nodeOrigin,
|
||||
nodeExtent,
|
||||
defaults,
|
||||
checkEquality: false
|
||||
});
|
||||
|
||||
value = nds;
|
||||
|
||||
set(value);
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
const _update: Update<Node[]> = (fn: (nds: Node[]) => Node[]) => _set(fn(value));
|
||||
|
||||
const setDefaultOptions = (options: DefaultNodeOptions) => {
|
||||
defaults = options;
|
||||
};
|
||||
|
||||
const setOptions = (options: NodeStoreOptions) => {
|
||||
elevateNodesOnSelect = options.elevateNodesOnSelect ?? elevateNodesOnSelect;
|
||||
};
|
||||
|
||||
_set(value);
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
set: _set,
|
||||
update: _update,
|
||||
setDefaultOptions,
|
||||
setOptions
|
||||
};
|
||||
};
|
||||
|
||||
export const createEdgesStore = (
|
||||
edges: Edge[],
|
||||
connectionLookup: ConnectionLookup,
|
||||
edgeLookup: EdgeLookup<Edge>,
|
||||
defaultOptions?: DefaultEdgeOptions
|
||||
): Writable<Edge[]> & { setDefaultOptions: (opts: DefaultEdgeOptions) => void } => {
|
||||
const { subscribe, set } = writable<Edge[]>([]);
|
||||
let value = edges;
|
||||
let defaults = defaultOptions || {};
|
||||
|
||||
const _set: typeof set = (eds: Edge[]) => {
|
||||
const nextEdges = defaults ? eds.map((edge) => ({ ...defaults, ...edge })) : eds;
|
||||
|
||||
updateConnectionLookup(connectionLookup, edgeLookup, nextEdges);
|
||||
|
||||
value = nextEdges;
|
||||
set(value);
|
||||
};
|
||||
|
||||
const _update: Update<Edge[]> = (fn: (eds: Edge[]) => Edge[]) => _set(fn(value));
|
||||
|
||||
const setDefaultOptions = (options: DefaultEdgeOptions) => {
|
||||
defaults = options;
|
||||
};
|
||||
|
||||
_set(value);
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
set: _set,
|
||||
update: _update,
|
||||
setDefaultOptions
|
||||
};
|
||||
};
|
||||
@@ -8,8 +8,7 @@
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"noErrorTruncation": true
|
||||
"strict": true
|
||||
}
|
||||
|
||||
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
|
||||
|
||||
Reference in New Issue
Block a user