import classNames from 'classnames'; import * as React from 'react'; import debounce from 'lodash/debounce.js'; import { Flex } from '../Flex'; import { Grid } from '../Grid'; import { Text } from '../Text'; import { Pagination, usePagination } from '../Pagination'; import { SearchField } from '../SearchField'; import { ComponentClassNames, ComponentText } from '../shared/constants'; import { strHasLength } from '../shared/utils'; import { BaseCollectionProps, ElementType, GridCollectionProps, ListCollectionProps, } from '../types'; import { getItemsAtPage, itemHasText, getPageCount } from './utils'; const DEFAULT_PAGE_SIZE = 10; const TYPEAHEAD_DELAY_MS = 300; const ListCollection = ({ children, direction = 'column', items, ...rest }: ListCollectionProps) => ( {Array.isArray(items) ? items.map(children) : null} ); const GridCollection = ({ children, items, ...rest }: GridCollectionProps) => ( {Array.isArray(items) ? items.map(children) : null} ); const renderCollectionOrNoResultsFound = ( collection: JSX.Element | null, items: Item[], searchNoResultsFound: React.ReactNode ) => { if (items.length) { return collection; } if (searchNoResultsFound) { return searchNoResultsFound; } return ( {ComponentText.Collection.searchNoResultsFound} ); }; /** * [📖 Docs](https://ui.docs.amplify.aws/react/components/collection) */ export const Collection = ({ className, isSearchable, isPaginated, items, itemsPerPage = DEFAULT_PAGE_SIZE, searchFilter = itemHasText, searchLabel = ComponentText.Collection.searchButtonLabel, searchNoResultsFound, searchPlaceholder, type = 'list', testId, ...rest }: BaseCollectionProps): JSX.Element => { const [searchText, setSearchText] = React.useState(); // eslint-disable-next-line react-hooks/exhaustive-deps const onSearch = React.useCallback( debounce(setSearchText, TYPEAHEAD_DELAY_MS), [setSearchText] ); // Make sure that items are iterable items = Array.isArray(items) ? items : []; // Filter items by text if (isSearchable && strHasLength(searchText)) { items = items.filter((item) => searchFilter(item, searchText)); } // Pagination const pagination = usePagination({ totalPages: getPageCount(items.length, itemsPerPage), }); if (isPaginated) { items = getItemsAtPage(items, pagination.currentPage, itemsPerPage); } const collection = type === 'list' ? ( ) : type === 'grid' ? ( ) : null; return ( {isSearchable ? ( ) => onSearch(e.target.value) } onClear={() => setSearchText('')} /> ) : null} {renderCollectionOrNoResultsFound( collection, items, searchNoResultsFound )} {isPaginated ? ( ) : null} ); }; Collection.displayName = 'Collection';