import React, { type HTMLProps, type ReactNode, Fragment } from 'react'; import { DropdownItem } from '../DropdownItem'; import styles from './DropdownMenuContentList.module.css'; type Option = { key: string; label: string }; type OptionGroup = { key: string; label: string; options: T[] }; export type Props = { isLoading?: boolean; options: (T | OptionGroup)[]; getItemProps(options: { item: T; index: number }): HTMLProps; renderOption(option: T, index: number): ReactNode; // should always return a DropdownItem component renderOptionGroup?(optionGroup: OptionGroup): ReactNode; renderNoOptions?(): ReactNode; renderLoadingOptions?(): ReactNode; }; export const DropdownMenuContentList = ({ isLoading = false, options, getItemProps, renderOption, renderOptionGroup = (optionGroup) => ( ), renderNoOptions, renderLoadingOptions, }: Props) => { const internalRenderOption = (option: T, index: number) => { const itemProps = getItemProps({ index, item: option }); return ( // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/click-events-have-key-events
  • { event.preventDefault(); }} onClick={(e) => { e.preventDefault(); e.stopPropagation(); if (itemProps.onClick) { itemProps.onClick(e); } }} > {renderOption(option, index)}
  • ); }; let optionIndex = -1; return ( <> {!isLoading && options.length > 0 && options.map((option) => { if ('options' in option) { if (!option.options.length) { return null; } return ( {renderOptionGroup?.(option)} {option.options.map((option) => { optionIndex += 1; return internalRenderOption(option, optionIndex); })} ); } optionIndex += 1; return internalRenderOption(option, optionIndex); })} {!isLoading && options.length === 0 && renderNoOptions?.()} {isLoading && renderLoadingOptions?.()} ); };