@spaced-out/ui-design-system
Version:
Sense UI components library
82 lines (70 loc) • 2.38 kB
Flow
// @flow strict
import * as React from 'react';
export type GroupTitleOption<V> = {
groupTitle: React.Node,
options?: V[],
showLineDivider?: boolean,
};
// TODO: V should generic with constraints.
export function useFilteredOptions<V>({
searchTerm,
options = [],
excludedKeys = [],
groupTitleOptions = [],
searchOptionsBy = (option: V, searchTerm: string): boolean => {
// $FlowFixMe
const {label, key}: {label: string, key: string} = option;
return (
key.toLowerCase().includes(searchTerm) ||
(label ? label.toLowerCase().includes(searchTerm) : false)
);
},
}: {
searchTerm: string,
options?: V[],
groupTitleOptions?: GroupTitleOption<V>[],
excludedKeys?: string[],
searchOptionsBy?: (option: V, searchTerm: string) => boolean,
}): {filteredOptions?: V[], filteredGroupTitleOptions?: GroupTitleOption<V>[]} {
// Memoize the filterExcluded function for performance
const filterExcluded = React.useCallback(
(list?: V[]): V[] =>
// $FlowFixMe - list has key property
list ? list.filter((option) => !excludedKeys.includes(option.key)) : [],
[excludedKeys],
);
return React.useMemo(() => {
const trimmedValue = (searchTerm || '').trim().toLowerCase();
// Initialize filteredOptions as an empty array if options are not provided
let filteredOptions: V[] = [];
if (options.length) {
filteredOptions = filterExcluded(options);
// Apply search term filtering
if (trimmedValue) {
filteredOptions = filteredOptions.filter((option) =>
searchOptionsBy(option, trimmedValue),
);
}
}
let filteredGroupTitleOptions: GroupTitleOption<V>[] = [];
// Process groupTitleOptions if provided
if (Array.isArray(groupTitleOptions) && groupTitleOptions.length) {
filteredGroupTitleOptions = groupTitleOptions
.map((group) => {
const filtered = filterExcluded(group.options).filter(
(option) => !trimmedValue || searchOptionsBy(option, trimmedValue),
);
return {...group, options: filtered};
})
.filter((group) => (group.options ? group.options.length > 0 : false));
}
return {filteredOptions, filteredGroupTitleOptions};
}, [
searchTerm,
options,
excludedKeys,
groupTitleOptions,
searchOptionsBy,
filterExcluded,
]);
}