migrate some components

This commit is contained in:
peterkogo
2024-11-13 13:33:49 +01:00
parent 880ed8886b
commit 28e4fad342
31 changed files with 505 additions and 459 deletions
@@ -2,13 +2,10 @@
import { Panel } from '$lib/container/Panel'; import { Panel } from '$lib/container/Panel';
import type { AttributionProps } from './types'; import type { AttributionProps } from './types';
type $$Props = AttributionProps; let { proOptions, position = 'bottom-right' }: AttributionProps = $props();
export let proOptions: $$Props['proOptions'] = undefined;
export let position: $$Props['position'] = 'bottom-right';
</script> </script>
{#if !proOptions?.hideAttribution} {#if proOptions?.hideAttribution}
<Panel <Panel
{position} {position}
class="svelte-flow__attribution" class="svelte-flow__attribution"
@@ -3,22 +3,19 @@
import type { BaseEdgeProps } from './types'; import type { BaseEdgeProps } from './types';
import EdgeLabel from '../EdgeLabel/EdgeLabel.svelte'; import EdgeLabel from '../EdgeLabel/EdgeLabel.svelte';
type $$Props = BaseEdgeProps; let {
id,
export let id: $$Props['id'] = undefined; path,
export let path: $$Props['path']; label,
export let label: $$Props['label'] = undefined; labelX,
export let labelX: $$Props['labelX'] = undefined; labelY,
export let labelY: $$Props['labelY'] = undefined; labelStyle,
export let labelStyle: $$Props['labelStyle'] = undefined; markerStart,
export let markerStart: $$Props['markerStart'] = undefined; markerEnd,
export let markerEnd: $$Props['markerEnd'] = undefined; style,
export let style: $$Props['style'] = undefined; interactionWidth = 20,
export let interactionWidth: $$Props['interactionWidth'] = 20; class: className
let className: $$Props['class'] = undefined; }: BaseEdgeProps = $props();
export { className as class };
let interactionWidthValue = interactionWidth === undefined ? 20 : interactionWidth;
</script> </script>
<path <path
@@ -31,11 +28,11 @@
{style} {style}
/> />
{#if interactionWidthValue} {#if interactionWidth > 0}
<path <path
d={path} d={path}
stroke-opacity={0} stroke-opacity={0}
stroke-width={interactionWidthValue} stroke-width={interactionWidth}
fill="none" fill="none"
class="svelte-flow__edge-interaction" class="svelte-flow__edge-interaction"
/> />
@@ -1,7 +1,6 @@
<script lang="ts"> <script lang="ts">
import cc from 'classcat'; import cc from 'classcat';
import type { Snippet } from 'svelte';
import { useStore } from '$lib/store';
import { import {
ConnectionLineType, ConnectionLineType,
getBezierPath, getBezierPath,
@@ -10,50 +9,61 @@
getStraightPath getStraightPath
} from '@xyflow/system'; } from '@xyflow/system';
export let containerStyle: string = ''; import { useStore } from '$lib/store';
export let style: string = '';
export let isCustomComponent: boolean = false; let {
containerStyle = '',
style = '',
connectionLine
}: {
containerStyle: string;
style: string;
connectionLine?: Snippet;
} = $props();
const { width, height, connection, connectionLineType } = useStore(); const { width, height, connection, connectionLineType } = useStore();
let path: string | null = null; let path = $derived.by(() => {
if (!$connection.inProgress) {
return '';
}
$: if ($connection.inProgress && !isCustomComponent) {
const { from, to, fromPosition, toPosition } = $connection;
const pathParams = { const pathParams = {
sourceX: from.x, sourceX: $connection.from.x,
sourceY: from.y, sourceY: $connection.from.y,
sourcePosition: fromPosition, sourcePosition: $connection.fromPosition,
targetX: to.x, targetX: $connection.to.x,
targetY: to.y, targetY: $connection.to.y,
targetPosition: toPosition targetPosition: $connection.toPosition
}; };
switch ($connectionLineType) { switch ($connectionLineType) {
case ConnectionLineType.Bezier: case ConnectionLineType.Bezier: {
[path] = getBezierPath(pathParams); const [path] = getBezierPath(pathParams);
break; return path;
}
case ConnectionLineType.Straight: {
const [path] = getStraightPath(pathParams);
return path;
}
case ConnectionLineType.Step: case ConnectionLineType.Step:
[path] = getSmoothStepPath({ case ConnectionLineType.SmoothStep: {
const [path] = getSmoothStepPath({
...pathParams, ...pathParams,
borderRadius: 0 borderRadius: $connectionLineType === ConnectionLineType.Step ? 0 : undefined
}); });
break; return path;
case ConnectionLineType.SmoothStep: }
[path] = getSmoothStepPath(pathParams);
break;
default:
[path] = getStraightPath(pathParams);
} }
} });
</script> </script>
{#if $connection.inProgress} {#if $connection.inProgress}
<svg width={$width} height={$height} class="svelte-flow__connectionline" style={containerStyle}> <svg width={$width} height={$height} class="svelte-flow__connectionline" style={containerStyle}>
<g class={cc(['svelte-flow__connection', getConnectionStatus($connection.isValid)])}> <g class={cc(['svelte-flow__connection', getConnectionStatus($connection.isValid)])}>
<slot name="connectionLine" /> {#if connectionLine}
<!-- slot fallbacks do not work if slots are forwarded in parent --> {@render connectionLine()}
{#if !isCustomComponent} {:else}
<path d={path} {style} fill="none" class="svelte-flow__connection-path" /> <path d={path} {style} fill="none" class="svelte-flow__connection-path" />
{/if} {/if}
</g> </g>
@@ -1,13 +1,20 @@
<script lang="ts"> <script lang="ts">
import { getContext } from 'svelte'; import { getContext, type Snippet } from 'svelte';
import { EdgeLabelRenderer } from '$lib/components/EdgeLabelRenderer'; import { EdgeLabelRenderer } from '$lib/components/EdgeLabelRenderer';
import { useHandleEdgeSelect } from '$lib/hooks/useHandleEdgeSelect'; import { useHandleEdgeSelect } from '$lib/hooks/useHandleEdgeSelect';
import type { BaseEdgeProps } from '$lib/components/BaseEdge/types';
export let style: BaseEdgeProps['labelStyle'] = undefined; let {
export let x: BaseEdgeProps['labelX'] = undefined; style,
export let y: BaseEdgeProps['labelY'] = undefined; x,
y,
children
}: {
style?: string;
x?: number;
y?: number;
children?: Snippet;
} = $props();
const handleEdgeSelect = useHandleEdgeSelect(); const handleEdgeSelect = useHandleEdgeSelect();
@@ -21,11 +28,11 @@
style={'pointer-events: all;' + style} style={'pointer-events: all;' + style}
role="button" role="button"
tabindex="-1" tabindex="-1"
on:keyup={() => {}} onkeyup={() => {}}
on:click={() => { onclick={() => {
if (id) handleEdgeSelect(id); if (id) handleEdgeSelect(id);
}} }}
> >
<slot /> {@render children?.()}
</div> </div>
</EdgeLabelRenderer> </EdgeLabelRenderer>
@@ -1,10 +1,13 @@
<script lang="ts"> <script lang="ts">
import type { Snippet } from 'svelte';
import portal from '$lib/actions/portal'; import portal from '$lib/actions/portal';
import { useStore } from '$lib/store'; import { useStore } from '$lib/store';
const { domNode } = useStore(); const { domNode } = useStore();
let { children }: { children?: Snippet } = $props();
</script> </script>
<div use:portal={{ target: '.svelte-flow__edgelabel-renderer', domNode: $domNode }}> <div use:portal={{ target: '.svelte-flow__edgelabel-renderer', domNode: $domNode }}>
<slot /> {@render children?.()}
</div> </div>
@@ -40,6 +40,8 @@
export let ariaLabel: $$Props['ariaLabel'] = undefined; export let ariaLabel: $$Props['ariaLabel'] = undefined;
export let interactionWidth: $$Props['interactionWidth'] = undefined; export let interactionWidth: $$Props['interactionWidth'] = undefined;
// TODO SVELTE5
// @ todo: support edge updates // @ todo: support edge updates
let className: string = ''; let className: string = '';
export { className as class }; export { className as class };
@@ -1,4 +1,5 @@
<script lang="ts"> <script lang="ts">
//TODO SVELTE5
import { getContext } from 'svelte'; import { getContext } from 'svelte';
import type { Writable } from 'svelte/store'; import type { Writable } from 'svelte/store';
import cc from 'classcat'; import cc from 'classcat';
@@ -1,22 +1,23 @@
<script lang="ts"> <script lang="ts">
import { get } from 'svelte/store';
import { import {
shortcut, shortcut,
type ShortcutEventDetail, type ShortcutEventDetail,
type ShortcutModifierDefinition type ShortcutModifierDefinition
} from '@svelte-put/shortcut'; } from '@svelte-put/shortcut';
import { isInputDOMNode, isMacOs } from '@xyflow/system'; import { getElementsToRemove, isInputDOMNode, isMacOs } from '@xyflow/system';
import { useStore } from '$lib/store'; import { useStore } from '$lib/store';
import type { KeyHandlerProps } from './types'; import type { KeyHandlerProps } from './types';
import type { KeyDefinition, KeyDefinitionObject } from '$lib/types'; import type { KeyDefinition, KeyDefinitionObject } from '$lib/types';
type $$Props = KeyHandlerProps; let {
selectionKey = 'Shift',
export let selectionKey: $$Props['selectionKey'] = 'Shift'; multiSelectionKey = isMacOs() ? 'Meta' : 'Control',
export let multiSelectionKey: $$Props['multiSelectionKey'] = isMacOs() ? 'Meta' : 'Control'; deleteKey = 'Backspace',
export let deleteKey: $$Props['deleteKey'] = 'Backspace'; panActivationKey = ' ',
export let panActivationKey: $$Props['panActivationKey'] = ' '; zoomActivationKey = isMacOs() ? 'Meta' : 'Control'
export let zoomActivationKey: $$Props['zoomActivationKey'] = isMacOs() ? 'Meta' : 'Control'; }: KeyHandlerProps = $props();
const { const {
selectionKeyPressed, selectionKeyPressed,
@@ -24,7 +25,11 @@
deleteKeyPressed, deleteKeyPressed,
panActivationKeyPressed, panActivationKeyPressed,
zoomActivationKeyPressed, zoomActivationKeyPressed,
selectionRect selectionRect,
onbeforedelete,
ondelete,
nodes: _nodes,
edges: _edges
} = useStore(); } = useStore();
function isKeyObject(key?: KeyDefinition | null): key is KeyDefinitionObject { function isKeyObject(key?: KeyDefinition | null): key is KeyDefinitionObject {
@@ -69,6 +74,31 @@
panActivationKeyPressed.set(false); panActivationKeyPressed.set(false);
zoomActivationKeyPressed.set(false); zoomActivationKeyPressed.set(false);
} }
async function handleDelete() {
const nodes = get(_nodes);
const edges = get(_edges);
const selectedNodes = nodes.filter((node) => node.selected);
const selectedEdges = edges.filter((edge) => edge.selected);
const { nodes: matchingNodes, edges: matchingEdges } = await getElementsToRemove({
nodesToRemove: selectedNodes,
edgesToRemove: selectedEdges,
nodes,
edges,
onBeforeDelete: get(onbeforedelete)
});
if (matchingNodes.length || matchingEdges.length) {
_nodes.update((nds) => nds.filter((node) => !matchingNodes.some((mN) => mN.id === node.id)));
_edges.update((eds) => eds.filter((edge) => !matchingEdges.some((mE) => mE.id === edge.id)));
get(ondelete)?.({
nodes: matchingNodes,
edges: matchingEdges
});
}
}
</script> </script>
<svelte:window <svelte:window
@@ -98,6 +128,7 @@
detail.originalEvent.shiftKey; detail.originalEvent.shiftKey;
if (!isModifierKey && !isInputDOMNode(detail.originalEvent)) { if (!isModifierKey && !isInputDOMNode(detail.originalEvent)) {
deleteKeyPressed.set(true); deleteKeyPressed.set(true);
handleDelete();
} }
}), }),
type: 'keydown' type: 'keydown'
@@ -1,37 +1,39 @@
<script lang="ts"> <script lang="ts">
import { createEventDispatcher } from 'svelte';
import { getInternalNodesBounds, isNumeric, type Rect } from '@xyflow/system'; import { getInternalNodesBounds, isNumeric, type Rect } from '@xyflow/system';
import { useStore } from '$lib/store'; import { useStore } from '$lib/store';
import { Selection } from '$lib/components/Selection'; import { Selection } from '$lib/components/Selection';
import drag from '$lib/actions/drag'; import drag from '$lib/actions/drag';
import type { Node, NodeEventMap } from '$lib/types';
import type { NodeSelectionProps } from './types';
let {
onnodedrag,
onnodedragstart,
onnodedragstop,
onselectionclick,
onselectioncontextmenu
}: NodeSelectionProps = $props();
const store = useStore(); const store = useStore();
const { selectionRectMode, nodes, nodeLookup } = store; const { selectionRectMode, nodes, nodeLookup } = store;
const dispatch = createEventDispatcher< let bounds: Rect | null = $derived.by(() => {
NodeEventMap & { if ($selectionRectMode === 'nodes') {
selectioncontextmenu: { nodes: Node[]; event: MouseEvent | TouchEvent }; $nodes;
selectionclick: { nodes: Node[]; event: MouseEvent | TouchEvent }; return getInternalNodesBounds($nodeLookup, { filter: (node) => !!node.selected });
} }
>(); return null;
});
let bounds: Rect | null = null; function oncontextmenu(event: MouseEvent | TouchEvent) {
const selectedNodes = $nodes.filter((n) => n.selected);
$: if ($selectionRectMode === 'nodes') { onselectioncontextmenu?.({ nodes: selectedNodes, event });
bounds = getInternalNodesBounds($nodeLookup, { filter: (node) => !!node.selected });
$nodes;
} }
function onContextMenu(event: MouseEvent | TouchEvent) { function onclick(event: MouseEvent | TouchEvent) {
const selectedNodes = $nodes.filter((n) => n.selected); const selectedNodes = $nodes.filter((n) => n.selected);
dispatch('selectioncontextmenu', { nodes: selectedNodes, event }); onselectionclick?.({ nodes: selectedNodes, event });
}
function onClick(event: MouseEvent | TouchEvent) {
const selectedNodes = $nodes.filter((n) => n.selected);
dispatch('selectionclick', { nodes: selectedNodes, event });
} }
</script> </script>
@@ -43,20 +45,20 @@
disabled: false, disabled: false,
store, store,
onDrag: (event, _, __, nodes) => { onDrag: (event, _, __, nodes) => {
dispatch('nodedrag', { event, targetNode: null, nodes }); onnodedrag?.({ event, targetNode: null, nodes });
}, },
onDragStart: (event, _, __, nodes) => { onDragStart: (event, _, __, nodes) => {
dispatch('nodedragstart', { event, targetNode: null, nodes }); onnodedragstart?.({ event, targetNode: null, nodes });
}, },
onDragStop: (event, _, __, nodes) => { onDragStop: (event, _, __, nodes) => {
dispatch('nodedragstop', { event, targetNode: null, nodes }); onnodedragstop?.({ event, targetNode: null, nodes });
} }
}} }}
on:contextmenu={onContextMenu} {oncontextmenu}
on:click={onClick} {onclick}
role="button" role="button"
tabindex="-1" tabindex="-1"
on:keyup={() => {}} onkeyup={() => {}}
> >
<Selection width="100%" height="100%" x={0} y={0} /> <Selection width="100%" height="100%" x={0} y={0} />
</div> </div>
@@ -0,0 +1,4 @@
import type { NodeEvents, NodeSelectionEvents } from '$lib/types';
export type NodeSelectionProps = NodeSelectionEvents &
Pick<NodeEvents, 'onnodedrag' | 'onnodedragstart' | 'onnodedragstop'>;
@@ -1,7 +1,5 @@
<svelte:options immutable />
<script lang="ts"> <script lang="ts">
import { setContext, onDestroy, createEventDispatcher } from 'svelte'; import { setContext, onDestroy } from 'svelte';
import { get, writable } from 'svelte/store'; import { get, writable } from 'svelte/store';
import cc from 'classcat'; import cc from 'classcat';
import { errorMessages, Position } from '@xyflow/system'; import { errorMessages, Position } from '@xyflow/system';
@@ -11,42 +9,48 @@
import DefaultNode from '$lib/components/nodes/DefaultNode.svelte'; import DefaultNode from '$lib/components/nodes/DefaultNode.svelte';
import type { NodeWrapperProps } from './types'; import type { NodeWrapperProps } from './types';
import { getNodeInlineStyleDimensions } from './utils'; import { getNodeInlineStyleDimensions } from './utils';
import type { NodeEventMap } from '$lib/types'; import type { NodeEvents } from '$lib/types';
interface $$Props extends NodeWrapperProps {} let {
node,
export let node: $$Props['node']; id,
export let id: $$Props['id']; data = {},
export let data: $$Props['data'] = {}; selected = false,
export let selected: $$Props['selected'] = false; draggable,
export let draggable: $$Props['draggable'] = undefined; selectable,
export let selectable: $$Props['selectable'] = undefined; deletable,
export let connectable: $$Props['connectable'] = true; connectable = true,
export let deletable: $$Props['deletable'] = true; hidden = false,
export let hidden: $$Props['hidden'] = false; dragging = false,
export let dragging: boolean = false; resizeObserver = null,
export let resizeObserver: $$Props['resizeObserver'] = null; style,
export let style: $$Props['style'] = undefined; class: className,
export let type: $$Props['type'] = 'default'; type = 'default',
export let isParent: $$Props['isParent'] = false; isParent = false,
export let positionX: $$Props['positionX']; parentId,
export let positionY: $$Props['positionY']; positionX,
export let sourcePosition: $$Props['sourcePosition'] = undefined; positionY,
export let targetPosition: $$Props['targetPosition'] = undefined; sourcePosition,
export let zIndex: $$Props['zIndex']; targetPosition,
export let measuredWidth: $$Props['measuredWidth'] = undefined; zIndex,
export let measuredHeight: $$Props['measuredHeight'] = undefined; measuredWidth,
export let initialWidth: $$Props['initialWidth'] = undefined; measuredHeight,
export let initialHeight: $$Props['initialHeight'] = undefined; initialWidth,
export let width: $$Props['width'] = undefined; initialHeight,
export let height: $$Props['height'] = undefined; width,
export let dragHandle: $$Props['dragHandle'] = undefined; height,
export let initialized: $$Props['initialized'] = false; dragHandle,
export let parentId: $$Props['parentId'] = undefined; initialized = false,
export let nodeClickDistance: $$Props['nodeClickDistance'] = undefined; nodeClickDistance,
onnodeclick,
let className: string = ''; onnodedrag,
export { className as class }; onnodedragstart,
onnodedragstop,
onnodemouseenter,
onnodemouseleave,
onnodemousemove,
onnodecontextmenu
}: NodeWrapperProps & NodeEvents = $props();
const store = useStore(); const store = useStore();
const { const {
@@ -57,78 +61,85 @@
updateNodeInternals updateNodeInternals
} = store; } = store;
let nodeRef: HTMLDivElement; let nodeRef: HTMLDivElement | null = $state(null);
let prevNodeRef: HTMLDivElement | null = null; let prevNodeRef: HTMLDivElement | null = null;
const dispatchNodeEvent = createEventDispatcher<NodeEventMap>();
const connectableStore = writable(connectable); const connectableStore = writable(connectable);
let prevType: string | undefined = undefined;
let prevSourcePosition: Position | undefined = undefined;
let prevTargetPosition: Position | undefined = undefined;
$: nodeType = type || 'default'; let prevType: string | undefined;
$: nodeTypeValid = !!$nodeTypes[nodeType]; let prevSourcePosition: Position | undefined;
$: nodeComponent = $nodeTypes[nodeType] || DefaultNode; let prevTargetPosition: Position | undefined;
$: { let NodeComponent = $derived($nodeTypes[type] ?? DefaultNode);
if (!nodeTypeValid) {
console.warn('003', errorMessages['error003'](type!)); if (process.env.NODE_ENV === 'development') {
} $effect(() => {
const valid = !!$nodeTypes[type];
if (!valid) {
console.warn('003', errorMessages['error003'](type!));
}
});
} }
$: inlineStyleDimensions = getNodeInlineStyleDimensions({ let inlineStyleDimensions = $derived(
width, getNodeInlineStyleDimensions({
height, width,
initialWidth, height,
initialHeight, initialWidth,
measuredWidth, initialHeight,
measuredHeight measuredWidth,
measuredHeight
})
);
$effect(() => {
connectableStore.set(!!connectable);
}); });
$: { $effect(() => {
connectableStore.set(!!connectable);
}
$: {
// if type, sourcePosition or targetPosition changes, // if type, sourcePosition or targetPosition changes,
// we need to re-calculate the handle positions // we need to re-calculate the handle positions
const doUpdate = const doUpdate =
(prevType && nodeType !== prevType) || (prevType && type !== prevType) ||
(prevSourcePosition && sourcePosition !== prevSourcePosition) || (prevSourcePosition && sourcePosition !== prevSourcePosition) ||
(prevTargetPosition && targetPosition !== prevTargetPosition); (prevTargetPosition && targetPosition !== prevTargetPosition);
if (doUpdate) { if (doUpdate && nodeRef !== null) {
requestAnimationFrame(() => requestAnimationFrame(() => {
updateNodeInternals( if (nodeRef !== null) {
new Map([ updateNodeInternals(
[ new Map([
id, [
{
id, id,
nodeElement: nodeRef, {
force: true id,
} nodeElement: nodeRef,
] force: true
]) }
) ]
); ])
);
}
});
} }
prevType = nodeType; prevType = type;
prevSourcePosition = sourcePosition; prevSourcePosition = sourcePosition;
prevTargetPosition = targetPosition; prevTargetPosition = targetPosition;
} });
setContext('svelteflow__node_id', id); setContext('svelteflow__node_id', id);
setContext('svelteflow__node_connectable', connectableStore); setContext('svelteflow__node_connectable', connectableStore);
$: { // TODO: extract this part!
if (resizeObserver && (nodeRef !== prevNodeRef || !initialized)) { $effect(() => {
// TODO: HOLY MOLY! changing the order of the initialized breaks effect subscriptions
if (resizeObserver && (!initialized || nodeRef !== prevNodeRef)) {
prevNodeRef && resizeObserver.unobserve(prevNodeRef); prevNodeRef && resizeObserver.unobserve(prevNodeRef);
nodeRef && resizeObserver.observe(nodeRef); nodeRef && resizeObserver.observe(nodeRef);
prevNodeRef = nodeRef; prevNodeRef = nodeRef;
} }
} });
onDestroy(() => { onDestroy(() => {
if (prevNodeRef) { if (prevNodeRef) {
@@ -143,12 +154,12 @@
handleNodeSelection(id); handleNodeSelection(id);
} }
dispatchNodeEvent('nodeclick', { node: node.internals.userNode, event }); onnodeclick?.({ node: node.internals.userNode, event });
} }
</script> </script>
<!-- svelte-ignore a11y-click-events-have-key-events --> <!-- svelte-ignore a11y_click_events_have_key_events -->
<!-- svelte-ignore a11y-no-static-element-interactions --> <!-- svelte-ignore a11y_no_static_element_interactions -->
{#if !hidden} {#if !hidden}
<div <div
use:drag={{ use:drag={{
@@ -160,19 +171,19 @@
nodeClickDistance, nodeClickDistance,
onNodeMouseDown: handleNodeSelection, onNodeMouseDown: handleNodeSelection,
onDrag: (event, _, targetNode, nodes) => { onDrag: (event, _, targetNode, nodes) => {
dispatchNodeEvent('nodedrag', { event, targetNode, nodes }); onnodedrag?.({ event, targetNode, nodes });
}, },
onDragStart: (event, _, targetNode, nodes) => { onDragStart: (event, _, targetNode, nodes) => {
dispatchNodeEvent('nodedragstart', { event, targetNode, nodes }); onnodedragstart?.({ event, targetNode, nodes });
}, },
onDragStop: (event, _, targetNode, nodes) => { onDragStop: (event, _, targetNode, nodes) => {
dispatchNodeEvent('nodedragstop', { event, targetNode, nodes }); onnodedragstop?.({ event, targetNode, nodes });
}, },
store store
}} }}
bind:this={nodeRef} bind:this={nodeRef}
data-id={id} data-id={id}
class={cc(['svelte-flow__node', `svelte-flow__node-${nodeType}`, className])} class={cc(['svelte-flow__node', `svelte-flow__node-${type}`, className])}
class:dragging class:dragging
class:selected class:selected
class:draggable class:draggable
@@ -184,14 +195,13 @@
style:transform="translate({positionX}px, {positionY}px)" style:transform="translate({positionX}px, {positionY}px)"
style:visibility={initialized ? 'visible' : 'hidden'} style:visibility={initialized ? 'visible' : 'hidden'}
style="{style ?? ''};{inlineStyleDimensions.width}{inlineStyleDimensions.height}" style="{style ?? ''};{inlineStyleDimensions.width}{inlineStyleDimensions.height}"
on:click={onSelectNodeHandler} onclick={onSelectNodeHandler}
on:mouseenter={(event) => dispatchNodeEvent('nodemouseenter', { node, event })} onmouseenter={onnodemouseenter ? (event) => onnodemouseenter({ node, event }) : undefined}
on:mouseleave={(event) => dispatchNodeEvent('nodemouseleave', { node, event })} onmouseleave={onnodemouseleave ? (event) => onnodemouseleave({ node, event }) : undefined}
on:mousemove={(event) => dispatchNodeEvent('nodemousemove', { node, event })} onmousemove={onnodemousemove ? (event) => onnodemousemove({ node, event }) : undefined}
on:contextmenu={(event) => dispatchNodeEvent('nodecontextmenu', { node, event })} oncontextmenu={onnodecontextmenu ? (event) => onnodecontextmenu({ node, event }) : undefined}
> >
<svelte:component <NodeComponent
this={nodeComponent}
{data} {data}
{id} {id}
{selected} {selected}
@@ -204,7 +214,7 @@
{draggable} {draggable}
{dragHandle} {dragHandle}
{parentId} {parentId}
type={nodeType} {type}
isConnectable={$connectableStore} isConnectable={$connectableStore}
positionAbsoluteX={positionX} positionAbsoluteX={positionX}
positionAbsoluteY={positionY} positionAbsoluteY={positionY}
@@ -34,5 +34,5 @@ export type NodeWrapperProps = Pick<
zIndex: number; zIndex: number;
node: InternalNode; node: InternalNode;
initialized: boolean; initialized: boolean;
nodeClickDistance?: number; nodeClickDistance: number;
}; };
@@ -1,9 +1,17 @@
<script lang="ts"> <script lang="ts">
export let x: number | null = 0; let {
export let y: number | null = 0; x = 0,
export let width: number | string | null = 0; y = 0,
export let height: number | string | null = 0; width = 0,
export let isVisible: boolean = true; height = 0,
isVisible = true
}: {
x?: number | null;
y?: number | null;
width?: number | string | null;
height?: number | string | null;
isVisible?: boolean;
} = $props();
</script> </script>
{#if isVisible} {#if isVisible}
@@ -12,7 +20,7 @@
style:width={typeof width === 'string' ? width : `${width}px`} style:width={typeof width === 'string' ? width : `${width}px`}
style:height={typeof height === 'string' ? height : `${height}px`} style:height={typeof height === 'string' ? height : `${height}px`}
style:transform={`translate(${x}px, ${y}px)`} style:transform={`translate(${x}px, ${y}px)`}
/> ></div>
{/if} {/if}
<style> <style>
@@ -1,10 +1,14 @@
<script lang="ts"> <script lang="ts">
import type { Snippet } from 'svelte';
import portal from '$lib/actions/portal'; import portal from '$lib/actions/portal';
import { useStore } from '$lib/store'; import { useStore } from '$lib/store';
let { children }: { children?: Snippet } = $props();
const { domNode } = useStore(); const { domNode } = useStore();
</script> </script>
<div use:portal={{ target: '.svelte-flow__viewport-portal', domNode: $domNode }}> <div use:portal={{ target: '.svelte-flow__viewport-portal', domNode: $domNode }}>
<slot /> {@render children?.()}
</div> </div>
@@ -2,36 +2,37 @@
import { getBezierPath } from '@xyflow/system'; import { getBezierPath } from '@xyflow/system';
import type { BezierEdgeProps } from '$lib/types'; import type { BezierEdgeProps } from '$lib/types';
import { BaseEdge } from '$lib/components/BaseEdge'; import { BaseEdge } from '$lib/components/BaseEdge';
type $$Props = BezierEdgeProps; let {
id,
export let id: $$Props['id'] = undefined; label,
export let label: $$Props['label'] = undefined; labelStyle,
export let labelStyle: $$Props['labelStyle'] = undefined; style,
export let style: $$Props['style'] = undefined; markerStart,
export let markerStart: $$Props['markerStart'] = undefined; markerEnd,
export let markerEnd: $$Props['markerEnd'] = undefined; pathOptions,
export let pathOptions: $$Props['pathOptions'] = undefined; interactionWidth,
export let interactionWidth: $$Props['interactionWidth'] = undefined;
export let sourceX: $$Props['sourceX'];
export let sourceY: $$Props['sourceY'];
export let sourcePosition: $$Props['sourcePosition'];
export let targetX: $$Props['targetX'];
export let targetY: $$Props['targetY'];
export let targetPosition: $$Props['targetPosition'];
$: [path, labelX, labelY] = getBezierPath({
sourceX, sourceX,
sourceY, sourceY,
sourcePosition,
targetX, targetX,
targetY, targetY,
sourcePosition, targetPosition
targetPosition, }: BezierEdgeProps = $props();
curvature: pathOptions?.curvature
}); let [path, labelX, labelY] = $derived(
getBezierPath({
sourceX,
sourceY,
targetX,
targetY,
sourcePosition,
targetPosition,
curvature: pathOptions?.curvature
})
);
</script> </script>
<BaseEdge <BaseEdge
@@ -3,35 +3,31 @@
import type { EdgeProps } from '$lib/types'; import type { EdgeProps } from '$lib/types';
import { BaseEdge } from '$lib/components/BaseEdge'; import { BaseEdge } from '$lib/components/BaseEdge';
let {
type $$Props = EdgeProps;
export let label: $$Props['label'] = undefined;
export let labelStyle: $$Props['labelStyle'] = undefined;
export let style: $$Props['style'] = undefined;
export let markerStart: $$Props['markerStart'] = undefined;
export let markerEnd: $$Props['markerEnd'] = undefined;
export let interactionWidth: $$Props['interactionWidth'] = undefined;
export let sourceX: $$Props['sourceX'];
export let sourceY: $$Props['sourceY'];
export let sourcePosition: $$Props['sourcePosition'];
export let targetX: $$Props['targetX'];
export let targetY: $$Props['targetY'];
export let targetPosition: $$Props['targetPosition'];
$: [path, labelX, labelY] = getBezierPath({
sourceX, sourceX,
sourceY, sourceY,
sourcePosition,
targetX, targetX,
targetY, targetY,
sourcePosition, targetPosition,
targetPosition label,
}); labelStyle,
markerStart,
markerEnd,
interactionWidth,
style
}: EdgeProps = $props();
// this is a workaround for suppressing the warning about unused props let [path, labelX, labelY] = $derived(
$$restProps; getBezierPath({
sourceX,
sourceY,
targetX,
targetY,
sourcePosition,
targetPosition
})
);
</script> </script>
<BaseEdge <BaseEdge
@@ -4,35 +4,35 @@
import type { SmoothStepEdgeProps } from '$lib/types'; import type { SmoothStepEdgeProps } from '$lib/types';
import { BaseEdge } from '$lib/components/BaseEdge'; import { BaseEdge } from '$lib/components/BaseEdge';
type $$Props = SmoothStepEdgeProps; let {
id,
export let id: $$Props['id'] = undefined; label,
export let label: $$Props['label'] = undefined; labelStyle,
export let labelStyle: $$Props['labelStyle'] = undefined; style,
export let style: $$Props['style'] = undefined; markerStart,
export let markerStart: $$Props['markerStart'] = undefined; markerEnd,
export let markerEnd: $$Props['markerEnd'] = undefined; pathOptions,
export let pathOptions: $$Props['pathOptions'] = undefined; interactionWidth,
export let interactionWidth: $$Props['interactionWidth'] = undefined;
export let sourceX: $$Props['sourceX'];
export let sourceY: $$Props['sourceY'];
export let sourcePosition: $$Props['sourcePosition'];
export let targetX: $$Props['targetX'];
export let targetY: $$Props['targetY'];
export let targetPosition: $$Props['targetPosition'];
$: [path, labelX, labelY] = getSmoothStepPath({
sourceX, sourceX,
sourceY, sourceY,
sourcePosition,
targetX, targetX,
targetY, targetY,
sourcePosition, targetPosition
targetPosition, }: SmoothStepEdgeProps = $props();
borderRadius: pathOptions?.borderRadius,
offset: pathOptions?.offset let [path, labelX, labelY] = $derived(
}); getSmoothStepPath({
sourceX,
sourceY,
targetX,
targetY,
sourcePosition,
targetPosition,
borderRadius: pathOptions?.borderRadius,
offset: pathOptions?.offset
})
);
</script> </script>
<BaseEdge <BaseEdge
@@ -4,34 +4,31 @@
import type { EdgeProps } from '$lib/types'; import type { EdgeProps } from '$lib/types';
import { BaseEdge } from '$lib/components/BaseEdge'; import { BaseEdge } from '$lib/components/BaseEdge';
type $$Props = EdgeProps; let {
export let label: $$Props['label'] = undefined;
export let labelStyle: $$Props['labelStyle'] = undefined;
export let style: $$Props['style'] = undefined;
export let markerStart: $$Props['markerStart'] = undefined;
export let markerEnd: $$Props['markerEnd'] = undefined;
export let interactionWidth: $$Props['interactionWidth'] = undefined;
export let sourceX: $$Props['sourceX'];
export let sourceY: $$Props['sourceY'];
export let sourcePosition: $$Props['sourcePosition'];
export let targetX: $$Props['targetX'];
export let targetY: $$Props['targetY'];
export let targetPosition: $$Props['targetPosition'];
$: [path, labelX, labelY] = getSmoothStepPath({
sourceX, sourceX,
sourceY, sourceY,
sourcePosition,
targetX, targetX,
targetY, targetY,
sourcePosition, targetPosition,
targetPosition label,
}); labelStyle,
markerStart,
markerEnd,
interactionWidth,
style
}: EdgeProps = $props();
// this is a workaround for suppressing the warning about unused props let [path, labelX, labelY] = $derived(
$$restProps; getSmoothStepPath({
sourceX,
sourceY,
targetX,
targetY,
sourcePosition,
targetPosition
})
);
</script> </script>
<BaseEdge <BaseEdge
@@ -4,35 +4,35 @@
import type { StepEdgeProps } from '$lib/types'; import type { StepEdgeProps } from '$lib/types';
import { BaseEdge } from '$lib/components/BaseEdge'; import { BaseEdge } from '$lib/components/BaseEdge';
type $$Props = StepEdgeProps; let {
id,
export let id: $$Props['id'] = undefined; label,
export let label: $$Props['label'] = undefined; labelStyle,
export let labelStyle: $$Props['labelStyle'] = undefined; style,
export let style: $$Props['style'] = undefined; markerStart,
export let markerStart: $$Props['markerStart'] = undefined; markerEnd,
export let markerEnd: $$Props['markerEnd'] = undefined; pathOptions,
export let pathOptions: $$Props['pathOptions'] = undefined; interactionWidth,
export let interactionWidth: $$Props['interactionWidth'] = undefined;
export let sourceX: $$Props['sourceX'];
export let sourceY: $$Props['sourceY'];
export let sourcePosition: $$Props['sourcePosition'];
export let targetX: $$Props['targetX'];
export let targetY: $$Props['targetY'];
export let targetPosition: $$Props['targetPosition'];
$: [path, labelX, labelY] = getSmoothStepPath({
sourceX, sourceX,
sourceY, sourceY,
sourcePosition,
targetX, targetX,
targetY, targetY,
sourcePosition, targetPosition
targetPosition, }: StepEdgeProps = $props();
borderRadius: 0,
offset: pathOptions?.offset let [path, labelX, labelY] = $derived(
}); getSmoothStepPath({
sourceX,
sourceY,
targetX,
targetY,
sourcePosition,
targetPosition,
borderRadius: 0,
offset: pathOptions?.offset
})
);
</script> </script>
<BaseEdge <BaseEdge
@@ -4,35 +4,32 @@
import type { EdgeProps } from '$lib/types'; import type { EdgeProps } from '$lib/types';
import { BaseEdge } from '$lib/components/BaseEdge'; import { BaseEdge } from '$lib/components/BaseEdge';
type $$Props = EdgeProps; let {
export let label: $$Props['label'] = undefined;
export let labelStyle: $$Props['labelStyle'] = undefined;
export let style: $$Props['style'] = undefined;
export let markerStart: $$Props['markerStart'] = undefined;
export let markerEnd: $$Props['markerEnd'] = undefined;
export let interactionWidth: $$Props['interactionWidth'] = undefined;
export let sourceX: $$Props['sourceX'];
export let sourceY: $$Props['sourceY'];
export let sourcePosition: $$Props['sourcePosition'];
export let targetX: $$Props['targetX'];
export let targetY: $$Props['targetY'];
export let targetPosition: $$Props['targetPosition'];
$: [path, labelX, labelY] = getSmoothStepPath({
sourceX, sourceX,
sourceY, sourceY,
sourcePosition,
targetX, targetX,
targetY, targetY,
sourcePosition,
targetPosition, targetPosition,
borderRadius: 0 label,
}); labelStyle,
markerStart,
markerEnd,
interactionWidth,
style
}: EdgeProps = $props();
// this is a workaround for suppressing the warning about unused props let [path, labelX, labelY] = $derived(
$$restProps; getSmoothStepPath({
sourceX,
sourceY,
targetX,
targetY,
sourcePosition,
targetPosition,
borderRadius: 0
})
);
</script> </script>
<BaseEdge <BaseEdge
@@ -4,28 +4,28 @@
import type { StraightEdgeProps } from '$lib/types'; import type { StraightEdgeProps } from '$lib/types';
import { BaseEdge } from '$lib/components/BaseEdge'; import { BaseEdge } from '$lib/components/BaseEdge';
type $$Props = StraightEdgeProps; let {
id,
export let id: $$Props['id'] = undefined; label,
export let label: $$Props['label'] = undefined; labelStyle,
export let labelStyle: $$Props['labelStyle'] = undefined; style,
export let style: $$Props['style'] = undefined; markerStart,
export let markerStart: $$Props['markerStart'] = undefined; markerEnd,
export let markerEnd: $$Props['markerEnd'] = undefined; interactionWidth,
export let interactionWidth: $$Props['interactionWidth'] = undefined;
export let sourceX: $$Props['sourceX'];
export let sourceY: $$Props['sourceY'];
export let targetX: $$Props['targetX'];
export let targetY: $$Props['targetY'];
$: [path, labelX, labelY] = getStraightPath({
sourceX, sourceX,
sourceY, sourceY,
targetX, targetX,
targetY targetY
}); }: StraightEdgeProps = $props();
let [path, labelX, labelY] = $derived(
getStraightPath({
sourceX,
sourceY,
targetX,
targetY
})
);
</script> </script>
<BaseEdge <BaseEdge
@@ -4,30 +4,27 @@
import type { EdgeProps } from '$lib/types'; import type { EdgeProps } from '$lib/types';
import { BaseEdge } from '$lib/components/BaseEdge'; import { BaseEdge } from '$lib/components/BaseEdge';
type $$Props = EdgeProps; let {
export let label: $$Props['label'] = undefined;
export let labelStyle: $$Props['labelStyle'] = undefined;
export let style: $$Props['style'] = undefined;
export let markerStart: $$Props['markerStart'] = undefined;
export let markerEnd: $$Props['markerEnd'] = undefined;
export let interactionWidth: $$Props['interactionWidth'] = undefined;
export let sourceX: $$Props['sourceX'];
export let sourceY: $$Props['sourceY'];
export let targetX: $$Props['targetX'];
export let targetY: $$Props['targetY'];
$: [path, labelX, labelY] = getStraightPath({
sourceX, sourceX,
sourceY, sourceY,
targetX, targetX,
targetY targetY,
}); label,
labelStyle,
markerStart,
markerEnd,
interactionWidth,
style
}: EdgeProps = $props();
// this is a workaround for suppressing the warning about unused props let [path, labelX, labelY] = $derived(
$$restProps; getStraightPath({
sourceX,
sourceY,
targetX,
targetY
})
);
</script> </script>
<BaseEdge <BaseEdge
@@ -4,16 +4,14 @@
import { Handle } from '$lib/components/Handle'; import { Handle } from '$lib/components/Handle';
import type { NodeProps } from '$lib/types'; import type { NodeProps } from '$lib/types';
interface $$Props extends NodeProps {} let {
// TODO: do we really want this!?
export let data: $$Props['data'] = { label: 'Node' }; data = { label: 'Node' },
export let targetPosition: $$Props['targetPosition'] = undefined; targetPosition = Position.Top,
export let sourcePosition: $$Props['sourcePosition'] = undefined; sourcePosition = Position.Bottom
}: NodeProps = $props();
// this is a workaround for suppressing the warning about unused props
$$restProps;
</script> </script>
<Handle type="target" position={targetPosition ?? Position.Top} /> <Handle type="target" position={targetPosition} />
{data?.label} {data?.label}
<Handle type="source" position={sourcePosition ?? Position.Bottom} /> <Handle type="source" position={sourcePosition} />
@@ -1,9 +1,5 @@
<script lang="ts"> <script lang="ts">
import type { NodeProps } from '$lib/types'; import type { NodeProps } from '$lib/types';
// eslint-disable-next-line @typescript-eslint/no-unused-vars let {}: NodeProps = $props();
interface $$Props extends NodeProps {}
// this is a workaround for suppressing the warning about unused props
$$restProps;
</script> </script>
@@ -4,14 +4,8 @@
import { Handle } from '$lib/components/Handle'; import { Handle } from '$lib/components/Handle';
interface $$Props extends NodeProps {} let { data = { label: 'Node' }, sourcePosition = Position.Bottom }: NodeProps = $props();
export let data: $$Props['data'] = { label: 'Node' };
export let sourcePosition: $$Props['sourcePosition'] = undefined;
// this is a workaround for suppressing the warning about unused props
$$restProps;
</script> </script>
{data?.label} {data?.label}
<Handle type="source" position={sourcePosition ?? Position.Bottom} /> <Handle type="source" position={sourcePosition} />
@@ -4,14 +4,8 @@
import { Handle } from '$lib/components/Handle'; import { Handle } from '$lib/components/Handle';
interface $$Props extends NodeProps {} let { data = { label: 'Node' }, targetPosition = Position.Top }: NodeProps = $props();
export let data: $$Props['data'] = { label: 'Node' };
export let targetPosition: $$Props['targetPosition'] = undefined;
// this is a workaround for suppressing the warning about unused props
$$restProps;
</script> </script>
{data?.label} {data?.label}
<Handle type="target" position={targetPosition ?? Position.Top} /> <Handle type="target" position={targetPosition} />
@@ -3,24 +3,24 @@
import type { PanelProps } from './types'; import type { PanelProps } from './types';
import { useStore } from '$lib/store'; import { useStore } from '$lib/store';
type $$Props = PanelProps; let {
position = 'top-right',
export let position: $$Props['position'] = 'top-right'; style,
export let style: $$Props['style'] = undefined; class: className,
children,
let className: $$Props['class'] = undefined; ...restProps
export { className as class }; }: PanelProps = $props();
const { selectionRectMode } = useStore(); const { selectionRectMode } = useStore();
$: positionClasses = `${position}`.split('-'); let positionClasses = $derived(`${position}`.split('-'));
</script> </script>
<div <div
class={cc(['svelte-flow__panel', className, ...positionClasses])} class={cc(['svelte-flow__panel', className, ...positionClasses])}
{style} {style}
style:pointer-events={$selectionRectMode ? 'none' : ''} style:pointer-events={$selectionRectMode ? 'none' : ''}
{...$$restProps} {...restProps}
> >
<slot /> {@render children?.()}
</div> </div>
@@ -79,8 +79,8 @@
onbeforedelete, onbeforedelete,
oninit, oninit,
nodeOrigin, nodeOrigin,
paneClickDistance = 0, paneClickDistance = 1,
nodeClickDistance = 0, nodeClickDistance = 1,
defaultMarkerColor = '#b1b1b7', defaultMarkerColor = '#b1b1b7',
style, style,
class: className, class: className,
@@ -109,6 +109,8 @@
const initViewport = $viewport || initialViewport; const initViewport = $viewport || initialViewport;
//TODO SVELTE5
const store = hasContext(key) const store = hasContext(key)
? useStore() ? useStore()
: createStoreContext({ : createStoreContext({
@@ -262,15 +264,11 @@
{onedgemouseleave} {onedgemouseleave}
{defaultEdgeOptions} {defaultEdgeOptions}
/> />
<!-- <ConnectionLine <ConnectionLine
containerStyle={connectionLineContainerStyle} containerStyle={connectionLineContainerStyle}
style={connectionLineStyle} style={connectionLineStyle}
isCustomComponent={connectionLine} {connectionLine}
> />
{#snippet connectionLine()}
{@render connectionLine_render?.()}
{/snippet}
</ConnectionLine> -->
<div class="svelte-flow__edgelabel-renderer"></div> <div class="svelte-flow__edgelabel-renderer"></div>
<div class="svelte-flow__viewport-portal"></div> <div class="svelte-flow__viewport-portal"></div>
<NodeRenderer <NodeRenderer
+27 -27
View File
@@ -271,36 +271,36 @@ export function createStore({
if (resetEdges) store.edges.set(get(store.edges)); if (resetEdges) store.edges.set(get(store.edges));
} }
store.deleteKeyPressed.subscribe(async (deleteKeyPressed) => { // store.deleteKeyPressed.subscribe(async (deleteKeyPressed) => {
if (deleteKeyPressed) { // if (deleteKeyPressed) {
const nodes = get(store.nodes); // const nodes = get(store.nodes);
const edges = get(store.edges); // const edges = get(store.edges);
const selectedNodes = nodes.filter((node) => node.selected); // const selectedNodes = nodes.filter((node) => node.selected);
const selectedEdges = edges.filter((edge) => edge.selected); // const selectedEdges = edges.filter((edge) => edge.selected);
const { nodes: matchingNodes, edges: matchingEdges } = await getElementsToRemove({ // const { nodes: matchingNodes, edges: matchingEdges } = await getElementsToRemove({
nodesToRemove: selectedNodes, // nodesToRemove: selectedNodes,
edgesToRemove: selectedEdges, // edgesToRemove: selectedEdges,
nodes, // nodes,
edges, // edges,
onBeforeDelete: get(store.onbeforedelete) // onBeforeDelete: get(store.onbeforedelete)
}); // });
if (matchingNodes.length || matchingEdges.length) { // if (matchingNodes.length || matchingEdges.length) {
store.nodes.update((nds) => // store.nodes.update((nds) =>
nds.filter((node) => !matchingNodes.some((mN) => mN.id === node.id)) // nds.filter((node) => !matchingNodes.some((mN) => mN.id === node.id))
); // );
store.edges.update((eds) => // store.edges.update((eds) =>
eds.filter((edge) => !matchingEdges.some((mE) => mE.id === edge.id)) // eds.filter((edge) => !matchingEdges.some((mE) => mE.id === edge.id))
); // );
get(store.ondelete)?.({ // get(store.ondelete)?.({
nodes: matchingNodes, // nodes: matchingNodes,
edges: matchingEdges // edges: matchingEdges
}); // });
} // }
} // }
}); // });
function addSelectedNodes(ids: string[]) { function addSelectedNodes(ids: string[]) {
const isMultiSelection = get(store.multiselectionKeyPressed); const isMultiSelection = get(store.multiselectionKeyPressed);
+1
View File
@@ -1,3 +1,4 @@
export * from './nodes'; export * from './nodes';
export * from './edges'; export * from './edges';
export * from './general'; export * from './general';
export * from './events';
+1
View File
@@ -44,6 +44,7 @@ export type DefaultNodeOptions = Partial<Omit<Node, 'id'>>;
export type BuiltInNode = Node<{ label: string }, 'input' | 'output' | 'default'>; export type BuiltInNode = Node<{ label: string }, 'input' | 'output' | 'default'>;
// TODO SVELTE5 remove this
export type NodeEventMap = { export type NodeEventMap = {
nodeclick: { node: Node; event: MouseEvent | TouchEvent }; nodeclick: { node: Node; event: MouseEvent | TouchEvent };
nodecontextmenu: { node: Node; event: MouseEvent | TouchEvent }; nodecontextmenu: { node: Node; event: MouseEvent | TouchEvent };