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' ;
33import { FlexibleOverlayProps , Placement , Point , UseOverlayFn , EmitEventFn , Rect } from './flexible-overlay-types' ;
4- import { getScrollParent } from './utils' ;
54
65function adjustArrowPosition ( isArrowCenter : boolean , point : Point , placement : Placement , originRect : Rect ) : Point {
76 let { x, y } = point ;
@@ -25,9 +24,10 @@ function adjustArrowPosition(isArrowCenter: boolean, point: Point, placement: Pl
2524}
2625
2726export function useOverlay ( props : FlexibleOverlayProps , emit : EmitEventFn ) : UseOverlayFn {
27+ const { position, showArrow } = toRefs ( props ) ;
2828 const overlayRef = ref < HTMLElement | undefined > ( ) ;
2929 const arrowRef = ref < HTMLElement | undefined > ( ) ;
30- let originParent = null ;
30+
3131 const updateArrowPosition = ( arrowEl : HTMLElement , placement : Placement , point : Point , overlayEl : HTMLElement ) => {
3232 const { x, y } = adjustArrowPosition ( props . isArrowCenter , point , placement , overlayEl . getBoundingClientRect ( ) ) ;
3333 const staticSide = {
@@ -48,54 +48,46 @@ export function useOverlay(props: FlexibleOverlayProps, emit: EmitEventFn): UseO
4848 const hostEl = < HTMLElement > props . origin ;
4949 const overlayEl = < HTMLElement > unref ( overlayRef . value ) ;
5050 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 ! } ) ) ;
6257 }
6358 const { x, y, placement, middlewareData } = await computePosition ( hostEl , overlayEl , {
6459 strategy : 'fixed' ,
60+ placement : mainPosition ,
6561 middleware,
6662 } ) ;
6763 let applyX = x ;
6864 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- }
7665 emit ( 'positionChange' , placement ) ;
7766 Object . assign ( overlayEl . style , { top : `${ applyY } px` , left : `${ applyX } px` } ) ;
7867 props . showArrow && updateArrowPosition ( arrowEl , placement , middlewareData . arrow , overlayEl ) ;
7968 } ;
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+ } ;
8076 watch (
8177 ( ) => props . modelValue ,
8278 ( ) => {
8379 if ( props . modelValue && props . origin ) {
84- originParent = getScrollParent ( props . origin ) ;
8580 nextTick ( updatePosition ) ;
86- originParent ?. addEventListener ( 'scroll' , updatePosition ) ;
87- originParent !== window && window . addEventListener ( 'scroll' , updatePosition ) ;
81+ window . addEventListener ( 'scroll' , scrollCallback , true ) ;
8882 window . addEventListener ( 'resize' , updatePosition ) ;
8983 } else {
90- originParent ?. removeEventListener ( 'scroll' , updatePosition ) ;
91- originParent !== window && window . removeEventListener ( 'scroll' , updatePosition ) ;
84+ window . removeEventListener ( 'scroll' , scrollCallback , true ) ;
9285 window . removeEventListener ( 'resize' , updatePosition ) ;
9386 }
9487 }
9588 ) ;
9689 onUnmounted ( ( ) => {
97- originParent ?. removeEventListener ( 'scroll' , updatePosition ) ;
98- originParent !== window && window . removeEventListener ( 'scroll' , updatePosition ) ;
90+ window . removeEventListener ( 'scroll' , scrollCallback , true ) ;
9991 window . removeEventListener ( 'resize' , updatePosition ) ;
10092 } ) ;
10193
0 commit comments