@@ -388,6 +388,8 @@ export default () => ({
388
388
389
389
methods : {
390
390
show ( { event = null , skipDelay = false , force = false } = { } ) {
391
+ if ( this . parentPopper ?. lockedChild && this . parentPopper . lockedChild !== this ) return
392
+
391
393
this . $_pendingHide = false
392
394
if ( force || ! this . disabled ) {
393
395
this . $_scheduleShow ( event , skipDelay )
@@ -404,10 +406,24 @@ export default () => ({
404
406
405
407
hide ( { event = null , skipDelay = false } = { } ) {
406
408
if ( this . $_hideInProgress ) return
409
+
410
+ // Abort if child is shown
407
411
if ( this . shownChildren . size > 0 ) {
408
412
this . $_pendingHide = true
409
413
return
410
414
}
415
+
416
+ // Abort if aiming for the popper
417
+ if ( this . $_isAimingPopper ( ) ) {
418
+ if ( this . parentPopper ) {
419
+ this . parentPopper . lockedChild = this
420
+ }
421
+ return
422
+ }
423
+ if ( this . parentPopper ?. lockedChild === this ) {
424
+ this . parentPopper . lockedChild = null
425
+ }
426
+
411
427
this . $_pendingHide = false
412
428
this . $_scheduleHide ( event , skipDelay )
413
429
@@ -935,6 +951,28 @@ export default () => ({
935
951
parent = parent . parentPopper
936
952
}
937
953
} ,
954
+
955
+ $_isAimingPopper ( ) {
956
+ const referenceBounds : DOMRect = this . $el . getBoundingClientRect ( )
957
+ if ( mouseX >= referenceBounds . left && mouseX <= referenceBounds . right && mouseY >= referenceBounds . top && mouseY <= referenceBounds . bottom ) {
958
+ const popperBounds : DOMRect = this . $_popperNode . getBoundingClientRect ( )
959
+ const vectorX = mouseX - mousePreviousX
960
+ const vectorY = mouseY - mousePreviousY
961
+ const distance = ( popperBounds . left + popperBounds . width / 2 ) - mousePreviousX + ( popperBounds . top + popperBounds . height / 2 ) - mousePreviousY
962
+ // Make the vector long enough to be sure that it can intersect with the popper
963
+ const newVectorLength = distance + popperBounds . width + popperBounds . height
964
+ const edgeX = mousePreviousX + vectorX * newVectorLength
965
+ const edgeY = mousePreviousY + vectorY * newVectorLength
966
+ // Check for collision between the vector and the popper bounds
967
+ return (
968
+ lineIntersectsLine ( mousePreviousX , mousePreviousY , edgeX , edgeY , popperBounds . left , popperBounds . top , popperBounds . left , popperBounds . bottom ) || // Left edge
969
+ lineIntersectsLine ( mousePreviousX , mousePreviousY , edgeX , edgeY , popperBounds . left , popperBounds . top , popperBounds . right , popperBounds . top ) || // Top edge
970
+ lineIntersectsLine ( mousePreviousX , mousePreviousY , edgeX , edgeY , popperBounds . right , popperBounds . top , popperBounds . right , popperBounds . bottom ) || // Right edge
971
+ lineIntersectsLine ( mousePreviousX , mousePreviousY , edgeX , edgeY , popperBounds . left , popperBounds . bottom , popperBounds . right , popperBounds . bottom ) // Bottom edge
972
+ )
973
+ }
974
+ return false
975
+ } ,
938
976
} ,
939
977
940
978
render ( ) {
@@ -1014,3 +1052,29 @@ export function hideAllPoppers () {
1014
1052
popper . hide ( )
1015
1053
}
1016
1054
}
1055
+
1056
+ // Track mouse movement to detect aiming at the popper
1057
+
1058
+ let mousePreviousX = 0
1059
+ let mousePreviousY = 0
1060
+ let mouseX = 0
1061
+ let mouseY = 0
1062
+
1063
+ if ( typeof window !== 'undefined' ) {
1064
+ window . addEventListener ( 'mousemove' , event => {
1065
+ mousePreviousX = mouseX
1066
+ mousePreviousY = mouseY
1067
+ mouseX = event . clientX
1068
+ mouseY = event . clientY
1069
+ } , supportsPassive
1070
+ ? {
1071
+ passive : true ,
1072
+ }
1073
+ : undefined )
1074
+ }
1075
+
1076
+ function lineIntersectsLine ( x1 : number , y1 : number , x2 : number , y2 : number , x3 : number , y3 : number , x4 : number , y4 : number ) {
1077
+ const uA = ( ( x4 - x3 ) * ( y1 - y3 ) - ( y4 - y3 ) * ( x1 - x3 ) ) / ( ( y4 - y3 ) * ( x2 - x1 ) - ( x4 - x3 ) * ( y2 - y1 ) )
1078
+ const uB = ( ( x2 - x1 ) * ( y1 - y3 ) - ( y2 - y1 ) * ( x1 - x3 ) ) / ( ( y4 - y3 ) * ( x2 - x1 ) - ( x4 - x3 ) * ( y2 - y1 ) )
1079
+ return ( uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1 )
1080
+ }
0 commit comments