Files
bsky-social-app/src/components/List/index.tsx
T
2025-09-23 15:37:28 -05:00

67 lines
1.8 KiB
TypeScript

import {forwardRef} from 'react'
import {type FlatList, type FlatListProps} from 'react-native'
import Animated, {
type FlatListPropsWithLayout,
useAnimatedScrollHandler,
} from 'react-native-reanimated'
import {atoms as a, web} from '#/alf'
import {useListScrollContext} from '#/components/List/ListScrollProvider'
export {
ListScrollProvider,
useListScrollHandler,
} from '#/components/List/ListScrollProvider'
/**
* Cleaned up FlatList without some problematic props.
*
* - `contentOffset` - Doesn't work, use padding on `contentContainerStyle` instead.
*/
type ListProps<Item> = Omit<FlatListProps<Item>, 'contentOffset'>
export const List = forwardRef(function List<Item>(
props: ListProps<Item>,
ref: React.Ref<FlatList<Item>>,
) {
const scrollHandlers = useListScrollContext()
const onScroll = useAnimatedScrollHandler({
onScroll(e, ctx) {
scrollHandlers.onScroll?.(e, ctx)
},
onBeginDrag(e, ctx) {
scrollHandlers.onScrollBeginDrag?.(e, ctx)
},
onEndDrag(e, ctx) {
scrollHandlers.onScrollEndDrag?.(e, ctx)
},
onMomentumBegin(e, ctx) {
scrollHandlers.onMomentumScrollBegin?.(e, ctx)
},
/*
* Note: adding onMomentumBegin here makes simulator scroll lag on Android.
* So either don't add it, or figure out why. - sfn
*/
onMomentumEnd(e, ctx) {
scrollHandlers.onMomentumScrollEnd?.(e, ctx)
},
})
return (
<Animated.FlatList<Item>
ref={ref}
{...(props as FlatListPropsWithLayout<Item>)}
style={[
/*
* On web, the List should always fill its container, otherwise
* `onScroll` will not work due to the entire page scrolling.
*/
web(a.h_full),
]}
onScroll={onScroll}
/>
)
}) as <Item>(
props: ListProps<Item> & {ref?: React.Ref<FlatList<Item>>},
) => React.ReactElement