Only intercept scroll handler on iOS

The ScrollProvider wrapping and animatedProps for scroll indicator
insets are iOS-only. On other platforms, let the List use the scroll
handler from context directly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Samuel Newman
2026-02-17 12:11:09 +02:00
parent 8485ac65df
commit 58629959e8
5 changed files with 186 additions and 149 deletions
@@ -201,40 +201,48 @@ export function ProfileStarterPacks({
[isTabletOrDesktop, t.atoms.border_contrast_low], [isTabletOrDesktop, t.atoms.border_contrast_low],
) )
const list = (
<List
testID={testID ? `${testID}-flatlist` : undefined}
ref={scrollElRef}
data={items}
renderItem={renderItem}
keyExtractor={keyExtractor}
refreshing={isPTRing}
headerOffset={headerOffset}
progressViewOffset={ios(0)}
contentContainerStyle={{
minHeight: height + headerOffset,
paddingBottom: bottomBarOffset,
}}
removeClippedSubviews={true}
desktopFixedHeight
onEndReached={onEndReached}
onRefresh={onRefresh}
ListEmptyComponent={
data ? (isMe ? EmptyComponent : undefined) : FeedLoadingPlaceholder
}
ListFooterComponent={
!!data && items?.length !== 0 && isMe ? CreateAnother : undefined
}
animatedProps={IS_IOS ? animatedProps : undefined}
/>
)
return ( return (
<View testID={testID} style={style}> <View testID={testID} style={style}>
<ScrollProvider {IS_IOS ? (
onScroll={onScrollWorklet} <ScrollProvider
onBeginDrag={onBeginDragFromContext} onScroll={onScrollWorklet}
onEndDrag={onEndDragFromContext} onBeginDrag={onBeginDragFromContext}
onMomentumBegin={onMomentumEndFromContext} onEndDrag={onEndDragFromContext}
onMomentumEnd={onMomentumEndFromContext}> onMomentumBegin={onMomentumEndFromContext}
<List onMomentumEnd={onMomentumEndFromContext}>
testID={testID ? `${testID}-flatlist` : undefined} {list}
ref={scrollElRef} </ScrollProvider>
data={items} ) : (
renderItem={renderItem} list
keyExtractor={keyExtractor} )}
refreshing={isPTRing}
headerOffset={headerOffset}
progressViewOffset={ios(0)}
contentContainerStyle={{
minHeight: height + headerOffset,
paddingBottom: bottomBarOffset,
}}
removeClippedSubviews={true}
desktopFixedHeight
onEndReached={onEndReached}
onRefresh={onRefresh}
ListEmptyComponent={
data ? (isMe ? EmptyComponent : undefined) : FeedLoadingPlaceholder
}
ListFooterComponent={
!!data && items?.length !== 0 && isMe ? CreateAnother : undefined
}
animatedProps={animatedProps}
/>
</ScrollProvider>
</View> </View>
) )
} }
+37 -32
View File
@@ -159,40 +159,45 @@ export function ProfileLabelsSection({
[labelerInfo, isSubscribed, numItems, t], [labelerInfo, isSubscribed, numItems, t],
) )
const list = (
<List
ref={scrollElRef}
data={labelValues}
renderItem={renderItem}
keyExtractor={keyExtractor}
contentContainerStyle={a.px_xl}
headerOffset={headerHeight}
progressViewOffset={ios(0)}
ListHeaderComponent={
<LabelerListHeader
isLabelerLoading={isLabelerLoading}
labelerInfo={labelerInfo}
labelerError={labelerError}
hasValues={labelValues.length !== 0}
isSubscribed={isSubscribed}
/>
}
ListFooterComponent={
<ListFooter height={headerHeight + 180} style={a.border_transparent} />
}
animatedProps={IS_IOS ? animatedProps : undefined}
/>
)
return ( return (
<View> <View>
<ScrollProvider {IS_IOS ? (
onScroll={onScrollWorklet} <ScrollProvider
onBeginDrag={onBeginDragFromContext} onScroll={onScrollWorklet}
onEndDrag={onEndDragFromContext} onBeginDrag={onBeginDragFromContext}
onMomentumBegin={onMomentumEndFromContext} onEndDrag={onEndDragFromContext}
onMomentumEnd={onMomentumEndFromContext}> onMomentumBegin={onMomentumEndFromContext}
<List onMomentumEnd={onMomentumEndFromContext}>
ref={scrollElRef} {list}
data={labelValues} </ScrollProvider>
renderItem={renderItem} ) : (
keyExtractor={keyExtractor} list
contentContainerStyle={a.px_xl} )}
headerOffset={headerHeight}
progressViewOffset={ios(0)}
ListHeaderComponent={
<LabelerListHeader
isLabelerLoading={isLabelerLoading}
labelerInfo={labelerInfo}
labelerError={labelerError}
hasValues={labelValues.length !== 0}
isSubscribed={isSubscribed}
/>
}
ListFooterComponent={
<ListFooter
height={headerHeight + 180}
style={a.border_transparent}
/>
}
animatedProps={animatedProps}
/>
</ScrollProvider>
</View> </View>
) )
} }
+32 -24
View File
@@ -286,32 +286,40 @@ export function ProfileFeedgens({
isEmpty, isEmpty,
]) ])
const list = (
<List
testID={testID ? `${testID}-flatlist` : undefined}
ref={scrollElRef}
data={items}
keyExtractor={keyExtractor}
renderItem={renderItem}
ListFooterComponent={ProfileFeedgensFooter}
refreshing={isPTRing}
onRefresh={onRefresh}
headerOffset={headerOffset}
progressViewOffset={ios(0)}
removeClippedSubviews={true}
desktopFixedHeight
onEndReached={onEndReached}
contentContainerStyle={{minHeight: height + headerOffset}}
animatedProps={IS_IOS ? animatedProps : undefined}
/>
)
return ( return (
<View testID={testID} style={style}> <View testID={testID} style={style}>
<ScrollProvider {IS_IOS ? (
onScroll={onScrollWorklet} <ScrollProvider
onBeginDrag={onBeginDragFromContext} onScroll={onScrollWorklet}
onEndDrag={onEndDragFromContext} onBeginDrag={onBeginDragFromContext}
onMomentumBegin={onMomentumEndFromContext} onEndDrag={onEndDragFromContext}
onMomentumEnd={onMomentumEndFromContext}> onMomentumBegin={onMomentumEndFromContext}
<List onMomentumEnd={onMomentumEndFromContext}>
testID={testID ? `${testID}-flatlist` : undefined} {list}
ref={scrollElRef} </ScrollProvider>
data={items} ) : (
keyExtractor={keyExtractor} list
renderItem={renderItem} )}
ListFooterComponent={ProfileFeedgensFooter}
refreshing={isPTRing}
onRefresh={onRefresh}
headerOffset={headerOffset}
progressViewOffset={ios(0)}
removeClippedSubviews={true}
desktopFixedHeight
onEndReached={onEndReached}
contentContainerStyle={{minHeight: height + headerOffset}}
animatedProps={animatedProps}
/>
</ScrollProvider>
</View> </View>
) )
} }
+32 -24
View File
@@ -285,32 +285,40 @@ export function ProfileLists({
isEmpty, isEmpty,
]) ])
const list = (
<List
testID={testID ? `${testID}-flatlist` : undefined}
ref={scrollElRef}
data={items}
keyExtractor={keyExtractor}
renderItem={renderItem}
ListFooterComponent={ProfileListsFooter}
refreshing={isPTRing}
onRefresh={onRefresh}
headerOffset={headerOffset}
progressViewOffset={ios(0)}
removeClippedSubviews={true}
desktopFixedHeight
onEndReached={onEndReached}
contentContainerStyle={{minHeight: height + headerOffset}}
animatedProps={IS_IOS ? animatedProps : undefined}
/>
)
return ( return (
<View testID={testID} style={style}> <View testID={testID} style={style}>
<ScrollProvider {IS_IOS ? (
onScroll={onScrollWorklet} <ScrollProvider
onBeginDrag={onBeginDragFromContext} onScroll={onScrollWorklet}
onEndDrag={onEndDragFromContext} onBeginDrag={onBeginDragFromContext}
onMomentumBegin={onMomentumEndFromContext} onEndDrag={onEndDragFromContext}
onMomentumEnd={onMomentumEndFromContext}> onMomentumBegin={onMomentumEndFromContext}
<List onMomentumEnd={onMomentumEndFromContext}>
testID={testID ? `${testID}-flatlist` : undefined} {list}
ref={scrollElRef} </ScrollProvider>
data={items} ) : (
keyExtractor={keyExtractor} list
renderItem={renderItem} )}
ListFooterComponent={ProfileListsFooter}
refreshing={isPTRing}
onRefresh={onRefresh}
headerOffset={headerOffset}
progressViewOffset={ios(0)}
removeClippedSubviews={true}
desktopFixedHeight
onEndReached={onEndReached}
contentContainerStyle={{minHeight: height + headerOffset}}
animatedProps={animatedProps}
/>
</ScrollProvider>
</View> </View>
) )
} }
+45 -37
View File
@@ -1045,45 +1045,53 @@ let PostFeed = ({
return {} return {}
}) })
const list = (
<List
testID={testID ? `${testID}-flatlist` : undefined}
ref={scrollElRef}
data={feedItems}
keyExtractor={(item: FeedRow) => item.key}
renderItem={renderItem}
ListFooterComponent={FeedFooter}
ListHeaderComponent={ListHeaderComponent}
refreshing={isPTRing}
onRefresh={() => void onRefresh()}
headerOffset={headerOffset}
progressViewOffset={progressViewOffset}
contentContainerStyle={{
minHeight: Dimensions.get('window').height * 1.5,
}}
onScrolledDownChange={handleScrolledDownChange}
onEndReached={() => void onEndReached()}
onEndReachedThreshold={2} // number of posts left to trigger load more
removeClippedSubviews={true}
extraData={extraData}
desktopFixedHeight={
desktopFixedHeightOffset ? desktopFixedHeightOffset : true
}
initialNumToRender={initialNumToRenderOverride ?? initialNumToRender}
windowSize={9}
maxToRenderPerBatch={IS_IOS ? 5 : 1}
updateCellsBatchingPeriod={40}
onItemSeen={onItemSeen}
animatedProps={IS_IOS ? animatedProps : undefined}
/>
)
return ( return (
<View testID={testID} style={style}> <View testID={testID} style={style}>
<ScrollProvider {IS_IOS ? (
onScroll={onScrollWorklet} <ScrollProvider
onBeginDrag={onBeginDragFromContext} onScroll={onScrollWorklet}
onEndDrag={onEndDragFromContext} onBeginDrag={onBeginDragFromContext}
onMomentumBegin={onMomentumEndFromContext} onEndDrag={onEndDragFromContext}
onMomentumEnd={onMomentumEndFromContext}> onMomentumBegin={onMomentumEndFromContext}
<List onMomentumEnd={onMomentumEndFromContext}>
testID={testID ? `${testID}-flatlist` : undefined} {list}
ref={scrollElRef} </ScrollProvider>
data={feedItems} ) : (
keyExtractor={(item: FeedRow) => item.key} list
renderItem={renderItem} )}
ListFooterComponent={FeedFooter}
ListHeaderComponent={ListHeaderComponent}
refreshing={isPTRing}
onRefresh={() => void onRefresh()}
headerOffset={headerOffset}
progressViewOffset={progressViewOffset}
contentContainerStyle={{
minHeight: Dimensions.get('window').height * 1.5,
}}
onScrolledDownChange={handleScrolledDownChange}
onEndReached={() => void onEndReached()}
onEndReachedThreshold={2} // number of posts left to trigger load more
removeClippedSubviews={true}
extraData={extraData}
desktopFixedHeight={
desktopFixedHeightOffset ? desktopFixedHeightOffset : true
}
initialNumToRender={initialNumToRenderOverride ?? initialNumToRender}
windowSize={9}
maxToRenderPerBatch={IS_IOS ? 5 : 1}
updateCellsBatchingPeriod={40}
onItemSeen={onItemSeen}
animatedProps={animatedProps}
/>
</ScrollProvider>
</View> </View>
) )
} }