Skip to content

Commit

Permalink
fix: fixed types to match MultiSelect (#16702)
Browse files Browse the repository at this point in the history
Co-authored-by: Nikhil Tomar <[email protected]>
  • Loading branch information
guidari and 2nikhiltom authored Jun 20, 2024
1 parent 47ef3e4 commit 5a2a702
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 101 deletions.
50 changes: 25 additions & 25 deletions packages/react/src/components/MultiSelect/FilterableMultiSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -74,8 +73,8 @@ const {
} =
useMultipleSelection.stateChangeTypes as UseMultipleSelectionInterface['stateChangeTypes'];

export interface FilterableMultiSelectProps<Item extends ItemBase>
extends SortingPropTypes<Item> {
export interface FilterableMultiSelectProps<ItemType>
extends MultiSelectSortingProps<ItemType> {
/**
* Specify a label to be read by screen readers on the container node
* @deprecated
Expand Down Expand Up @@ -109,20 +108,20 @@ export interface FilterableMultiSelectProps<Item extends ItemBase>
/**
* Additional props passed to Downshift
*/
downshiftProps?: UseMultipleSelectionProps<Item>;
downshiftProps?: UseMultipleSelectionProps<ItemType>;

/**
* Default sorter is assigned if not provided.
*/
filterItems(
items: readonly Item[],
items: readonly ItemType[],
extra: {
inputValue: string | null;
itemToString: NonNullable<
UseMultipleSelectionProps<Item>['itemToString']
UseMultipleSelectionProps<ItemType>['itemToString']
>;
}
): Item[];
): ItemType[];

/**
* Specify whether the title text should be hidden or not
Expand All @@ -144,7 +143,7 @@ export interface FilterableMultiSelectProps<Item extends ItemBase>
* Allow users to pass in arbitrary items from their collection that are
* pre-selected
*/
initialSelectedItems?: Item[];
initialSelectedItems?: ItemType[];

/**
* Is the current selection invalid?
Expand All @@ -160,7 +159,7 @@ export interface FilterableMultiSelectProps<Item extends ItemBase>
* Function to render items as custom components instead of strings.
* Defaults to null and is overridden by a getter
*/
itemToElement?: FunctionComponent<Item>;
itemToElement?: FunctionComponent<ItemType>;

/**
* Helper function passed to downshift that allows the library to render
Expand All @@ -169,13 +168,13 @@ export interface FilterableMultiSelectProps<Item extends ItemBase>
* 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.
Expand All @@ -193,13 +192,13 @@ export interface FilterableMultiSelectProps<Item extends ItemBase>
* `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<Item>['onInputValueChange'];
onInputValueChange?: UseComboboxProps<ItemType>['onInputValueChange'];

/**
* `onMenuChange` is a utility for this controlled component to communicate to a
Expand Down Expand Up @@ -229,7 +228,7 @@ export interface FilterableMultiSelectProps<Item extends ItemBase>
/**
* For full control of the selected items
*/
selectedItems?: Item[];
selectedItems?: ItemType[];

/**
* Specify the size of the ListBox.
Expand Down Expand Up @@ -272,7 +271,7 @@ export interface FilterableMultiSelectProps<Item extends ItemBase>
}

const FilterableMultiSelect = React.forwardRef(function FilterableMultiSelect<
Item extends ItemBase
ItemType
>(
{
className: containerClassName,
Expand Down Expand Up @@ -304,21 +303,23 @@ const FilterableMultiSelect = React.forwardRef(function FilterableMultiSelect<
selectionFeedback = 'top-after-reopen',
selectedItems: selected,
size,
sortItems = defaultSortItems as FilterableMultiSelectProps<Item>['sortItems'],
sortItems = defaultSortItems as FilterableMultiSelectProps<ItemType>['sortItems'],
translateWithId,
useTitleInItem,
warn,
warnText,
slug,
}: FilterableMultiSelectProps<Item>,
}: FilterableMultiSelectProps<ItemType>,
ref: ForwardedRef<HTMLDivElement>
) {
const { isFluid } = useContext(FormContext);
const [isFocused, setIsFocused] = useState<boolean>(false);
const [isOpen, setIsOpen] = useState<boolean>(!!open);
const [prevOpen, setPrevOpen] = useState<boolean>(!!open);
const [inputValue, setInputValue] = useState<string>('');
const [topItems, setTopItems] = useState<Item[]>(initialSelectedItems ?? []);
const [topItems, setTopItems] = useState<ItemType[]>(
initialSelectedItems ?? []
);
const [inputFocused, setInputFocused] = useState<boolean>(false);

const {
Expand All @@ -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: {
Expand Down Expand Up @@ -425,7 +427,7 @@ const FilterableMultiSelect = React.forwardRef(function FilterableMultiSelect<
getItemProps,
openMenu,
isOpen: isMenuOpen,
} = useCombobox<Item>({
} = useCombobox<ItemType>({
isOpen,
items: sortedItems,
itemToString,
Expand Down Expand Up @@ -523,7 +525,7 @@ const FilterableMultiSelect = React.forwardRef(function FilterableMultiSelect<
}
}

const { getDropdownProps } = useMultipleSelection<Item>({
const { getDropdownProps } = useMultipleSelection<ItemType>({
...downshiftProps,
activeIndex: highlightedIndex,
initialSelectedItems,
Expand Down Expand Up @@ -818,9 +820,7 @@ const FilterableMultiSelect = React.forwardRef(function FilterableMultiSelect<
</div>
);
}) as {
<Item extends ItemBase>(
props: FilterableMultiSelectProps<Item>
): ReactElement;
<ItemType>(props: FilterableMultiSelectProps<ItemType>): ReactElement;
propTypes?: any;
contextTypes?: any;
defaultProps?: any;
Expand Down
62 changes: 5 additions & 57 deletions packages/react/src/components/MultiSelect/MultiSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -78,66 +82,10 @@ const defaultItemToString = <ItemType,>(item?: ItemType): string => {
return '';
};

interface SharedOptions {
locale: string;
}

interface DownshiftTypedProps<ItemType> {
itemToString?(item: ItemType): string;
}

interface SortItemsOptions<ItemType>
extends SharedOptions,
DownshiftTypedProps<ItemType> {
compareItems(
item1: ItemType,
item2: ItemType,
options: SharedOptions
): number;
selectedItems: ItemType[];
}

interface selectedItemType {
text: string;
}

interface MultiSelectSortingProps<ItemType> {
/**
* 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<Item>, {
* selectedItems: Array<Item>,
* itemToString: Item => string,
* compareItems: (itemA: string, itemB: string, {
* locale: string
* }) => number,
* locale: string,
* }) => Array<Item>
*/
sortItems?(
items: ReadonlyArray<ItemType>,
options: SortItemsOptions<ItemType>
): ItemType[];
}

interface OnChangeData<ItemType> {
selectedItems: ItemType[] | null;
}
Expand Down
53 changes: 34 additions & 19 deletions packages/react/src/components/MultiSelect/MultiSelectPropTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,33 +38,48 @@ export const sortingPropTypes = {
sortItems: PropTypes.func,
};

export interface ItemBase {
disabled?: boolean;
interface DownshiftTypedProps<ItemType> {
itemToString?(item: ItemType): string;
}
export interface SortingPropTypes<Item extends ItemBase> {

interface SharedOptions {
locale: string;
}

export interface SortItemsOptions<ItemType>
extends SharedOptions,
DownshiftTypedProps<ItemType> {
compareItems(
item1: ItemType,
item2: ItemType,
options: SharedOptions
): number;
selectedItems: ItemType[];
}

export interface MultiSelectSortingProps<ItemType> {
/**
* 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<ItemType>,
options: SortItemsOptions<ItemType>
): ItemType[];
}

0 comments on commit 5a2a702

Please sign in to comment.