From 72d01685b0372ad3c8fe57750db67ca590c0e2ec Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 22 Dec 2023 02:52:23 +0000 Subject: [PATCH] Fix pager scroll restoration --- src/Navigation.tsx | 5 +-- src/view/com/pager/Pager.web.tsx | 37 +++++++++++++++------- src/view/com/pager/PagerWithHeader.web.tsx | 4 +++ 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/Navigation.tsx b/src/Navigation.tsx index 27e9beadd0..c1b28f9ac8 100644 --- a/src/Navigation.tsx +++ b/src/Navigation.tsx @@ -521,10 +521,7 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) { // TODO: Clean up? navigationRef.current?.addListener('__unsafe_action__', e => { if (webFocusedScreen) { - webScrollPositions.set( - webFocusedScreen, - Math.round(window.scrollY), - ) + webScrollPositions.set(webFocusedScreen, window.scrollY) } }) } diff --git a/src/view/com/pager/Pager.web.tsx b/src/view/com/pager/Pager.web.tsx index fdb969038f..1c4f7edf44 100644 --- a/src/view/com/pager/Pager.web.tsx +++ b/src/view/com/pager/Pager.web.tsx @@ -1,4 +1,5 @@ import React from 'react' +import {flushSync} from 'react-dom' import {View} from 'react-native' import {s} from 'lib/styles' @@ -28,6 +29,7 @@ export const Pager = React.forwardRef(function PagerImpl( ) { const [selectedPage, setSelectedPage] = React.useState(initialPage) const scrollYs = React.useRef([]) + const anchorRef = React.useRef(null) React.useImperativeHandle(ref, () => ({ setPage: (index: number) => setSelectedPage(index), @@ -35,18 +37,28 @@ export const Pager = React.forwardRef(function PagerImpl( const onTabBarSelect = React.useCallback( (index: number) => { - const scrollY = Math.round(window.scrollY) - scrollYs.current[selectedPage] = scrollY - setSelectedPage(index) - onPageSelected?.(index) - onPageSelecting?.(index) - // if (scrollY >= headerOnlyHeight) { - window.scrollTo( - 0, - scrollYs.current[index] ?? 0, - // Math.max(headerOnlyHeight, scrollYs.current[index] ?? 0), - ) - // } + const scrollY = window.scrollY + let anchorTop = anchorRef.current + ? anchorRef.current.getBoundingClientRect().top + : -scrollY + const isSticking = anchorTop <= 5 + if (isSticking) { + scrollYs.current[selectedPage] = window.scrollY + } else { + scrollYs.current[selectedPage] = null + } + flushSync(() => { + setSelectedPage(index) + onPageSelected?.(index) + onPageSelecting?.(index) + }) + if (isSticking) { + if (scrollYs.current[index]) { + window.scrollTo(0, scrollYs.current[index]) + } else { + window.scrollTo(0, scrollY + anchorTop) + } + } }, [selectedPage, setSelectedPage, onPageSelected, onPageSelecting], ) @@ -56,6 +68,7 @@ export const Pager = React.forwardRef(function PagerImpl( {tabBarPosition === 'top' && renderTabBar({ selectedPage, + tabBarAnchor: , onSelect: onTabBarSelect, })} {React.Children.map(children, (child, i) => ( diff --git a/src/view/com/pager/PagerWithHeader.web.tsx b/src/view/com/pager/PagerWithHeader.web.tsx index cfdedb2a28..bc276722fb 100644 --- a/src/view/com/pager/PagerWithHeader.web.tsx +++ b/src/view/com/pager/PagerWithHeader.web.tsx @@ -6,6 +6,7 @@ import {TabBar} from './TabBar' import {usePalette} from '#/lib/hooks/usePalette' import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' import {ListMethods} from '../util/List' +import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' export interface PagerWithHeaderChildParams { headerHeight: number @@ -49,6 +50,7 @@ export const PagerWithHeader = React.forwardRef( currentPage={currentPage} onCurrentPageSelected={onCurrentPageSelected} onSelect={props.onSelect} + tabBarAnchor={props.tabBarAnchor} testID={testID} /> ) @@ -98,6 +100,7 @@ let PagerTabBar = ({ renderHeader, onCurrentPageSelected, onSelect, + tabBarAnchor, }: { currentPage: number items: string[] @@ -113,6 +116,7 @@ let PagerTabBar = ({ {renderHeader?.()} + {tabBarAnchor}