1/** 2 * Copyright (c) Meta Platforms, Inc. and affiliates. 3 * 4 * This source code is licensed under the MIT license found in the 5 * LICENSE file in the root directory of this source tree. 6 * 7 * @format 8 */ 9 10import type * as React from 'react'; 11import type {LayoutChangeEvent} from '../../types'; 12import {StyleProp} from '../StyleSheet/StyleSheet'; 13import {ViewStyle} from '../StyleSheet/StyleSheetTypes'; 14import type { 15 ScrollResponderMixin, 16 ScrollView, 17 ScrollViewProps, 18} from '../Components/ScrollView/ScrollView'; 19import type {View} from '../Components/View/View'; 20 21export interface ViewToken { 22 item: any; 23 key: string; 24 index: number | null; 25 isViewable: boolean; 26 section?: any; 27} 28 29export interface ViewabilityConfig { 30 /** 31 * Minimum amount of time (in milliseconds) that an item must be physically viewable before the 32 * viewability callback will be fired. A high number means that scrolling through content without 33 * stopping will not mark the content as viewable. 34 */ 35 minimumViewTime?: number | undefined; 36 37 /** 38 * Percent of viewport that must be covered for a partially occluded item to count as 39 * "viewable", 0-100. Fully visible items are always considered viewable. A value of 0 means 40 * that a single pixel in the viewport makes the item viewable, and a value of 100 means that 41 * an item must be either entirely visible or cover the entire viewport to count as viewable. 42 */ 43 viewAreaCoveragePercentThreshold?: number | undefined; 44 45 /** 46 * Similar to `viewAreaCoveragePercentThreshold`, but considers the percent of the item that is visible, 47 * rather than the fraction of the viewable area it covers. 48 */ 49 itemVisiblePercentThreshold?: number | undefined; 50 51 /** 52 * Nothing is considered viewable until the user scrolls or `recordInteraction` is called after 53 * render. 54 */ 55 waitForInteraction?: boolean | undefined; 56} 57 58export interface ViewabilityConfigCallbackPair { 59 viewabilityConfig: ViewabilityConfig; 60 onViewableItemsChanged: 61 | ((info: { 62 viewableItems: Array<ViewToken>; 63 changed: Array<ViewToken>; 64 }) => void) 65 | null; 66} 67 68export type ViewabilityConfigCallbackPairs = ViewabilityConfigCallbackPair[]; 69 70/** 71 * @see https://reactnative.dev/docs/flatlist#props 72 */ 73 74export interface ListRenderItemInfo<ItemT> { 75 item: ItemT; 76 77 index: number; 78 79 separators: { 80 highlight: () => void; 81 unhighlight: () => void; 82 updateProps: (select: 'leading' | 'trailing', newProps: any) => void; 83 }; 84} 85 86export type ListRenderItem<ItemT> = ( 87 info: ListRenderItemInfo<ItemT>, 88) => React.ReactElement | null; 89 90/** 91 * @see https://reactnative.dev/docs/virtualizedlist 92 */ 93export class VirtualizedList<ItemT> extends React.Component< 94 VirtualizedListProps<ItemT> 95> { 96 scrollToEnd: (params?: {animated?: boolean | undefined}) => void; 97 scrollToIndex: (params: { 98 animated?: boolean | undefined; 99 index: number; 100 viewOffset?: number | undefined; 101 viewPosition?: number | undefined; 102 }) => void; 103 scrollToItem: (params: { 104 animated?: boolean | undefined; 105 item: ItemT; 106 viewOffset?: number | undefined; 107 viewPosition?: number | undefined; 108 }) => void; 109 110 /** 111 * Scroll to a specific content pixel offset in the list. 112 * Param `offset` expects the offset to scroll to. In case of horizontal is true, the 113 * offset is the x-value, in any other case the offset is the y-value. 114 * Param `animated` (true by default) defines whether the list should do an animation while scrolling. 115 */ 116 scrollToOffset: (params: { 117 animated?: boolean | undefined; 118 offset: number; 119 }) => void; 120 121 recordInteraction: () => void; 122 123 getScrollRef: () => 124 | React.ElementRef<typeof ScrollView> 125 | React.ElementRef<typeof View> 126 | null; 127 128 getScrollResponder: () => ScrollResponderMixin | null; 129} 130 131/** 132 * @see https://reactnative.dev/docs/virtualizedlist#props 133 */ 134 135export interface VirtualizedListProps<ItemT> 136 extends VirtualizedListWithoutRenderItemProps<ItemT> { 137 renderItem: ListRenderItem<ItemT> | null | undefined; 138} 139 140export interface VirtualizedListWithoutRenderItemProps<ItemT> 141 extends ScrollViewProps { 142 /** 143 * Rendered in between each item, but not at the top or bottom 144 */ 145 ItemSeparatorComponent?: React.ComponentType<any> | null | undefined; 146 147 /** 148 * Rendered when the list is empty. Can be a React Component Class, a render function, or 149 * a rendered element. 150 */ 151 ListEmptyComponent?: 152 | React.ComponentType<any> 153 | React.ReactElement 154 | null 155 | undefined; 156 157 /** 158 * Rendered at the bottom of all the items. Can be a React Component Class, a render function, or 159 * a rendered element. 160 */ 161 ListFooterComponent?: 162 | React.ComponentType<any> 163 | React.ReactElement 164 | null 165 | undefined; 166 167 /** 168 * Styling for internal View for ListFooterComponent 169 */ 170 ListFooterComponentStyle?: StyleProp<ViewStyle> | undefined; 171 172 /** 173 * Rendered at the top of all the items. Can be a React Component Class, a render function, or 174 * a rendered element. 175 */ 176 ListHeaderComponent?: 177 | React.ComponentType<any> 178 | React.ReactElement 179 | null 180 | undefined; 181 182 /** 183 * Styling for internal View for ListHeaderComponent 184 */ 185 ListHeaderComponentStyle?: StyleProp<ViewStyle> | undefined; 186 187 /** 188 * The default accessor functions assume this is an Array<{key: string}> but you can override 189 * getItem, getItemCount, and keyExtractor to handle any type of index-based data. 190 */ 191 data?: any; 192 193 /** 194 * `debug` will turn on extra logging and visual overlays to aid with debugging both usage and 195 * implementation, but with a significant perf hit. 196 */ 197 debug?: boolean | undefined; 198 199 /** 200 * DEPRECATED: Virtualization provides significant performance and memory optimizations, but fully 201 * unmounts react instances that are outside of the render window. You should only need to disable 202 * this for debugging purposes. 203 */ 204 disableVirtualization?: boolean | undefined; 205 206 /** 207 * A marker property for telling the list to re-render (since it implements `PureComponent`). If 208 * any of your `renderItem`, Header, Footer, etc. functions depend on anything outside of the 209 * `data` prop, stick it here and treat it immutably. 210 */ 211 extraData?: any; 212 213 /** 214 * A generic accessor for extracting an item from any sort of data blob. 215 */ 216 getItem?: ((data: any, index: number) => ItemT) | undefined; 217 218 /** 219 * Determines how many items are in the data blob. 220 */ 221 getItemCount?: ((data: any) => number) | undefined; 222 223 getItemLayout?: 224 | (( 225 data: any, 226 index: number, 227 ) => { 228 length: number; 229 offset: number; 230 index: number; 231 }) 232 | undefined; 233 234 horizontal?: boolean | null | undefined; 235 236 /** 237 * How many items to render in the initial batch. This should be enough to fill the screen but not 238 * much more. Note these items will never be unmounted as part of the windowed rendering in order 239 * to improve perceived performance of scroll-to-top actions. 240 */ 241 initialNumToRender?: number | undefined; 242 243 /** 244 * Instead of starting at the top with the first item, start at `initialScrollIndex`. This 245 * disables the "scroll to top" optimization that keeps the first `initialNumToRender` items 246 * always rendered and immediately renders the items starting at this initial index. Requires 247 * `getItemLayout` to be implemented. 248 */ 249 initialScrollIndex?: number | null | undefined; 250 251 /** 252 * Reverses the direction of scroll. Uses scale transforms of -1. 253 */ 254 inverted?: boolean | null | undefined; 255 256 keyExtractor?: ((item: ItemT, index: number) => string) | undefined; 257 258 /** 259 * The maximum number of items to render in each incremental render batch. The more rendered at 260 * once, the better the fill rate, but responsiveness my suffer because rendering content may 261 * interfere with responding to button taps or other interactions. 262 */ 263 maxToRenderPerBatch?: number | undefined; 264 265 onEndReached?: ((info: {distanceFromEnd: number}) => void) | null | undefined; 266 267 onEndReachedThreshold?: number | null | undefined; 268 269 onLayout?: ((event: LayoutChangeEvent) => void) | undefined; 270 271 /** 272 * If provided, a standard RefreshControl will be added for "Pull to Refresh" functionality. Make 273 * sure to also set the `refreshing` prop correctly. 274 */ 275 onRefresh?: (() => void) | null | undefined; 276 277 /** 278 * Used to handle failures when scrolling to an index that has not been measured yet. 279 * Recommended action is to either compute your own offset and `scrollTo` it, or scroll as far 280 * as possible and then try again after more items have been rendered. 281 */ 282 onScrollToIndexFailed?: 283 | ((info: { 284 index: number; 285 highestMeasuredFrameIndex: number; 286 averageItemLength: number; 287 }) => void) 288 | undefined; 289 290 /** 291 * Called when the viewability of rows changes, as defined by the 292 * `viewabilityConfig` prop. 293 */ 294 onViewableItemsChanged?: 295 | ((info: { 296 viewableItems: Array<ViewToken>; 297 changed: Array<ViewToken>; 298 }) => void) 299 | null 300 | undefined; 301 302 /** 303 * Set this when offset is needed for the loading indicator to show correctly. 304 * @platform android 305 */ 306 progressViewOffset?: number | undefined; 307 308 /** 309 * Set this true while waiting for new data from a refresh. 310 */ 311 refreshing?: boolean | null | undefined; 312 313 /** 314 * Note: may have bugs (missing content) in some circumstances - use at your own risk. 315 * 316 * This may improve scroll performance for large lists. 317 */ 318 removeClippedSubviews?: boolean | undefined; 319 320 /** 321 * Render a custom scroll component, e.g. with a differently styled `RefreshControl`. 322 */ 323 renderScrollComponent?: 324 | ((props: ScrollViewProps) => React.ReactElement<ScrollViewProps>) 325 | undefined; 326 327 /** 328 * Amount of time between low-pri item render batches, e.g. for rendering items quite a ways off 329 * screen. Similar fill rate/responsiveness tradeoff as `maxToRenderPerBatch`. 330 */ 331 updateCellsBatchingPeriod?: number | undefined; 332 333 viewabilityConfig?: ViewabilityConfig | undefined; 334 335 viewabilityConfigCallbackPairs?: ViewabilityConfigCallbackPairs | undefined; 336 337 /** 338 * Determines the maximum number of items rendered outside of the visible area, in units of 339 * visible lengths. So if your list fills the screen, then `windowSize={21}` (the default) will 340 * render the visible screen area plus up to 10 screens above and 10 below the viewport. Reducing 341 * this number will reduce memory consumption and may improve performance, but will increase the 342 * chance that fast scrolling may reveal momentary blank areas of unrendered content. 343 */ 344 windowSize?: number | undefined; 345 346 CellRendererComponent?: React.ComponentType<any> | undefined; 347} 348