New Web Layout (#2126)

* Rip out virtualization on the web

* Screw around with layout

* onEndReached

* scrollToOffset

* Fix background

* onScroll

* Shell bars

* More scroll

* Fixes

* position: sticky

* Clean up 1

* Clean up 2

* Undo PagerWithHeader changes and fork it

* Trim down both versions

* Cleanup 3

* Memoize, lint

* Don't scroll away modal or lightbox

* Add content-visibility for rows

* Fix composer

* Fix types

* Fix borked scroll animation

* Fixes to layout

* More FlatList parity

* Layout fixes

* Fix more layout

* More layout

* More layouts

* Fix profile layout

* Remove onScroll

* Display: none inactive pages

* Add an intermediate List component

* Fix type

* Add onScrolledDownChange

* Port pager to use onScrolledDownChange

* Fix on mobile

* Don't pass down onScroll (replacement TBD)

* Remove resetMainScroll

* Replace onMainScroll with MainScrollProvider

* Hook ScrollProvider to pager

* Fix the remaining special case

* Optimize a bit

* Enforce that onScroll cannot be passed

* Keep value updated even if no handler

* Also memo it

* Move the fork to List.web

* Add scroll handler

* Consolidate List props a bit

* More stuff

* Rm unused

* Simplify

* Make isScrolledDown work

* Oops

* Fixes

* Hook up context scroll handlers

* Scroll restore for tabs

* Route scroll restoration POC

* Fix some issues with restoration

* Remove bad idea

* Fix pager scroll restoration

* Undo accidental locale changes

* onContentSizeChange

* Scroll to post

* Better positioning

* Layout fixes

* Factor out navigation stuff

* Cleanup

* Oops

* Cleanup

* Fixes and types

* Naming etc

* Fix crash

* Match FL semantics

* Snap the header scroll on the web

* Add body scroll lock

* Scroll to top on search

* Fix types

* Typos

* Fix Safari overflow

* Fix search positioning

* Add border

* Patch react navigation

* Revert "Patch react navigation"

This reverts commit 62516ed9c20410d166e1582b43b656c819495ddc.

* fixes

* scroll

* scrollbar

* cleanup unrelated

* undo unrel

* flatter

* Fix css

* twk
This commit is contained in:
dan 2024-01-22 22:46:32 +00:00 committed by GitHub
parent cd02922b03
commit f015229acf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
35 changed files with 849 additions and 97 deletions

View file

@ -0,0 +1,194 @@
import * as React from 'react'
import {FlatList, ScrollView, StyleSheet, View} from 'react-native'
import {useAnimatedRef} from 'react-native-reanimated'
import {Pager, PagerRef, RenderTabBarFnProps} from 'view/com/pager/Pager'
import {TabBar} from './TabBar'
import {usePalette} from '#/lib/hooks/usePalette'
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
import {ListMethods} from '../util/List'
export interface PagerWithHeaderChildParams {
headerHeight: number
isFocused: boolean
scrollElRef: React.MutableRefObject<FlatList<any> | ScrollView | null>
}
export interface PagerWithHeaderProps {
testID?: string
children:
| (((props: PagerWithHeaderChildParams) => JSX.Element) | null)[]
| ((props: PagerWithHeaderChildParams) => JSX.Element)
items: string[]
isHeaderReady: boolean
renderHeader?: () => JSX.Element
initialPage?: number
onPageSelected?: (index: number) => void
onCurrentPageSelected?: (index: number) => void
}
export const PagerWithHeader = React.forwardRef<PagerRef, PagerWithHeaderProps>(
function PageWithHeaderImpl(
{
children,
testID,
items,
renderHeader,
initialPage,
onPageSelected,
onCurrentPageSelected,
}: PagerWithHeaderProps,
ref,
) {
const [currentPage, setCurrentPage] = React.useState(0)
const renderTabBar = React.useCallback(
(props: RenderTabBarFnProps) => {
return (
<PagerTabBar
items={items}
renderHeader={renderHeader}
currentPage={currentPage}
onCurrentPageSelected={onCurrentPageSelected}
onSelect={props.onSelect}
tabBarAnchor={props.tabBarAnchor}
testID={testID}
/>
)
},
[items, renderHeader, currentPage, onCurrentPageSelected, testID],
)
const onPageSelectedInner = React.useCallback(
(index: number) => {
setCurrentPage(index)
onPageSelected?.(index)
},
[onPageSelected, setCurrentPage],
)
const onPageSelecting = React.useCallback((index: number) => {
setCurrentPage(index)
}, [])
return (
<Pager
ref={ref}
testID={testID}
initialPage={initialPage}
onPageSelected={onPageSelectedInner}
onPageSelecting={onPageSelecting}
renderTabBar={renderTabBar}
tabBarPosition="top">
{toArray(children)
.filter(Boolean)
.map((child, i) => {
return (
<View key={i} collapsable={false}>
<PagerItem isFocused={i === currentPage} renderTab={child} />
</View>
)
})}
</Pager>
)
},
)
let PagerTabBar = ({
currentPage,
items,
testID,
renderHeader,
onCurrentPageSelected,
onSelect,
tabBarAnchor,
}: {
currentPage: number
items: string[]
testID?: string
renderHeader?: () => JSX.Element
onCurrentPageSelected?: (index: number) => void
onSelect?: (index: number) => void
tabBarAnchor?: JSX.Element | null | undefined
}): React.ReactNode => {
const pal = usePalette('default')
const {isMobile} = useWebMediaQueries()
return (
<>
<View style={[!isMobile && styles.headerContainerDesktop, pal.border]}>
{renderHeader?.()}
</View>
{tabBarAnchor}
<View
style={[
styles.tabBarContainer,
isMobile
? styles.tabBarContainerMobile
: styles.tabBarContainerDesktop,
pal.border,
]}>
<TabBar
testID={testID}
items={items}
selectedPage={currentPage}
onSelect={onSelect}
onPressSelected={onCurrentPageSelected}
/>
</View>
</>
)
}
PagerTabBar = React.memo(PagerTabBar)
function PagerItem({
isFocused,
renderTab,
}: {
isFocused: boolean
renderTab: ((props: PagerWithHeaderChildParams) => JSX.Element) | null
}) {
const scrollElRef = useAnimatedRef()
if (renderTab == null) {
return null
}
return renderTab({
headerHeight: 0,
isFocused,
scrollElRef: scrollElRef as React.MutableRefObject<
ListMethods | ScrollView | null
>,
})
}
const styles = StyleSheet.create({
headerContainerDesktop: {
marginLeft: 'auto',
marginRight: 'auto',
width: 600,
borderLeftWidth: 1,
borderRightWidth: 1,
},
tabBarContainer: {
// @ts-ignore web-only
position: 'sticky',
overflow: 'hidden',
top: 0,
zIndex: 1,
},
tabBarContainerDesktop: {
marginLeft: 'auto',
marginRight: 'auto',
width: 600,
borderLeftWidth: 1,
borderRightWidth: 1,
},
tabBarContainerMobile: {
paddingLeft: 14,
paddingRight: 14,
},
})
function toArray<T>(v: T | T[]): T[] {
if (Array.isArray(v)) {
return v
}
return [v]
}