-
Notifications
You must be signed in to change notification settings - Fork 48.3k
Add scrollIntoView to fragment instances #32814
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
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.
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.
Updated to walk up the DOM tree checking for scrollable containers between the instance and the common ancestor with the last instance checked as a way of partitioning the elements.
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. |
4b46c8c
to
51e0162
Compare
@sebmarkbage I added a test case like the two portals example and also added a portal into a scroll container in the fixture. And also changed the semantics around the ordering of scrolling to each container based on alignToTop. alignToTop true (default call) will scroll to the first element in each container, in reverse order. alignToTop false will scroll to the last item in each container in top down order. This follows the example you showed and works in the current fixture. The remaining thing is checking the viewport to see if we can scroll to the next container without pushing the current one out. I'll work on that but might make it another PR. |
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