feat(svelte): add BaseEdge and EdgeLabelRenderer

This commit is contained in:
moklick
2023-02-23 18:21:39 +01:00
parent bb528e6798
commit 1dd5613482
15 changed files with 225 additions and 122 deletions
@@ -0,0 +1,15 @@
export default function (node: Element, target = 'body') {
const targetEl = document.querySelector(target);
if (targetEl) {
targetEl.appendChild(node);
}
return {
destroy() {
if (node.parentNode) {
node.parentNode.removeChild(node);
}
}
};
}
@@ -0,0 +1,9 @@
<script lang="ts">
import portal from '$lib/actions/portal';
type $$Props = {}
</script>
<div use:portal={'.react-flow__edgelabel-renderer'}>
<slot />
</div>
@@ -1,44 +1,46 @@
<script lang="ts">
import type { SvelteComponentTyped } from 'svelte';
import { Position } from '@reactflow/system';
import type { BaseEdgeProps } from '$lib/types';
import EdgeLabelRenderer from '$lib/components/EdgeLabelRenderer/index.svelte';
import { useStore } from '$lib/store';
import BezierEdge from '$lib/components/edges/StraightEdge.svelte';
import type { EdgeProps } from '$lib/types';
type $$Props = BaseEdgeProps;
export let id: string;
export let type: string = 'default';
export let sourceX: number = 0;
export let sourceY: number = 0;
export let targetX: number = 0;
export let targetY: number = 0;
export let sourcePosition: Position = Position.Bottom;
export let targetPosition: Position = Position.Top;
const { edgeTypesStore } = useStore();
const edgeComponent: typeof SvelteComponentTyped<EdgeProps> = $edgeTypesStore[type] || BezierEdge;
export let path: $$Props['path'];
export let label: $$Props['label'];
export let labelX: $$Props['labelX'];
export let labelY: $$Props['labelY'];
export let interactionWidth: $$Props['interactionWidth'] = 20;
</script>
<g
class="react-flow__edge"
data-id={id}
>
<svelte:component
this={edgeComponent}
{id}
{sourceX}
{sourceY}
{targetX}
{targetY}
{sourcePosition}
{targetPosition}
<path
d={path}
fill="none"
class="react-flow__edge-path"
/>
{#if interactionWidth}
<path
d={path}
fill="none"
stroke-opacity={0}
stroke-width={interactionWidth}
class="react-flow__edge-interaction"
/>
</g>
{/if}
{#if label}
<EdgeLabelRenderer>
<div
class="react-flow__edge-label"
style:transform={`translate(-50%, -50%) translate(${labelX}px,${labelY}px)`}
>
{label}
</div>
</EdgeLabelRenderer>
{/if}
<style>
.react-flow__edge :global(path) {
stroke: #ccc;
stroke-width: 1;
fill: none;
.react-flow__edge-label {
position: absolute;
background: white;
}
</style>
@@ -1,21 +1,24 @@
<script lang="ts">
import { getBezierPath } from '@reactflow/edge-utils';
import type { EdgeProps } from '$lib/types';
interface $$Props extends EdgeProps {}
import BaseEdge from './BaseEdge.svelte';
export let id: $$Props['id'];
export let sourceX: $$Props['sourceX'] = 0;
export let sourceY: $$Props['sourceY'] = 0;
export let targetX: $$Props['targetX'] = 0;
export let targetY: $$Props['targetY'] = 0;
export let sourcePosition: $$Props['sourcePosition'] = undefined;
export let targetPosition: $$Props['targetPosition'] = undefined;
type $$Props = EdgeProps;
$: [path] = getBezierPath({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition });
$: [path, labelX, labelY] = getBezierPath({
sourceX: $$props.sourceX,
sourceY: $$props.sourceY,
targetX: $$props.targetX,
targetY: $$props.targetY,
sourcePosition: $$props.sourcePosition,
targetPosition: $$props.targetPosition,
});
</script>
<path
d={path}
class="react-flow__edge-path"
/>
<BaseEdge
{path}
{labelX}
{labelY}
{...$$props}
/>
@@ -0,0 +1,73 @@
<script lang="ts">
import type { SvelteComponentTyped } from 'svelte';
import { Position } from '@reactflow/system';
import { useStore } from '$lib/store';
import BezierEdge from '$lib/components/edges/StraightEdge.svelte';
import type { EdgeProps, WrapEdgeProps } from '$lib/types';
type $$Props = WrapEdgeProps;
export let id: $$Props['id'];
export let type: $$Props['type'] = 'default';
export let source: $$Props['source'] = '';
export let target: $$Props['target'] = '';
export let sourceX: $$Props['sourceX'] = 0;
export let sourceY: $$Props['sourceY'] = 0;
export let targetX: $$Props['targetX'] = 0;
export let targetY: $$Props['targetY'] = 0;
export let sourcePosition: $$Props['sourcePosition'] = Position.Bottom;
export let targetPosition: $$Props['targetPosition'] = Position.Top;
export let animated: $$Props['animated'] = false;
export let selected: $$Props['selected'] = false;
export let label: $$Props['label'] = undefined;
const { edgeTypesStore } = useStore();
const edgeComponent: typeof SvelteComponentTyped<EdgeProps> = $edgeTypesStore[type!] || BezierEdge;
</script>
<g
class="react-flow__edge"
class:animated
data-id={id}
>
<svelte:component
this={edgeComponent}
{id}
{source}
{target}
{sourceX}
{sourceY}
{targetX}
{targetY}
{sourcePosition}
{targetPosition}
{animated}
{selected}
{label}
/>
</g>
<style>
.react-flow__edge {
pointer-events: visibleStroke;
cursor: pointer;
}
.react-flow__edge :global(path) {
stroke: #ccc;
stroke-width: 1;
fill: none;
}
.animated :global(path) {
stroke-dasharray: 5;
animation: dashdraw 0.5s linear infinite;
}
@keyframes dashdraw {
from {
stroke-dashoffset: 10;
}
}
</style>
@@ -1,21 +1,24 @@
<script lang="ts">
import { getSmoothStepPath } from '@reactflow/edge-utils';
import type { EdgeProps } from '$lib/types';
interface $$Props extends EdgeProps {}
import BaseEdge from './BaseEdge.svelte';
export let id: $$Props['id'];
export let sourceX: $$Props['sourceX'] = 0;
export let sourceY: $$Props['sourceY'] = 0;
export let targetX: $$Props['targetX'] = 0;
export let targetY: $$Props['targetY'] = 0;
export let sourcePosition: $$Props['sourcePosition'] = undefined;
export let targetPosition: $$Props['targetPosition'] = undefined;
type $$Props = EdgeProps;
$: [path] = getSmoothStepPath({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition });
$: [path, labelX, labelY] = getSmoothStepPath({
sourceX: $$props.sourceX,
sourceY: $$props.sourceY,
targetX: $$props.targetX,
targetY: $$props.targetY,
sourcePosition: $$props.sourcePosition,
targetPosition: $$props.targetPosition,
});
</script>
<path
d={path}
class="react-flow__edge-path"
<BaseEdge
{path}
{labelX}
{labelY}
{...$$props}
/>
@@ -1,19 +1,22 @@
<script lang="ts">
import { getStraightPath } from '@reactflow/edge-utils';
import type { EdgeProps } from '$lib/types';
import BaseEdge from './BaseEdge.svelte';
interface $$Props extends EdgeProps {}
type $$Props = EdgeProps;
export let id: $$Props['id'];
export let sourceX: $$Props['sourceX'] = 0;
export let sourceY: $$Props['sourceY'] = 0;
export let targetX: $$Props['targetX'] = 0;
export let targetY: $$Props['targetY'] = 0;
$: [path] = getStraightPath({ sourceX, sourceY, targetX, targetY });
$: [path, labelX, labelY] = getStraightPath({
sourceX: $$props.sourceX,
sourceY: $$props.sourceY,
targetX: $$props.targetX,
targetY: $$props.targetY,
});
</script>
<path
d={path}
class="react-flow__edge-path"
<BaseEdge
{path}
{labelX}
{labelY}
{...$$props}
/>
@@ -85,7 +85,6 @@
<style>
.react-flow__node {
border-radius: 3px;
font-size: 12px;
color: #222;
text-align: center;
border-width: 1px;
@@ -1,5 +1,5 @@
<script lang="ts">
import Edge from '$lib/components/edges/BaseEdge.svelte';
import EdgeWrapper from '$lib/components/edges/EdgeWrapper.svelte';
import { useStore } from '$lib/store';
const { edgesWithDataStore, widthStore, heightStore } = useStore();
@@ -8,10 +8,10 @@
<svg
width={$widthStore}
height={$heightStore}
height={$heightStore}
class="react-flow__edges"
>
{#each $edgesWithDataStore as edge (edge.id)}
{#each $edgesWithDataStore as edge (edge.id)}
<EdgeWrapper {...edge} />
{/each}
</svg>
@@ -1,7 +1,7 @@
<script lang="ts">
import { onDestroy } from 'svelte';
import BaseNode from '$lib/components/nodes/BaseNode.svelte';
import NodeWrapper from '$lib/components/nodes/NodeWrapper.svelte';
import { useStore } from '$lib/store';
const { nodesStore, updateNodeDimensions } = useStore();
@@ -22,7 +22,7 @@
<div class="react-flow__nodes">
{#each $nodesStore as node (node.id)}
<BaseNode {...node} {resizeObserver} />
<NodeWrapper {...node} {resizeObserver} />
{/each}
</div>
@@ -68,9 +68,10 @@
<Zoom>
<Pane>
<Viewport>
<NodeSelection />
<NodeRenderer />
<EdgeRenderer />
<div class="react-flow__edgelabel-renderer" />
<NodeRenderer />
<NodeSelection />
</Viewport>
<UserSelection />
</Pane>
@@ -92,4 +93,12 @@
.react-flow :global(.react-flow__node-output) {
padding: 10px;
}
.react-flow__edgelabel-renderer {
position: absolute;
width: 100%;
height: 100%;
pointer-events: none;
user-select: none;
}
</style>
+16 -17
View File
@@ -6,6 +6,7 @@ import {
type NodeDimensionUpdate,
Position,
internalsSymbol,
SelectionMode,
type NodeOrigin,
type D3ZoomInstance,
type D3SelectionInstance,
@@ -16,17 +17,11 @@ import {
import { fitView, getConnectedEdges, getD3Transition, getDimensions } from '@reactflow/utils';
import { getHandleBounds } from '../../utils';
import {
getEdgePositions,
getHandle,
getNodeData,
type EdgePosition
} from '$lib/container/EdgeRenderer/utils';
import { SelectionMode } from 'reactflow';
import { getEdgePositions, getHandle, getNodeData } from '$lib/container/EdgeRenderer/utils';
import DefaultNode from '$lib/components/nodes/DefaultNode.svelte';
import InputNode from '$lib/components/nodes/InputNode.svelte';
import OutputNode from '$lib/components/nodes/OutputNode.svelte';
import type { EdgeTypes, NodeTypes, Node, Edge } from '$lib/types';
import type { EdgeTypes, NodeTypes, Node, Edge, WrapEdgeProps } from '$lib/types';
import BezierEdge from '$lib/components/edges/BezierEdge.svelte';
import StraightEdge from '$lib/components/edges/StraightEdge.svelte';
import SmoothStepEdge from '$lib/components/edges/SmoothStepEdge.svelte';
@@ -42,11 +37,6 @@ type CreateStoreProps = {
id?: string;
};
export type EdgeWithData = EdgePosition & {
id: string;
type: string;
};
type SvelteFlowStore = {
nodesStore: Writable<Node[]>;
edgesStore: Writable<Edge[]>;
@@ -57,7 +47,7 @@ type SvelteFlowStore = {
selection: D3SelectionInstance | null;
}>;
transformStore: Writable<Transform>;
edgesWithDataStore: Readable<EdgeWithData[]>;
edgesWithDataStore: Readable<WrapEdgeProps[]>;
idStore: Writable<string>;
nodeOriginStore: Writable<NodeOrigin>;
draggingStore: Writable<boolean>;
@@ -162,16 +152,24 @@ export function createStore({
targetPosition
);
// we nee to do this to match the types
const sourceHandleId = edge.sourceHandle;
const targetHandleId = edge.targetHandle;
return {
id: edge.id,
...edge,
type: edgeType,
sourceX,
sourceY,
targetX,
targetY
targetY,
sourcePosition,
targetPosition,
sourceHandleId,
targetHandleId
};
})
.filter((e) => e !== null) as EdgeWithData[];
.filter((e) => e !== null) as WrapEdgeProps[];
});
function setEdges(edges: Edge[]) {
@@ -359,6 +357,7 @@ export function createStore({
function addSelectedNodes(ids: string[]) {
selectionRectStore.set(null);
selectionRectModeStore.set(null);
if (get(multiselectionKeyPressedStore)) {
// @todo handle multiselection key
+1 -22
View File
@@ -1,25 +1,4 @@
import type { SvelteComponentTyped } from 'svelte';
import type { Position } from '@reactflow/system';
export type Edge = {
id: string;
type: string;
source: string;
target: string;
sourceHandle?: string;
targetHandle?: string;
selected?: boolean;
deletable?: boolean;
};
export type EdgeProps = {
id: string;
sourceX: number;
sourceY: number;
targetX: number;
targetY: number;
sourcePosition?: Position;
targetPosition?: Position;
};
import type { EdgeProps } from '$lib/types';
export type EdgeTypes = Record<string, typeof SvelteComponentTyped<EdgeProps>>;
+8 -1
View File
@@ -1,4 +1,11 @@
export type { Position, XYPosition } from '@reactflow/system';
export type {
Position,
XYPosition,
Edge,
BaseEdgeProps,
WrapEdgeProps,
EdgeProps
} from '@reactflow/system';
export * from './nodes';
export * from './edges';
+4 -2
View File
@@ -83,7 +83,8 @@
id: '1-2',
type: 'default',
source: '1',
target: '2'
target: '2',
label: 'Edge Text'
}, {
id: '1-3',
type: 'smoothstep',
@@ -93,7 +94,8 @@
id: '2-4',
type: 'default',
source: '2',
target: '4'
target: '4',
animated: true
}];
function updateNode() {