@@ -4,9 +4,12 @@ import {
44 useControlledState ,
55 useGetLatest ,
66 generateBoundingClientRect ,
7+ isMouseOutside ,
78} from './utils' ;
89import { Config , PopperOptions , PropsGetterArgs , TriggerType } from './types' ;
910
11+ const { isArray } = Array ;
12+
1013const virtualElement = {
1114 getBoundingClientRect : generateBoundingClientRect ( ) ,
1215} ;
@@ -24,7 +27,7 @@ const defaultConfig: Config = {
2427 childList : true ,
2528 subtree : true ,
2629 } ,
27- offset : [ 0 , 7 ] ,
30+ offset : [ 0 , 6 ] ,
2831 trigger : 'hover' ,
2932} ;
3033
@@ -47,7 +50,8 @@ export function usePopperTooltip(
4750
4851 const defaultModifiers = React . useMemo (
4952 ( ) => [ { name : 'offset' , options : { offset : finalConfig . offset } } ] ,
50- [ finalConfig . offset ]
53+ // eslint-disable-next-line react-hooks/exhaustive-deps
54+ isArray ( finalConfig . offset ) ? finalConfig . offset : [ ]
5155 ) ;
5256
5357 const finalPopperOptions = {
@@ -83,11 +87,12 @@ export function usePopperTooltip(
8387
8488 const isTriggeredBy = React . useCallback (
8589 ( trigger : TriggerType ) => {
86- return Array . isArray ( finalConfig . trigger )
90+ return isArray ( finalConfig . trigger )
8791 ? finalConfig . trigger . includes ( trigger )
8892 : finalConfig . trigger === trigger ;
8993 } ,
90- [ finalConfig . trigger ]
94+ // eslint-disable-next-line react-hooks/exhaustive-deps
95+ isArray ( finalConfig . trigger ) ? finalConfig . trigger : [ finalConfig . trigger ]
9196 ) ;
9297
9398 const hideTooltip = React . useCallback ( ( ) => {
@@ -180,12 +185,56 @@ export function usePopperTooltip(
180185 if ( triggerRef == null || ! isTriggeredBy ( 'hover' ) ) return ;
181186
182187 triggerRef . addEventListener ( 'mouseenter' , showTooltip ) ;
183- triggerRef . addEventListener ( 'mouseleave' , hideTooltip ) ;
184188 return ( ) => {
185189 triggerRef . removeEventListener ( 'mouseenter' , showTooltip ) ;
186- triggerRef . removeEventListener ( 'mouseleave' , hideTooltip ) ;
187190 } ;
188191 } , [ triggerRef , isTriggeredBy , showTooltip , hideTooltip ] ) ;
192+ // Listen for mouse exiting the hover area &&
193+ // handle the followCursor
194+ React . useEffect ( ( ) => {
195+ if (
196+ ! visible ||
197+ triggerRef == null ||
198+ ( ! isTriggeredBy ( 'hover' ) && ! finalConfig . followCursor )
199+ ) {
200+ return ;
201+ }
202+
203+ let lastMouseOutside = false ;
204+ const handleMouseMove = ( event : MouseEvent ) => {
205+ const mouseOutside = isMouseOutside (
206+ event ,
207+ triggerRef ,
208+ ! finalConfig . followCursor &&
209+ getLatest ( ) . finalConfig . interactive &&
210+ tooltipRef
211+ ) ;
212+ if ( mouseOutside && lastMouseOutside !== mouseOutside ) {
213+ hideTooltip ( ) ;
214+ }
215+ if ( ! mouseOutside && finalConfig . followCursor ) {
216+ virtualElement . getBoundingClientRect = generateBoundingClientRect (
217+ event . clientX ,
218+ event . clientY
219+ ) ;
220+ update ?.( ) ;
221+ }
222+ lastMouseOutside = mouseOutside ;
223+ } ;
224+ window . addEventListener ( 'mousemove' , handleMouseMove ) ;
225+ return ( ) => {
226+ window . removeEventListener ( 'mousemove' , handleMouseMove ) ;
227+ } ;
228+ } , [
229+ finalConfig . followCursor ,
230+ getLatest ,
231+ hideTooltip ,
232+ isTriggeredBy ,
233+ tooltipRef ,
234+ triggerRef ,
235+ update ,
236+ visible ,
237+ ] ) ;
189238
190239 // Trigger: hover on tooltip, keep it open if hovered
191240 React . useEffect ( ( ) => {
@@ -206,28 +255,6 @@ export function usePopperTooltip(
206255 if ( finalConfig . closeOnTriggerHidden && isReferenceHidden ) hideTooltip ( ) ;
207256 } , [ finalConfig . closeOnTriggerHidden , hideTooltip , isReferenceHidden ] ) ;
208257
209- // Handle follow cursor
210- React . useEffect ( ( ) => {
211- if ( ! finalConfig . followCursor || triggerRef == null ) return ;
212-
213- function setMousePosition ( {
214- clientX,
215- clientY,
216- } : {
217- clientX : number ;
218- clientY : number ;
219- } ) {
220- virtualElement . getBoundingClientRect = generateBoundingClientRect (
221- clientX ,
222- clientY
223- ) ;
224- update ?.( ) ;
225- }
226-
227- triggerRef . addEventListener ( 'mousemove' , setMousePosition ) ;
228- return ( ) => triggerRef . removeEventListener ( 'mousemove' , setMousePosition ) ;
229- } , [ finalConfig . followCursor , triggerRef , update ] ) ;
230-
231258 // Handle tooltip DOM mutation changes (aka mutation observer)
232259 React . useEffect ( ( ) => {
233260 if (
@@ -249,9 +276,6 @@ export function usePopperTooltip(
249276 style : {
250277 ...args . style ,
251278 ...styles . popper ,
252- ...( finalConfig . followCursor && {
253- pointerEvents : 'none' as React . CSSProperties [ 'pointerEvents' ] ,
254- } ) ,
255279 } ,
256280 ...attributes . popper ,
257281 } ;
0 commit comments