-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Description
Provide a general summary of the issue here
In our design system, we had an issue with the delay functionality from the useTooltipTriggerState hook from react-stately
🤔 Expected Behavior?
When a delay is set on useTooltipTriggerState and state.open() is called twice in quick succession, the initial timeout should be respected, and the tooltip is only opened once the delay is lapsed.
😯 Current Behavior
When a delay is set on useTooltipTriggerState and state.open() is called twice in quick succession, the tooltip is immediately opened without any delay.
💁 Possible Solution
I believe there is an idempotency issue with the implementation of warmupTooltip in @react-stately/useTooltipTriggerState.ts. See the snippet below:
let warmupTooltip = () => {
closeOpenTooltips();
ensureTooltipEntry();
if (!isOpen && !globalWarmUpTimeout && !globalWarmedUp) {
globalWarmUpTimeout = setTimeout(() => {
globalWarmUpTimeout = null;
globalWarmedUp = true;
showTooltip();
}, delay);
} else if (!isOpen) {
showTooltip();
}
};If this function is called twice in quick succession. the condition !isOpen && !globalWarmUpTimeout && !globalWarmedUp will evaluate to false on the second call. This is because globalWarmUpTimeout is initialised on the first call and is not falsy on the second call.
A potential fix could look like the following:
let warmupTooltip = () => {
closeOpenTooltips();
ensureTooltipEntry();
if (!isOpen && !globalWarmedUp) {
// don't let an initialised timeout cause the tooltip to be opened immediately.
if (!globalWarmUpTimeout) {
globalWarmUpTimeout = setTimeout(() => {
globalWarmUpTimeout = null;
globalWarmedUp = true;
showTooltip();
}, delay);
}
} else if (!isOpen) {
showTooltip();
}
};🔦 Context
No response
🖥️ Steps to Reproduce
You can repro in our storybook here, but it's somewhat meaningless without seeing our tooltip implementation. Our minimal repro looks something like the following:
import { useTooltipTriggerState } from 'react-stately'
import { useTooltip, useTooltipTrigger } from 'react-aria'
// ... somewhere in a hook
const state = useTooltipTriggerState({ delay: 1000 })
const {triggerProps} = useTooltipTrigger(props, state, triggerRef)
const { tooltipProps } = useTooltip(triggerProps, state)We fixed it on our end by removing the state from useTooltip like the following:
import { useTooltipTriggerState } from 'react-stately'
import { useTooltip, useTooltipTrigger } from 'react-aria'
// ... somewhere in a hook
const state = useTooltipTriggerState({ delay: 1000 })
const {triggerProps} = useTooltipTrigger(props, state, triggerRef)
// stop double handling of `state.open` by `useTooltipTrigger` and `useTooltip`
const { tooltipProps } = useTooltip(triggerProps)This works fine, but in my investigation I believe I found an issue with the react-stately implementation of useTooltipTriggerState.
Version
react-stately@3.36.1, react-aria@3.38.1
What browsers are you seeing the problem on?
Chrome
If other, please specify.
No response
What operating system are you using?
MacOS Sequoia 15.3.2
🧢 Your Company/Team
No response
🕷 Tracking Issue
No response