-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix transition bug on Firefox, triggered by clicking the PopoverButton
in rapid succession
#3452
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
Up until now, we've tried to do this ourselves by listening to the correct events. The new `node.getAnimations()` API is a much simpler API to use. The only requirement is that we call `node.getAnimations()` in a `requestAnimationFrame` so that the browser can flush all the changes. We couldn't do this before, because we needed to setup the event listeners to prevent race conditions. Now there are no race conditions, in fact, if all transitions already complete before we can call the `waitForTransition`, then the `node.getAnimations()` list will be empty and we can call the `done()` function. The `Element.prototype.getAnimations` has been available in browsers since mid 2020, but at the time it was too new to use. Now seems like a safe time to use this. See: https://developer.mozilla.org/en-US/docs/Web/API/Element/getAnimations#browser_compatibility
The order slightly changed here, but it looks more correct now as well. The `child-2-1` and `child-2-2` have the same duration/delay, so the order that they are rendered in seems to be the correct order. That said, these DOM nodes are on the same level (siblings), so for these callbacks we are testing here the order doesn't really matter. The order that _does_ matter is that the `after*` events of a parent fire _after_ the `after*` events of the children, which it still does.
fe1b1a6
to
aa9e189
Compare
PopoverButton
in rapid succession on Firefox
4bdddbe
to
03da4d5
Compare
PopoverButton
in rapid succession on Firefox PopoverButton
in rapid succession
'child-2-1: afterEnter', | ||
'child-2-2: afterEnter', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you know why the order of these changed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's based on the order that the setTimeout
is being called. I can get the old behavior by applying this diff:
diff --git a/packages/@headlessui-react/jest.setup.js b/packages/@headlessui-react/jest.setup.js
index 771a30cb..9e656463 100644
--- a/packages/@headlessui-react/jest.setup.js
+++ b/packages/@headlessui-react/jest.setup.js
@@ -15,9 +15,11 @@ globalThis.IS_REACT_ACT_ENVIRONMENT = true
this.duration = duration
}
- finished = new Promise((resolve) => {
- setTimeout(resolve, this.duration)
- })
+ get finished() {
+ return new Promise((resolve) => {
+ setTimeout(resolve, this.duration)
+ })
+ }
}
}
But the exact reason why I am still unsure about. The order is also only different on the same level (siblings) which is the less important part I think. The more important part is the relation between child and parent and that that order is correct.
That said, note that the order here (and in the old code) was determined by the setTimeout
(not by the real events because JSDOM doesn't have proper support for them all).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could revert the change to the test, and apply the diff above. But it feels incorrect since that would rely on us accessing the finished
property, instead of relying on the creation of the CSSTransition
object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah that's fine — was just curious and hoping it wasn't a side effect of some "problem"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW, if you look at the browser example of this:
- Main: https://headlessui-react.vercel.app/transitions/component-examples/modal
- PR: https://headlessui-react-git-fix-improve-transition-20b73f-tailwindlabs.vercel.app/transitions/component-examples/modal
The output is in the exact same order (notice the order of the siblings "overlay" and "panel")
Main version:
Events:
2024-09-04T14:04:49.428Z - [Root] Before enter
2024-09-04T14:04:49.430Z - [Overlay] Before enter
2024-09-04T14:04:49.430Z - [Panel] Before enter
2024-09-04T14:04:49.765Z - [Overlay] After enter
2024-09-04T14:04:49.794Z - [Panel] After enter
2024-09-04T14:04:49.794Z - [Root] After enter
2024-09-04T14:04:50.873Z - [Overlay] Before leave
2024-09-04T14:04:50.873Z - [Panel] Before leave
2024-09-04T14:04:50.873Z - [Root] Before leave
2024-09-04T14:04:51.116Z - [Overlay] After leave
2024-09-04T14:04:51.124Z - [Panel] After leave
2024-09-04T14:04:51.124Z - [Root] After leave
PR version:
Events:
2024-09-04T14:04:17.440Z - [Root] Before enter
2024-09-04T14:04:17.441Z - [Overlay] Before enter
2024-09-04T14:04:17.441Z - [Panel] Before enter
2024-09-04T14:04:17.781Z - [Overlay] After enter
2024-09-04T14:04:17.820Z - [Panel] After enter
2024-09-04T14:04:17.820Z - [Root] After enter
2024-09-04T14:04:19.504Z - [Overlay] Before leave
2024-09-04T14:04:19.504Z - [Panel] Before leave
2024-09-04T14:04:19.504Z - [Root] Before leave
2024-09-04T14:04:19.765Z - [Overlay] After leave
2024-09-04T14:04:19.767Z - [Panel] After leave
2024-09-04T14:04:19.767Z - [Root] After leave
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sweet 👍
We now have jest tests failing with
|
Indeed, also having a regression, see #3469 |
@RobinMalfait we got a bug report on linktr.ee that I believe might be fixed by this. https://bugzilla.mozilla.org/show_bug.cgi?id=1916176 I'd like to better understand why Firefox isn't firing the |
We recently landed a fix for
Popover
s not closing correctly when using thetransition
prop (#3448). Once this fix was published, some users still ran into issues using Firefox on Windows (see: tailwindlabs/tailwindui-issues#1625).One fun thing I discovered is that transitions somehow behave differently based on where they are triggered from (?). What I mean by this is that holding down the space key on the button does properly open/close the
Popover
. But if you rapidly click the button, thePopover
will eventually get stuck.The debugging continues…
One thing I noticed is that when the
Popover
gets stuck, it meant that a transition didn't properly complete.The current implementation of the internal
useTransition(…)
hook has to wait for all the transitions to finish. This is done using awaitForTransition(…)
helper. This helper sets up some event listeners (transitionstart
,transitionend
, …) and waits for them to fire.This seems to be unreliable on Firefox for some unknown reason.
I knew the code for waiting for transitions wasn't ideal, so I wanted to see if using the native
node.getAnimations()
simplifies this and makes it work in general.Lo and behold, it did! 🎉
This now has multiple benefits:
The
getAnimations(…)
function is supported in all modern browsers (since 2020). At the time it was too early to rely on it, but right now it should be safe to use.Fixes: tailwindlabs/tailwindui-issues#1625