import { UseComboboxReturnValue } from 'downshift'; import React, { useRef, useCallback, useEffect, CSSProperties } from 'react'; import { GroupedOption, BaseOption } from '../types'; import { MenuWrapper, CategoryWrapper } from '../StyledSelect'; import { SelectProps } from '.'; import { checkAtBottom, getAccumulatedIndex, getItemOffsetTop } from '../utils'; import { fromNullable, map, getOrElse } from '../../../fp/Option'; import { pipe, noop } from '../../../fp/function'; import Divider from '../../Divider'; import Menu from '../../Menu'; import Typography from '../../Typography'; type OptionListComponentProps = { categories: GroupedOption[]; hasResults: boolean; newOption: BaseOption; selectedItem: T | undefined; style: CSSProperties; } & Pick< UseComboboxReturnValue, 'getMenuProps' | 'getItemProps' | 'highlightedIndex' > & Pick< SelectProps, | 'optionRenderer' | 'loading' | 'onScrollListToBottom' | 'onCreateNewOption' | 'noResults' >; const OptionList = ({ categories, hasResults, newOption, selectedItem, getItemProps, getMenuProps, highlightedIndex, onScrollListToBottom, onCreateNewOption, loading, noResults, optionRenderer, style, }: OptionListComponentProps) => { const menuRef = useRef(null); const activeItemRef = useRef(null); const onScrollToBottom = useCallback((): void => { const isAtBottom = checkAtBottom(menuRef.current); if ( isAtBottom === true && loading !== true && onScrollListToBottom !== undefined ) { onScrollListToBottom(); } }, [loading, onScrollListToBottom]); useEffect(() => { pipe( fromNullable(menuRef.current), map(el => { const offsetTop = getItemOffsetTop(activeItemRef.current); if (offsetTop !== undefined) { const menuEl = el; menuEl.scrollTop = offsetTop; } }), getOrElse(noop) ); }, [selectedItem]); return ( {categories.map(({ category, options }, catIndex) => { const accumulatedIndex = getAccumulatedIndex(categories, catIndex); return ( {category !== '' && ( {category} )} {options.map((item, index) => { const actualIndex = accumulatedIndex + index; const isActiveItem = item.value === selectedItem?.value; const ariaProps = item.disabled === true ? {} : { ...getItemProps({ item, index: actualIndex, ref: isActiveItem === true ? activeItemRef : undefined, onClick: e => e.stopPropagation(), }), }; return ( {item.helpText} ) } {...ariaProps} /> ); })} {catIndex < categories.length - 1 && } ); })} {hasResults === false && loading !== true && onCreateNewOption !== undefined && ( e.stopPropagation(), })} /> )} {hasResults === false && onCreateNewOption === undefined && noResults} ); }; export default OptionList;