feat(svelte): add isValidConnection prop, cleanup handle classes

This commit is contained in:
moklick
2023-03-14 14:55:49 +01:00
parent 1df4736203
commit 233e6aedca
13 changed files with 120 additions and 32 deletions

View File

@@ -4,7 +4,8 @@
const routes = [
'overview',
'stress',
'usesvelteflow'
'usesvelteflow',
'validation'
];
const onChange = (event: Event) => {

View File

@@ -13,14 +13,14 @@
export let id: $$Props['id'] = undefined;
export let type: $$Props['type'] = 'source';
export let position: $$Props['position'] = Position.Top;
export let isConnectable: $$Props['isConnectable'] = true;
export let style: $$Props['style'] = undefined;
export let isValidConnection: $$Props['isValidConnection'] = (_: Connection) => true;
let className: $$Props['class'] = undefined;
export { className as class };
const isTarget = type === 'target';
const nodeId = getContext<string>('rf_nodeid');
const nodeId = getContext<string>('svelteflow__node_id');
const connectable = getContext<string>('svelteflow__node_connectable');
const handleId = id || null;
const dispatch = createEventDispatcher();
@@ -30,10 +30,11 @@
nodes,
connectionRadius,
transform,
isValidConnection,
addEdge,
panBy,
cancelConnection,
updateConnection
updateConnection,
} = useStore();
function dispatchEvent(eventName: string, params?: Connection) {
@@ -56,10 +57,10 @@
isTarget,
connectionRadius: $connectionRadius,
domNode: $domNode,
nodes: $nodes,
nodes,
connectionMode: $connectionMode,
transform,
isValidConnection: isValidConnection!,
isValidConnection: $isValidConnection,
onConnect: onConnectExtended,
updateConnection,
cancelConnection,
@@ -86,7 +87,7 @@
])}
class:source={!isTarget}
class:target={isTarget}
class:connectable={isConnectable}
class:connectable
on:mousedown={onPointerDown}
on:touchstart={onPointerDown}
{style}

View File

@@ -22,10 +22,9 @@ import {
getHandleType,
isValidHandle,
resetRecentHandle,
type ConnectionHandle,
type ValidConnectionFunc
type ConnectionHandle
} from './utils';
import type { ConnectionData, Node } from '$lib/types';
import type { ConnectionData, IsValidConnection, Node } from '$lib/types';
export function handlePointerDown({
event,
@@ -54,9 +53,9 @@ export function handlePointerDown({
isTarget: boolean;
connectionMode: ConnectionMode;
domNode: HTMLDivElement | null;
nodes: Node[];
nodes: Writable<Node[]>;
connectionRadius: number;
isValidConnection: ValidConnectionFunc;
isValidConnection: IsValidConnection;
transform: Writable<Transform>;
updateConnection: (connection: Partial<ConnectionData>) => void;
cancelConnection: () => void;
@@ -90,7 +89,7 @@ export function handlePointerDown({
const autoPanOnConnect = true;
const handleLookup = getHandleLookup({
nodes,
nodes: get(nodes),
nodeId,
handleId,
handleType
@@ -116,8 +115,6 @@ export function handlePointerDown({
status: null
});
// @todo add prop
// onConnectStart?.(event, { nodeId, handleId, handleType });
onConnectStart();
@@ -144,7 +141,8 @@ export function handlePointerDown({
handleId,
isTarget ? 'target' : 'source',
isValidConnection,
doc
doc,
get(nodes)
);
handleDomNode = result.handleDomNode;

View File

@@ -2,7 +2,7 @@ import { internalsSymbol, ConnectionMode, type ConnectionStatus } from '@reactfl
import type { Connection, HandleType, XYPosition, NodeHandleBounds } from '@reactflow/system';
import { getEventPosition } from '@reactflow/utils';
import type { Node } from '$lib/types';
import type { IsValidConnection, Node } from '$lib/types';
export type ConnectionHandle = {
id: string | null;
@@ -76,8 +76,9 @@ export function isValidHandle(
fromNodeId: string,
fromHandleId: string | null,
fromType: string,
isValidConnection: ValidConnectionFunc,
doc: Document | ShadowRoot
isValidConnection: IsValidConnection,
doc: Document | ShadowRoot,
nodes: Node[]
) {
const isTarget = fromType === 'target';
const handleDomNode = doc.querySelector(
@@ -116,7 +117,10 @@ export function isValidHandle(
: handleNodeId !== fromNodeId || handleId !== fromHandleId;
if (isValid) {
result.isValid = isValidConnection(connection);
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 });
}
}

View File

@@ -15,6 +15,7 @@
export let data: NodeWrapperProps['data'] = {};
export let selected: NodeWrapperProps['selected'] = false;
export let draggable: NodeWrapperProps['draggable'] = undefined;
export let connectable: NodeWrapperProps['connectable'] = true;
export let dragging: boolean = false;
export let resizeObserver: NodeWrapperProps['resizeObserver'] = null;
export let style: NodeWrapperProps['style'] = undefined;
@@ -45,7 +46,8 @@
const selectNodesOnDrag = false;
const dispatch = createEventDispatcher();
setContext('rf_nodeid', id);
setContext('svelteflow__node_id', id);
setContext('svelteflow__node_connectable', connectable);
onMount(() => {
resizeObserver?.observe(nodeRef);
@@ -79,6 +81,7 @@
class:dragging
class:selected
class:draggable
class:connectable
style:transform={`translate(${positionOrigin?.x ?? 0}px, ${positionOrigin?.y ?? 0}px)`}
{style}
on:click={onSelectNodeHandler}
@@ -93,7 +96,6 @@
{selected}
{sourcePosition}
{targetPosition}
isConnectable={true}
xPos={positionAbsolute?.x ?? 0}
yPos={positionAbsolute?.y ?? 0}
on:connect:start

View File

@@ -5,6 +5,7 @@ export type NodeWrapperProps = Pick<
Node,
| 'id'
| 'class'
| 'connectable'
| 'data'
| 'draggable'
| 'dragging'

View File

@@ -38,6 +38,7 @@
data={node.data}
selected={node.selected}
draggable={node.draggable || node.draggable === undefined}
connectable={node.connectable || node.connectable === undefined}
positionAbsolute={node.positionAbsolute}
positionOrigin={posOrigin}
width={node.width}

View File

@@ -27,7 +27,9 @@
export let selectionKey: $$Props['selectionKey'] = undefined;
export let deleteKey: $$Props['deleteKey'] = undefined;
export let connectionRadius: $$Props['connectionRadius'] = undefined;
export let connectionLineType: $$Props['connectionLineType'] = undefined
export let connectionLineType: $$Props['connectionLineType'] = undefined;
export let isValidConnection: $$Props['isValidConnection'] = undefined;
export let style: $$Props['style'] = undefined;
let className: $$Props['class'] = undefined;
export { className as class };
@@ -52,6 +54,7 @@
id,
connectionLineType,
connectionRadius,
isValidConnection
};
Object.keys(updatableProps).forEach(prop => {

View File

@@ -6,9 +6,14 @@ import type {
Viewport
} from '@reactflow/system';
import type { Edge, Node, NodeTypes, KeyDefinition, EdgeTypes } from '$lib/types';
import type { Writable } from 'svelte/store';
import type { createNodes } from '$lib/utils';
import type {
Edge,
Node,
NodeTypes,
KeyDefinition,
EdgeTypes,
IsValidConnection
} from '$lib/types';
export type SvelteFlowProps = {
id?: string;
@@ -27,6 +32,7 @@ export type SvelteFlowProps = {
style?: string;
connectionLineType?: ConnectionLineType;
isValidConnection?: IsValidConnection;
};
export type SvelteFlowEvents = {

View File

@@ -15,7 +15,15 @@ import OutputNode from '$lib/components/nodes/OutputNode.svelte';
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 type { ConnectionData, NodeTypes, EdgeTypes, EdgeLayouted, Edge, Node } from '$lib/types';
import type {
ConnectionData,
NodeTypes,
EdgeTypes,
EdgeLayouted,
Edge,
Node,
IsValidConnection
} from '$lib/types';
export const initConnectionData = {
nodeId: null,
@@ -67,5 +75,6 @@ export const initialStoreState = {
connectionPath: readable<string | null>(null),
connection: writable<ConnectionData>(initConnectionData),
connectionRadius: writable<number>(25),
connectionLineType: writable<ConnectionLineType>(ConnectionLineType.Bezier)
connectionLineType: writable<ConnectionLineType>(ConnectionLineType.Bezier),
isValidConnection: writable<IsValidConnection>(() => true)
};

View File

@@ -1,5 +1,11 @@
import type { ShortcutModifierDefinition } from '@svelte-put/shortcut';
import type { FitViewOptionsBase, HandleProps, HandleType, XYPosition } from '@reactflow/system';
import type {
Connection,
FitViewOptionsBase,
HandleProps,
HandleType,
XYPosition
} from '@reactflow/system';
import type { Node } from './nodes';
@@ -15,9 +21,14 @@ export type ConnectionData = {
status: string | null;
};
export type HandleComponentProps = HandleProps & {
export type HandleComponentProps = Omit<HandleProps, 'isConnectable'> & {
class?: string;
style?: string;
};
export type FitViewOptions = FitViewOptionsBase<Node>;
export type IsValidConnection = (
connection: Connection,
{ fromNode, toNode }: { fromNode: Node; toNode: Node }
) => boolean;

View File

@@ -26,4 +26,4 @@ export type NodeProps<NodeData = any> = Pick<
export type NodeTypes = Record<string, typeof SvelteComponentTyped<Partial<NodeProps>>>;
export type DefaultNodeOptions = Omit<Node, 'id'>;
export type DefaultNodeOptions = Partial<Omit<Node, 'id'>>;

View File

@@ -0,0 +1,51 @@
<script lang="ts">
import SvelteFlow, {
SvelteFlowProvider,
Controls,
Background,
BackgroundVariant,
createNodes,
createEdges,
type IsValidConnection
} from '../../lib/index';
import { Position } from '@reactflow/system';
const nodes = createNodes([
{ id: '0', type: 'default', position: { x: 0, y: 150 }, data: { label: 'only connecatbale with B' } },
{ id: 'A', type: 'default', position: { x: 250, y: 0 }, data: { label: 'A' } },
{ id: 'B', type: 'default', position: { x: 250, y: 150 }, data: { label: 'B' } },
{ id: 'C', type: 'default', position: { x: 250, y: 300 }, data: { label: 'C' } }
], {
sourcePosition: Position.Right,
targetPosition: Position.Left
});
const edges = createEdges([]);
const isValidConnection: IsValidConnection = (connection) => connection.target === 'B'
</script>
<SvelteFlowProvider
{nodes}
{edges}
>
<SvelteFlow
fitView
minZoom={0.1}
maxZoom={2.5}
isValidConnection={isValidConnection}
>
<Controls />
<Background variant={BackgroundVariant.Dots} />
</SvelteFlow>
</SvelteFlowProvider>
<style>
:global(.svelte-flow__handle.connecting) {
background: #ff6060;
}
:global(.svelte-flow__handle.valid) {
background: #55dd99;
}
</style>