feat(svelte): add drag n drop example

This commit is contained in:
moklick
2023-03-14 16:48:47 +01:00
parent 9c7bd6dc68
commit 2e486384a8
8 changed files with 202 additions and 17 deletions
@@ -2,6 +2,7 @@
import { goto } from '$app/navigation';
const routes = [
'drag-n-drop',
'overview',
'stress',
'usesvelteflow',
@@ -12,10 +12,9 @@
import { KeyHandler } from '$lib/components/KeyHandler';
import { ConnectionLine } from '$lib/components/ConnectionLine';
import { useStore } from '$lib/store';
import type { SvelteFlowProps, SvelteFlowEvents } from './types';
import type { SvelteFlowProps } from './types';
type $$Props = SvelteFlowProps;
type $$Events = SvelteFlowEvents;
export let id: $$Props['id'] = '1';
export let fitView: $$Props['fitView'] = undefined;
@@ -98,6 +97,9 @@
style={style}
class={cc(['svelte-flow', className])}
data-testid="rf__wrapper"
on:dragover
on:drop
{...$$restProps}
>
<KeyHandler {selectionKey} {deleteKey} />
<Zoom {initialViewport}>
@@ -1,3 +1,4 @@
import type { DOMAttributes } from 'svelte/elements';
import type {
Connection,
ConnectionLineType,
@@ -17,7 +18,7 @@ import type {
IsValidConnection
} from '$lib/types';
export type SvelteFlowProps = {
export type SvelteFlowProps = DOMAttributes<HTMLDivElement> & {
id?: string;
nodeTypes?: NodeTypes;
edgeTypes?: EdgeTypes;
@@ -37,19 +38,17 @@ export type SvelteFlowProps = {
connectionLineType?: ConnectionLineType;
isValidConnection?: IsValidConnection;
};
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<OnConnectStartParams>;
connect: CustomEvent<Connection>;
'connect:end': CustomEvent<OnConnectStartParams>;
'pane:click': CustomEvent;
'pane:contextmenu': CustomEvent;
'on:node:click'?: CustomEvent<Node>;
'on:node:mouseenter'?: CustomEvent<Node>;
'on:node:mousemove'?: CustomEvent<Node>;
'on:node:mouseleave'?: CustomEvent<Node>;
'on:edge:click'?: CustomEvent<Edge>;
'on:connect:start'?: CustomEvent<OnConnectStartParams>;
'on:connect'?: CustomEvent<Connection>;
'on:connect:end'?: CustomEvent<OnConnectStartParams>;
'on:pane:click'?: CustomEvent;
'on:pane:contextmenu'?: CustomEvent;
};
export type SvelteFlowSlots = {
@@ -1,9 +1,10 @@
import type { Viewport, ZoomInOut } from '@reactflow/system';
import type { Project, Viewport, XYPosition, ZoomInOut } from '@reactflow/system';
import { useStore } from '$lib/store';
import type { FitViewOptions } from '$lib/types';
import { get, writable, type Writable } from 'svelte/store';
import type { SvelteFlowStore } from '$lib/store/types';
import { pointToRendererPoint } from '@reactflow/utils';
export function useSvelteFlow(): {
zoomIn: ZoomInOut;
@@ -12,9 +13,10 @@ export function useSvelteFlow(): {
viewport: Writable<Viewport>;
nodes: SvelteFlowStore['nodes'];
edges: SvelteFlowStore['edges'];
project: Project;
} {
// how to get the new context here? fit view doesn't work, because the store is not updated (uses old nodes store)
const { zoomIn, zoomOut, fitView, transform, nodes, edges } = useStore();
const { zoomIn, zoomOut, fitView, snapGrid: snapGridStore, transform, nodes, edges } = useStore();
const transformValues = get(transform);
const viewportWritable = writable({
@@ -35,6 +37,10 @@ export function useSvelteFlow(): {
zoomIn,
zoomOut,
fitView,
project: (position: XYPosition) => {
const snapGrid = get(snapGridStore);
return pointToRendererPoint(position, get(transform), snapGrid !== null, snapGrid || [1, 1]);
},
nodes,
edges,
viewport: viewportWritable
+1
View File
@@ -292,6 +292,7 @@ export function createStore(params: CreateStoreParams): SvelteFlowStore {
store.fitViewOnInitDone.set(false);
store.selectionRect.set(null);
store.selectionRectMode.set(null);
store.snapGrid.set(null);
resetSelectedElements();
cancelConnection();
@@ -0,0 +1,52 @@
<script lang="ts">
import { createNodes, createEdges, SvelteFlowProvider } from '../../lib/index';
import Flow from './Flow.svelte';
const nodes = createNodes(
[
{
id: '1',
type: 'input',
data: { label: 'Input Node' },
position: { x: 150, y: 5 }
},
{
id: '2',
type: 'default',
data: { label: 'Node' },
position: { x: 0, y: 150 }
},
{
id: '3',
type: 'output',
data: { label: 'Output Node' },
position: { x: 300, y: 150 }
}
],
{ origin: [0.5, 0.5] }
);
const edges = createEdges([
{
id: '1-2',
type: 'default',
source: '1',
target: '2',
label: 'Edge Text'
},
{
id: '1-3',
type: 'smoothstep',
source: '1',
target: '3'
}
]);
</script>
<SvelteFlowProvider
{nodes}
{edges}
>
<Flow />
</SvelteFlowProvider>
@@ -0,0 +1,65 @@
<script lang="ts">
import SvelteFlow, {
Controls,
Background,
BackgroundVariant,
Minimap,
useSvelteFlow,
type Node
} from '../../lib/index';
import Sidebar from './Sidebar.svelte';
const svelteFlow = useSvelteFlow();
const onDragOver = (event: DragEvent) => {
event.preventDefault();
console.log(event)
if (event.dataTransfer) {
event.dataTransfer.dropEffect = 'move';
}
};
const onDrop = (event: DragEvent) => {
event.preventDefault();
if (!event.dataTransfer) {
return null;
}
const type = event.dataTransfer.getData('application/svelteflow');
const position = svelteFlow.project({
x: event.clientX,
y: event.clientY - 40,
});
const newNode: Node = {
id: `${Math.random()}`,
type,
position,
data: { label: `${type} node` },
};
svelteFlow.nodes.update(nds => nds.concat(newNode));
};
</script>
<main>
<SvelteFlow
fitView
on:dragover={onDragOver}
on:drop={onDrop}
>
<Controls />
<Background variant={BackgroundVariant.Dots} />
<Minimap />
</SvelteFlow>
<Sidebar />
</main>
<style>
main {
height: 100%;
display: flex;
}
</style>
@@ -0,0 +1,59 @@
<script lang="ts">
import {
useSvelteFlow
} from '../../lib/index';
const onDragStart = (event: DragEvent, nodeType: string) => {
if (!event.dataTransfer) {
return null;
}
event.dataTransfer.setData('application/svelteflow', nodeType);
event.dataTransfer.effectAllowed = 'move';
};
const { zoomIn, zoomOut, fitView, viewport, nodes } = useSvelteFlow();
</script>
<aside>
<div class="label">You can drag these nodes to the pane on the left.</div>
<div class="input-node node" on:dragstart={(event) => onDragStart(event, 'input')} draggable={true}>
Input Node
</div>
<div
class="default-node node"
on:dragstart={(event) => onDragStart(event, 'default')}
draggable={true}
>
Default Node
</div>
<div
class="output-node node"
on:dragstart={(event) => onDragStart(event, 'output')}
draggable={true}
>
Output Node
</div>
</aside>
<style>
.label {
margin: 0.5rem 0 .25rem 0;
}
aside {
width: 20vw;
background: #f4f4f4;
padding: 0.4rem 0.8rem;
font-size: 12px;
}
.node {
margin-bottom: 0.5rem;
border: 1px solid #111;
padding: .5rem 1rem;
font-weight: 700;
border-radius: 3px;
cursor: grab;
}
</style>