feat(svelte): add event handlers and props, rename class names

This commit is contained in:
moklick
2023-03-01 17:28:59 +01:00
parent 9391b36869
commit e2961bfa8c
38 changed files with 410 additions and 163 deletions
@@ -11,7 +11,7 @@
export let interactionWidth: $$Props['interactionWidth'] = 20;
</script>
<path d={path} fill="none" class="react-flow__edge-path" />
<path d={path} fill="none" class="svelte-flow__edge-path" />
{#if interactionWidth}
<path
@@ -19,14 +19,14 @@
fill="none"
stroke-opacity={0}
stroke-width={interactionWidth}
class="react-flow__edge-interaction"
class="svelte-flow__edge-interaction"
/>
{/if}
{#if label}
<EdgeLabelRenderer>
<div
class="react-flow__edge-label"
class="svelte-flow__edge-label"
style:transform={`translate(-50%, -50%) translate(${labelX}px,${labelY}px)`}
>
{label}
@@ -35,7 +35,7 @@
{/if}
<style>
.react-flow__edge-label {
.svelte-flow__edge-label {
position: absolute;
background: white;
}
@@ -7,15 +7,15 @@
</script>
{#if $connectionPath}
<svg width={$width} height={$height} class="react-flow__connectionline">
<g class={cc(['react-flow__connection', $connection.status])}>
<path d={$connectionPath} fill="none" class="react-flow__connection-path" />
<svg width={$width} height={$height} class="svelte-flow__connectionline">
<g class={cc(['svelte-flow__connection', $connection.status])}>
<path d={$connectionPath} fill="none" class="svelte-flow__connection-path" />
</g>
</svg>
{/if}
<style>
.react-flow__connectionline {
.svelte-flow__connectionline {
position: absolute;
top: 0;
left: 0;
@@ -26,12 +26,12 @@
z-index: 1001;
}
.react-flow__connection {
.svelte-flow__connection {
pointer-events: none;
}
.react-flow__edge-path,
.react-flow__connection-path {
.svelte-flow__edge-path,
.svelte-flow__connection-path {
stroke: #b1b1b7;
stroke-width: 1;
fill: none;
@@ -4,6 +4,6 @@
type $$Props = {};
</script>
<div use:portal={'.react-flow__edgelabel-renderer'}>
<div use:portal={'.svelte-flow__edgelabel-renderer'}>
<slot />
</div>
@@ -1,5 +1,5 @@
<script lang="ts">
import type { SvelteComponentTyped } from 'svelte';
import { createEventDispatcher, type SvelteComponentTyped } from 'svelte';
import { Position } from '@reactflow/system';
import { useStore } from '$lib/store';
@@ -24,11 +24,23 @@
export let selected: $$Props['selected'] = false;
export let label: $$Props['label'] = undefined;
const { edgeTypes } = useStore();
const { edgeTypes, edges } = useStore();
const dispatch = createEventDispatcher();
const edgeComponent: typeof SvelteComponentTyped<EdgeProps> = $edgeTypes[type!] || BezierEdge;
function onClick() {
const edge = $edges.find(e => e.id === id);
dispatch('edge:click', edge);
}
</script>
<g class="react-flow__edge" class:animated data-id={id}>
<g
class="svelte-flow__edge"
class:animated
data-id={id}
on:click={onClick}
>
<svelte:component
this={edgeComponent}
{id}
@@ -47,12 +59,12 @@
</g>
<style>
.react-flow__edge {
.svelte-flow__edge {
pointer-events: visibleStroke;
cursor: pointer;
}
.react-flow__edge :global(path) {
.svelte-flow__edge :global(path) {
stroke: #ccc;
stroke-width: 1;
fill: none;
@@ -1,5 +1,6 @@
<script lang="ts">
import { getContext } from 'svelte';
import { createEventDispatcher } from 'svelte';
import cc from 'classcat';
import { Position, type Connection, type HandleProps } from '@reactflow/system';
import { isMouseEvent } from '@reactflow/utils';
@@ -18,6 +19,8 @@
const isTarget = type === 'target';
const nodeId = getContext<string>('rf_nodeid');
const handleId = id || null;
const dispatch = createEventDispatcher();
const {
connectionMode,
@@ -31,11 +34,16 @@
updateConnection
} = useStore();
function dispatchEvent(eventName: string) {
dispatch(eventName, { nodeId, handleId, type });
}
function onConnectExtended(params: Connection) {
addEdge(params);
// @todo add props
// onConnectAction?.(edgeParams);
// onConnect?.(edgeParams);
dispatchEvent('connect')
}
function onPointerDown(event: MouseEvent | TouchEvent) {
@@ -56,7 +64,9 @@
onConnect: onConnectExtended,
updateConnection,
cancelConnection,
panBy
panBy,
onConnectStart: () => dispatchEvent('connect:start'),
onConnectEnd: () => dispatchEvent('connect:end')
});
}
@@ -74,8 +84,8 @@
data-handlepos={position}
data-id={`${nodeId}-${id}-${type}`}
class={cc([
'react-flow__handle',
`react-flow__handle-${position}`,
'svelte-flow__handle',
`svelte-flow__handle-${position}`,
'nodrag',
'nopan',
position
@@ -90,7 +100,7 @@
</div>
<style>
.react-flow__handle {
.svelte-flow__handle {
position: absolute;
pointer-events: none;
min-width: 5px;
@@ -43,7 +43,9 @@ export function handlePointerDown({
cancelConnection,
isValidConnection,
edgeUpdaterType,
onEdgeUpdateEnd
onEdgeUpdateEnd,
onConnectStart,
onConnectEnd
}: {
event: MouseEvent | TouchEvent;
handleId: string | null;
@@ -61,8 +63,10 @@ export function handlePointerDown({
panBy: (delta: XYPosition) => void;
edgeUpdaterType?: HandleType;
onEdgeUpdateEnd?: (evt: MouseEvent | TouchEvent) => void;
onConnectStart: () => void;
onConnectEnd: () => void;
}): void {
// when react-flow is used inside a shadow root we can't use document
// when svelte-flow is used inside a shadow root we can't use document
const doc = getHostForElement(event.target as HTMLElement);
let autoPanId = 0;
let prevClosestHandle: ConnectionHandle | null;
@@ -113,7 +117,9 @@ export function handlePointerDown({
});
// @todo add prop
// onConnectStart?.(event, { nodeId, handleId, handleType });
onConnectStart();
function onPointerMove(event: MouseEvent | TouchEvent) {
const transform = get(transformStore);
@@ -166,7 +172,7 @@ export function handlePointerDown({
if (connection.source !== connection.target && handleDomNode) {
resetRecentHandle(prevActiveHandle);
prevActiveHandle = handleDomNode;
// @todo: remove the old class names "react-flow__handle-" in the next major version
// @todo: remove the old class names "svelte-flow__handle-" in the next major version
handleDomNode.classList.add('connecting');
handleDomNode.classList.toggle('valid', isValid);
}
@@ -179,8 +185,8 @@ export function handlePointerDown({
// it's important to get a fresh reference from the store here
// in order to get the latest state of onConnectEnd
// @todo add onConnectEnd prop
// getState().onConnectEnd?.(event);
onConnectEnd();
if (edgeUpdaterType) {
onEdgeUpdateEnd?.(event);
@@ -81,11 +81,11 @@ export function isValidHandle(
) {
const isTarget = fromType === 'target';
const handleDomNode = doc.querySelector(
`.react-flow__handle[data-id="${handle?.nodeId}-${handle?.id}-${handle?.type}"]`
`.svelte-flow__handle[data-id="${handle?.nodeId}-${handle?.id}-${handle?.type}"]`
);
const { x, y } = getEventPosition(event);
const handleBelow = doc.elementFromPoint(x, y);
const handleToCheck = handleBelow?.classList.contains('react-flow__handle')
const handleToCheck = handleBelow?.classList.contains('svelte-flow__handle')
? handleBelow
: handleDomNode;
@@ -11,7 +11,7 @@
$: rect = getRectOfNodes(selectedNodes, $nodeOrigin);
</script>
{#if selectedNodes}
{#if selectedNodes && $selectionRectMode === 'nodes'}
<div
class="selection-wrapper nopan"
style={`width: ${rect.width}px; height: ${rect.height}px; transform: translate(${rect.x}px, ${rect.y}px)`}
@@ -1,5 +1,5 @@
<script lang="ts">
import { onMount, setContext, SvelteComponentTyped } from 'svelte';
import { createEventDispatcher, onMount, setContext, SvelteComponentTyped } from 'svelte';
import cc from 'classcat';
import { type XYPosition, Position, errorMessages } from '@reactflow/system';
@@ -28,10 +28,9 @@
let className: string = '';
export { className as class };
let nodeRef: HTMLDivElement;
const { nodes, transform, nodeTypes, updateNodePositions, addSelectedNodes } = useStore();
let nodeRef: HTMLDivElement;
const nodeTypeValid = !!$nodeTypes[type!];
if (!nodeTypeValid) {
@@ -44,6 +43,7 @@
const isSelectable = true;
const selectNodesOnDrag = false;
const isDraggable = true;
const dispatch = createEventDispatcher();
setContext('rf_nodeid', id);
@@ -55,30 +55,35 @@
};
});
function dispatchEvent(eventName: string) {
const node = $nodes.find(n => n.id === id);
dispatch(eventName, node);
}
function onSelectNodeHandler(event: MouseEvent) {
if (isSelectable && (!selectNodesOnDrag || !isDraggable)) {
// this handler gets called within the drag start event when selectNodesOnDrag=true
addSelectedNodes([id]);
}
// if (onClick) {
// const node = store.getState().nodeInternals.get(id)!;
// onClick(event, { ...node });
// }
dispatchEvent('node:click')
}
</script>
<div
use:drag={{ nodeId: id, nodes, transform, updateNodePositions }}
class={cc(['react-flow__node', `react-flow__node-${type}`, className])}
data-id={id}
class={cc(['svelte-flow__node', `svelte-flow__node-${type}`, className])}
class:initializing={!width && !height}
class:dragging
class:selected
bind:this={nodeRef}
on:click={onSelectNodeHandler}
style:transform={`translate(${positionAbsolute.x}px, ${positionAbsolute.y}px)`}
{style}
data-id={id}
on:click={onSelectNodeHandler}
on:mouseenter={() => dispatchEvent('node:mouseenter')}
on:mouseleave={() => dispatchEvent('node:mouseleave')}
on:mousemove={() => dispatchEvent('node:mousemove')}
>
<svelte:component
this={nodeComponent}
@@ -90,11 +95,14 @@
isConnectable={true}
xPos={positionAbsolute.x}
yPos={positionAbsolute.y}
on:connect:start
on:connect
on:connect:end
/>
</div>
<style>
.react-flow__node {
.svelte-flow__node {
border-radius: 3px;
color: #222;
text-align: center;
@@ -1,5 +1,6 @@
import type { Node } from '$lib/types';
export type NodeWrapperProps = Node & {
'on:nodeclick'?: (event: MouseEvent) => void;
resizeObserver?: ResizeObserver | null;
};
@@ -8,13 +8,13 @@
{#if isVisible}
<div
class="react-flow__selection"
class="svelte-flow__selection"
style={`width: ${width}px; height: ${height}px; transform: translate(${x}px, ${y}px)`}
/>
{/if}
<style>
.react-flow__selection {
.svelte-flow__selection {
position: absolute;
top: 0;
left: 0;
@@ -23,8 +23,8 @@
z-index: 6;
}
.react-flow__selection:focus,
.react-flow__selection:focus-visible {
.svelte-flow__selection:focus,
.svelte-flow__selection:focus-visible {
outline: none;
}
</style>
@@ -16,6 +16,7 @@
export let selected: $$Props['selected'] = false;
</script>
<Handle type="target" position={targetPosition} />
<Handle type="target" position={targetPosition} on:connect:start on:connect on:connect:end />
{data?.label}
<Handle type="source" position={sourcePosition} />
<Handle type="source" position={sourcePosition} on:connect:start on:connect on:connect:end />
@@ -1,12 +1,20 @@
<script lang="ts">
import { Position } from '@reactflow/system';
import type { NodeProps } from '$lib/types';
import { Handle } from '$lib/components/Handle';
export let data: { label: string } = { label: 'Node' };
export let isConnectable: boolean = true;
export let sourcePosition: Position = Position.Bottom;
interface $$Props extends NodeProps<{ label: string }> {}
export let id: $$Props['id'];
export let data: $$Props['data'] = { label: 'Node' };
export let isConnectable: $$Props['isConnectable'] = true;
export let targetPosition: $$Props['targetPosition'] = Position.Top;
export let sourcePosition: $$Props['sourcePosition'] = Position.Bottom;
export let xPos: $$Props['xPos'];
export let yPos: $$Props['yPos'];
export let selected: $$Props['selected'] = false;
</script>
{data?.label}
<Handle type="source" position={sourcePosition} />
<Handle type="source" position={sourcePosition} on:connect:start on:connect on:connect:end />
@@ -1,12 +1,20 @@
<script lang="ts">
import { Position } from '@reactflow/system';
import type { NodeProps } from '$lib/types';
import { Handle } from '$lib/components/Handle';
export let data: { label: string } = { label: 'Node' };
export let isConnectable: boolean = true;
export let targetPosition: Position = Position.Top;
interface $$Props extends NodeProps<{ label: string }> {}
export let id: $$Props['id'];
export let data: $$Props['data'] = { label: 'Node' };
export let isConnectable: $$Props['isConnectable'] = true;
export let targetPosition: $$Props['targetPosition'] = Position.Top;
export let sourcePosition: $$Props['sourcePosition'] = Position.Bottom;
export let xPos: $$Props['xPos'];
export let yPos: $$Props['yPos'];
export let selected: $$Props['selected'] = false;
</script>
{data?.label}
<Handle type="target" position={targetPosition} />
<Handle type="target" position={targetPosition} on:connect:start on:connect on:connect:end />