-
Notifications
You must be signed in to change notification settings - Fork 48.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
Add scrollIntoView to fragment instances #32814
base: main
Are you sure you want to change the base?
Conversation
fiber => { | ||
const hostNode = getHostNodeFromHostFiber(fiber); | ||
const position = getComputedStyle(hostNode).position; | ||
return position === 'sticky' || position === 'fixed'; |
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.
If a child is sticky or fixed, we really shouldn't need to call scrollIntoView on them because they're always in the viewport. At least fixed. Where as sticky might need it but not because it is sticky but because its parent might be outside the viewport which makes it no different from other nodes.
What makes a group interesting is really the parent of the hostNode, not the hostNode itself. It's the question of whether calling it would be able to shift a different parent than another node.
Unfortunately, the scrollable parent might not be the immediate DOM node parent. It might be any of the parents. In fact, commonly it's the root document.documentElement
.
The other issue is that we'd have to call getComputedStyle(...)
(checking overflow
and position
) on every parent above to figure out if it would. However, we can be smarter than that. To know if two nodes are in different scroll parents we only have to answer the question if there are any scrollable things between the shared common ancestor and each of the nodes.
In the common case the shared common ancestor is the parent node and so there are nothing in between and so no need to make a getComputedStyle
call. Worst case something is like a portal in document.body
whose child is not position stick/fixed and a deep node sibling. In that case we'd have to check every parent of the deep node to figure out if there's a scroll between. But this would be very unusual.
) { | ||
// Skip hidden subtrees | ||
} else { | ||
// Add children of a portal into their own group |
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.
There's not really anything special about portals in that you can have one portal point to the same parent as the regular children and a different portal to document.body. Really what matters is the .parentNode
of the DOM node inside the portal.
An interesting case is something like:
Then you have a fragment with two portals that render into a and b. Showing both would require scrolling both the child inside a and the child inside b into view. However, if you call it on a and then b you might scroll a out of view as a result. You could flip it and scroll b into view first and then a since in general we want to show the top edge. I think technically scrolling b into view is not technically required by the API since we don't guarantee all children all visible since that may be impossible. However, if we didn't then if a is like a portal into a toolbar (for example a breadcrumb) then just showing that isn't sufficient to show the primary content which is in a nested scroll below the toolbar. So I do think we need to treat this case as first scrolling b into view and then scrolling a into view to attempt to show both. |
Based off #32813
This adds
scrollIntoView(alignToTop)
. It doesn't yet supportscrollIntoView(options)
.Cases:
alignToTop=true|undefined
or the last childalignToTop=false
. We call scroll on that element.I'll continue testing on some additional examples to see if these semantics need adjusting but publishing in the meantime for any initial feedback