@@ -16,60 +16,103 @@ const SPACE = 4;
1616/**
1717 * Calculate Tooltip left offset.
1818 *
19+ * @param placementRef Tooltip placement.
1920 * @param activatorEl Activator Element
2021 * @param tooltipWidth Tooltip element width
21- * @param placement Tooltip placement.
2222 * @returns Tooltip left offset
2323 */
2424function getTooltipLeftPosition (
25+ placementRef : Ref < TPlacementPosition > ,
2526 activatorEl : Element ,
26- tooltipWidth : number ,
27- placement ?: TPlacementPosition
28- ) {
27+ tooltipWidth : number
28+ ) : number {
2929 const domRect = activatorEl . getBoundingClientRect ( ) ;
3030 const parentRect = activatorEl . parentElement ?. getBoundingClientRect ( ) ;
31+ const maxLeft = window . innerWidth - SPACE - tooltipWidth ;
32+ const plX = domRect . left - tooltipWidth - SPACE ;
33+ const prX = domRect . left + domRect . width + SPACE ;
3134
32- switch ( placement ) {
35+ switch ( placementRef . value ) {
3336 case 'left' :
34- return domRect . left - tooltipWidth - SPACE ;
37+ if ( plX >= SPACE ) {
38+ return plX ;
39+ } else {
40+ placementRef . value = 'right' ;
41+ return prX ;
42+ }
3543 case 'right' :
36- return domRect . left + domRect . width + SPACE ;
44+ if ( prX <= maxLeft ) {
45+ return prX ;
46+ } else {
47+ placementRef . value = 'left' ;
48+ return plX ;
49+ }
3750 case 'top' :
3851 case 'bottom' :
3952 default :
40- return (
53+ const tx =
4154 domRect . left +
4255 Math . min ( domRect . width / 2 , ( parentRect ?. width ?? domRect . width ) / 2 ) -
43- tooltipWidth / 2
44- ) ;
56+ tooltipWidth / 2 ;
57+ return Math . min ( maxLeft , tx ) ;
4558 }
4659}
4760
4861/**
4962 * Calculate Tooltip top offset.
5063 *
64+ * @param placementRef Tooltip placement reference.
5165 * @param activatorEl Activator Element
5266 * @param tooltipHeight Tooltip element height
53- * @param placement Tooltip placement.
5467 * @returns Tooltip top offset
5568 */
5669function getTooltipTopPosition (
70+ placementRef : Ref < TPlacementPosition > ,
5771 activatorEl : Element ,
58- tooltipHeight : number ,
59- placement ?: TPlacementPosition
60- ) {
61- const rect = activatorEl . getBoundingClientRect ( ) ;
72+ tooltipHeight : number
73+ ) : number {
74+ const domRect = activatorEl . getBoundingClientRect ( ) ;
75+ const ptY = domRect . top - tooltipHeight - SPACE ;
76+ const pbY = domRect . top + domRect . height + SPACE ;
6277
63- switch ( placement ) {
78+ switch ( placementRef . value ) {
6479 case 'top' :
65- return rect . top - tooltipHeight - SPACE ;
80+ if ( ptY >= SPACE ) {
81+ return ptY ;
82+ } else {
83+ placementRef . value = 'bottom' ;
84+ return pbY ;
85+ }
6686 case 'bottom' :
67- return rect . top + rect . height + SPACE ;
87+ const maxY = domRect . bottom + tooltipHeight + SPACE ;
88+ if ( pbY + tooltipHeight <= maxY ) {
89+ return pbY ;
90+ } else {
91+ placementRef . value = 'top' ;
92+ return ptY ;
93+ }
6894 case 'left' :
6995 case 'right' :
7096 default :
71- return rect . top + rect . height / 2 - tooltipHeight / 2 ;
97+ return domRect . top + domRect . height / 2 - tooltipHeight / 2 ;
98+ }
99+ }
100+
101+ function getArrowLeftPosition (
102+ activatorEl : Element ,
103+ tooltipEl : Element ,
104+ placement ?: TPlacementPosition
105+ ) : number {
106+ const domRect = activatorEl . getBoundingClientRect ( ) ;
107+ const tooltipRect = tooltipEl . getBoundingClientRect ( ) ;
108+ const domWidth = domRect . width / 2 ;
109+ const arrow = 13 / 2 ;
110+
111+ if ( placement === 'top' || placement === 'bottom' ) {
112+ return domRect . left - tooltipRect . left + domWidth - arrow ;
72113 }
114+
115+ return 0 ;
73116}
74117
75118/**
@@ -120,10 +163,12 @@ function findActivatorElement(
120163export function useSetTooltipPosition (
121164 activatorRef : Ref < Element | null > ,
122165 tooltipRef : Ref < Element | null > ,
123- placement ?: TPlacementPosition
166+ tooltipArrowRef : Ref < Element | null > ,
167+ placementRef : Ref < TPlacementPosition >
124168) : void {
125169 const activatorEl = unref ( activatorRef ) as Element | null ;
126170 const tooltipEl = unref ( tooltipRef ) as HTMLElement | null ;
171+ const arrowEl = unref ( tooltipArrowRef ) as HTMLElement | null ;
127172
128173 if ( ! activatorEl || ! tooltipEl ) {
129174 return ;
@@ -133,20 +178,26 @@ export function useSetTooltipPosition(
133178 const tooltipRect = tooltipEl . getBoundingClientRect ( ) ;
134179
135180 tooltipEl . style . top =
136- getTooltipTopPosition ( activatorEl , tooltipRect . height , placement ) + 'px' ;
181+ getTooltipTopPosition ( placementRef , activatorEl , tooltipRect . height ) + 'px' ;
137182 tooltipEl . style . left =
138- getTooltipLeftPosition ( activatorEl , tooltipRect . width , placement ) + 'px' ;
183+ getTooltipLeftPosition ( placementRef , activatorEl , tooltipRect . width ) + 'px' ;
184+
185+ if ( arrowEl ) {
186+ const px = getArrowLeftPosition ( activatorEl , tooltipEl , placementRef . value ) ;
187+ arrowEl . style . left = px > 0 ? `${ px } px` : '' ;
188+ }
139189 }
140190}
141191
142192export function useAddTooltipListener (
143193 tooltipRef : Ref < Element | null > ,
194+ tooltipArrowRef : Ref < Element | null > ,
144195 activatorRef : Ref < Element | null > ,
196+ placementRef : Ref < TPlacementPosition > ,
145197 active : Ref < boolean > ,
146198 disabled : Ref < boolean > ,
147199 instance : ComponentInternalInstance | null ,
148- trigger ?: string | Element | ComponentPublicInstance ,
149- placement ?: TPlacementPosition
200+ trigger ?: string | Element | ComponentPublicInstance
150201) {
151202 if ( ! instance ) {
152203 return ;
@@ -158,7 +209,7 @@ export function useAddTooltipListener(
158209 }
159210
160211 window . requestAnimationFrame ( ( ) => {
161- useSetTooltipPosition ( activatorRef , tooltipRef , placement ) ;
212+ useSetTooltipPosition ( activatorRef , tooltipRef , tooltipArrowRef , placementRef ) ;
162213 instance . emit ( 'update:show' , true ) ;
163214 active . value = true ;
164215 } ) ;
@@ -173,11 +224,10 @@ export function useAddTooltipListener(
173224 activatorRef . value = activatorEl ;
174225
175226 if ( activatorEl ) {
176- const options = { capture : true , passive : false } ;
177-
227+ // const options = { capture: true, passive: false };
178228 ( activatorEl as IBindingElement ) . __mouseEvents = {
179- mouseEnter : EventListener . listen ( activatorEl , 'mouseenter' , showTooltip , options ) ,
180- mouseLeave : EventListener . listen ( activatorEl , 'mouseleave' , hideTooltip , options ) ,
229+ mouseEnter : EventListener . listen ( activatorEl , 'mouseenter' , showTooltip ) ,
230+ mouseLeave : EventListener . listen ( activatorEl , 'mouseleave' , hideTooltip ) ,
181231 focus : EventListener . listen ( activatorEl , 'focus' , showTooltip ) ,
182232 blur : EventListener . listen ( activatorEl , 'blur' , hideTooltip ) ,
183233 } ;
0 commit comments