import { type FC, Children, useState, type ReactNode, type HTMLAttributes, } from 'react'; import cn from 'classnames'; import Button from './button'; import '../styles/components/expandable-list.scss'; type ExpandableMessageProps = { expanded?: boolean; setExpanded: (expanded: boolean) => unknown; descriptionString?: string; showHideWording?: boolean; nHiddenItems?: number; }; export const ExpandableMessage: FC = ({ descriptionString = 'items', expanded, setExpanded, showHideWording, nHiddenItems, }) => { let message = `${showHideWording ? 'Hide' : 'Fewer'} ${descriptionString}`; if (!expanded) { if (nHiddenItems === undefined) { message = showHideWording ? 'Show' : 'More'; } else { message = showHideWording ? `Show ${nHiddenItems}` : `${nHiddenItems} more`; } message += ` ${descriptionString}`; } return ( ); }; type ExpandableListProps = { /** * Children as an array of react elements, items of the list */ children?: ReactNode; /** * Threshold from which to start hiding items of the list */ numberCollapsedItems?: number; /** * Description of the items to put in text of the open/close button */ descriptionString?: string; /** * Wether to show or hide the visual bullet points */ showBullets?: boolean; /** * Extra element to place alongside the open/close button */ extraActions?: ReactNode; /** * Wether to display or not the number of hidden elements */ displayNumberOfHiddenItems?: boolean; /** * Classnames to be added to the list container */ className?: string; }; export const ExpandableList = ({ children: c, numberCollapsedItems = 5, descriptionString = 'items', showBullets, extraActions, displayNumberOfHiddenItems, className, ...props }: ExpandableListProps & HTMLAttributes) => { const [expanded, setExpanded] = useState(false); // get an array of children, filter out null or undefined children to avoid // counting them towards the threshold limit const children = Children.toArray(c).filter(Boolean); if (!children.length) { return null; } const enoughChildren = children.length > numberCollapsedItems + 1; const itemNodes = Children.map( children.slice( 0, expanded || !enoughChildren ? children.length : numberCollapsedItems ), (child, index) => { let key: string | number = index; if (typeof child === 'object' && 'key' in child && child.key) { key = child.key; } return
  • {child}
  • ; } ); let actions = null; if (enoughChildren || extraActions) { actions = (
  • {enoughChildren && ( )} {extraActions}
  • ); } return ( ); }; export default ExpandableList;