import { includesNoncase } from '@monorail/sharedHelpers/strings' import { isNumber, isString } from '@monorail/sharedHelpers/typeGuards' import { Undefinedable } from '@monorail/sharedHelpers/typeLevel' import { DropdownItemType, DropdownItemValue, DropdownType, isDropdownItem, } from './helpers' type DropdownParserProps = { value: (item: T) => Undefinedable label: (item: T) => string } export type DropdownParser = DropdownParserProps & { isActive: (item: T) => boolean includes: (target: string) => (source: T) => boolean compare: ( target: T | DropdownItemValue, ) => (source: T | DropdownItemValue) => boolean } export type DropdownParserHook = ( props?: Partial>, ) => DropdownParser export function createDropdownTypeParser( props?: Partial>, ): DropdownParser { const { value = (item: T) => (isDropdownItem(item) ? item.value : String(item)), label = (item: T) => isDropdownItem(item) ? item.label || '' : String(item), } = props || {} const itemValue = (item: T | DropdownItemValue) => isString(item) || isNumber(item) ? item : value(item) const includes = (target: string) => (source: T): boolean => includesNoncase(target)(label(source)) const compare = (target: T | DropdownItemValue) => ( source: T | DropdownItemValue, ): boolean => itemValue(source) === itemValue(target) const isActive = (item: T) => !(item as DropdownItemType).disabled return { value: itemValue, label, isActive, // Match by String includes, // Compare item compare, } } export const createCustomParser = ( options: Partial> & Partial>, ) => { const { value, label, ...override } = options const parser = createDropdownTypeParser({ value, label }) return () => ({ ...parser, ...override, }) }