Files
xyflow/packages/svelte/src/lib/components/NodeWrapper/NodeWrapper.svelte
Moritz Klack 1dab08f36e feat(utils): add vanilla drag and panzoom (#3108)
* refactor(panzoom): create vanilla helper

* feat(svelte): add interaction example

* refactor(panzoom): cleanup

* Update function-runner.ts

* refactor(panzoom): cleanup

* refactor(panzoom): rename functions

* feat(utils): add vanilla drag helper (#3107)

* feat(utils): add vanilla drag helper

* refactor(drag): cleanup

* refactor(drag): cleanup

* chore(packages): cleanup

* refactor(panzoom): cleanup and simplify
2023-05-31 15:55:36 +02:00

142 lines
4.2 KiB
Svelte

<script lang="ts">
import { createEventDispatcher, onMount, setContext, SvelteComponentTyped } from 'svelte';
import cc from 'classcat';
import { errorMessages, type NodeProps } from '@reactflow/system';
import drag from '$lib/actions/drag';
import { useStore } from '$lib/store';
import DefaultNode from '$lib/components/nodes/DefaultNode.svelte';
import type { NodeWrapperProps } from './types';
interface $$Props extends NodeWrapperProps {}
export let id: NodeWrapperProps['id'];
export let data: NodeWrapperProps['data'] = {};
export let selected: NodeWrapperProps['selected'] = false;
export let draggable: NodeWrapperProps['draggable'] = undefined;
export let selectable: NodeWrapperProps['selectable'] = undefined;
export let connectable: NodeWrapperProps['connectable'] = true;
export let dragging: boolean = false;
export let resizeObserver: NodeWrapperProps['resizeObserver'] = null;
export let style: NodeWrapperProps['style'] = undefined;
export let width: NodeWrapperProps['width'] = undefined;
export let height: NodeWrapperProps['height'] = undefined;
export let type: NodeWrapperProps['type'] = 'default';
export let isParent: NodeWrapperProps['isParent'] = false;
export let positionAbsolute: NodeWrapperProps['positionAbsolute'] = undefined;
export let positionOrigin: NodeWrapperProps['positionOrigin'] = undefined;
export let sourcePosition: NodeWrapperProps['sourcePosition'] = undefined;
export let targetPosition: NodeWrapperProps['targetPosition'] = undefined;
let className: string = '';
export { className as class };
const store = useStore();
const { nodes, nodeTypes, addSelectedNodes } = store;
let nodeRef: HTMLDivElement;
const nodeTypeValid = !!$nodeTypes[type!];
if (!nodeTypeValid) {
console.warn('003', errorMessages['error003'](type!));
type = 'default';
}
const nodeComponent: typeof SvelteComponentTyped<Partial<NodeProps>> =
$nodeTypes[type!] || DefaultNode;
const selectNodesOnDrag = false;
const dispatch = createEventDispatcher();
setContext('svelteflow__node_id', id);
setContext('svelteflow__node_connectable', connectable);
onMount(() => {
resizeObserver?.observe(nodeRef);
return () => {
resizeObserver?.unobserve(nodeRef);
};
});
function dispatchEvent(eventName: string) {
const node = $nodes.find(n => n.id === id);
dispatch(eventName, node);
}
function onSelectNodeHandler(event: MouseEvent) {
if (selectable && (!selectNodesOnDrag || !draggable)) {
// this handler gets called within the drag start event when selectNodesOnDrag=true
addSelectedNodes([id]);
}
dispatchEvent('node:click')
}
</script>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
use:drag={{ nodeId: id, isSelectable: selectable, disabled: false, handleSelector: undefined, noDragClassName: 'nodrag', store }}
bind:this={nodeRef}
data-id={id}
class={cc(['svelte-flow__node', `svelte-flow__node-${type || 'default'}`, className])}
class:initializing={!width && !height}
class:dragging
class:selected
class:draggable
class:connectable
class:parent={isParent}
style:transform={`translate(${positionOrigin?.x ?? 0}px, ${positionOrigin?.y ?? 0}px)`}
{style}
on:click={onSelectNodeHandler}
on:mouseenter={() => dispatchEvent('node:mouseenter')}
on:mouseleave={() => dispatchEvent('node:mouseleave')}
on:mousemove={() => dispatchEvent('node:mousemove')}
>
<svelte:component
this={nodeComponent}
{data}
{id}
{selected}
{sourcePosition}
{targetPosition}
xPos={positionAbsolute?.x ?? 0}
yPos={positionAbsolute?.y ?? 0}
on:connect:start
on:connect
on:connect:end
/>
</div>
<style>
.svelte-flow__node {
border-radius: 3px;
color: #222;
text-align: center;
border-width: 1px;
border-style: solid;
border-color: #1a192b;
background-color: white;
position: absolute;
pointer-events: none;
user-select: none;
}
.draggable {
cursor: grab;
pointer-events: all;
}
.selected {
outline: none;
box-shadow: 0 0 0 0.5px #1a192b;
}
.dragging {
cursor: grabbing;
}
.initializing {
visibility: hidden;
}
</style>