Merge pull request #3998 from xyflow/svelte-selection-drag

added nodedrag events to selection box
This commit is contained in:
Moritz Klack
2024-03-14 15:25:29 +01:00
committed by GitHub
4 changed files with 48 additions and 23 deletions
@@ -6,6 +6,7 @@
import { Selection } from '$lib/components/Selection'; import { Selection } from '$lib/components/Selection';
import drag from '$lib/actions/drag'; import drag from '$lib/actions/drag';
import type { Node } from '$lib/types'; import type { Node } from '$lib/types';
import { createNodeEventDispatcher } from '$lib';
const store = useStore(); const store = useStore();
const { selectionRectMode, nodes } = store; const { selectionRectMode, nodes } = store;
@@ -14,6 +15,7 @@
selectioncontextmenu: { nodes: Node[]; event: MouseEvent | TouchEvent }; selectioncontextmenu: { nodes: Node[]; event: MouseEvent | TouchEvent };
selectionclick: { nodes: Node[]; event: MouseEvent | TouchEvent }; selectionclick: { nodes: Node[]; event: MouseEvent | TouchEvent };
}>(); }>();
const dispatchNodeEvent = createNodeEventDispatcher();
$: selectedNodes = $nodes.filter((n) => n.selected); $: selectedNodes = $nodes.filter((n) => n.selected);
$: bounds = getNodesBounds(selectedNodes); $: bounds = getNodesBounds(selectedNodes);
@@ -31,7 +33,19 @@
<div <div
class="selection-wrapper nopan" class="selection-wrapper nopan"
style="width: {bounds.width}px; height: {bounds.height}px; transform: translate({bounds.x}px, {bounds.y}px)" style="width: {bounds.width}px; height: {bounds.height}px; transform: translate({bounds.x}px, {bounds.y}px)"
use:drag={{ disabled: false, store }} use:drag={{
disabled: false,
store,
onDrag: (event, _, __, nodes) => {
dispatchNodeEvent('nodedrag', { event, targetNode: null, nodes });
},
onDragStart: (event, _, __, nodes) => {
dispatchNodeEvent('nodedragstart', { event, targetNode: null, nodes });
},
onDragStop: (event, _, __, nodes) => {
dispatchNodeEvent('nodedragstop', { event, targetNode: null, nodes });
}
}}
on:contextmenu={onContextMenu} on:contextmenu={onContextMenu}
on:click={onClick} on:click={onClick}
> >
@@ -12,6 +12,7 @@
import type { NodeWrapperProps } from './types'; import type { NodeWrapperProps } from './types';
import type { Node } from '$lib/types'; import type { Node } from '$lib/types';
import { getNodeInlineStyleDimensions } from './utils'; import { getNodeInlineStyleDimensions } from './utils';
import { createNodeEventDispatcher } from '$lib';
interface $$Props extends NodeWrapperProps {} interface $$Props extends NodeWrapperProps {}
@@ -66,16 +67,7 @@
} }
const nodeComponent = $nodeTypes[nodeType] || DefaultNode; const nodeComponent = $nodeTypes[nodeType] || DefaultNode;
const dispatch = createEventDispatcher<{ const dispatchNodeEvent = createNodeEventDispatcher();
nodeclick: { node: Node; event: MouseEvent | TouchEvent };
nodecontextmenu: { node: Node; event: MouseEvent | TouchEvent };
nodedrag: { node: Node; nodes: Node[]; event: MouseEvent | TouchEvent };
nodedragstart: { node: Node; nodes: Node[]; event: MouseEvent | TouchEvent };
nodedragstop: { node: Node; nodes: Node[]; event: MouseEvent | TouchEvent };
nodemouseenter: { node: Node; event: MouseEvent | TouchEvent };
nodemouseleave: { node: Node; event: MouseEvent | TouchEvent };
nodemousemove: { node: Node; event: MouseEvent | TouchEvent };
}>();
const connectableStore = writable(connectable); const connectableStore = writable(connectable);
let prevType: string | undefined = undefined; let prevType: string | undefined = undefined;
let prevSourcePosition: Position | undefined = undefined; let prevSourcePosition: Position | undefined = undefined;
@@ -151,7 +143,7 @@
handleNodeSelection(id); handleNodeSelection(id);
} }
dispatch('nodeclick', { node, event }); dispatchNodeEvent('nodeclick', { node, event });
} }
</script> </script>
@@ -166,14 +158,14 @@
handleSelector: dragHandle, handleSelector: dragHandle,
noDragClass: 'nodrag', noDragClass: 'nodrag',
onNodeMouseDown: handleNodeSelection, onNodeMouseDown: handleNodeSelection,
onDrag: (event, _, node, nodes) => { onDrag: (event, _, targetNode, nodes) => {
dispatch('nodedrag', { event, node, nodes }); dispatchNodeEvent('nodedrag', { event, targetNode, nodes });
}, },
onDragStart: (event, _, node, nodes) => { onDragStart: (event, _, targetNode, nodes) => {
dispatch('nodedragstart', { event, node, nodes }); dispatchNodeEvent('nodedragstart', { event, targetNode, nodes });
}, },
onDragStop: (event, _, node, nodes) => { onDragStop: (event, _, targetNode, nodes) => {
dispatch('nodedragstop', { event, node, nodes }); dispatchNodeEvent('nodedragstop', { event, targetNode, nodes });
}, },
store store
}} }}
@@ -192,10 +184,10 @@
style:visibility={initialized ? 'visible' : 'hidden'} style:visibility={initialized ? 'visible' : 'hidden'}
style="{style ?? ''};{inlineStyleDimensions.width}{inlineStyleDimensions.height}" style="{style ?? ''};{inlineStyleDimensions.width}{inlineStyleDimensions.height}"
on:click={onSelectNodeHandler} on:click={onSelectNodeHandler}
on:mouseenter={(event) => dispatch('nodemouseenter', { node, event })} on:mouseenter={(event) => dispatchNodeEvent('nodemouseenter', { node, event })}
on:mouseleave={(event) => dispatch('nodemouseleave', { node, event })} on:mouseleave={(event) => dispatchNodeEvent('nodemouseleave', { node, event })}
on:mousemove={(event) => dispatch('nodemousemove', { node, event })} on:mousemove={(event) => dispatchNodeEvent('nodemousemove', { node, event })}
on:contextmenu={(event) => dispatch('nodecontextmenu', { node, event })} on:contextmenu={(event) => dispatchNodeEvent('nodecontextmenu', { node, event })}
> >
<svelte:component <svelte:component
this={nodeComponent} this={nodeComponent}
@@ -242,7 +242,13 @@
on:nodedragstop on:nodedragstop
on:nodecontextmenu on:nodecontextmenu
/> />
<NodeSelection on:selectionclick on:selectioncontextmenu /> <NodeSelection
on:selectionclick
on:selectioncontextmenu
on:nodedragstart
on:nodedrag
on:nodedragstop
/>
</ViewportComponent> </ViewportComponent>
<UserSelection /> <UserSelection />
</Pane> </Pane>
+13
View File
@@ -1,3 +1,4 @@
import { createEventDispatcher } from 'svelte';
import { isNodeBase, isEdgeBase } from '@xyflow/system'; import { isNodeBase, isEdgeBase } from '@xyflow/system';
import type { Edge, Node } from '$lib/types'; import type { Edge, Node } from '$lib/types';
@@ -21,3 +22,15 @@ export const isNode = <NodeType extends Node = Node>(element: unknown): element
*/ */
export const isEdge = <EdgeType extends Edge = Edge>(element: unknown): element is EdgeType => export const isEdge = <EdgeType extends Edge = Edge>(element: unknown): element is EdgeType =>
isEdgeBase<EdgeType>(element); isEdgeBase<EdgeType>(element);
export const createNodeEventDispatcher = () =>
createEventDispatcher<{
nodeclick: { node: Node; event: MouseEvent | TouchEvent };
nodecontextmenu: { node: Node; event: MouseEvent | TouchEvent };
nodedrag: { targetNode: Node | null; nodes: Node[]; event: MouseEvent | TouchEvent };
nodedragstart: { targetNode: Node | null; nodes: Node[]; event: MouseEvent | TouchEvent };
nodedragstop: { targetNode: Node | null; nodes: Node[]; event: MouseEvent | TouchEvent };
nodemouseenter: { node: Node; event: MouseEvent | TouchEvent };
nodemouseleave: { node: Node; event: MouseEvent | TouchEvent };
nodemousemove: { node: Node; event: MouseEvent | TouchEvent };
}>();