added Edge Reconnection
This commit is contained in:
@@ -5,38 +5,21 @@
|
|||||||
type EdgeProps,
|
type EdgeProps,
|
||||||
EdgeLabelRenderer,
|
EdgeLabelRenderer,
|
||||||
useSvelteFlow,
|
useSvelteFlow,
|
||||||
MarkerType
|
MarkerType,
|
||||||
|
EdgeReconnectAnchor
|
||||||
} from '@xyflow/svelte';
|
} from '@xyflow/svelte';
|
||||||
|
|
||||||
type $$Props = EdgeProps;
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
id?: $$Props['id'];
|
|
||||||
style?: $$Props['style'];
|
|
||||||
markerEnd?: $$Props['markerEnd'];
|
|
||||||
sourceX: $$Props['sourceX'];
|
|
||||||
sourceY: $$Props['sourceY'];
|
|
||||||
sourcePosition: $$Props['sourcePosition'];
|
|
||||||
targetX: $$Props['targetX'];
|
|
||||||
targetY: $$Props['targetY'];
|
|
||||||
targetPosition: $$Props['targetPosition'];
|
|
||||||
[key: string]: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
let {
|
let {
|
||||||
id = '',
|
style,
|
||||||
style = undefined,
|
markerEnd,
|
||||||
markerEnd = undefined,
|
|
||||||
sourceX,
|
sourceX,
|
||||||
sourceY,
|
sourceY,
|
||||||
sourcePosition,
|
sourcePosition,
|
||||||
targetX,
|
targetX,
|
||||||
targetY,
|
targetY,
|
||||||
targetPosition,
|
targetPosition,
|
||||||
...rest
|
selected
|
||||||
}: Props = $props();
|
}: EdgeProps = $props();
|
||||||
|
|
||||||
rest;
|
|
||||||
|
|
||||||
let [edgePath, labelX, labelY] = $derived(
|
let [edgePath, labelX, labelY] = $derived(
|
||||||
getBezierPath({
|
getBezierPath({
|
||||||
@@ -50,42 +33,61 @@
|
|||||||
);
|
);
|
||||||
|
|
||||||
const { updateEdge } = useSvelteFlow();
|
const { updateEdge } = useSvelteFlow();
|
||||||
|
|
||||||
|
let reconnecting = $state(false);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<BaseEdge path={edgePath} {markerEnd} {style} />
|
{#if !reconnecting}
|
||||||
<EdgeLabelRenderer>
|
<BaseEdge path={edgePath} {markerEnd} {style} />
|
||||||
<div
|
<EdgeLabelRenderer>
|
||||||
class="edgeButtonContainer nodrag nopan"
|
<div
|
||||||
style:transform="translate(-50%, -50%) translate({labelX}px,{labelY}px)"
|
class="edgeButtonContainer nodrag nopan"
|
||||||
>
|
style:transform="translate(-50%, -50%) translate({labelX}px,{labelY}px)"
|
||||||
<button
|
|
||||||
class="edgeButton"
|
|
||||||
onclick={(event) => {
|
|
||||||
event.stopPropagation();
|
|
||||||
updateEdge('e5-6', {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
×
|
<button
|
||||||
</button>
|
class="edgeButton"
|
||||||
</div>
|
onclick={(event) => {
|
||||||
</EdgeLabelRenderer>
|
event.stopPropagation();
|
||||||
|
updateEdge('e5-6', {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
×
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</EdgeLabelRenderer>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if selected}
|
||||||
|
<EdgeReconnectAnchor
|
||||||
|
bind:reconnecting
|
||||||
|
type="source"
|
||||||
|
position={{ x: sourceX, y: sourceY }}
|
||||||
|
asDomNode
|
||||||
|
/>
|
||||||
|
<EdgeReconnectAnchor
|
||||||
|
bind:reconnecting
|
||||||
|
type="target"
|
||||||
|
position={{ x: targetX, y: targetY }}
|
||||||
|
asDomNode
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.edgeButtonContainer {
|
.edgeButtonContainer {
|
||||||
|
|||||||
@@ -1,57 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { BezierEdge, type EdgeProps } from '@xyflow/svelte';
|
import { BezierEdge, type EdgeProps } from '@xyflow/svelte';
|
||||||
|
|
||||||
type $$Props = EdgeProps;
|
let { ...props }: EdgeProps = $props();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
label?: $$Props['label'];
|
|
||||||
labelStyle?: $$Props['labelStyle'];
|
|
||||||
style?: $$Props['style'];
|
|
||||||
markerStart?: $$Props['markerStart'];
|
|
||||||
markerEnd?: $$Props['markerEnd'];
|
|
||||||
interactionWidth?: $$Props['interactionWidth'];
|
|
||||||
sourceX: $$Props['sourceX'];
|
|
||||||
sourceY: $$Props['sourceY'];
|
|
||||||
sourcePosition: $$Props['sourcePosition'];
|
|
||||||
targetX: $$Props['targetX'];
|
|
||||||
targetY: $$Props['targetY'];
|
|
||||||
targetPosition: $$Props['targetPosition'];
|
|
||||||
[key: string]: any
|
|
||||||
}
|
|
||||||
|
|
||||||
let {
|
|
||||||
label = undefined,
|
|
||||||
labelStyle = undefined,
|
|
||||||
style = undefined,
|
|
||||||
markerStart = undefined,
|
|
||||||
markerEnd = undefined,
|
|
||||||
interactionWidth = undefined,
|
|
||||||
sourceX,
|
|
||||||
sourceY,
|
|
||||||
sourcePosition,
|
|
||||||
targetX,
|
|
||||||
targetY,
|
|
||||||
targetPosition,
|
|
||||||
...rest
|
|
||||||
}: Props = $props();
|
|
||||||
|
|
||||||
rest;
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<BezierEdge
|
<BezierEdge {...props} pathOptions={{ curvature: 1 }} />
|
||||||
{sourceX}
|
|
||||||
{sourceY}
|
|
||||||
{sourcePosition}
|
|
||||||
{targetX}
|
|
||||||
{targetY}
|
|
||||||
{targetPosition}
|
|
||||||
{label}
|
|
||||||
{labelStyle}
|
|
||||||
{markerStart}
|
|
||||||
{markerEnd}
|
|
||||||
{style}
|
|
||||||
{interactionWidth}
|
|
||||||
pathOptions={{ curvature: 1 }}
|
|
||||||
/>
|
|
||||||
|
|||||||
@@ -1,31 +1 @@
|
|||||||
type PortalOptions = {
|
export { default as portal } from './portal.svelte';
|
||||||
target?: string;
|
|
||||||
domNode: Element | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
function tryToMount(node: Element, domNode: Element | null, target: string | undefined) {
|
|
||||||
if (!domNode) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const targetEl = target ? domNode.querySelector(target) : domNode;
|
|
||||||
|
|
||||||
if (targetEl) {
|
|
||||||
targetEl.appendChild(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function (node: Element, { target, domNode }: PortalOptions) {
|
|
||||||
tryToMount(node, domNode, target);
|
|
||||||
|
|
||||||
return {
|
|
||||||
async update({ target, domNode }: PortalOptions) {
|
|
||||||
tryToMount(node, domNode, target);
|
|
||||||
},
|
|
||||||
destroy() {
|
|
||||||
if (node.parentNode) {
|
|
||||||
node.parentNode.removeChild(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import { useStore } from '$lib/store';
|
||||||
|
|
||||||
|
type Portal = 'viewport' | 'edgelabel' | 'root';
|
||||||
|
|
||||||
|
const selector: Record<Exclude<Portal, 'root'>, string> = {
|
||||||
|
viewport: '.svelte-flow__viewport-portal',
|
||||||
|
edgelabel: '.svelte-flow__edgelabel-renderer'
|
||||||
|
};
|
||||||
|
|
||||||
|
function tryToMount(node: Element, domNode: Element | null, target: Portal | undefined) {
|
||||||
|
if (!target || !domNode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetEl = target === 'root' ? domNode : domNode.querySelector(selector[target]);
|
||||||
|
|
||||||
|
if (targetEl) {
|
||||||
|
targetEl.appendChild(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function (node: Element, target: Portal | undefined) {
|
||||||
|
const { domNode } = $derived(useStore());
|
||||||
|
|
||||||
|
let previousTarget: Portal | undefined = target;
|
||||||
|
|
||||||
|
tryToMount(node, domNode, target);
|
||||||
|
|
||||||
|
return {
|
||||||
|
async update(target: Portal) {
|
||||||
|
if (target !== previousTarget) {
|
||||||
|
node.parentNode?.removeChild(node);
|
||||||
|
}
|
||||||
|
tryToMount(node, domNode, target);
|
||||||
|
},
|
||||||
|
destroy() {
|
||||||
|
if (node.parentNode) {
|
||||||
|
node.parentNode.removeChild(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,13 +1,10 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Snippet } from 'svelte';
|
import type { Snippet } from 'svelte';
|
||||||
import portal from '$lib/actions/portal';
|
import { portal } from '$lib/actions/portal';
|
||||||
import { useStore } from '$lib/store';
|
|
||||||
|
|
||||||
const store = useStore();
|
|
||||||
|
|
||||||
let { children }: { children?: Snippet } = $props();
|
let { children }: { children?: Snippet } = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div use:portal={{ target: '.svelte-flow__edgelabel-renderer', domNode: store.domNode }}>
|
<div use:portal={'edgelabel'}>
|
||||||
{@render children?.()}
|
{@render children?.()}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,145 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { useStore } from '$lib/store';
|
||||||
|
import type { Edge } from '$lib/types';
|
||||||
|
import { XYHandle, type HandleType, type XYPosition } from '@xyflow/system';
|
||||||
|
import { getContext, type Snippet } from 'svelte';
|
||||||
|
import type { ClassValue } from 'svelte/elements';
|
||||||
|
import { portal } from '$lib/actions/portal';
|
||||||
|
|
||||||
|
let {
|
||||||
|
type,
|
||||||
|
reconnecting = $bindable(false),
|
||||||
|
position,
|
||||||
|
class: className,
|
||||||
|
size = 25,
|
||||||
|
style,
|
||||||
|
children,
|
||||||
|
asDomNode = false
|
||||||
|
}: {
|
||||||
|
type: HandleType;
|
||||||
|
reconnecting?: boolean;
|
||||||
|
style?: string;
|
||||||
|
class?: ClassValue;
|
||||||
|
position?: XYPosition;
|
||||||
|
asDomNode?: boolean;
|
||||||
|
size?: number;
|
||||||
|
children?: Snippet;
|
||||||
|
} = $props();
|
||||||
|
|
||||||
|
const store = useStore();
|
||||||
|
|
||||||
|
let edgeId: string | undefined = getContext('svelteflow__edge_id');
|
||||||
|
|
||||||
|
if (!edgeId) {
|
||||||
|
throw new Error('EdgeReconnectAnchor must be used within an Edge component');
|
||||||
|
}
|
||||||
|
|
||||||
|
const onPointerDown = (event: PointerEvent) => {
|
||||||
|
if (event.button !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
autoPanOnConnect,
|
||||||
|
domNode,
|
||||||
|
isValidConnection,
|
||||||
|
connectionMode,
|
||||||
|
connectionRadius,
|
||||||
|
onconnectstart,
|
||||||
|
onconnectend,
|
||||||
|
onreconnect,
|
||||||
|
onreconnectstart,
|
||||||
|
onreconnectend,
|
||||||
|
onbeforereconnect,
|
||||||
|
cancelConnection,
|
||||||
|
nodeLookup,
|
||||||
|
flowId,
|
||||||
|
panBy,
|
||||||
|
updateConnection,
|
||||||
|
edgeLookup
|
||||||
|
} = store;
|
||||||
|
|
||||||
|
let newEdge: Edge | undefined;
|
||||||
|
let edge = edgeLookup.get(edgeId)!;
|
||||||
|
|
||||||
|
reconnecting = true;
|
||||||
|
onreconnectstart?.(event, edge, type);
|
||||||
|
|
||||||
|
const opposite =
|
||||||
|
type === 'target'
|
||||||
|
? { nodeId: edge.source, handleId: edge.sourceHandle ?? null, type: 'source' as HandleType }
|
||||||
|
: {
|
||||||
|
nodeId: edge.target,
|
||||||
|
handleId: edge.targetHandle ?? null,
|
||||||
|
type: 'target' as HandleType
|
||||||
|
};
|
||||||
|
|
||||||
|
XYHandle.onPointerDown(event, {
|
||||||
|
autoPanOnConnect,
|
||||||
|
connectionMode,
|
||||||
|
connectionRadius,
|
||||||
|
domNode,
|
||||||
|
handleId: opposite.handleId,
|
||||||
|
nodeId: opposite.nodeId,
|
||||||
|
nodeLookup,
|
||||||
|
isTarget: opposite.type === 'target',
|
||||||
|
edgeUpdaterType: opposite.type,
|
||||||
|
lib: 'svelte',
|
||||||
|
flowId,
|
||||||
|
cancelConnection,
|
||||||
|
panBy,
|
||||||
|
isValidConnection,
|
||||||
|
onConnectStart: onconnectstart,
|
||||||
|
onConnectEnd: onconnectend,
|
||||||
|
onConnect: (connection) => {
|
||||||
|
newEdge = { ...edge, ...connection };
|
||||||
|
newEdge = onbeforereconnect ? (onbeforereconnect(newEdge, edge) ?? undefined) : newEdge;
|
||||||
|
|
||||||
|
if (newEdge) {
|
||||||
|
store.edges = store.edges.map((e) => (e.id === edge.id ? (newEdge as Edge) : e));
|
||||||
|
}
|
||||||
|
|
||||||
|
onreconnect?.(edge, connection);
|
||||||
|
},
|
||||||
|
onReconnectEnd: (event, connectionState) => {
|
||||||
|
reconnecting = false;
|
||||||
|
onreconnectend?.(event, edge, opposite.type, connectionState);
|
||||||
|
},
|
||||||
|
updateConnection,
|
||||||
|
getTransform: () => [store.viewport.x, store.viewport.y, store.viewport.zoom],
|
||||||
|
getFromHandle: () => store.connection.fromHandle
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
let offset = $derived(asDomNode ? '-50%' : `-${size * 0.5}px`);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:element
|
||||||
|
this={asDomNode ? 'div' : 'g'}
|
||||||
|
use:portal={asDomNode ? 'edgelabel' : undefined}
|
||||||
|
xmlns={asDomNode ? undefined : 'http://www.w3.org/2000/svg'}
|
||||||
|
class={['svelte-flow__edgeupdater nopan', `svelte-flow__edgeupdater-${type}`, className]}
|
||||||
|
style:position="absolute"
|
||||||
|
style:width={`${size}px`}
|
||||||
|
style:height={`${size}px`}
|
||||||
|
style:transform={position
|
||||||
|
? `translate(calc(${offset} + ${position.x}px), calc(${offset} + ${position.y}px))`
|
||||||
|
: `translate(${offset}, ${offset})`}
|
||||||
|
{style}
|
||||||
|
onpointerdown={onPointerDown}
|
||||||
|
>
|
||||||
|
{#if !reconnecting}
|
||||||
|
{#if children}
|
||||||
|
{@render children()}
|
||||||
|
{:else if !asDomNode}
|
||||||
|
<rect
|
||||||
|
width={size}
|
||||||
|
height={size}
|
||||||
|
x={0}
|
||||||
|
fill="transparent"
|
||||||
|
stroke="transparent"
|
||||||
|
pointer-events="all"
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
</svelte:element>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default as EdgeReconnectAnchor } from './EdgeReconnectAnchor.svelte';
|
||||||
@@ -196,10 +196,10 @@
|
|||||||
The Handle component is the part of a node that can be used to connect nodes.
|
The Handle component is the part of a node that can be used to connect nodes.
|
||||||
-->
|
-->
|
||||||
<div
|
<div
|
||||||
data-handleid={handleId}
|
data-handleid={handleId ?? 'null'}
|
||||||
data-nodeid={nodeId}
|
data-nodeid={nodeId}
|
||||||
data-handlepos={position}
|
data-handlepos={position}
|
||||||
data-id="{store.flowId}-{nodeId}-{handleId}-{type}"
|
data-id="{store.flowId}-{nodeId}-{handleId ?? 'null'}-{type}"
|
||||||
class={[
|
class={[
|
||||||
'svelte-flow__handle',
|
'svelte-flow__handle',
|
||||||
`svelte-flow__handle-${position}`,
|
`svelte-flow__handle-${position}`,
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Snippet } from 'svelte';
|
import type { Snippet } from 'svelte';
|
||||||
|
|
||||||
import portal from '$lib/actions/portal';
|
import { portal } from '$lib/actions/portal';
|
||||||
import { useStore } from '$lib/store';
|
|
||||||
|
|
||||||
let { children }: { children?: Snippet } = $props();
|
let { children }: { children?: Snippet } = $props();
|
||||||
|
|
||||||
const store = useStore();
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div use:portal={{ target: '.svelte-flow__viewport-portal', domNode: store.domNode }}>
|
<div use:portal={'viewport'}>
|
||||||
{@render children?.()}
|
{@render children?.()}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -66,9 +66,6 @@
|
|||||||
nodes = $bindable([]),
|
nodes = $bindable([]),
|
||||||
edges = $bindable([]),
|
edges = $bindable([]),
|
||||||
viewport = $bindable(undefined),
|
viewport = $bindable(undefined),
|
||||||
nodesDraggable = $bindable(true),
|
|
||||||
nodesConnectable = $bindable(true),
|
|
||||||
elementsSelectable = $bindable(true),
|
|
||||||
...props
|
...props
|
||||||
}: SvelteFlowProps & HTMLAttributes<HTMLDivElement> = $props();
|
}: SvelteFlowProps & HTMLAttributes<HTMLDivElement> = $props();
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,9 @@
|
|||||||
edgeTypes,
|
edgeTypes,
|
||||||
colorMode: _colorMode,
|
colorMode: _colorMode,
|
||||||
isValidConnection,
|
isValidConnection,
|
||||||
|
onmove,
|
||||||
|
onmovestart,
|
||||||
|
onmoveend,
|
||||||
onerror,
|
onerror,
|
||||||
ondelete,
|
ondelete,
|
||||||
onbeforedelete,
|
onbeforedelete,
|
||||||
@@ -39,6 +42,10 @@
|
|||||||
onconnect,
|
onconnect,
|
||||||
onconnectstart,
|
onconnectstart,
|
||||||
onconnectend,
|
onconnectend,
|
||||||
|
onbeforereconnect,
|
||||||
|
onreconnect,
|
||||||
|
onreconnectstart,
|
||||||
|
onreconnectend,
|
||||||
onclickconnectstart,
|
onclickconnectstart,
|
||||||
onclickconnectend,
|
onclickconnectend,
|
||||||
clickConnect,
|
clickConnect,
|
||||||
|
|||||||
@@ -18,7 +18,10 @@ import type {
|
|||||||
OnConnect,
|
OnConnect,
|
||||||
OnConnectStart,
|
OnConnectStart,
|
||||||
OnConnectEnd,
|
OnConnectEnd,
|
||||||
ColorModeClass
|
ColorModeClass,
|
||||||
|
OnReconnect,
|
||||||
|
OnRecoonnectStart,
|
||||||
|
OnReconnectEnd
|
||||||
} from '@xyflow/system';
|
} from '@xyflow/system';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
@@ -32,7 +35,8 @@ import type {
|
|||||||
OnDelete,
|
OnDelete,
|
||||||
OnBeforeConnect,
|
OnBeforeConnect,
|
||||||
OnBeforeDelete,
|
OnBeforeDelete,
|
||||||
IsValidConnection
|
IsValidConnection,
|
||||||
|
OnBeforeReconnect
|
||||||
} from '$lib/types';
|
} from '$lib/types';
|
||||||
|
|
||||||
import type { Component } from 'svelte';
|
import type { Component } from 'svelte';
|
||||||
@@ -356,16 +360,22 @@ export type SvelteFlowProps = NodeEvents &
|
|||||||
ondelete?: OnDelete;
|
ondelete?: OnDelete;
|
||||||
/** This handler gets called before the user deletes nodes or edges and provides a way to abort the deletion by returning false. */
|
/** This handler gets called before the user deletes nodes or edges and provides a way to abort the deletion by returning false. */
|
||||||
onbeforedelete?: OnBeforeDelete;
|
onbeforedelete?: OnBeforeDelete;
|
||||||
|
|
||||||
/** This handler gets called when a new edge is created. You can use it to modify the newly created edge. */
|
/** This handler gets called when a new edge is created. You can use it to modify the newly created edge. */
|
||||||
onbeforeconnect?: OnBeforeConnect;
|
onbeforeconnect?: OnBeforeConnect;
|
||||||
|
|
||||||
/** This event gets fired when a connection successfully completes and an edge is created. */
|
/** This event gets fired when a connection successfully completes and an edge is created. */
|
||||||
onconnect?: OnConnect;
|
onconnect?: OnConnect;
|
||||||
/** When a user starts to drag a connection line, this event gets fired. */
|
/** When a user starts to drag a connection line, this event gets fired. */
|
||||||
onconnectstart?: OnConnectStart;
|
onconnectstart?: OnConnectStart;
|
||||||
/** When a user stops dragging a connection line, this event gets fired. */
|
/** When a user stops dragging a connection line, this event gets fired. */
|
||||||
onconnectend?: OnConnectEnd;
|
onconnectend?: OnConnectEnd;
|
||||||
|
/** This event gets fired when after an edge was reconnected*/
|
||||||
|
onreconnect?: OnReconnect;
|
||||||
|
/** This event gets fired when a user starts to reconnect an edge */
|
||||||
|
onreconnectstart?: OnRecoonnectStart;
|
||||||
|
/** This event gets fired when a user stops reconnecting an edge */
|
||||||
|
onreconnectend?: OnReconnectEnd;
|
||||||
|
/** This handler gets called when an edge is reconnected. You can use it to modify the edge before the update is applied. */
|
||||||
|
onbeforereconnect?: OnBeforeReconnect;
|
||||||
/** A connection is started by clicking on a handle */
|
/** A connection is started by clicking on a handle */
|
||||||
onclickconnectstart?: OnConnectStart;
|
onclickconnectstart?: OnConnectStart;
|
||||||
/** A connection is finished by clicking on a handle */
|
/** A connection is finished by clicking on a handle */
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export {
|
|||||||
} from '$lib/components/edges';
|
} from '$lib/components/edges';
|
||||||
export * from '$lib/components/Handle';
|
export * from '$lib/components/Handle';
|
||||||
export * from '$lib/components/EdgeLabel';
|
export * from '$lib/components/EdgeLabel';
|
||||||
|
export * from '$lib/components/EdgeReconnectAnchor';
|
||||||
|
|
||||||
// plugins
|
// plugins
|
||||||
export * from '$lib/plugins/Controls';
|
export * from '$lib/plugins/Controls';
|
||||||
@@ -40,6 +41,9 @@ export * from '$lib/hooks/useNodesData.svelte';
|
|||||||
export * from '$lib/hooks/useInternalNode.svelte';
|
export * from '$lib/hooks/useInternalNode.svelte';
|
||||||
export * from '$lib/hooks/useInitialized.svelte';
|
export * from '$lib/hooks/useInitialized.svelte';
|
||||||
|
|
||||||
|
//actions
|
||||||
|
export * from '$lib/actions/portal';
|
||||||
|
|
||||||
// types
|
// types
|
||||||
export type {
|
export type {
|
||||||
Edge,
|
Edge,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import { getContext } from 'svelte';
|
import { getContext } from 'svelte';
|
||||||
import { Position, getNodeToolbarTransform } from '@xyflow/system';
|
import { Position, getNodeToolbarTransform } from '@xyflow/system';
|
||||||
|
|
||||||
import portal from '$lib/actions/portal';
|
import { portal } from '$lib/actions/portal';
|
||||||
import { useStore } from '$lib/store';
|
import { useStore } from '$lib/store';
|
||||||
import { useSvelteFlow } from '$lib/hooks/useSvelteFlow.svelte';
|
import { useSvelteFlow } from '$lib/hooks/useSvelteFlow.svelte';
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@
|
|||||||
<div
|
<div
|
||||||
data-id={toolbarNodes.reduce((acc, node) => `${acc}${node.id} `, '').trim()}
|
data-id={toolbarNodes.reduce((acc, node) => `${acc}${node.id} `, '').trim()}
|
||||||
class="svelte-flow__node-toolbar"
|
class="svelte-flow__node-toolbar"
|
||||||
use:portal={{ domNode: store.domNode }}
|
use:portal={'root'}
|
||||||
style:position="absolute"
|
style:position="absolute"
|
||||||
style:transform
|
style:transform
|
||||||
style:z-index={zIndex}
|
style:z-index={zIndex}
|
||||||
|
|||||||
@@ -29,7 +29,10 @@ import {
|
|||||||
type ColorModeClass,
|
type ColorModeClass,
|
||||||
type Transform,
|
type Transform,
|
||||||
fitViewport,
|
fitViewport,
|
||||||
type Handle
|
type Handle,
|
||||||
|
type OnReconnect,
|
||||||
|
type OnRecoonnectStart,
|
||||||
|
type OnReconnectEnd
|
||||||
} from '@xyflow/system';
|
} from '@xyflow/system';
|
||||||
|
|
||||||
import DefaultNode from '$lib/components/nodes/DefaultNode.svelte';
|
import DefaultNode from '$lib/components/nodes/DefaultNode.svelte';
|
||||||
@@ -54,7 +57,8 @@ import type {
|
|||||||
IsValidConnection,
|
IsValidConnection,
|
||||||
Edge,
|
Edge,
|
||||||
EdgeLayouted,
|
EdgeLayouted,
|
||||||
InternalNode
|
InternalNode,
|
||||||
|
OnBeforeReconnect
|
||||||
} from '$lib/types';
|
} from '$lib/types';
|
||||||
|
|
||||||
import type { StoreSignals } from './types';
|
import type { StoreSignals } from './types';
|
||||||
@@ -270,16 +274,22 @@ export const getInitialStore = (signals: StoreSignals) => {
|
|||||||
onlyRenderVisibleElements: boolean = $derived(signals.props.onlyRenderVisibleElements ?? false);
|
onlyRenderVisibleElements: boolean = $derived(signals.props.onlyRenderVisibleElements ?? false);
|
||||||
onerror: OnError = $derived(signals.props.onerror ?? devWarn);
|
onerror: OnError = $derived(signals.props.onerror ?? devWarn);
|
||||||
|
|
||||||
ondelete?: OnDelete = $derived(signals.props.ondelete ?? undefined);
|
ondelete?: OnDelete = $derived(signals.props.ondelete);
|
||||||
onbeforedelete?: OnBeforeDelete = $derived(signals.props.onbeforedelete);
|
onbeforedelete?: OnBeforeDelete = $derived(signals.props.onbeforedelete);
|
||||||
|
|
||||||
onbeforeconnect?: OnBeforeConnect = $derived(signals.props.onbeforeconnect);
|
onbeforeconnect?: OnBeforeConnect = $derived(signals.props.onbeforeconnect);
|
||||||
onconnect?: OnConnect = $derived(signals.props.onconnect);
|
onconnect?: OnConnect = $derived(signals.props.onconnect);
|
||||||
onconnectstart?: OnConnectStart = $derived(signals.props.onconnectstart);
|
onconnectstart?: OnConnectStart = $derived(signals.props.onconnectstart);
|
||||||
onconnectend?: OnConnectEnd = $derived(signals.props.onconnectend);
|
onconnectend?: OnConnectEnd = $derived(signals.props.onconnectend);
|
||||||
|
|
||||||
|
onbeforereconnect?: OnBeforeReconnect = $derived(signals.props.onbeforereconnect);
|
||||||
|
onreconnect?: OnReconnect = $derived(signals.props.onreconnect);
|
||||||
|
onreconnectstart?: OnRecoonnectStart = $derived(signals.props.onreconnectstart);
|
||||||
|
onreconnectend?: OnReconnectEnd = $derived(signals.props.onreconnectend);
|
||||||
|
|
||||||
clickConnect?: boolean = $derived(signals.props.clickConnect ?? true);
|
clickConnect?: boolean = $derived(signals.props.clickConnect ?? true);
|
||||||
onclickconnectstart?: OnConnectStart = $derived(signals.props.onclickconnectstart ?? undefined);
|
onclickconnectstart?: OnConnectStart = $derived(signals.props.onclickconnectstart);
|
||||||
onclickconnectend?: OnConnectEnd = $derived(signals.props.onclickconnectend ?? undefined);
|
onclickconnectend?: OnConnectEnd = $derived(signals.props.onclickconnectend);
|
||||||
clickConnectStartHandle: Pick<Handle, 'id' | 'nodeId' | 'type'> | null = $state(null);
|
clickConnectStartHandle: Pick<Handle, 'id' | 'nodeId' | 'type'> | null = $state(null);
|
||||||
|
|
||||||
resolveFitView = async () => {
|
resolveFitView = async () => {
|
||||||
|
|||||||
@@ -36,6 +36,10 @@ export type FitViewOptions<NodeType extends Node = Node> = FitViewOptionsBase<No
|
|||||||
|
|
||||||
export type OnDelete = (params: { nodes: Node[]; edges: Edge[] }) => void;
|
export type OnDelete = (params: { nodes: Node[]; edges: Edge[] }) => void;
|
||||||
export type OnBeforeConnect = (connection: Connection) => Edge | Connection | void;
|
export type OnBeforeConnect = (connection: Connection) => Edge | Connection | void;
|
||||||
|
export type OnBeforeReconnect<EdgeType extends Edge = Edge> = (
|
||||||
|
newEdge: EdgeType,
|
||||||
|
oldEdge: EdgeType
|
||||||
|
) => EdgeType | void;
|
||||||
export type OnBeforeDelete<
|
export type OnBeforeDelete<
|
||||||
NodeType extends Node = Node,
|
NodeType extends Node = Node,
|
||||||
EdgeType extends Edge = Edge
|
EdgeType extends Edge = Edge
|
||||||
|
|||||||
@@ -80,6 +80,19 @@ export type OnConnectStart = (event: MouseEvent | TouchEvent, params: OnConnectS
|
|||||||
export type OnConnect = (connection: Connection) => void;
|
export type OnConnect = (connection: Connection) => void;
|
||||||
export type OnConnectEnd = (event: MouseEvent | TouchEvent, connectionState: FinalConnectionState) => void;
|
export type OnConnectEnd = (event: MouseEvent | TouchEvent, connectionState: FinalConnectionState) => void;
|
||||||
|
|
||||||
|
export type OnReconnect<EdgeType extends EdgeBase = EdgeBase> = (oldEdge: EdgeType, newConnection: Connection) => void;
|
||||||
|
export type OnRecoonnectStart<EdgeType extends EdgeBase = EdgeBase> = (
|
||||||
|
event: MouseEvent | TouchEvent,
|
||||||
|
edge: EdgeType,
|
||||||
|
handleType: HandleType
|
||||||
|
) => void;
|
||||||
|
export type OnReconnectEnd<EdgeType extends EdgeBase = EdgeBase> = (
|
||||||
|
event: MouseEvent | TouchEvent,
|
||||||
|
edge: EdgeType,
|
||||||
|
handleType: HandleType,
|
||||||
|
connectionState: FinalConnectionState
|
||||||
|
) => void;
|
||||||
|
|
||||||
export type IsValidConnection = (edge: EdgeBase | Connection) => boolean;
|
export type IsValidConnection = (edge: EdgeBase | Connection) => boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user