import { GroupedOption, BaseOption } from './types'; import { fromNullable, map, getOrElse } from '../../fp/Option'; import { pipe } from '../../fp/function'; const checkAtBottom = (element: HTMLDivElement | null): boolean | undefined => pipe( fromNullable(element), map(el => el.scrollHeight - el.scrollTop === el.clientHeight), getOrElse(() => undefined) ); const getItemOffsetTop = (itemEl: HTMLLIElement | null): number | undefined => pipe( fromNullable(itemEl), map(el => el.offsetTop), getOrElse(() => undefined) ); const isGroupedOptions = ( options: T[] | GroupedOption[] ): options is GroupedOption[] => { const firstOption = options[0]; return ( firstOption !== undefined && (firstOption as GroupedOption).category !== undefined ); }; const mapOptions = ( options: T[] | GroupedOption[] ): GroupedOption[] => { if (isGroupedOptions(options)) { return options; } return [{ category: '', options }]; }; const optionPredicate = (query?: string) => ( option: T ): boolean => { if (query === undefined) { return true; } const matchedOptionText = option.text .toLowerCase() .includes(query.toLowerCase()); const matchedOptionHelpText = option.helpText?.toLowerCase().includes(query.toLowerCase()) ?? false; return matchedOptionText || matchedOptionHelpText; }; const filterGroupedOptions = ( predicate: (opt: T) => boolean, groupedOptions: GroupedOption[] ): GroupedOption[] => groupedOptions .map((groupedOpt: GroupedOption) => ({ ...groupedOpt, options: groupedOpt.options.filter(predicate), })) .filter((groupedOpt: GroupedOption) => groupedOpt.options.length > 0); const getAccumulatedIndex = ( options: GroupedOption[], catIndex: number ): number => { if (catIndex === 0) { return 0; } return options .slice(0, catIndex) .reduce((acc, groupedOpt) => acc + groupedOpt.options.length, 0); }; export { isGroupedOptions, checkAtBottom, getItemOffsetTop, mapOptions, filterGroupedOptions, optionPredicate, getAccumulatedIndex, };