diff --git a/src/components/List/List.scss b/src/components/List/List.scss index dce8d412ef..563c36890f 100644 --- a/src/components/List/List.scss +++ b/src/components/List/List.scss @@ -90,4 +90,11 @@ $block: '.#{variables.$ns}list'; flex: 0 0 auto; color: var(--g-color-text-hint); } + + &__loading-indicator { + display: flex; + width: 100%; + align-items: center; + justify-content: center; + } } diff --git a/src/components/List/List.tsx b/src/components/List/List.tsx index 66b20edfce..45db569dad 100644 --- a/src/components/List/List.tsx +++ b/src/components/List/List.tsx @@ -6,13 +6,14 @@ import {SortableContainer, SortableElement} from 'react-sortable-hoc'; import AutoSizer, {Size} from 'react-virtualized-auto-sizer'; import {VariableSizeList as ListContainer} from 'react-window'; +import {SelectLoadingIndicator} from '../Select/components/SelectList/SelectLoadingIndicator'; import {TextInput} from '../controls'; import {MobileContext} from '../mobile'; import {block} from '../utils/cn'; -import {ListItem, SimpleContainer} from './components'; +import {ListItem, SimpleContainer, defaultRenderItem} from './components'; import {listNavigationIgnoredKeys} from './constants'; -import type {ListItemData, ListProps, ListSortParams} from './types'; +import type {ListItemData, ListItemProps, ListProps, ListSortParams} from './types'; import './List.scss'; @@ -77,6 +78,9 @@ export class List extends React.Component, ListState(); refContainer = React.createRef(); blurTimer: ReturnType | null = null; + loadingItem = {value: '__LIST_ITEM_LOADING__', disabled: true} as unknown as ListItemData< + T & {value: string} + >; componentDidUpdate(prevProps: ListProps) { if (this.props.items !== prevProps.items) { @@ -137,6 +141,14 @@ export class List extends React.Component, ListState extends React.Component, ListState['renderItem'] = (item, isItemActive, itemIndex) => { + const {onLoadMore} = this.props; + + if ('value' in item && item.value === this.loadingItem.value) { + return ( + + ); + } + + return this.props.renderItem + ? this.props.renderItem(item, isItemActive, itemIndex) + : defaultRenderItem(item); + }; + private renderItem = ({index, style}: {index: number; style?: React.CSSProperties}) => { const {sortHandleAlign} = this.props; const {items, activeItem} = this.state; - const item = items[index]; + const item = this.getItemsWithLoading()[index]; const sortable = this.props.sortable && items.length > 1 && !this.getFilter(); const active = index === activeItem || index === this.props.activeItemIndex; const Item = sortable ? SortableListItem : ListItem; @@ -213,7 +239,7 @@ export class List extends React.Component, ListState extends React.Component, ListState extends React.Component, ListState {({width, height}: Size) => ( @@ -286,8 +313,8 @@ export class List extends React.Component, ListState void}) => { + const ref = React.useRef(null); + + useIntersection({element: ref.current, onIntersect: props?.onIntersect}); + + return ( +
+ +
+ ); +}; diff --git a/src/components/List/README.md b/src/components/List/README.md index 300903ab7c..d669d19ae1 100644 --- a/src/components/List/README.md +++ b/src/components/List/README.md @@ -30,6 +30,8 @@ Lets you filter and sort items, render items of different height, and select the | selectedItemIndex | `Number` | | | If a value is set, an item with this index is rendered as selected (the background color is from `--g-color-base-selection`). | | itemClassName | `String` | | | Custom class name to be added to an item container | | itemsClassName | `String` | | | Custom class name to be added to an item list | +| loading | `boolean` | | | Add the loading item to the end of the items list. Works like persistant loading indicator while the items list is empty. Does Not work with `sortable` prop. | +| onLoadMore | `Function` | | | Fires when loading indicator gets visible. | ### Virtualization diff --git a/src/components/List/components/ListItem.tsx b/src/components/List/components/ListItem.tsx index d6bba3e45a..a1bd8d903d 100644 --- a/src/components/List/components/ListItem.tsx +++ b/src/components/List/components/ListItem.tsx @@ -9,7 +9,7 @@ import {DragHandleIcon} from './DragHandleIcon'; const b = block('list'); -const defaultRenderItem = (item: T) => String(item); +export const defaultRenderItem = (item: T) => String(item); export class ListItem extends React.Component> { private static publishEvent = eventBroker.withEventPublisher('List'); diff --git a/src/components/List/types.ts b/src/components/List/types.ts index b720bab524..94a022b972 100644 --- a/src/components/List/types.ts +++ b/src/components/List/types.ts @@ -37,6 +37,8 @@ export type ListProps = QAProps & { onFilterEnd?: ({items}: {items: ListItemData[]}) => void; onSortEnd?: (params: ListSortParams) => void; autoFocus?: boolean; + loading?: boolean; + onLoadMore?: () => void; }; export type ListItemProps = {