268 lines
8.1 KiB
TypeScript
268 lines
8.1 KiB
TypeScript
|
/**
|
||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||
|
*
|
||
|
* This source code is licensed under the MIT license found in the
|
||
|
* LICENSE file in the root directory of this source tree.
|
||
|
*
|
||
|
* @format
|
||
|
*/
|
||
|
|
||
|
import type * as React from 'react';
|
||
|
import type {
|
||
|
ListRenderItemInfo,
|
||
|
VirtualizedListWithoutRenderItemProps,
|
||
|
} from '@react-native/virtualized-lists';
|
||
|
import type {
|
||
|
ScrollView,
|
||
|
ScrollViewProps,
|
||
|
} from '../Components/ScrollView/ScrollView';
|
||
|
import {NodeHandle} from '../ReactNative/RendererProxy';
|
||
|
import {StyleProp} from '../StyleSheet/StyleSheet';
|
||
|
import {ViewStyle} from '../StyleSheet/StyleSheetTypes';
|
||
|
|
||
|
/**
|
||
|
* @see https://reactnative.dev/docs/sectionlist
|
||
|
*/
|
||
|
|
||
|
type DefaultSectionT = {
|
||
|
[key: string]: any;
|
||
|
};
|
||
|
|
||
|
export interface SectionBase<ItemT, SectionT = DefaultSectionT> {
|
||
|
data: ReadonlyArray<ItemT>;
|
||
|
|
||
|
key?: string | undefined;
|
||
|
|
||
|
renderItem?: SectionListRenderItem<ItemT, SectionT> | undefined;
|
||
|
|
||
|
ItemSeparatorComponent?: React.ComponentType<any> | null | undefined;
|
||
|
|
||
|
keyExtractor?: ((item: ItemT, index: number) => string) | undefined;
|
||
|
}
|
||
|
|
||
|
export type SectionListData<ItemT, SectionT = DefaultSectionT> = SectionBase<
|
||
|
ItemT,
|
||
|
SectionT
|
||
|
> &
|
||
|
SectionT;
|
||
|
|
||
|
/**
|
||
|
* @see https://reactnative.dev/docs/sectionlist.html#props
|
||
|
*/
|
||
|
|
||
|
export interface SectionListRenderItemInfo<ItemT, SectionT = DefaultSectionT>
|
||
|
extends ListRenderItemInfo<ItemT> {
|
||
|
section: SectionListData<ItemT, SectionT>;
|
||
|
}
|
||
|
|
||
|
export type SectionListRenderItem<ItemT, SectionT = DefaultSectionT> = (
|
||
|
info: SectionListRenderItemInfo<ItemT, SectionT>,
|
||
|
) => React.ReactElement | null;
|
||
|
|
||
|
type VirtualizedListWithoutPreConfiguredProps<ItemT> = Omit<
|
||
|
VirtualizedListWithoutRenderItemProps<ItemT>,
|
||
|
'stickyHeaderIndices'
|
||
|
>;
|
||
|
|
||
|
export interface SectionListProps<ItemT, SectionT = DefaultSectionT>
|
||
|
extends VirtualizedListWithoutPreConfiguredProps<ItemT> {
|
||
|
/**
|
||
|
* Rendered in between each section.
|
||
|
*/
|
||
|
SectionSeparatorComponent?:
|
||
|
| React.ComponentType<any>
|
||
|
| React.ReactElement
|
||
|
| null
|
||
|
| undefined;
|
||
|
|
||
|
/**
|
||
|
* A marker property for telling the list to re-render (since it implements PureComponent).
|
||
|
* If any of your `renderItem`, Header, Footer, etc. functions depend on anything outside of the `data` prop,
|
||
|
* stick it here and treat it immutably.
|
||
|
*/
|
||
|
extraData?: any | undefined;
|
||
|
|
||
|
/**
|
||
|
* `getItemLayout` is an optional optimization that lets us skip measurement of dynamic
|
||
|
* content if you know the height of items a priori. getItemLayout is the most efficient,
|
||
|
* and is easy to use if you have fixed height items, for example:
|
||
|
* ```
|
||
|
* getItemLayout={(data, index) => (
|
||
|
* {length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index}
|
||
|
* )}
|
||
|
* ```
|
||
|
*/
|
||
|
getItemLayout?:
|
||
|
| ((
|
||
|
data: SectionListData<ItemT, SectionT>[] | null,
|
||
|
index: number,
|
||
|
) => {length: number; offset: number; index: number})
|
||
|
| undefined;
|
||
|
|
||
|
/**
|
||
|
* How many items to render in the initial batch
|
||
|
*/
|
||
|
initialNumToRender?: number | undefined;
|
||
|
|
||
|
/**
|
||
|
* Reverses the direction of scroll. Uses scale transforms of -1.
|
||
|
*/
|
||
|
inverted?: boolean | null | undefined;
|
||
|
|
||
|
/**
|
||
|
* Used to extract a unique key for a given item at the specified index. Key is used for caching
|
||
|
* and as the react key to track item re-ordering. The default extractor checks `item.key`, then
|
||
|
* falls back to using the index, like React does.
|
||
|
*/
|
||
|
keyExtractor?: ((item: ItemT, index: number) => string) | undefined;
|
||
|
|
||
|
/**
|
||
|
* Called once when the scroll position gets within onEndReachedThreshold of the rendered content.
|
||
|
*/
|
||
|
onEndReached?: ((info: {distanceFromEnd: number}) => void) | null | undefined;
|
||
|
|
||
|
/**
|
||
|
* How far from the end (in units of visible length of the list) the bottom edge of the
|
||
|
* list must be from the end of the content to trigger the `onEndReached` callback.
|
||
|
* Thus a value of 0.5 will trigger `onEndReached` when the end of the content is
|
||
|
* within half the visible length of the list.
|
||
|
*/
|
||
|
onEndReachedThreshold?: number | null | undefined;
|
||
|
|
||
|
/**
|
||
|
* If provided, a standard RefreshControl will be added for "Pull to Refresh" functionality.
|
||
|
* Make sure to also set the refreshing prop correctly.
|
||
|
*/
|
||
|
onRefresh?: (() => void) | null | undefined;
|
||
|
|
||
|
/**
|
||
|
* Used to handle failures when scrolling to an index that has not been measured yet.
|
||
|
* Recommended action is to either compute your own offset and `scrollTo` it, or scroll as far
|
||
|
* as possible and then try again after more items have been rendered.
|
||
|
*/
|
||
|
onScrollToIndexFailed?:
|
||
|
| ((info: {
|
||
|
index: number;
|
||
|
highestMeasuredFrameIndex: number;
|
||
|
averageItemLength: number;
|
||
|
}) => void)
|
||
|
| undefined;
|
||
|
|
||
|
/**
|
||
|
* Set this true while waiting for new data from a refresh.
|
||
|
*/
|
||
|
refreshing?: boolean | null | undefined;
|
||
|
|
||
|
/**
|
||
|
* Default renderer for every item in every section. Can be over-ridden on a per-section basis.
|
||
|
*/
|
||
|
renderItem?: SectionListRenderItem<ItemT, SectionT> | undefined;
|
||
|
|
||
|
/**
|
||
|
* Rendered at the top of each section. Sticky headers are not yet supported.
|
||
|
*/
|
||
|
renderSectionHeader?:
|
||
|
| ((info: {
|
||
|
section: SectionListData<ItemT, SectionT>;
|
||
|
}) => React.ReactElement | null)
|
||
|
| undefined;
|
||
|
|
||
|
/**
|
||
|
* Rendered at the bottom of each section.
|
||
|
*/
|
||
|
renderSectionFooter?:
|
||
|
| ((info: {
|
||
|
section: SectionListData<ItemT, SectionT>;
|
||
|
}) => React.ReactElement | null)
|
||
|
| undefined;
|
||
|
|
||
|
/**
|
||
|
* An array of objects with data for each section.
|
||
|
*/
|
||
|
sections: ReadonlyArray<SectionListData<ItemT, SectionT>>;
|
||
|
|
||
|
/**
|
||
|
* Render a custom scroll component, e.g. with a differently styled `RefreshControl`.
|
||
|
*/
|
||
|
renderScrollComponent?:
|
||
|
| ((props: ScrollViewProps) => React.ReactElement<ScrollViewProps>)
|
||
|
| undefined;
|
||
|
|
||
|
/**
|
||
|
* Note: may have bugs (missing content) in some circumstances - use at your own risk.
|
||
|
*
|
||
|
* This may improve scroll performance for large lists.
|
||
|
*/
|
||
|
removeClippedSubviews?: boolean | undefined;
|
||
|
|
||
|
/**
|
||
|
* Makes section headers stick to the top of the screen until the next one pushes it off.
|
||
|
* Only enabled by default on iOS because that is the platform standard there.
|
||
|
*/
|
||
|
stickySectionHeadersEnabled?: boolean | undefined;
|
||
|
|
||
|
/**
|
||
|
* Uses legacy MetroListView instead of default VirtualizedSectionList
|
||
|
*/
|
||
|
legacyImplementation?: boolean | undefined;
|
||
|
}
|
||
|
|
||
|
export interface SectionListScrollParams {
|
||
|
animated?: boolean | undefined;
|
||
|
itemIndex: number;
|
||
|
sectionIndex: number;
|
||
|
viewOffset?: number | undefined;
|
||
|
viewPosition?: number | undefined;
|
||
|
}
|
||
|
|
||
|
export abstract class SectionListComponent<
|
||
|
Props,
|
||
|
> extends React.Component<Props> {
|
||
|
/**
|
||
|
* Scrolls to the item at the specified sectionIndex and itemIndex (within the section)
|
||
|
* positioned in the viewable area such that viewPosition 0 places it at the top
|
||
|
* (and may be covered by a sticky header), 1 at the bottom, and 0.5 centered in the middle.
|
||
|
*/
|
||
|
scrollToLocation(params: SectionListScrollParams): void;
|
||
|
|
||
|
/**
|
||
|
* Tells the list an interaction has occurred, which should trigger viewability calculations, e.g.
|
||
|
* if `waitForInteractions` is true and the user has not scrolled. This is typically called by
|
||
|
* taps on items or by navigation actions.
|
||
|
*/
|
||
|
recordInteraction(): void;
|
||
|
|
||
|
/**
|
||
|
* Displays the scroll indicators momentarily.
|
||
|
*
|
||
|
* @platform ios
|
||
|
*/
|
||
|
flashScrollIndicators(): void;
|
||
|
|
||
|
/**
|
||
|
* Provides a handle to the underlying scroll responder.
|
||
|
*/
|
||
|
getScrollResponder(): ScrollView | undefined;
|
||
|
|
||
|
/**
|
||
|
* Provides a handle to the underlying scroll node.
|
||
|
*/
|
||
|
getScrollableNode(): NodeHandle | undefined;
|
||
|
}
|
||
|
|
||
|
export class SectionList<
|
||
|
ItemT = any,
|
||
|
SectionT = DefaultSectionT,
|
||
|
> extends SectionListComponent<SectionListProps<ItemT, SectionT>> {}
|
||
|
|
||
|
/* This definition is deprecated because it extends the wrong base type */
|
||
|
export interface SectionListStatic<ItemT, SectionT = DefaultSectionT>
|
||
|
extends React.ComponentClass<SectionListProps<ItemT, SectionT>> {
|
||
|
/**
|
||
|
* Scrolls to the item at the specified sectionIndex and itemIndex (within the section)
|
||
|
* positioned in the viewable area such that viewPosition 0 places it at the top
|
||
|
* (and may be covered by a sticky header), 1 at the bottom, and 0.5 centered in the middle.
|
||
|
*/
|
||
|
scrollToLocation?(params: SectionListScrollParams): void;
|
||
|
}
|