Further align web List with FlatList, add contain mode to web list implementation (#3867)

* add `onStartReached` to web list

* fix `rootMargin`

* Add `contain`, handle scroll events

* improve types, fix typo

* simplify

* adjust `scrollToTop` and `scrollToOffset` to support `contain`, add `scrollToEnd`

* rename `handleWindowScroll` to `handleScroll`

* support basic `maintainVisibleContentPosition`

* rename `contain` to `containWeb`

* remove unnecessary `flex: 1`

* add missing props

* add root prop to `Visibility`

* add root prop to `Visibility`

* revert adding `maintainVisibleContentPosition`

* oops

* always apply `flex: 1` to styles when contained

* add a contained list to storybook

* make `onScroll` a worklet in storybook

* revert test code

* add scrolling to storybook

* simplify getting scrollable node

* nit: extra whitespace

* nit: random comment

* foolproof the logic

* typecheck
This commit is contained in:
Hailey
2024-05-06 08:34:32 -07:00
committed by GitHub
parent 594b40c3ae
commit bc07019911
4 changed files with 316 additions and 91 deletions
@@ -0,0 +1,98 @@
import React from 'react'
import {FlatList, View} from 'react-native'
import {ScrollProvider} from 'lib/ScrollContext'
import {List} from 'view/com/util/List'
import {Button, ButtonText} from '#/components/Button'
import * as Toggle from '#/components/forms/Toggle'
import {Text} from '#/components/Typography'
export function ListContained() {
const [animated, setAnimated] = React.useState(false)
const ref = React.useRef<FlatList>(null)
const data = React.useMemo(() => {
return Array.from({length: 100}, (_, i) => ({
id: i,
text: `Message ${i}`,
}))
}, [])
return (
<>
<View style={{width: '100%', height: 300}}>
<ScrollProvider
onScroll={() => {
'worklet'
console.log('onScroll')
}}>
<List
data={data}
renderItem={item => {
return (
<View
style={{
padding: 10,
borderBottomWidth: 1,
borderBottomColor: 'rgba(0,0,0,0.1)',
}}>
<Text>{item.item.text}</Text>
</View>
)
}}
keyExtractor={item => item.id.toString()}
containWeb={true}
style={{flex: 1}}
onStartReached={() => {
console.log('Start Reached')
}}
onEndReached={() => {
console.log('End Reached (threshold of 2)')
}}
onEndReachedThreshold={2}
ref={ref}
disableVirtualization={true}
/>
</ScrollProvider>
</View>
<View style={{flexDirection: 'row', gap: 10, alignItems: 'center'}}>
<Toggle.Item
name="a"
label="Click me"
value={animated}
onChange={() => setAnimated(prev => !prev)}>
<Toggle.Checkbox />
<Toggle.LabelText>Animated Scrolling</Toggle.LabelText>
</Toggle.Item>
</View>
<Button
variant="solid"
color="primary"
size="large"
label="Scroll to End"
onPress={() => ref.current?.scrollToOffset({animated, offset: 0})}>
<ButtonText>Scroll to Top</ButtonText>
</Button>
<Button
variant="solid"
color="primary"
size="large"
label="Scroll to End"
onPress={() => ref.current?.scrollToEnd({animated})}>
<ButtonText>Scroll to End</ButtonText>
</Button>
<Button
variant="solid"
color="primary"
size="large"
label="Scroll to Offset 100"
onPress={() => ref.current?.scrollToOffset({animated, offset: 500})}>
<ButtonText>Scroll to Offset 500</ButtonText>
</Button>
</>
)
}