Skip to content

Commit f5bdb39

Browse files
committed
refactor(core): use pointer evts in pane and prevent cancel of selection
1 parent 6d98b41 commit f5bdb39

File tree

2 files changed

+57
-68
lines changed

2 files changed

+57
-68
lines changed

packages/core/src/container/Pane/Pane.vue

Lines changed: 56 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
<script lang="ts" setup>
2-
import { ref, toRef } from 'vue'
2+
import { ref, toRef, watch } from 'vue'
33
import UserSelection from '../../components/UserSelection/UserSelection.vue'
44
import NodesSelection from '../../components/NodesSelection/NodesSelection.vue'
5-
import type { GraphNode } from '../../types'
6-
import { SelectionMode } from '../../types'
5+
import { type GraphNode, SelectionMode } from '../../types'
76
import { useKeyPress, useVueFlow } from '../../composables'
87
import { getConnectedEdges, getNodesInside } from '../../utils'
98
import { getMousePosition } from './utils'
109
11-
const { isSelecting } = defineProps<{ isSelecting: boolean }>()
10+
const { isSelecting, selectionKeyPressed } = defineProps<{ isSelecting: boolean; selectionKeyPressed: boolean }>()
1211
1312
const {
1413
vueFlowRef,
@@ -43,41 +42,44 @@ const containerBounds = ref<DOMRect>()
4342
4443
const hasActiveSelection = toRef(() => elementsSelectable.value && (isSelecting || userSelectionActive.value))
4544
46-
useKeyPress(
47-
deleteKeyCode,
48-
(keyPressed) => {
49-
if (!keyPressed) {
50-
return
51-
}
45+
// Used to prevent click events when the user lets go of the selectionKey during a selection
46+
const selectionInProgress = ref(false)
5247
53-
const nodesToRemove: GraphNode[] = []
54-
for (const node of getNodes.value) {
55-
if (!node.selected && node.parentNode && nodesToRemove.some((n) => n.id === node.parentNode)) {
56-
nodesToRemove.push(node)
57-
} else if (node.selected) {
58-
nodesToRemove.push(node)
59-
}
60-
}
48+
const deleteKeyPressed = useKeyPress(deleteKeyCode, { actInsideInputWithModifier: false })
6149
62-
if (nodesToRemove || getSelectedEdges.value) {
63-
if (getSelectedEdges.value.length > 0) {
64-
removeEdges(getSelectedEdges.value)
65-
}
50+
const multiSelectKeyPressed = useKeyPress(multiSelectionKeyCode)
6651
67-
if (nodesToRemove.length > 0) {
68-
removeNodes(nodesToRemove)
69-
}
52+
watch(deleteKeyPressed, (isKeyPressed) => {
53+
if (!isKeyPressed) {
54+
return
55+
}
56+
57+
const nodesToRemove: GraphNode[] = []
58+
for (const node of getNodes.value) {
59+
if (!node.selected && node.parentNode && nodesToRemove.some((n) => n.id === node.parentNode)) {
60+
nodesToRemove.push(node)
61+
} else if (node.selected) {
62+
nodesToRemove.push(node)
63+
}
64+
}
7065
71-
nodesSelectionActive.value = false
66+
if (nodesToRemove || getSelectedEdges.value) {
67+
if (getSelectedEdges.value.length > 0) {
68+
removeEdges(getSelectedEdges.value)
69+
}
7270
73-
removeSelectedElements()
71+
if (nodesToRemove.length > 0) {
72+
removeNodes(nodesToRemove)
7473
}
75-
},
76-
{ actInsideInputWithModifier: false },
77-
)
7874
79-
useKeyPress(multiSelectionKeyCode, (keyPressed) => {
80-
multiSelectionActive.value = keyPressed
75+
nodesSelectionActive.value = false
76+
77+
removeSelectedElements()
78+
}
79+
})
80+
81+
watch(multiSelectKeyPressed, (isKeyPressed) => {
82+
multiSelectionActive.value = isKeyPressed
8183
})
8284
8385
function resetUserSelection() {
@@ -89,7 +91,8 @@ function resetUserSelection() {
8991
}
9092
9193
function onClick(event: MouseEvent) {
92-
if (event.target !== container.value || hasActiveSelection.value) {
94+
if (selectionInProgress.value || event.target !== container.value || hasActiveSelection.value) {
95+
selectionInProgress.value = false
9396
return
9497
}
9598
@@ -121,8 +124,9 @@ function onWheel(event: WheelEvent) {
121124
emits.paneScroll(event)
122125
}
123126
124-
function onMouseDown(event: MouseEvent) {
125-
containerBounds.value = vueFlowRef.value!.getBoundingClientRect()
127+
function onPointerDown(event: PointerEvent) {
128+
containerBounds.value = vueFlowRef.value?.getBoundingClientRect()
129+
container.value?.setPointerCapture(event.pointerId)
126130
127131
if (
128132
!hasActiveSelection.value ||
@@ -153,26 +157,19 @@ function onMouseDown(event: MouseEvent) {
153157
emits.selectionStart(event)
154158
}
155159
156-
function onMouseMove(event: MouseEvent) {
160+
function onPointerMove(event: PointerEvent) {
157161
if (!hasActiveSelection.value) {
158162
return emits.paneMouseMove(event)
159163
}
160164
161-
if (!isSelecting || !containerBounds.value || !userSelectionRect.value) {
165+
if (!containerBounds.value || !userSelectionRect.value) {
162166
return
163167
}
164168
165-
if (!userSelectionActive.value) {
166-
userSelectionActive.value = true
167-
}
168-
169-
if (nodesSelectionActive.value) {
170-
nodesSelectionActive.value = false
171-
}
169+
selectionInProgress.value = true
172170
173171
const mousePos = getMousePosition(event, containerBounds.value)
174-
const startX = userSelectionRect.value.startX ?? 0
175-
const startY = userSelectionRect.value.startY ?? 0
172+
const { startX = 0, startY = 0 } = userSelectionRect.value
176173
177174
const nextUserSelectRect = {
178175
...userSelectionRect.value,
@@ -187,6 +184,7 @@ function onMouseMove(event: MouseEvent) {
187184
userSelectionRect.value,
188185
viewport.value,
189186
selectionMode.value === SelectionMode.Partial,
187+
true,
190188
)
191189
192190
const selectedEdges = getConnectedEdges(selectedNodes, getEdges.value)
@@ -199,14 +197,12 @@ function onMouseMove(event: MouseEvent) {
199197
addSelectedElements([...selectedNodes, ...selectedEdges])
200198
}
201199
202-
function onMouseUp(event: MouseEvent) {
203-
if (!hasActiveSelection.value) {
200+
function onPointerUp(event: PointerEvent) {
201+
if (!hasActiveSelection.value || event.button !== 0) {
204202
return
205203
}
206204
207-
if (event.button !== 0) {
208-
return
209-
}
205+
container.value?.releasePointerCapture(event.pointerId)
210206
211207
// We only want to trigger click functions when in selection mode if
212208
// the user did not move the mouse.
@@ -219,22 +215,15 @@ function onMouseUp(event: MouseEvent) {
219215
resetUserSelection()
220216
221217
emits.selectionEnd(event)
222-
}
223-
224-
function onMouseLeave(event: MouseEvent) {
225-
if (!hasActiveSelection.value) {
226-
return emits.paneMouseLeave(event)
227-
}
228218
229-
if (userSelectionActive.value) {
230-
nodesSelectionActive.value = prevSelectedNodesCount.value > 0
231-
emits.selectionEnd?.(event)
219+
// If the user kept holding the selectionKey during the selection,
220+
// we need to reset the selectionInProgress, so the next click event is not prevented
221+
if (selectionKeyPressed) {
222+
selectionInProgress.value = false
232223
}
233-
234-
resetUserSelection()
235224
}
236225
237-
function onMouseEnter(event: MouseEvent) {
226+
function onPointerEnter(event: PointerEvent) {
238227
if (hasActiveSelection.value) {
239228
return
240229
}
@@ -258,11 +247,10 @@ export default {
258247
@click="onClick"
259248
@contextmenu="onContextMenu"
260249
@wheel.passive="onWheel"
261-
@mouseenter="onMouseEnter"
262-
@mousedown="onMouseDown"
263-
@mousemove="onMouseMove"
264-
@mouseup="onMouseUp"
265-
@mouseleave="onMouseLeave"
250+
@pointerenter="onPointerEnter"
251+
@pointerdown="onPointerDown"
252+
@pointermove="onPointerMove"
253+
@pointerup="onPointerUp"
266254
>
267255
<slot />
268256
<UserSelection v-if="userSelectionActive && userSelectionRect" :user-selection-rect="userSelectionRect" />

packages/core/src/container/Viewport/Viewport.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ export default {
403403
<div ref="viewportRef" class="vue-flow__viewport vue-flow__container">
404404
<Pane
405405
:is-selecting="isSelecting"
406+
:selection-key-pressed="selectionKeyPressed"
406407
:class="{ connecting: !!connectionStartHandle, dragging: paneDragging, draggable: shouldPanOnDrag }"
407408
>
408409
<Transform>

0 commit comments

Comments
 (0)