Files
xyflow/packages/svelte/src/lib/store/initial-store.svelte.ts
T

316 lines
12 KiB
TypeScript

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 OnConnect,
type OnConnectStart,
type OnConnectEnd,
type NodeLookup,
type ConnectionState,
getInternalNodesBounds,
type ColorMode,
createMarkerIds,
type EdgeLookup,
type ConnectionLookup,
type ParentLookup,
pointToRendererPoint
} 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,
FitViewOptions,
OnDelete,
OnEdgeCreate,
OnBeforeDelete,
IsValidConnection
} from '$lib/types';
import type { StoreSignals } from './types';
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 = (signals: StoreSignals) => {
class SvelteFlowStore {
get nodes() {
return signals.nodes;
}
set nodes(nodes) {
signals.nodes = nodes;
}
get edges() {
return signals.edges;
}
set edges(edges) {
signals.edges = edges;
}
nodeLookup: NodeLookup = new Map();
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,
nodeOrigin: this.nodeOrigin,
elevateNodesOnSelect: false,
checkEquality: true
});
return true;
});
adoptEdges: true = $derived.by(() => {
updateConnectionLookup(this.connectionLookup, this.edgeLookup, signals.edges);
return true;
});
domNode: HTMLDivElement | null = $derived(signals.domNode ?? signals.props.domNode ?? null);
width: number = $derived(signals.width ?? signals.props.width ?? 0);
height: number = $derived(signals.height ?? signals.props.height ?? 0);
flowId: string = $derived(signals.props.id ?? '1');
minZoom: number = $derived(signals.props.minZoom ?? 0.5);
maxZoom: number = $derived(signals.props.maxZoom ?? 2);
nodeOrigin: NodeOrigin = $derived(signals.props.nodeOrigin ?? [0, 0]);
nodeExtent: CoordinateExtent = $derived(signals.props.nodeExtent ?? infiniteExtent);
translateExtent: CoordinateExtent = $derived(signals.props.translateExtent ?? infiniteExtent);
nodeDragThreshold: number = $derived(signals.props.nodeDragThreshold ?? 1);
autoPanOnNodeDrag: boolean = $derived(signals.props.autoPanOnNodeDrag ?? true);
autoPanOnConnect: boolean = $derived(signals.props.autoPanOnConnect ?? true);
fitViewOnInitDone: boolean = $state(false);
fitViewOnInit: boolean = $derived(signals.props.fitView ?? false);
fitViewOptions: FitViewOptions | undefined = $derived(signals.props.fitViewOptions);
panZoom: PanZoomInstance | null = $state(null);
snapGrid: SnapGrid | null = $derived(signals.props.snapGrid ?? null);
dragging: boolean = $state(false);
selectionRect: SelectionRect | null = $state(null);
selectionKeyPressed: boolean = $state(false);
multiselectionKeyPressed: boolean = $state(false);
deleteKeyPressed: boolean = $state(false);
panActivationKeyPressed: boolean = $state(false);
zoomActivationKeyPressed: boolean = $state(false);
selectionRectMode: string | null = $state(null);
selectionMode: SelectionMode = $derived(signals.props.selectionMode ?? SelectionMode.Partial);
nodeTypes: NodeTypes = $derived({ ...initialNodeTypes, ...signals.props.nodeTypes });
edgeTypes: EdgeTypes = $derived({ ...initialEdgeTypes, ...signals.props.edgeTypes });
viewport: Viewport = $state(signals.props.initialViewport ?? { x: 0, y: 0, zoom: 1 });
connectionMode: ConnectionMode = $derived(
signals.props.connectionMode ?? ConnectionMode.Strict
);
rawConnection: ConnectionState = $state(initialConnection);
connection: ConnectionState = $derived.by(() => {
if (this.rawConnection.inProgress) {
return {
...this.rawConnection,
to: pointToRendererPoint(this.rawConnection.to, [
this.viewport.x,
this.viewport.y,
this.viewport.zoom
])
};
} else {
return { ...this.rawConnection };
}
});
connectionLineType: ConnectionLineType = $derived(
signals.props.connectionLineType ?? ConnectionLineType.Bezier
);
connectionRadius: number = $derived(signals.props.connectionRadius ?? 20);
isValidConnection: IsValidConnection = $derived(
signals.props.isValidConnection ?? (() => true)
);
nodesDraggable: boolean = $derived(signals.props.nodesDraggable ?? true);
nodesConnectable: boolean = $derived(signals.props.nodesConnectable ?? true);
elementsSelectable: boolean = $derived(signals.props.elementsSelectable ?? true);
selectNodesOnDrag: boolean = $derived(signals.props.selectNodesOnDrag ?? true);
defaultMarkerColor: string = $derived(signals.props.defaultMarkerColor ?? '#b1b1b7');
markers: MarkerProps[] = $derived.by(() => {
return createMarkerIds(signals.edges, {
defaultColor: this.defaultMarkerColor,
id: this.flowId
});
});
onlyRenderVisibleElements: boolean = $derived(signals.props.onlyRenderVisibleElements ?? false);
onerror: OnError = $derived(signals.props.onerror ?? devWarn);
ondelete?: OnDelete = $derived(signals.props.ondelete ?? undefined);
onedgecreate?: OnEdgeCreate = $derived(signals.props.onedgecreate);
onconnect?: OnConnect = $derived(signals.props.onconnect);
onconnectstart?: OnConnectStart = $derived(signals.props.onconnectstart);
onconnectend?: OnConnectEnd = $derived(signals.props.onconnectend);
onbeforedelete?: OnBeforeDelete = $derived(signals.props.onbeforedelete);
nodesInitialized: boolean = $state(false);
edgesInitialized: boolean = $state(false);
viewportInitialized: boolean = $state(false);
initialNodesLength: number = signals.nodes.length;
initialEdgesLength: number = signals.edges.length;
initialized: boolean = $derived.by(() => {
let initialized = false;
// if it hasn't been initialised check if it's now
if (this.initialNodesLength === 0) {
initialized = this.viewportInitialized;
} else if (this.initialEdgesLength === 0) {
initialized = this.viewportInitialized && this.nodesInitialized;
} else {
initialized = this.viewportInitialized && this.nodesInitialized && this.edgesInitialized;
}
return initialized;
});
colorMode: ColorMode = $derived(signals.props.colorMode ?? 'light');
constructor() {
if (signals.props.fitView && !signals.props.initialViewport && this.width && this.height) {
const bounds = getInternalNodesBounds(this.nodeLookup, {
filter: (node) =>
!!((node.width || node.initialWidth) && (node.height || node.initialHeight))
});
this.viewport = getViewportForBounds(bounds, this.width, this.height, 0.5, 2, 0.1);
}
}
resetStoreValues() {
// TODO: reset all store values here
}
}
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)
// };
};