1
- import { ref , unref , watch , nextTick , onUnmounted } from 'vue' ;
2
- import { arrow , autoPlacement , computePosition , offset , shift } from '@floating-ui/dom' ;
1
+ import { ref , unref , watch , nextTick , onUnmounted , toRefs } from 'vue' ;
2
+ import { arrow , computePosition , offset , flip } from '@floating-ui/dom' ;
3
3
import { FlexibleOverlayProps , Placement , Point , UseOverlayFn , EmitEventFn , Rect } from './flexible-overlay-types' ;
4
- import { getScrollParent } from './utils' ;
5
4
6
5
function adjustArrowPosition ( isArrowCenter : boolean , point : Point , placement : Placement , originRect : Rect ) : Point {
7
6
let { x, y } = point ;
@@ -25,9 +24,10 @@ function adjustArrowPosition(isArrowCenter: boolean, point: Point, placement: Pl
25
24
}
26
25
27
26
export function useOverlay ( props : FlexibleOverlayProps , emit : EmitEventFn ) : UseOverlayFn {
27
+ const { position, showArrow } = toRefs ( props ) ;
28
28
const overlayRef = ref < HTMLElement | undefined > ( ) ;
29
29
const arrowRef = ref < HTMLElement | undefined > ( ) ;
30
- let originParent = null ;
30
+
31
31
const updateArrowPosition = ( arrowEl : HTMLElement , placement : Placement , point : Point , overlayEl : HTMLElement ) => {
32
32
const { x, y } = adjustArrowPosition ( props . isArrowCenter , point , placement , overlayEl . getBoundingClientRect ( ) ) ;
33
33
const staticSide = {
@@ -48,54 +48,46 @@ export function useOverlay(props: FlexibleOverlayProps, emit: EmitEventFn): UseO
48
48
const hostEl = < HTMLElement > props . origin ;
49
49
const overlayEl = < HTMLElement > unref ( overlayRef . value ) ;
50
50
const arrowEl = < HTMLElement > unref ( arrowRef . value ) ;
51
- const middleware = [
52
- offset ( props . offset ) ,
53
- autoPlacement ( {
54
- alignment : props . align ,
55
- allowedPlacements : props . position ,
56
- } ) ,
57
- ] ;
58
- props . showArrow && middleware . push ( arrow ( { element : arrowEl } ) ) ;
59
- props . shiftOffset !== undefined && middleware . push ( shift ( ) ) ;
60
- if ( ! overlayEl ) {
61
- return ;
51
+
52
+ const [ mainPosition , ...fallbackPosition ] = position . value ;
53
+ const middleware = [ offset ( props . offset ) ] ;
54
+ middleware . push ( fallbackPosition . length ? flip ( { fallbackPlacements : fallbackPosition } ) : flip ( ) ) ;
55
+ if ( showArrow . value ) {
56
+ middleware . push ( arrow ( { element : arrowRef . value ! } ) ) ;
62
57
}
63
58
const { x, y, placement, middlewareData } = await computePosition ( hostEl , overlayEl , {
64
59
strategy : 'fixed' ,
60
+ placement : mainPosition ,
65
61
middleware,
66
62
} ) ;
67
63
let applyX = x ;
68
64
let applyY = y ;
69
- if ( props . shiftOffset !== undefined ) {
70
- const { x : shiftX , y : shiftY } = middlewareData . shift ;
71
- shiftX < 0 && ( applyX -= props . shiftOffset ) ;
72
- shiftX > 0 && ( applyX += props . shiftOffset ) ;
73
- shiftY < 0 && ( applyY -= props . shiftOffset ) ;
74
- shiftY > 0 && ( applyY += props . shiftOffset ) ;
75
- }
76
65
emit ( 'positionChange' , placement ) ;
77
66
Object . assign ( overlayEl . style , { top : `${ applyY } px` , left : `${ applyX } px` } ) ;
78
67
props . showArrow && updateArrowPosition ( arrowEl , placement , middlewareData . arrow , overlayEl ) ;
79
68
} ;
69
+
70
+ const scrollCallback = ( e : Event ) => {
71
+ const scrollElement = e . target as HTMLElement ;
72
+ if ( scrollElement ?. contains ( props . origin ?. $el ?? props . origin ) ) {
73
+ updatePosition ( ) ;
74
+ }
75
+ } ;
80
76
watch (
81
77
( ) => props . modelValue ,
82
78
( ) => {
83
79
if ( props . modelValue && props . origin ) {
84
- originParent = getScrollParent ( props . origin ) ;
85
80
nextTick ( updatePosition ) ;
86
- originParent ?. addEventListener ( 'scroll' , updatePosition ) ;
87
- originParent !== window && window . addEventListener ( 'scroll' , updatePosition ) ;
81
+ window . addEventListener ( 'scroll' , scrollCallback , true ) ;
88
82
window . addEventListener ( 'resize' , updatePosition ) ;
89
83
} else {
90
- originParent ?. removeEventListener ( 'scroll' , updatePosition ) ;
91
- originParent !== window && window . removeEventListener ( 'scroll' , updatePosition ) ;
84
+ window . removeEventListener ( 'scroll' , scrollCallback , true ) ;
92
85
window . removeEventListener ( 'resize' , updatePosition ) ;
93
86
}
94
87
}
95
88
) ;
96
89
onUnmounted ( ( ) => {
97
- originParent ?. removeEventListener ( 'scroll' , updatePosition ) ;
98
- originParent !== window && window . removeEventListener ( 'scroll' , updatePosition ) ;
90
+ window . removeEventListener ( 'scroll' , scrollCallback , true ) ;
99
91
window . removeEventListener ( 'resize' , updatePosition ) ;
100
92
} ) ;
101
93
0 commit comments