1
1
<script lang="ts" setup>
2
- import { ref , toRef } from ' vue'
2
+ import { ref , toRef , watch } from ' vue'
3
3
import UserSelection from ' ../../components/UserSelection/UserSelection.vue'
4
4
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'
7
6
import { useKeyPress , useVueFlow } from ' ../../composables'
8
7
import { getConnectedEdges , getNodesInside } from ' ../../utils'
9
8
import { getMousePosition } from ' ./utils'
10
9
11
- const { isSelecting } = defineProps <{ isSelecting: boolean }>()
10
+ const { isSelecting, selectionKeyPressed } = defineProps <{ isSelecting: boolean ; selectionKeyPressed : boolean }>()
12
11
13
12
const {
14
13
vueFlowRef,
@@ -43,41 +42,44 @@ const containerBounds = ref<DOMRect>()
43
42
44
43
const hasActiveSelection = toRef (() => elementsSelectable .value && (isSelecting || userSelectionActive .value ))
45
44
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 )
52
47
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 })
61
49
62
- if (nodesToRemove || getSelectedEdges .value ) {
63
- if (getSelectedEdges .value .length > 0 ) {
64
- removeEdges (getSelectedEdges .value )
65
- }
50
+ const multiSelectKeyPressed = useKeyPress (multiSelectionKeyCode )
66
51
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
+ }
70
65
71
- nodesSelectionActive .value = false
66
+ if (nodesToRemove || getSelectedEdges .value ) {
67
+ if (getSelectedEdges .value .length > 0 ) {
68
+ removeEdges (getSelectedEdges .value )
69
+ }
72
70
73
- removeSelectedElements ()
71
+ if (nodesToRemove .length > 0 ) {
72
+ removeNodes (nodesToRemove )
74
73
}
75
- },
76
- { actInsideInputWithModifier: false },
77
- )
78
74
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
81
83
})
82
84
83
85
function resetUserSelection() {
@@ -89,7 +91,8 @@ function resetUserSelection() {
89
91
}
90
92
91
93
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
93
96
return
94
97
}
95
98
@@ -121,8 +124,9 @@ function onWheel(event: WheelEvent) {
121
124
emits .paneScroll (event )
122
125
}
123
126
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 )
126
130
127
131
if (
128
132
! hasActiveSelection .value ||
@@ -153,26 +157,19 @@ function onMouseDown(event: MouseEvent) {
153
157
emits .selectionStart (event )
154
158
}
155
159
156
- function onMouseMove (event : MouseEvent ) {
160
+ function onPointerMove (event : PointerEvent ) {
157
161
if (! hasActiveSelection .value ) {
158
162
return emits .paneMouseMove (event )
159
163
}
160
164
161
- if (! isSelecting || ! containerBounds .value || ! userSelectionRect .value ) {
165
+ if (! containerBounds .value || ! userSelectionRect .value ) {
162
166
return
163
167
}
164
168
165
- if (! userSelectionActive .value ) {
166
- userSelectionActive .value = true
167
- }
168
-
169
- if (nodesSelectionActive .value ) {
170
- nodesSelectionActive .value = false
171
- }
169
+ selectionInProgress .value = true
172
170
173
171
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
176
173
177
174
const nextUserSelectRect = {
178
175
... userSelectionRect .value ,
@@ -187,6 +184,7 @@ function onMouseMove(event: MouseEvent) {
187
184
userSelectionRect .value ,
188
185
viewport .value ,
189
186
selectionMode .value === SelectionMode .Partial ,
187
+ true ,
190
188
)
191
189
192
190
const selectedEdges = getConnectedEdges (selectedNodes , getEdges .value )
@@ -199,14 +197,12 @@ function onMouseMove(event: MouseEvent) {
199
197
addSelectedElements ([... selectedNodes , ... selectedEdges ])
200
198
}
201
199
202
- function onMouseUp (event : MouseEvent ) {
203
- if (! hasActiveSelection .value ) {
200
+ function onPointerUp (event : PointerEvent ) {
201
+ if (! hasActiveSelection .value || event . button !== 0 ) {
204
202
return
205
203
}
206
204
207
- if (event .button !== 0 ) {
208
- return
209
- }
205
+ container .value ?.releasePointerCapture (event .pointerId )
210
206
211
207
// We only want to trigger click functions when in selection mode if
212
208
// the user did not move the mouse.
@@ -219,22 +215,15 @@ function onMouseUp(event: MouseEvent) {
219
215
resetUserSelection ()
220
216
221
217
emits .selectionEnd (event )
222
- }
223
-
224
- function onMouseLeave(event : MouseEvent ) {
225
- if (! hasActiveSelection .value ) {
226
- return emits .paneMouseLeave (event )
227
- }
228
218
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
232
223
}
233
-
234
- resetUserSelection ()
235
224
}
236
225
237
- function onMouseEnter (event : MouseEvent ) {
226
+ function onPointerEnter (event : PointerEvent ) {
238
227
if (hasActiveSelection .value ) {
239
228
return
240
229
}
@@ -258,11 +247,10 @@ export default {
258
247
@click =" onClick"
259
248
@contextmenu =" onContextMenu"
260
249
@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"
266
254
>
267
255
<slot />
268
256
<UserSelection v-if =" userSelectionActive && userSelectionRect" :user-selection-rect =" userSelectionRect" />
0 commit comments