refactor(store): connection data
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
|
||||
{#if $connectionPath}
|
||||
<svg width={$width} height={$height} class="svelte-flow__connectionline">
|
||||
<g class={cc(['svelte-flow__connection', $connection.status])}>
|
||||
<g class={cc(['svelte-flow__connection', $connection.connectionStatus])}>
|
||||
<path d={$connectionPath} fill="none" class="svelte-flow__connection-path" />
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
import { getContext, createEventDispatcher } from 'svelte';
|
||||
import cc from 'classcat';
|
||||
import { Position, type Connection } from '@reactflow/system';
|
||||
import { isMouseEvent } from '@reactflow/utils';
|
||||
import { XYHandle, isMouseEvent } from '@reactflow/utils';
|
||||
|
||||
import { handlePointerDown } from './handler';
|
||||
import { useStore } from '$lib/store';
|
||||
import type { HandleComponentProps } from '$lib/types';
|
||||
|
||||
@@ -23,7 +22,8 @@
|
||||
|
||||
const handleId = id || null;
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
|
||||
const store = useStore();
|
||||
const {
|
||||
connectionMode,
|
||||
domNode,
|
||||
@@ -31,11 +31,12 @@
|
||||
connectionRadius,
|
||||
transform,
|
||||
isValidConnection,
|
||||
lib,
|
||||
addEdge,
|
||||
panBy,
|
||||
cancelConnection,
|
||||
updateConnection,
|
||||
} = useStore();
|
||||
} = store;
|
||||
|
||||
function dispatchEvent(eventName: string, params?: Connection) {
|
||||
dispatch(eventName, params || { nodeId, handleId, type });
|
||||
@@ -50,23 +51,22 @@
|
||||
const isMouseTriggered = isMouseEvent(event);
|
||||
|
||||
if ((isMouseTriggered && event.button === 0) || !isMouseTriggered) {
|
||||
handlePointerDown({
|
||||
event,
|
||||
XYHandle.onPointerDown(event, {
|
||||
handleId,
|
||||
nodeId,
|
||||
isTarget,
|
||||
connectionRadius: $connectionRadius,
|
||||
domNode: $domNode,
|
||||
nodes,
|
||||
nodes: $nodes,
|
||||
connectionMode: $connectionMode,
|
||||
transform,
|
||||
transform: $transform,
|
||||
lib: $lib,
|
||||
autoPanOnConnect: true,
|
||||
isValidConnection: $isValidConnection,
|
||||
onConnect: onConnectExtended,
|
||||
updateConnection,
|
||||
cancelConnection,
|
||||
panBy,
|
||||
onConnectStart: () => dispatchEvent('connect:start'),
|
||||
onConnectEnd: () => dispatchEvent('connect:end')
|
||||
onConnect: onConnectExtended,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,213 +0,0 @@
|
||||
import { get, type Writable } from 'svelte/store';
|
||||
import {
|
||||
getHostForElement,
|
||||
calcAutoPan,
|
||||
getEventPosition,
|
||||
pointToRendererPoint,
|
||||
rendererPointToPoint
|
||||
} from '@reactflow/utils';
|
||||
import type {
|
||||
OnConnect,
|
||||
HandleType,
|
||||
Connection,
|
||||
ConnectionMode,
|
||||
XYPosition,
|
||||
Transform
|
||||
} from '@reactflow/system';
|
||||
|
||||
import {
|
||||
getClosestHandle,
|
||||
getConnectionStatus,
|
||||
getHandleLookup,
|
||||
getHandleType,
|
||||
isValidHandle,
|
||||
resetRecentHandle,
|
||||
type ConnectionHandle
|
||||
} from './utils';
|
||||
import type { ConnectionData, IsValidConnection, Node } from '$lib/types';
|
||||
|
||||
export function handlePointerDown({
|
||||
event,
|
||||
handleId,
|
||||
nodeId,
|
||||
onConnect,
|
||||
domNode,
|
||||
nodes,
|
||||
connectionMode,
|
||||
connectionRadius,
|
||||
isTarget,
|
||||
transform: transformStore,
|
||||
panBy,
|
||||
updateConnection,
|
||||
cancelConnection,
|
||||
isValidConnection,
|
||||
edgeUpdaterType,
|
||||
onEdgeUpdateEnd,
|
||||
onConnectStart,
|
||||
onConnectEnd
|
||||
}: {
|
||||
event: MouseEvent | TouchEvent;
|
||||
handleId: string | null;
|
||||
nodeId: string;
|
||||
onConnect: OnConnect;
|
||||
isTarget: boolean;
|
||||
connectionMode: ConnectionMode;
|
||||
domNode: HTMLDivElement | null;
|
||||
nodes: Writable<Node[]>;
|
||||
connectionRadius: number;
|
||||
isValidConnection: IsValidConnection;
|
||||
transform: Writable<Transform>;
|
||||
updateConnection: (connection: Partial<ConnectionData>) => void;
|
||||
cancelConnection: () => void;
|
||||
panBy: (delta: XYPosition) => void;
|
||||
edgeUpdaterType?: HandleType;
|
||||
onEdgeUpdateEnd?: (evt: MouseEvent | TouchEvent) => void;
|
||||
onConnectStart: () => void;
|
||||
onConnectEnd: () => void;
|
||||
}): void {
|
||||
// when svelte-flow is used inside a shadow root we can't use document
|
||||
const doc = getHostForElement(event.target as HTMLElement);
|
||||
let autoPanId = 0;
|
||||
let prevClosestHandle: ConnectionHandle | null;
|
||||
|
||||
const { x, y } = getEventPosition(event);
|
||||
const clickedHandle = doc?.elementFromPoint(x, y);
|
||||
const handleType = getHandleType(edgeUpdaterType, clickedHandle);
|
||||
const containerBounds = domNode?.getBoundingClientRect();
|
||||
|
||||
if (!containerBounds || !handleType) {
|
||||
return;
|
||||
}
|
||||
|
||||
let prevActiveHandle: Element;
|
||||
let connectionPosition = getEventPosition(event, containerBounds);
|
||||
let autoPanStarted = false;
|
||||
let connection: Connection | null = null;
|
||||
let isValid = false;
|
||||
let handleDomNode: Element | null = null;
|
||||
|
||||
const autoPanOnConnect = true;
|
||||
|
||||
const handleLookup = getHandleLookup({
|
||||
nodes: get(nodes),
|
||||
nodeId,
|
||||
handleId,
|
||||
handleType
|
||||
});
|
||||
|
||||
// when the user is moving the mouse close to the edge of the canvas while connecting we move the canvas
|
||||
const autoPan = (): void => {
|
||||
// @todd add prop
|
||||
if (!autoPanOnConnect) {
|
||||
return;
|
||||
}
|
||||
const [xMovement, yMovement] = calcAutoPan(connectionPosition, containerBounds);
|
||||
|
||||
panBy({ x: xMovement, y: yMovement });
|
||||
autoPanId = requestAnimationFrame(autoPan);
|
||||
};
|
||||
|
||||
updateConnection({
|
||||
position: connectionPosition,
|
||||
nodeId,
|
||||
handleId,
|
||||
handleType,
|
||||
status: null
|
||||
});
|
||||
|
||||
// onConnectStart?.(event, { nodeId, handleId, handleType });
|
||||
onConnectStart();
|
||||
|
||||
function onPointerMove(event: MouseEvent | TouchEvent) {
|
||||
const transform = get(transformStore);
|
||||
connectionPosition = getEventPosition(event, containerBounds);
|
||||
|
||||
prevClosestHandle = getClosestHandle(
|
||||
pointToRendererPoint(connectionPosition, transform, false, [1, 1]),
|
||||
connectionRadius,
|
||||
handleLookup
|
||||
);
|
||||
|
||||
if (!autoPanStarted) {
|
||||
autoPan();
|
||||
autoPanStarted = true;
|
||||
}
|
||||
|
||||
const result = isValidHandle(
|
||||
event,
|
||||
prevClosestHandle,
|
||||
connectionMode,
|
||||
nodeId,
|
||||
handleId,
|
||||
isTarget ? 'target' : 'source',
|
||||
isValidConnection,
|
||||
doc,
|
||||
get(nodes)
|
||||
);
|
||||
|
||||
handleDomNode = result.handleDomNode;
|
||||
connection = result.connection;
|
||||
isValid = result.isValid;
|
||||
|
||||
updateConnection({
|
||||
position:
|
||||
prevClosestHandle && isValid
|
||||
? rendererPointToPoint(
|
||||
{
|
||||
x: prevClosestHandle.x,
|
||||
y: prevClosestHandle.y
|
||||
},
|
||||
transform
|
||||
)
|
||||
: connectionPosition,
|
||||
status: getConnectionStatus(!!prevClosestHandle, isValid)
|
||||
});
|
||||
|
||||
if (!prevClosestHandle && !isValid && !handleDomNode) {
|
||||
return resetRecentHandle(prevActiveHandle);
|
||||
}
|
||||
|
||||
if (connection.source !== connection.target && handleDomNode) {
|
||||
resetRecentHandle(prevActiveHandle);
|
||||
prevActiveHandle = handleDomNode;
|
||||
// @todo: remove the old class names "svelte-flow__handle-" in the next major version
|
||||
handleDomNode.classList.add('connecting');
|
||||
handleDomNode.classList.toggle('valid', isValid);
|
||||
}
|
||||
}
|
||||
|
||||
function onPointerUp(event: MouseEvent | TouchEvent) {
|
||||
if ((prevClosestHandle || handleDomNode) && connection && isValid) {
|
||||
onConnect?.(connection);
|
||||
}
|
||||
|
||||
// it's important to get a fresh reference from the store here
|
||||
// in order to get the latest state of onConnectEnd
|
||||
|
||||
onConnectEnd();
|
||||
|
||||
if (edgeUpdaterType) {
|
||||
onEdgeUpdateEnd?.(event);
|
||||
}
|
||||
|
||||
resetRecentHandle(prevActiveHandle);
|
||||
cancelConnection();
|
||||
cancelAnimationFrame(autoPanId);
|
||||
autoPanStarted = false;
|
||||
isValid = false;
|
||||
connection = null;
|
||||
handleDomNode = null;
|
||||
|
||||
doc.removeEventListener('mousemove', onPointerMove as EventListener);
|
||||
doc.removeEventListener('mouseup', onPointerUp as EventListener);
|
||||
|
||||
doc.removeEventListener('touchmove', onPointerMove as EventListener);
|
||||
doc.removeEventListener('touchend', onPointerUp as EventListener);
|
||||
}
|
||||
|
||||
doc.addEventListener('mousemove', onPointerMove as EventListener);
|
||||
doc.addEventListener('mouseup', onPointerUp as EventListener);
|
||||
|
||||
doc.addEventListener('touchmove', onPointerMove as EventListener);
|
||||
doc.addEventListener('touchend', onPointerUp as EventListener);
|
||||
}
|
||||
@@ -1,194 +0,0 @@
|
||||
import { internalsSymbol, ConnectionMode, type ConnectionStatus } from '@reactflow/system';
|
||||
import type { Connection, HandleType, XYPosition, NodeHandleBounds } from '@reactflow/system';
|
||||
import { getEventPosition } from '@reactflow/utils';
|
||||
|
||||
import type { IsValidConnection, Node } from '$lib/types';
|
||||
|
||||
export type ConnectionHandle = {
|
||||
id: string | null;
|
||||
type: HandleType;
|
||||
nodeId: string;
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
|
||||
export type ValidConnectionFunc = (connection: Connection) => boolean;
|
||||
|
||||
// this functions collects all handles and adds an absolute position
|
||||
// so that we can later find the closest handle to the mouse position
|
||||
export function getHandles(
|
||||
node: Node,
|
||||
handleBounds: NodeHandleBounds,
|
||||
type: HandleType,
|
||||
currentHandle: string
|
||||
): ConnectionHandle[] {
|
||||
return (handleBounds[type] || []).reduce<ConnectionHandle[]>((res, h) => {
|
||||
if (`${node.id}-${h.id}-${type}` !== currentHandle) {
|
||||
res.push({
|
||||
id: h.id || null,
|
||||
type,
|
||||
nodeId: node.id,
|
||||
x: (node.positionAbsolute?.x ?? 0) + h.x + h.width / 2,
|
||||
y: (node.positionAbsolute?.y ?? 0) + h.y + h.height / 2
|
||||
});
|
||||
}
|
||||
return res;
|
||||
}, []);
|
||||
}
|
||||
|
||||
export function getClosestHandle(
|
||||
pos: XYPosition,
|
||||
connectionRadius: number,
|
||||
handles: ConnectionHandle[]
|
||||
): ConnectionHandle | null {
|
||||
let closestHandle: ConnectionHandle | null = null;
|
||||
let minDistance = Infinity;
|
||||
|
||||
handles.forEach((handle) => {
|
||||
const distance = Math.sqrt(Math.pow(handle.x - pos.x, 2) + Math.pow(handle.y - pos.y, 2));
|
||||
if (distance <= connectionRadius && distance < minDistance) {
|
||||
minDistance = distance;
|
||||
closestHandle = handle;
|
||||
}
|
||||
});
|
||||
|
||||
return closestHandle;
|
||||
}
|
||||
|
||||
type Result = {
|
||||
handleDomNode: Element | null;
|
||||
isValid: boolean;
|
||||
connection: Connection;
|
||||
};
|
||||
|
||||
const nullConnection: Connection = {
|
||||
source: null,
|
||||
target: null,
|
||||
sourceHandle: null,
|
||||
targetHandle: null
|
||||
};
|
||||
|
||||
// checks if and returns connection in fom of an object { source: 123, target: 312 }
|
||||
export function isValidHandle(
|
||||
event: MouseEvent | TouchEvent,
|
||||
handle: Pick<ConnectionHandle, 'nodeId' | 'id' | 'type'> | null,
|
||||
connectionMode: ConnectionMode,
|
||||
fromNodeId: string,
|
||||
fromHandleId: string | null,
|
||||
fromType: string,
|
||||
isValidConnection: IsValidConnection,
|
||||
doc: Document | ShadowRoot,
|
||||
nodes: Node[]
|
||||
) {
|
||||
const isTarget = fromType === 'target';
|
||||
const handleDomNode = doc.querySelector(
|
||||
`.svelte-flow__handle[data-id="${handle?.nodeId}-${handle?.id}-${handle?.type}"]`
|
||||
);
|
||||
const { x, y } = getEventPosition(event);
|
||||
const handleBelow = doc.elementFromPoint(x, y);
|
||||
const handleToCheck = handleBelow?.classList.contains('svelte-flow__handle')
|
||||
? handleBelow
|
||||
: handleDomNode;
|
||||
|
||||
const result: Result = {
|
||||
handleDomNode: handleToCheck,
|
||||
isValid: false,
|
||||
connection: nullConnection
|
||||
};
|
||||
|
||||
if (handleToCheck) {
|
||||
const handleType = getHandleType(undefined, handleToCheck);
|
||||
const handleNodeId = handleToCheck.getAttribute('data-nodeid');
|
||||
const handleId = handleToCheck.getAttribute('data-handleid');
|
||||
|
||||
const connection: Connection = {
|
||||
source: isTarget ? handleNodeId : fromNodeId,
|
||||
sourceHandle: isTarget ? handleId : fromHandleId,
|
||||
target: isTarget ? fromNodeId : handleNodeId,
|
||||
targetHandle: isTarget ? fromHandleId : handleId
|
||||
};
|
||||
|
||||
result.connection = connection;
|
||||
|
||||
// in strict mode we don't allow target to target or source to source connections
|
||||
const isValid =
|
||||
connectionMode === ConnectionMode.Strict
|
||||
? (isTarget && handleType === 'source') || (!isTarget && handleType === 'target')
|
||||
: handleNodeId !== fromNodeId || handleId !== fromHandleId;
|
||||
|
||||
if (isValid) {
|
||||
const fromNode: Node | undefined = nodes.find((n) => n.id === connection.source);
|
||||
const toNode: Node | undefined = nodes.find((n) => n.id === connection.target);
|
||||
|
||||
if (fromNode && toNode) result.isValid = isValidConnection(connection, { fromNode, toNode });
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
type GetHandleLookupParams = {
|
||||
nodes: Node[];
|
||||
nodeId: string;
|
||||
handleId: string | null;
|
||||
handleType: string;
|
||||
};
|
||||
|
||||
export function getHandleLookup({ nodes, nodeId, handleId, handleType }: GetHandleLookupParams) {
|
||||
return nodes.reduce<ConnectionHandle[]>((res, node) => {
|
||||
if (node[internalsSymbol]) {
|
||||
const { handleBounds } = node[internalsSymbol];
|
||||
let sourceHandles: ConnectionHandle[] = [];
|
||||
let targetHandles: ConnectionHandle[] = [];
|
||||
|
||||
if (handleBounds) {
|
||||
sourceHandles = getHandles(
|
||||
node,
|
||||
handleBounds,
|
||||
'source',
|
||||
`${nodeId}-${handleId}-${handleType}`
|
||||
);
|
||||
targetHandles = getHandles(
|
||||
node,
|
||||
handleBounds,
|
||||
'target',
|
||||
`${nodeId}-${handleId}-${handleType}`
|
||||
);
|
||||
}
|
||||
|
||||
res.push(...sourceHandles, ...targetHandles);
|
||||
}
|
||||
return res;
|
||||
}, []);
|
||||
}
|
||||
|
||||
export function getHandleType(
|
||||
edgeUpdaterType: HandleType | undefined,
|
||||
handleDomNode: Element | null
|
||||
): HandleType | null {
|
||||
if (edgeUpdaterType) {
|
||||
return edgeUpdaterType;
|
||||
} else if (handleDomNode?.classList.contains('target')) {
|
||||
return 'target';
|
||||
} else if (handleDomNode?.classList.contains('source')) {
|
||||
return 'source';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function resetRecentHandle(handleDomNode: Element): void {
|
||||
handleDomNode?.classList.remove('valid', 'connecting');
|
||||
}
|
||||
|
||||
export function getConnectionStatus(isInsideConnectionRadius: boolean, isHandleValid: boolean) {
|
||||
let connectionStatus = null;
|
||||
|
||||
if (isHandleValid) {
|
||||
connectionStatus = 'valid';
|
||||
} else if (isInsideConnectionRadius && !isHandleValid) {
|
||||
connectionStatus = 'invalid';
|
||||
}
|
||||
|
||||
return connectionStatus as ConnectionStatus;
|
||||
}
|
||||
@@ -36,6 +36,11 @@
|
||||
import { useStore } from '$lib/store';
|
||||
import { getConnectedEdges } from '$lib/utils';
|
||||
import type { Node, Edge } from '$lib/types';
|
||||
import type { PaneProps } from './types';
|
||||
|
||||
type $$Props = PaneProps;
|
||||
|
||||
export let panOnDrag: $$Props['panOnDrag'] = undefined;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const {
|
||||
@@ -133,9 +138,9 @@
|
||||
|
||||
// We only want to trigger click functions when in selection mode if
|
||||
// the user did not move the mouse.
|
||||
// if (!userSelectionActive && userSelectionRect && event.target === container.current) {
|
||||
// onClick?.(event);
|
||||
// }
|
||||
if (!isSelecting && $selectionRectMode === 'user' && event.target === container) {
|
||||
onClick?.(event);
|
||||
}
|
||||
selectionRect.set(null);
|
||||
|
||||
if (selectedNodes.length > 0) {
|
||||
@@ -155,10 +160,10 @@
|
||||
};
|
||||
|
||||
const onContextMenu = (event: MouseEvent) => {
|
||||
// if (Array.isArray(panOnDrag) && panOnDrag?.includes(2)) {
|
||||
// event.preventDefault();
|
||||
// return;
|
||||
// }
|
||||
if (Array.isArray(panOnDrag) && panOnDrag?.includes(2)) {
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch('pane:contextmenu', event);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export type PaneProps = {
|
||||
panOnDrag?: boolean | number[];
|
||||
};
|
||||
@@ -167,7 +167,7 @@
|
||||
{panOnScroll}
|
||||
{panOnDrag}
|
||||
>
|
||||
<Pane on:pane:click>
|
||||
<Pane on:pane:click {panOnDrag}>
|
||||
<ViewportComponent>
|
||||
<EdgeRenderer on:edge:click />
|
||||
<ConnectionLine />
|
||||
|
||||
@@ -11,17 +11,11 @@ import type {
|
||||
OnMove,
|
||||
OnMoveEnd,
|
||||
CoordinateExtent,
|
||||
PanOnScrollMode
|
||||
PanOnScrollMode,
|
||||
IsValidConnection
|
||||
} from '@reactflow/system';
|
||||
|
||||
import type {
|
||||
Edge,
|
||||
Node,
|
||||
NodeTypes,
|
||||
KeyDefinition,
|
||||
EdgeTypes,
|
||||
IsValidConnection
|
||||
} from '$lib/types';
|
||||
import type { Edge, Node, NodeTypes, KeyDefinition, EdgeTypes } from '$lib/types';
|
||||
|
||||
export type SvelteFlowProps = DOMAttributes<HTMLDivElement> & {
|
||||
id?: string;
|
||||
|
||||
@@ -21,20 +21,23 @@ export function getConnectionPath(store: SvelteFlowStoreState) {
|
||||
store.transform
|
||||
],
|
||||
([connection, connectionLineType, connectionMode, nodes, transform]) => {
|
||||
if (!connection.nodeId) {
|
||||
if (!connection.connectionStartHandle?.nodeId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const fromNode = nodes.find((n) => n.id === connection.nodeId);
|
||||
const fromNode = nodes.find((n) => n.id === connection.connectionStartHandle?.nodeId);
|
||||
const fromHandleBounds = fromNode?.[internalsSymbol]?.handleBounds;
|
||||
const handleBoundsStrict = fromHandleBounds?.[connection.handleType || 'source'] || [];
|
||||
const handleBoundsStrict =
|
||||
fromHandleBounds?.[connection.connectionStartHandle.type || 'source'] || [];
|
||||
const handleBoundsLoose = handleBoundsStrict
|
||||
? handleBoundsStrict
|
||||
: fromHandleBounds?.[connection.handleType === 'source' ? 'target' : 'source']!;
|
||||
: fromHandleBounds?.[
|
||||
connection?.connectionStartHandle?.type === 'source' ? 'target' : 'source'
|
||||
]!;
|
||||
const handleBounds =
|
||||
connectionMode === ConnectionMode.Strict ? handleBoundsStrict : handleBoundsLoose;
|
||||
const fromHandle = connection.handleId
|
||||
? handleBounds.find((d) => d.id === connection.handleId)
|
||||
const fromHandle = connection.connectionStartHandle?.handleId
|
||||
? handleBounds.find((d) => d.id === connection.connectionStartHandle?.handleId)
|
||||
: handleBounds[0];
|
||||
const fromHandleX = fromHandle
|
||||
? fromHandle.x + fromHandle.width / 2
|
||||
@@ -49,8 +52,8 @@ export function getConnectionPath(store: SvelteFlowStoreState) {
|
||||
sourceX: fromX,
|
||||
sourceY: fromY,
|
||||
sourcePosition: fromPosition,
|
||||
targetX: ((connection.position?.x ?? 0) - transform[0]) / transform[2],
|
||||
targetY: ((connection.position?.y ?? 0) - transform[1]) / transform[2],
|
||||
targetX: ((connection.connectionPosition?.x ?? 0) - transform[0]) / transform[2],
|
||||
targetY: ((connection.connectionPosition?.y ?? 0) - transform[1]) / transform[2],
|
||||
targetPosition: toPosition
|
||||
};
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@ import {
|
||||
type ViewportHelperFunctionOptions,
|
||||
type Connection,
|
||||
type XYPosition,
|
||||
type CoordinateExtent
|
||||
type CoordinateExtent,
|
||||
type UpdateConnection
|
||||
} from '@reactflow/system';
|
||||
import {
|
||||
createMarkerIds,
|
||||
@@ -304,21 +305,22 @@ export function createStore(params: CreateStoreParams): SvelteFlowStore {
|
||||
return transformChanged;
|
||||
}
|
||||
|
||||
function updateConnection(connectionUpdate: Partial<ConnectionData> | null) {
|
||||
const updateConnection: UpdateConnection = (update) => {
|
||||
const currentConnectionData = get(store.connection);
|
||||
|
||||
const nextConnectionData = currentConnectionData
|
||||
? {
|
||||
...initConnectionData,
|
||||
...currentConnectionData,
|
||||
...connectionUpdate
|
||||
...update
|
||||
}
|
||||
: {
|
||||
...initConnectionData,
|
||||
...connectionUpdate
|
||||
...update
|
||||
};
|
||||
|
||||
store.connection.set(nextConnectionData);
|
||||
}
|
||||
};
|
||||
|
||||
function cancelConnection() {
|
||||
updateConnection(initConnectionData);
|
||||
|
||||
@@ -8,7 +8,8 @@ import {
|
||||
type SnapGrid,
|
||||
type MarkerProps,
|
||||
type PanZoomInstance,
|
||||
type CoordinateExtent
|
||||
type CoordinateExtent,
|
||||
type IsValidConnection
|
||||
} from '@reactflow/system';
|
||||
|
||||
import DefaultNode from '$lib/components/nodes/DefaultNode.svelte';
|
||||
@@ -18,23 +19,14 @@ 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 StepEdge from '$lib/components/edges/StepEdge.svelte';
|
||||
import type {
|
||||
ConnectionData,
|
||||
NodeTypes,
|
||||
EdgeTypes,
|
||||
EdgeLayouted,
|
||||
Edge,
|
||||
Node,
|
||||
IsValidConnection
|
||||
} from '$lib/types';
|
||||
import type { ConnectionData, NodeTypes, EdgeTypes, EdgeLayouted, Edge, Node } from '$lib/types';
|
||||
import { infiniteExtent } from '@reactflow/utils';
|
||||
|
||||
export const initConnectionData = {
|
||||
nodeId: null,
|
||||
handleId: null,
|
||||
handleType: null,
|
||||
position: null,
|
||||
status: null
|
||||
connectionStartHandle: null,
|
||||
connectionEndHandle: null,
|
||||
connectionPosition: null,
|
||||
connectionStatus: null
|
||||
};
|
||||
|
||||
export const initialNodeTypes = {
|
||||
@@ -88,5 +80,6 @@ export const initialStoreState = {
|
||||
elementsSelectable: writable<boolean>(true),
|
||||
selectNodesOnDrag: writable<boolean>(true),
|
||||
markers: readable<MarkerProps[]>([]),
|
||||
defaultMarkerColor: writable<string>('#b1b1b7')
|
||||
defaultMarkerColor: writable<string>('#b1b1b7'),
|
||||
lib: readable<string>('svelte')
|
||||
};
|
||||
|
||||
@@ -4,11 +4,12 @@ import type {
|
||||
ViewportHelperFunctionOptions,
|
||||
Connection,
|
||||
UpdateNodePositions,
|
||||
CoordinateExtent
|
||||
CoordinateExtent,
|
||||
UpdateConnection
|
||||
} from '@reactflow/system';
|
||||
|
||||
import type { initialStoreState } from './initial-store';
|
||||
import type { Node, Edge, ConnectionData, NodeTypes, EdgeTypes, FitViewOptions } from '$lib/types';
|
||||
import type { Node, Edge, NodeTypes, EdgeTypes, FitViewOptions } from '$lib/types';
|
||||
import type { Writable } from 'svelte/store';
|
||||
|
||||
export type SvelteFlowStoreActions = {
|
||||
@@ -27,7 +28,7 @@ export type SvelteFlowStoreActions = {
|
||||
addSelectedNodes: (ids: string[]) => void;
|
||||
addSelectedEdges: (ids: string[]) => void;
|
||||
panBy: (delta: XYPosition) => boolean;
|
||||
updateConnection: (connection: Partial<ConnectionData>) => void;
|
||||
updateConnection: UpdateConnection;
|
||||
cancelConnection: () => void;
|
||||
reset(): void;
|
||||
};
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import type { ShortcutModifierDefinition } from '@svelte-put/shortcut';
|
||||
import type {
|
||||
Connection,
|
||||
FitViewOptionsBase,
|
||||
HandleType,
|
||||
Position,
|
||||
XYPosition
|
||||
XYPosition,
|
||||
ConnectingHandle
|
||||
} from '@reactflow/system';
|
||||
|
||||
import type { Node } from './nodes';
|
||||
@@ -14,11 +14,10 @@ export type KeyDefinitionObject = { key: string; modifier?: KeyModifier };
|
||||
export type KeyDefinition = string | KeyDefinitionObject;
|
||||
|
||||
export type ConnectionData = {
|
||||
position: XYPosition | null;
|
||||
nodeId: string | null;
|
||||
handleId: string | null;
|
||||
handleType: HandleType | null;
|
||||
status: string | null;
|
||||
connectionPosition: XYPosition | null;
|
||||
connectionStartHandle: ConnectingHandle | null;
|
||||
connectionEndHandle: ConnectingHandle | null;
|
||||
connectionStatus: string | null;
|
||||
};
|
||||
|
||||
export type HandleComponentProps = {
|
||||
@@ -30,8 +29,3 @@ export type HandleComponentProps = {
|
||||
};
|
||||
|
||||
export type FitViewOptions = FitViewOptionsBase<Node>;
|
||||
|
||||
export type IsValidConnection = (
|
||||
connection: Connection,
|
||||
{ fromNode, toNode }: { fromNode: Node; toNode: Node }
|
||||
) => boolean;
|
||||
|
||||
Reference in New Issue
Block a user