diff --git a/packages/react/src/components/MultiSelect/FilterableMultiSelect.tsx b/packages/react/src/components/MultiSelect/FilterableMultiSelect.tsx index 482f5414b542..e9e0a04a782c 100644 --- a/packages/react/src/components/MultiSelect/FilterableMultiSelect.tsx +++ b/packages/react/src/components/MultiSelect/FilterableMultiSelect.tsx @@ -32,8 +32,7 @@ import React, { } from 'react'; import { defaultFilterItems } from '../ComboBox/tools/filter'; import { - type ItemBase, - type SortingPropTypes, + type MultiSelectSortingProps, sortingPropTypes, } from './MultiSelectPropTypes'; import ListBox, { PropTypes as ListBoxPropTypes } from '../ListBox'; @@ -74,8 +73,8 @@ const { } = useMultipleSelection.stateChangeTypes as UseMultipleSelectionInterface['stateChangeTypes']; -export interface FilterableMultiSelectProps - extends SortingPropTypes { +export interface FilterableMultiSelectProps + extends MultiSelectSortingProps { /** * Specify a label to be read by screen readers on the container node * @deprecated @@ -109,20 +108,20 @@ export interface FilterableMultiSelectProps /** * Additional props passed to Downshift */ - downshiftProps?: UseMultipleSelectionProps; + downshiftProps?: UseMultipleSelectionProps; /** * Default sorter is assigned if not provided. */ filterItems( - items: readonly Item[], + items: readonly ItemType[], extra: { inputValue: string | null; itemToString: NonNullable< - UseMultipleSelectionProps['itemToString'] + UseMultipleSelectionProps['itemToString'] >; } - ): Item[]; + ): ItemType[]; /** * Specify whether the title text should be hidden or not @@ -144,7 +143,7 @@ export interface FilterableMultiSelectProps * Allow users to pass in arbitrary items from their collection that are * pre-selected */ - initialSelectedItems?: Item[]; + initialSelectedItems?: ItemType[]; /** * Is the current selection invalid? @@ -160,7 +159,7 @@ export interface FilterableMultiSelectProps * Function to render items as custom components instead of strings. * Defaults to null and is overridden by a getter */ - itemToElement?: FunctionComponent; + itemToElement?: FunctionComponent; /** * Helper function passed to downshift that allows the library to render @@ -169,13 +168,13 @@ export interface FilterableMultiSelectProps * By default, it extracts the `label` field from a given item * to serve as the item label in the list. */ - itemToString?(item: Item | null): string; + itemToString?(item: ItemType | null): string; /** * We try to stay as generic as possible here to allow individuals to pass * in a collection of whatever kind of data structure they prefer */ - items: Item[]; + items: ItemType[]; /** * @deprecated `true` to use the light version. @@ -193,13 +192,13 @@ export interface FilterableMultiSelectProps * `onChange` is a utility for this controlled component to communicate to a * consuming component what kind of internal state changes are occurring. */ - onChange?(changes: { selectedItems: Item[] }): void; + onChange?(changes: { selectedItems: ItemType[] }): void; /** * A utility for this controlled component * to communicate to the currently typed input. */ - onInputValueChange?: UseComboboxProps['onInputValueChange']; + onInputValueChange?: UseComboboxProps['onInputValueChange']; /** * `onMenuChange` is a utility for this controlled component to communicate to a @@ -229,7 +228,7 @@ export interface FilterableMultiSelectProps /** * For full control of the selected items */ - selectedItems?: Item[]; + selectedItems?: ItemType[]; /** * Specify the size of the ListBox. @@ -272,7 +271,7 @@ export interface FilterableMultiSelectProps } const FilterableMultiSelect = React.forwardRef(function FilterableMultiSelect< - Item extends ItemBase + ItemType >( { className: containerClassName, @@ -304,13 +303,13 @@ const FilterableMultiSelect = React.forwardRef(function FilterableMultiSelect< selectionFeedback = 'top-after-reopen', selectedItems: selected, size, - sortItems = defaultSortItems as FilterableMultiSelectProps['sortItems'], + sortItems = defaultSortItems as FilterableMultiSelectProps['sortItems'], translateWithId, useTitleInItem, warn, warnText, slug, - }: FilterableMultiSelectProps, + }: FilterableMultiSelectProps, ref: ForwardedRef ) { const { isFluid } = useContext(FormContext); @@ -318,7 +317,9 @@ const FilterableMultiSelect = React.forwardRef(function FilterableMultiSelect< const [isOpen, setIsOpen] = useState(!!open); const [prevOpen, setPrevOpen] = useState(!!open); const [inputValue, setInputValue] = useState(''); - const [topItems, setTopItems] = useState(initialSelectedItems ?? []); + const [topItems, setTopItems] = useState( + initialSelectedItems ?? [] + ); const [inputFocused, setInputFocused] = useState(false); const { @@ -342,7 +343,8 @@ const FilterableMultiSelect = React.forwardRef(function FilterableMultiSelect< setPrevOpen(open); } - const sortedItems = sortItems( + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const sortedItems = sortItems!( filterItems(items, { itemToString, inputValue }), { selectedItems: { @@ -425,7 +427,7 @@ const FilterableMultiSelect = React.forwardRef(function FilterableMultiSelect< getItemProps, openMenu, isOpen: isMenuOpen, - } = useCombobox({ + } = useCombobox({ isOpen, items: sortedItems, itemToString, @@ -523,7 +525,7 @@ const FilterableMultiSelect = React.forwardRef(function FilterableMultiSelect< } } - const { getDropdownProps } = useMultipleSelection({ + const { getDropdownProps } = useMultipleSelection({ ...downshiftProps, activeIndex: highlightedIndex, initialSelectedItems, @@ -818,9 +820,7 @@ const FilterableMultiSelect = React.forwardRef(function FilterableMultiSelect< ); }) as { - ( - props: FilterableMultiSelectProps - ): ReactElement; + (props: FilterableMultiSelectProps): ReactElement; propTypes?: any; contextTypes?: any; defaultProps?: any; diff --git a/packages/react/src/components/MultiSelect/MultiSelect.tsx b/packages/react/src/components/MultiSelect/MultiSelect.tsx index c8d711cf0371..7ecb6abfabc8 100644 --- a/packages/react/src/components/MultiSelect/MultiSelect.tsx +++ b/packages/react/src/components/MultiSelect/MultiSelect.tsx @@ -28,7 +28,11 @@ import ListBox, { ListBoxType, PropTypes as ListBoxPropTypes, } from '../ListBox'; -import { sortingPropTypes } from './MultiSelectPropTypes'; +import { + MultiSelectSortingProps, + SortItemsOptions, + sortingPropTypes, +} from './MultiSelectPropTypes'; import { defaultSortItems, defaultCompareItems } from './tools/sorting'; import { useSelection } from '../../internal/Selection'; import setupGetInstanceId from '../../tools/setupGetInstanceId'; @@ -78,66 +82,10 @@ const defaultItemToString = (item?: ItemType): string => { return ''; }; -interface SharedOptions { - locale: string; -} - -interface DownshiftTypedProps { - itemToString?(item: ItemType): string; -} - -interface SortItemsOptions - extends SharedOptions, - DownshiftTypedProps { - compareItems( - item1: ItemType, - item2: ItemType, - options: SharedOptions - ): number; - selectedItems: ItemType[]; -} - interface selectedItemType { text: string; } -interface MultiSelectSortingProps { - /** - * Provide a compare function that is used to determine the ordering of - * options. See 'sortItems' for more control. - */ - compareItems?( - item1: ItemType, - item2: ItemType, - options: SharedOptions - ): number; - - /** - * Provide a method that sorts all options in the control. Overriding this - * prop means that you also have to handle the sort logic for selected versus - * un-selected items. If you just want to control ordering, consider the - * `compareItems` prop instead. - * - * The return value should be a number whose sign indicates the relative order - * of the two elements: negative if a is less than b, positive if a is greater - * than b, and zero if they are equal. - * - * sortItems : - * (items: Array, { - * selectedItems: Array, - * itemToString: Item => string, - * compareItems: (itemA: string, itemB: string, { - * locale: string - * }) => number, - * locale: string, - * }) => Array - */ - sortItems?( - items: ReadonlyArray, - options: SortItemsOptions - ): ItemType[]; -} - interface OnChangeData { selectedItems: ItemType[] | null; } diff --git a/packages/react/src/components/MultiSelect/MultiSelectPropTypes.ts b/packages/react/src/components/MultiSelect/MultiSelectPropTypes.ts index fbb593507a5c..b9e6298dc4cc 100644 --- a/packages/react/src/components/MultiSelect/MultiSelectPropTypes.ts +++ b/packages/react/src/components/MultiSelect/MultiSelectPropTypes.ts @@ -38,33 +38,48 @@ export const sortingPropTypes = { sortItems: PropTypes.func, }; -export interface ItemBase { - disabled?: boolean; +interface DownshiftTypedProps { + itemToString?(item: ItemType): string; } -export interface SortingPropTypes { + +interface SharedOptions { + locale: string; +} + +export interface SortItemsOptions + extends SharedOptions, + DownshiftTypedProps { + compareItems( + item1: ItemType, + item2: ItemType, + options: SharedOptions + ): number; + selectedItems: ItemType[]; +} + +export interface MultiSelectSortingProps { /** - * Provide a compare function that is used - * to determine the ordering of options. + * Provide a compare function that is used to determine the ordering of + * options. See 'sortItems' for more control. */ - compareItems(itemA: string, itemB: string, ctx: { locale: string }): number; + compareItems?( + item1: ItemType, + item2: ItemType, + options: SharedOptions + ): number; /** * Provide a method that sorts all options in the control. Overriding this * prop means that you also have to handle the sort logic for selected versus * un-selected items. If you just want to control ordering, consider the * `compareItems` prop instead. + * + * The return value should be a number whose sign indicates the relative order + * of the two elements: negative if a is less than b, positive if a is greater + * than b, and zero if they are equal. */ - sortItems( - items: Item[], - state: { - selectedItems: Item[]; - itemToString(item: Item): string; - compareItems( - itemA: string, - itemB: string, - ctx: { locale: string } - ): number; - locale: string; - } - ): Item[]; + sortItems?( + items: ReadonlyArray, + options: SortItemsOptions + ): ItemType[]; }