Implement scroll anchoring for overlay positioning
Closes https://github.com/orgs/adobe/projects/19/views/4?pane=issue&itemId=63064435
I think this fixes #3944 as well.
When an overlay repositions, its height might change, causing the focused item to go out of view. Even if the height didn't change, this might occur because we change the max-height before positioning in order to get the correct intrinsic size. This causes the browser to lose the previous scroll position. This happens during auto focus as well, when focusing happens prior to positioning.
This PR implements scroll anchoring. We save the offset of the focused element from the scroll container before positioning, and adjust the scroll position afterward so that it appears to remain in the same place relative to the viewport, even if the height of the scroll container changed.
Test instructions:
- Open Picker story
- resize the window to be small and select an item at the bottom
- re-open the picker. Should scroll the auto focused item into view
- Resize the height of the browser window. Focused item should remain anchored in view.
- Repeat the same steps with RAC Select many items story.
Build successful! 🎉
I'm not getting the item scrolled into view for https://reactspectrum.blob.core.windows.net/reactspectrum/a7d75fc6e8e32b6fcf1997a4fa15138c2f5e9bee/storybook/index.html?path=/story/picker--dynamic-sections&providerSwitcher-express=false
Steps:
- Open picker
- Select Ross
- Close picker
- Open picker
observe Ross is not scrolled into view
hmm this looks like a different problem with ListLayout not including the persisted key...
@snowystinger added a commit to address it. Needed to clean up some old layout infos that should have been removed when we relayout from scratch (when Picker re-opens) so that we don't think the persisted keys are available when they are not.
Build successful! 🎉
@snowystinger added a commit to address it. Needed to clean up some old layout infos that should have been removed when we relayout from scratch (when Picker re-opens) so that we don't think the persisted keys are available when they are not.
~It doesn't appear to have fixed it, in Chrome MacOS. Happy to help debug tomorrow.~
~The scroll anchoring seems to help, but I think it can jitter sometimes because we constantly flip the overlay to see if it can fit better one way or the other.~ UPDATE: it started working when we tested together, must've been bad cache or something
hmm it's working for me...
I believe this one should be fixed also: https://github.com/orgs/adobe/projects/19/views/4?pane=issue&itemId=66042530 Specifically by these lines https://github.com/adobe/react-spectrum/pull/6527/commits/c7e714598a3ba3093990ec8b053fe06c063ee2f3#diff-2eb943b500782eb9da514ad98c5fb7855a412a495cb133e9a8e81cf656dff9f6R196-R197
This doesn't seem to work after selecting of a long item below the fold in stories like: https://reactspectrum.blob.core.windows.net/reactspectrum/c7e714598a3ba3093990ec8b053fe06c063ee2f3/storybook/index.html?path=/story/picker--long-item-text&providerSwitcher-express=false or https://reactspectrum.blob.core.windows.net/reactspectrum/c7e714598a3ba3093990ec8b053fe06c063ee2f3/storybook/index.html?path=/story/picker--long-item-text&providerSwitcher-express=false, and focus does not seem to go to the open listbox.
Build successful! 🎉
Build successful! 🎉
Build successful! 🎉
## API Changes
unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any', access: 'private' } unknown top level export { type: 'any', access: 'private' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'identifier', name: 'Column' } unknown top level export { type: 'identifier', name: 'Column' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown type { type: 'link' } unknown type { type: 'link' } unknown type { type: 'link' } unknown type { type: 'link' } unknown type { type: 'link' } unknown type { type: 'link' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' } unknown top level export { type: 'any' }