UNPKG

@spaced-out/ui-design-system

Version:
118 lines (107 loc) 4 kB
// @flow strict import type {GroupTitleOption} from '../useFilteredOptions'; import {useFilteredOptions} from '../useFilteredOptions'; export type ArbitraryOption = { key: string, label: string, arbitrary?: boolean, multiArbitrary?: boolean, }; export function useArbitraryOptionAddition<V>({ searchTerm, options = [], excludedKeys = [], allowArbitraryValues = true, allowMultiArbitraryValues = false, validateArbitraryValue = (value: string): boolean => value.trim() !== '', // $FlowFixMe[incompatible-return] - Object literal is compatible with V due to type constraint makeArbitraryValue = (searchTerm): V => ({ key: searchTerm, label: searchTerm, arbitrary: true, }), // $FlowFixMe[incompatible-return] - Object literal is compatible with V due to type constraint makeMultiArbitraryValue = (searchTerm): V => { const regex = /^(?=.*[,\n]).+$/s; if (regex.test(searchTerm)) { // $FlowFixMe - Object literal is compatible with V due to type constraint return {key: searchTerm, label: searchTerm, multiArbitrary: true}; } }, groupTitleOptions = [], arbitraryGroup = {groupTitle: '', showLineDivider: false, options: []}, searchOptionsBy = (option: V, searchTerm: string): boolean => { // $FlowFixMe const {label, key}: {label: string, key: string} = option; return ( key.toLowerCase().includes(searchTerm) || label.toLowerCase().includes(searchTerm) ); }, }: { searchTerm: string, options?: V[], excludedKeys?: string[], allowArbitraryValues?: boolean, allowMultiArbitraryValues?: boolean, validateArbitraryValue?: (string) => boolean, makeArbitraryValue?: (string) => V, makeMultiArbitraryValue?: (string) => V, groupTitleOptions?: GroupTitleOption<V>[], arbitraryGroup?: GroupTitleOption<V>, searchOptionsBy?: (option: V, searchTerm: string) => boolean, }): { optionsWithArbitrary: Array<V>, groupTitleOptionsWithArbitrary: Array<GroupTitleOption<V>>, } { const trimmedSearchTerm = (searchTerm || '').trim().toLowerCase(); const {filteredOptions, filteredGroupTitleOptions} = useFilteredOptions({ searchTerm: trimmedSearchTerm, options, // $FlowFixMe[incompatible-call] groupTitleOptions, searchOptionsBy, }); // Find if an arbitrary option should be added const arbitraryOption = allowArbitraryValues && trimmedSearchTerm && // $FlowFixMe - Array methods are valid here !filteredOptions.some((option) => option.key === trimmedSearchTerm) && // $FlowFixMe - Array methods are valid here !filteredGroupTitleOptions.some( (group) => Array.isArray(group.options) && // $FlowFixMe- option has key property group.options.some((option) => option.key === trimmedSearchTerm), ) && !excludedKeys.includes(trimmedSearchTerm) && validateArbitraryValue(trimmedSearchTerm) && makeArbitraryValue(trimmedSearchTerm); // Find if a multi-arbitrary option should be added const multiArbitraryOption = allowMultiArbitraryValues && trimmedSearchTerm && makeMultiArbitraryValue(trimmedSearchTerm); // Compose the results let optionsWithArbitrary = filteredOptions; let groupTitleOptionsWithArbitrary = groupTitleOptions; if (arbitraryOption) { // $FlowFixMe[incompatible-type] - Array spread is valid here optionsWithArbitrary = [arbitraryOption, ...optionsWithArbitrary]; groupTitleOptionsWithArbitrary = [ {...arbitraryGroup, options: [arbitraryOption]}, ...groupTitleOptionsWithArbitrary, ]; } if (multiArbitraryOption) { // $FlowFixMe[incompatible-type] - Array spread is valid here optionsWithArbitrary = [multiArbitraryOption, ...optionsWithArbitrary]; groupTitleOptionsWithArbitrary = [ {...arbitraryGroup, options: [multiArbitraryOption]}, ...groupTitleOptionsWithArbitrary, ]; } // $FlowFixMe[incompatible-return] return {optionsWithArbitrary, groupTitleOptionsWithArbitrary}; }