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
@@ -5,14 +5,14 @@
const { edgesLayouted, width, height } = useStore();
</script>
<svg width={$width} height={$height} class="react-flow__edges">
<svg width={$width} height={$height} class="svelte-flow__edges">
{#each $edgesLayouted as edge (edge.id)}
<EdgeWrapper {...edge} />
<EdgeWrapper {...edge} on:edge:click />
{/each}
</svg>
<style>
.react-flow__edges {
.svelte-flow__edges {
width: 100%;
height: 100%;
position: absolute;
@@ -21,16 +21,27 @@
onDestroy(() => {
resizeObserver?.disconnect();
});
</script>
<div class="react-flow__nodes">
<div class="svelte-flow__nodes">
{#each $nodes as node (node.id)}
<NodeWrapper {...node} {resizeObserver} />
<NodeWrapper
{...node}
{resizeObserver}
on:node:click
on:node:mouseenter
on:node:mousemove
on:node:mouseleave
on:connect:start
on:connect
on:connect:end
/>
{/each}
</div>
<style>
.react-flow__nodes {
.svelte-flow__nodes {
width: 100%;
height: 100%;
pointer-events: none;
@@ -29,13 +29,15 @@
</script>
<script lang="ts">
import { useStore } from '$lib/store';
import { createEventDispatcher } from 'svelte';
import { SelectionMode } from '@reactflow/system';
import { getEventPosition, getNodesInside } from '@reactflow/utils';
import { useStore } from '$lib/store';
import { getConnectedEdges } from '$lib/utils';
import type { Node, Edge } from '$lib/types';
const dispatch = createEventDispatcher();
const {
nodes,
edges,
@@ -60,7 +62,7 @@
$: hasActiveSelection = elementsSelectable && (isSelecting || $selectionRectMode === 'user');
function onClick(event: MouseEvent) {
// onPaneClick?.(event);
dispatch('pane:click');
resetSelectedElements();
selectionRectMode.set(null);
@@ -155,11 +157,21 @@
selectionRect.set(null);
};
const onContextMenu = (event: MouseEvent) => {
// if (Array.isArray(panOnDrag) && panOnDrag?.includes(2)) {
// event.preventDefault();
// return;
// }
dispatch('pane:contextmenu');
};
</script>
<div
bind:this={container}
class="react-flow__pane"
class="svelte-flow__pane"
class:dragging={$dragging}
class:selection={isSelecting}
on:click={hasActiveSelection ? undefined : wrapHandler(onClick, container)}
@@ -167,12 +179,13 @@
on:mousemove={hasActiveSelection ? onMouseMove : undefined}
on:mouseup={hasActiveSelection ? onMouseUp : undefined}
on:mouseleave={hasActiveSelection ? onMouseLeave : undefined}
on:contextmenu={wrapHandler(onContextMenu, container)}
>
<slot />
</div>
<style>
.react-flow__pane {
.svelte-flow__pane {
cursor: grab;
position: absolute;
top: 0;
@@ -12,34 +12,34 @@
$: positionClasses = `${position}`.split('-');
</script>
<div class={cc(['react-flow__panel', className, ...positionClasses])} {style}>
<div class={cc(['svelte-flow__panel', className, ...positionClasses])} {style}>
<slot />
</div>
<style>
.react-flow__panel {
.svelte-flow__panel {
position: absolute;
z-index: 5;
margin: 15px;
}
.react-flow__panel.top {
.svelte-flow__panel.top {
top: 0;
}
.react-flow__panel.bottom {
.svelte-flow__panel.bottom {
bottom: 0;
}
.react-flow__panel.left {
.svelte-flow__panel.left {
left: 0;
}
.react-flow__panel.right {
.svelte-flow__panel.right {
right: 0;
}
.react-flow__panel.center {
.svelte-flow__panel.center {
left: 50%;
transform: translateX(-50%);
}
@@ -1,6 +1,5 @@
<script lang="ts">
import { setContext, onMount } from 'svelte';
import { ConnectionLineType } from '@reactflow/system';
import { setContext, onMount, createEventDispatcher } from 'svelte';
import cc from 'classcat';
import { key, createStore } from '$lib/store';
@@ -13,21 +12,27 @@
import { NodeSelection } from '$lib/components/NodeSelection';
import { KeyHandler } from '$lib/components/KeyHandler';
import { ConnectionLine } from '$lib/components/ConnectionLine';
import type { SvelteFlowProps } from './types';
import type { SvelteFlowProps, SvelteFlowEvents } from './types';
type $$Props = SvelteFlowProps;
type $$Events = SvelteFlowEvents;
export let id: $$Props['id'] = '1';
export let nodes: $$Props['nodes'] = [];
export let edges: $$Props['edges'] = [];
export let fitView: $$Props['fitView'] = undefined;
export let minZoom: $$Props['minZoom'] = undefined;
export let maxZoom: $$Props['maxZoom'] = undefined;
export let initialViewport: $$Props['initialViewport'] = undefined;
export let nodeTypes: $$Props['nodeTypes'] = undefined;
export let edgeTypes: $$Props['edgeTypes'] = undefined;
export let selectionKey: $$Props['selectionKey'] = undefined;
export let deleteKey: $$Props['deleteKey'] = undefined;
export let connectionLineType: $$Props['connectionLineType'] = ConnectionLineType.Bezier;
export let connectionLineType: $$Props['connectionLineType'] = undefined
let className: $$Props['class'] = undefined;
export { className as class };
const dispatch = createEventDispatcher<{ 'on:nodeclick': number }>();
let domNode: HTMLDivElement;
@@ -51,8 +56,33 @@
store.nodes.subscribe((ns) => {
nodes = ns;
});
store.edges.subscribe((es) => {
edges = es;
});
});
$: {
const updatableProps = {
id,
connectionLineType,
};
Object.keys(updatableProps).forEach(prop => {
// @ts-ignore
if (updatableProps[prop] !== undefined) {
// @ts-ignore
if (!store[prop]) {
// @ts-ignore
console.warn(store[prop], prop, 'ups')
} else {
// @ts-ignore
store[prop].set(updatableProps[prop]);
}
}
})
}
$: {
store.setNodes(nodes);
}
@@ -60,23 +90,47 @@
$: {
store.setEdges(edges);
}
$: {
if (nodeTypes !== undefined) {
store.setNodeTypes(nodeTypes);
}
if (edgeTypes !== undefined) {
store.setEdgeTypes(edgeTypes);
}
if (minZoom !== undefined) {
store.setMinZoom(minZoom);
}
if (maxZoom !== undefined) {
store.setMaxZoom(maxZoom);
}
}
</script>
<div
{...$$restProps}
class={cc(['react-flow', className])}
class={cc(['svelte-flow', className])}
data-testid="rf__wrapper"
{id}
bind:this={domNode}
>
<KeyHandler {selectionKey} {deleteKey} />
<Zoom>
<Pane>
<Zoom {initialViewport}>
<Pane on:pane:click>
<Viewport>
<EdgeRenderer />
<EdgeRenderer on:edge:click />
<ConnectionLine />
<div class="react-flow__edgelabel-renderer" />
<NodeRenderer />
<div class="svelte-flow__edgelabel-renderer" />
<NodeRenderer
on:node:click
on:node:mouseenter
on:node:mousemove
on:node:mouseleave
on:connect:start
on:connect
on:connect:end
/>
<NodeSelection />
</Viewport>
<UserSelection />
@@ -86,7 +140,7 @@
</div>
<style>
.react-flow {
.svelte-flow {
width: 100%;
height: 100%;
overflow: hidden;
@@ -94,13 +148,13 @@
z-index: 0;
}
.react-flow :global(.react-flow__node-default),
.react-flow :global(.react-flow__node-input),
.react-flow :global(.react-flow__node-output) {
.svelte-flow :global(.svelte-flow__node-default),
.svelte-flow :global(.svelte-flow__node-input),
.svelte-flow :global(.svelte-flow__node-output) {
padding: 10px;
}
.react-flow__edgelabel-renderer {
.svelte-flow__edgelabel-renderer {
position: absolute;
width: 100%;
height: 100%;
@@ -1,2 +1,2 @@
export { default as SvelteFlow } from './SvelteFlow.svelte';
export type { SvelteFlowProps } from './types';
export * from './types';
@@ -1,17 +1,49 @@
import type { ConnectionLineType } from '@reactflow/system';
import type { ConnectionLineType, NodeOrigin, Viewport } from '@reactflow/system';
import type { Edge, Node, NodeTypes, KeyDefinition } from '$lib/types';
import type {
Edge,
Node,
NodeTypes,
KeyDefinition,
EdgeTypes,
DefaultEdgeOptions
} from '$lib/types';
export type SvelteFlowProps = {
nodes: Node[];
edges: Edge[];
connectionLineType?: ConnectionLineType;
id?: string;
nodeTypes?: NodeTypes;
edgeTypes?: EdgeTypes;
selectionKey?: KeyDefinition;
deleteKey?: KeyDefinition;
nodeTypes?: NodeTypes;
fitView?: boolean;
nodeOrigin?: NodeOrigin;
minZoom?: number;
maxZoom?: number;
initialViewport?: Viewport;
defaultEdgeOptions?: DefaultEdgeOptions;
class?: string;
style?: string;
id?: string;
connectionLineType?: ConnectionLineType;
};
export type SvelteFlowEvents = {
'node:click': CustomEvent<Node>;
'node:mouseenter': CustomEvent<Node>;
'node:mousemove': CustomEvent<Node>;
'node:mouseleave': CustomEvent<Node>;
'edge:click': CustomEvent<Edge>;
'connect:start': CustomEvent<number>;
connect: CustomEvent<number>;
'connect:end': CustomEvent<number>;
'pane:click': CustomEvent;
'pane:contextmenu': CustomEvent;
};
export type SvelteFlowSlots = {
default: { slotValue: string };
};
@@ -5,14 +5,14 @@
</script>
<div
class="react-flow__viewport"
class="svelte-flow__viewport"
style="transform: translate({$transform[0]}px, {$transform[1]}px) scale({$transform[2]})"
>
<slot />
</div>
<style>
.react-flow__viewport {
.svelte-flow__viewport {
width: 100%;
height: 100%;
position: absolute;
@@ -1,18 +1,23 @@
<script lang="ts">
import { get } from 'svelte/store';
import type { Viewport } from '@reactflow/system';
import { useStore } from '$lib/store';
import zoom from '$lib/actions/zoom';
const { transform, d3, selectionKeyPressed, selectionRectMode } = useStore();
export let initialViewport: Viewport = { x: 0, y: 0, zoom: 1 };
const { transform, d3, selectionKeyPressed, selectionRectMode, minZoom, maxZoom } = useStore();
$: selecting = $selectionKeyPressed || $selectionRectMode === 'user';
</script>
<div class="react-flow__zoom" use:zoom={{ transform, d3, selecting }}>
<div class="svelte-flow__zoom" use:zoom={{ transform, d3, selecting, minZoom: get(minZoom), maxZoom: get(maxZoom), initialViewport }}>
<slot />
</div>
<style>
.react-flow__zoom {
.svelte-flow__zoom {
width: 100%;
height: 100%;
position: absolute;