1- import React , { Fragment , memo , useCallback , useMemo , useRef , useState } from 'react' ;
1+ import React , { Fragment , memo , useCallback , useEffect , useMemo , useRef , useState } from 'react' ;
22import { Modal as RNModal , TouchableOpacity , View } from 'react-native' ;
33
44import { InvertedThemeProvider } from '../../system/ThemeProvider' ;
@@ -24,24 +24,55 @@ export const Tooltip = memo(
2424 visible,
2525 invertColorScheme = true ,
2626 elevation,
27+ openDelay = 0 ,
28+ closeDelay = 0 ,
2729 } : TooltipProps ) => {
2830 const subjectRef = useRef < View | null > ( null ) ;
2931 const [ isOpen , setIsOpen ] = useState ( false ) ;
3032 const isVisible = visible !== false && isOpen ;
3133 const [ subjectLayout , setSubjectLayout ] = useState < SubjectLayout > ( ) ;
34+ const openTimeoutRef = useRef < ReturnType < typeof setTimeout > | null > ( null ) ;
35+ const closeTimeoutRef = useRef < ReturnType < typeof setTimeout > | null > ( null ) ;
3236
3337 const WrapperComponent = invertColorScheme ? InvertedThemeProvider : Fragment ;
3438
3539 const { opacity, translateY, animateIn, animateOut } = useTooltipAnimation ( placement ) ;
3640
41+ const clearOpenTimeout = useCallback ( ( ) => {
42+ if ( openTimeoutRef . current ) {
43+ clearTimeout ( openTimeoutRef . current ) ;
44+ openTimeoutRef . current = null ;
45+ }
46+ } , [ ] ) ;
47+
48+ const clearCloseTimeout = useCallback ( ( ) => {
49+ if ( closeTimeoutRef . current ) {
50+ clearTimeout ( closeTimeoutRef . current ) ;
51+ closeTimeoutRef . current = null ;
52+ }
53+ } , [ ] ) ;
54+
3755 const handleRequestClose = useCallback ( ( ) => {
38- animateOut . start ( ( ) => {
39- setIsOpen ( false ) ;
40- onCloseTooltip ?.( ) ;
41- } ) ;
42- } , [ animateOut , onCloseTooltip ] ) ;
56+ clearOpenTimeout ( ) ;
57+ clearCloseTimeout ( ) ;
58+
59+ const closeTooltip = ( ) => {
60+ animateOut . start ( ( ) => {
61+ setIsOpen ( false ) ;
62+ onCloseTooltip ?.( ) ;
63+ } ) ;
64+ } ;
65+
66+ if ( closeDelay > 0 ) {
67+ closeTimeoutRef . current = setTimeout ( closeTooltip , closeDelay ) ;
68+ return ;
69+ }
70+
71+ closeTooltip ( ) ;
72+ } , [ animateOut , clearCloseTimeout , clearOpenTimeout , closeDelay , onCloseTooltip ] ) ;
4373
4474 const handlePressSubject = useCallback ( ( ) => {
75+ clearCloseTimeout ( ) ;
4576 subjectRef . current ?. measure ( ( x , y , width , height , pageOffsetX , pageOffsetY ) => {
4677 setSubjectLayout ( {
4778 width,
@@ -50,9 +81,19 @@ export const Tooltip = memo(
5081 pageOffsetY,
5182 } ) ;
5283 } ) ;
53- setIsOpen ( true ) ;
54- onOpenTooltip ?.( ) ;
55- } , [ onOpenTooltip ] ) ;
84+ const openTooltip = ( ) => {
85+ setIsOpen ( true ) ;
86+ onOpenTooltip ?.( ) ;
87+ } ;
88+
89+ clearOpenTimeout ( ) ;
90+ if ( openDelay > 0 ) {
91+ openTimeoutRef . current = setTimeout ( openTooltip , openDelay ) ;
92+ return ;
93+ }
94+
95+ openTooltip ( ) ;
96+ } , [ clearCloseTimeout , clearOpenTimeout , onOpenTooltip , openDelay ] ) ;
5697
5798 // The accessibility props for the trigger component. Trigger component
5899 // equals the component where when you click on it, it will show the tooltip
@@ -86,6 +127,13 @@ export const Tooltip = memo(
86127 [ content , accessibilityLabelForContent , accessibilityHintForContent , handleRequestClose ] ,
87128 ) ;
88129
130+ useEffect ( ( ) => {
131+ return ( ) => {
132+ clearOpenTimeout ( ) ;
133+ clearCloseTimeout ( ) ;
134+ } ;
135+ } , [ clearCloseTimeout , clearOpenTimeout ] ) ;
136+
89137 return (
90138 < View ref = { subjectRef } collapsable = { false } >
91139 < TouchableOpacity
0 commit comments