This commit is contained in:
Dan Abramov
2023-12-23 01:17:39 +00:00
parent 85fcff8f7f
commit 24f5dd593d
8 changed files with 26 additions and 11 deletions
+13 -6
View File
@@ -6,6 +6,7 @@ import {s} from 'lib/styles'
export interface RenderTabBarFnProps {
selectedPage: number
onSelect?: (index: number) => void
tabBarAnchor?: JSX.Element
}
export type RenderTabBarFn = (props: RenderTabBarFnProps) => JSX.Element
@@ -28,7 +29,7 @@ export const Pager = React.forwardRef(function PagerImpl(
ref,
) {
const [selectedPage, setSelectedPage] = React.useState(initialPage)
const scrollYs = React.useRef([])
const scrollYs = React.useRef<Array<number | null>>([])
const anchorRef = React.useRef(null)
React.useImperativeHandle(ref, () => ({
@@ -38,10 +39,15 @@ export const Pager = React.forwardRef(function PagerImpl(
const onTabBarSelect = React.useCallback(
(index: number) => {
const scrollY = window.scrollY
// We want to determine if the tabbar is already "sticking" at the top (in which
// case we should preserve and restore scroll), or if it is somewhere below in the
// viewport (in which case a scroll jump would be jarring). We determine this by
// measuring where the "anchor"" element is (which we place just above the tabbar).
let anchorTop = anchorRef.current
? anchorRef.current.getBoundingClientRect().top
: -scrollY
const isSticking = anchorTop <= 5
? (anchorRef.current as Element).getBoundingClientRect().top
: -scrollY // If there's no anchor, treat the top of the page as one.
const isSticking = anchorTop <= 5 // This would be 0 if browser scrollTo() was reliable.
if (isSticking) {
scrollYs.current[selectedPage] = window.scrollY
} else {
@@ -53,8 +59,9 @@ export const Pager = React.forwardRef(function PagerImpl(
onPageSelecting?.(index)
})
if (isSticking) {
if (scrollYs.current[index]) {
window.scrollTo(0, scrollYs.current[index])
const restoredScrollY = scrollYs.current[index]
if (restoredScrollY != null) {
window.scrollTo(0, restoredScrollY)
} else {
window.scrollTo(0, scrollY + anchorTop)
}