UNPKG

wix-style-react

Version:
227 lines (202 loc) 6.35 kB
import React from 'react'; import PropTypes from 'prop-types'; import { classes } from './Content.st.css'; import { dataHooks } from '../SelectorList.helpers'; import Selector from '../../Selector'; import Loader from '../../Loader'; import InfiniteScroll from '../../utils/InfiniteScroll'; import Text from '../../Text'; const DEFAULT_EMPTY = ( <div className={classes.defaultEmptyStateWrapper}> <Text>{"You don't have any items"}</Text> </div> ); const ListItems = ({ items, checkIsSelected, onToggle, imageSize, imageShape, multiple, }) => { if (!items.length) { return null; } return ( <ul data-hook={dataHooks.list} className={classes.list}> {items.map(item => ( <Selector id={item.id} key={item.id} dataHook={dataHooks.selector} imageSize={imageSize} imageShape={imageShape} toggleType={multiple ? 'checkbox' : 'radio'} image={item.image} title={item.title} subtitle={item.subtitle} extraNode={ item.extraNode ? item.extraNode : item.extraText && <Text secondary>{item.extraText}</Text> } subtitleNode={item.subtitleNode} belowNode={item.belowNode} showBelowNodeOnSelect={item.showBelowNodeOnSelect} isSelected={checkIsSelected(item)} isDisabled={item.disabled} onToggle={() => { !item.disabled && onToggle(item); }} /> ))} </ul> ); }; const SelectorListContent = ({ dataHook, items, topScrollableContent, onToggle, emptyState, renderNoResults, isLoading, checkIsSelected, isEmpty, noResultsFound, imageSize, imageShape, multiple, searchValue, loadMore, hasMore, infiniteScrollRef, }) => { return ( <div className={classes.content} data-hook={dataHook}> {isLoading && ( <div className={classes.mainLoaderWrapper}> <Loader size="medium" dataHook={dataHooks.mainLoader} /> </div> )} {isEmpty && ( <div data-hook={dataHooks.emptyState} className={classes.emptyStateWrapper} children={emptyState} /> )} {items.length > 0 && ( <InfiniteScroll key={searchValue} ref={infiniteScrollRef} data={items} loadMore={loadMore} hasMore={hasMore} useWindow={false} initialLoad={false} loader={ <div className={classes.nextPageLoaderWrapper}> <Loader size="small" dataHook={dataHooks.nextPageLoader} /> </div> } > {topScrollableContent} <ListItems {...{ items, checkIsSelected, onToggle, imageSize, imageShape, multiple, }} /> </InfiniteScroll> )} {noResultsFound && ( <div data-hook={dataHooks.noResultsFoundState} className={classes.noResultsFoundStateWrapper} children={renderNoResults(searchValue)} /> )} </div> ); }; SelectorListContent.propTypes = { /** applied as data-hook HTML attribute that can be used to create driver in testing */ dataHook: PropTypes.string, /** array of selector items to show */ items: PropTypes.arrayOf( PropTypes.shape({ id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, title: PropTypes.node.isRequired, subtitle: PropTypes.string, extraText: PropTypes.string, extraNode: PropTypes.node, disabled: PropTypes.bool, // show item as disabled, dont count it in "select all", exclude from `onOk` selected: PropTypes.bool, // force item as selected image: PropTypes.node, subtitleNode: PropTypes.node, belowNode: PropTypes.node, showBelowNodeOnSelect: PropTypes.bool, }), ), /** Component/element that will be rendered above the list that will not be sticky, but scrollable */ topScrollableContent: PropTypes.node, /** callback to trigger when toggling a selector, receives SelectorList item */ onToggle: PropTypes.func, /** * Component/element that will be rendered when there is nothing to display, * i.e. empty `{items:[], totalCount: 0}` was returned on the first call to `dataSource` * */ emptyState: PropTypes.node, /** * Function that will get the current `searchQuery` and should return the component/element * that will be rendered when there are no items that suffice the entered search query * */ renderNoResults: PropTypes.func, /** whether list is loading */ isLoading: PropTypes.bool, /** a function that receives an item and checks if it is selected */ checkIsSelected: PropTypes.func.isRequired, /** whether list is empty */ isEmpty: PropTypes.bool, /** whether list search found no matching items */ noResultsFound: PropTypes.bool, /** Image icon size */ imageSize: PropTypes.oneOf(['tiny', 'small', 'portrait', 'large', 'cinema']), /** * Image icon shape, `rectangular` or `circle`.<br> * NOTE: `circle` is not compatible with `imageSize` of `portrait` or `cinema` * */ imageShape: (props, propName, componentName) => { if ( ['portrait', 'cinema'].includes(props.imageSize) && props[propName] === 'circle' ) { return new Error( `${componentName}: prop "imageSize" with value of "${props.imageSize}" is incompatible with prop imageShape with value of "circle" — use "rectangular" instead.`, ); } }, /** display checkbox and allow multi selection */ multiple: PropTypes.bool, /** search input value */ searchValue: PropTypes.string.isRequired, /** A callback called when more items are requested to be rendered. */ loadMore: PropTypes.func.isRequired, /** Whether there are more items to be loaded. */ hasMore: PropTypes.bool, }; SelectorListContent.defaultProps = { dataHook: dataHooks.content, emptyState: DEFAULT_EMPTY, renderNoResults: searchValue => ( <div className={classes.defaultNoResultsFoundStateWrapper}> <Text>No items matched your search {`"${searchValue}"`}</Text> </div> ), }; export default SelectorListContent;