-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Popover: make sure offset middleware always applies the latest frame offset values #43329
Conversation
ed95a32
to
85eb8df
Compare
|
||
const middleware = [ | ||
frameOffset.current || offset |
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.
Removed the frameOffset.current || offset
check, since it can cause a situation where offsetMiddleware is not added/removed when needed
Example:
frameOffset.current
starts asundefined
- therefore,
offsetMiddleware
is not added to the array frameOffset.current
is assigned to an object (e.g{x: 0, y: 32 }
)- the change to
frameOffset.current
doesn't cause a re-render, and thereforeoffsetMiddleware
is still not added to the list of middlewares
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.
Thanks for catching that, this change makes sense 👍
@@ -390,33 +388,37 @@ const Popover = ( | |||
// we need to manually update the floating's position as the reference's owner | |||
// document scrolls. Also update the frame offset if the view resizes. | |||
useLayoutEffect( () => { | |||
if ( ownerDocument === document ) { | |||
if ( referenceOwnerDocument === document ) { | |||
frameOffsetRef.current = undefined; |
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.
Resetting frameOffsetRef.current
when there's no iframe
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.
Yes, I guess this is possible if the popover anchor changes from something in an iframe to something outside. Good spot 👍
@@ -244,7 +244,7 @@ export const WithSlotOutsideIframe = ( args ) => { | |||
<Iframe | |||
style={ { | |||
width: '100%', | |||
height: '100%', | |||
height: '400px', |
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.
These are just some cosmetic changes for the Storybook iframe example (see PR description for more info)
Size Change: +17 B (0%) Total Size: 1.24 MB
ℹ️ View Unchanged
|
@@ -166,7 +166,7 @@ const Popover = ( | |||
? positionToPlacement( position ) | |||
: placementProp; | |||
|
|||
const ownerDocument = useMemo( () => { | |||
const referenceOwnerDocument = useMemo( () => { |
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.
Renamed to a more clear name
: undefined, | ||
offsetMiddleware( ( { placement: currentPlacement } ) => { | ||
if ( ! frameOffsetRef.current ) { | ||
return offset ?? 0; |
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.
Added a fallback, since now we're not guaranteed that offset
will be defined when the middleware runs
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.
Another option could be to give the prop a default value. That would also mean normalizedOffset
could be removed a few lines below this.
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.
Good point, done as part of 4bf6dfc
I'm working on a follow-up PR (#43335) which could hopefully solve more glitches related to the component not updating correctly, although this PR will need to be merged first |
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.
Looks good, I left a few comments, but nothing blocking.
85eb8df
to
4bf6dfc
Compare
@talldan thank you for your review! I pushed a new commit where I applied your feedback (default value for the |
Awesome, thanks! |
Thanks for your work here Marco! |
What?
Tracked in #42770
Fixes a regression introduced by #43172 and #43267 where the
Popover
would sometimes not position correctly compared to its anchorWhy?
The cause of this regression is that when
frameOffset
was refactored to be a ref object, we didn't take into account the fact that theoffset
middleware was being added based (also) onframeOffset.current
— and therefore, since the value offrameOffset.current
wouldn't cause a re-render when changing (it's a ref), theoffset
middleware would not be correctly added / removed.(see #43329 (comment) for more details)
How?
This PR makes the
offset
middleware always present in the middleware chain, removing the conditional check. This ensures that the middleware runs every time — the resulting offset will be still based offframeOffset.current
anyway.Testing Instructions
Open Storybook and make sure that the examples work as expected
In both the site editor and the post editor:
Known issues:
The iframe storybook example is still not behaving as expected (it never did since its introduction), but it's getting better every time. The reason for this may be related to the
anchorRef
object and the fact that its changes don't always trigger hook runs as they should.Screenshots
trunk
:Kapture.2022-08-17.at.17.00.21.mp4
This PR:
Kapture.2022-08-17.at.16.58.55.mp4