It was considered as a bad practice to include array indexes in list elements keys even though it was made this way in the documentation. We removed them and also decided to drop the use of options value in the keys too to the profit of optionToValue which can never be undefined or null. This changes caused test crashing due to the fact that it made the useSelect onStateChange trigger a onBlur event that was causing the first option of the list to be selected automatically, which was a really weird behavior. Before it was not happening because newSelectedItem was not defined, using the new keys made it defined, we don't 100% understand why yet.
100 lines
3.3 KiB
TypeScript
100 lines
3.3 KiB
TypeScript
import React from "react";
|
|
import { useMultipleSelection, useSelect } from "downshift";
|
|
import {
|
|
getMultiOptionsFilter,
|
|
SelectMultiAux,
|
|
SubProps,
|
|
} from ":/components/Forms/Select/multi-common";
|
|
import { optionToString } from ":/components/Forms/Select/mono-common";
|
|
|
|
export const SelectMultiSimple = (props: SubProps) => {
|
|
const options = React.useMemo(
|
|
() => props.options.filter(getMultiOptionsFilter(props.selectedItems, "")),
|
|
[props.selectedItems],
|
|
);
|
|
|
|
const useMultipleSelectionReturn = useMultipleSelection({
|
|
selectedItems: props.selectedItems,
|
|
onStateChange({ selectedItems: newSelectedItems, type }) {
|
|
switch (type) {
|
|
case useMultipleSelection.stateChangeTypes.SelectedItemKeyDownBackspace:
|
|
case useMultipleSelection.stateChangeTypes.SelectedItemKeyDownDelete:
|
|
case useMultipleSelection.stateChangeTypes.DropdownKeyDownBackspace:
|
|
case useMultipleSelection.stateChangeTypes.FunctionRemoveSelectedItem:
|
|
props.onSelectedItemsChange(newSelectedItems ?? []);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
},
|
|
});
|
|
|
|
const downshiftReturn = useSelect({
|
|
items: options,
|
|
itemToString: optionToString,
|
|
defaultHighlightedIndex: 0, // after selection, highlight the first item.
|
|
stateReducer: (state, actionAndChanges) => {
|
|
const { changes, type } = actionAndChanges;
|
|
switch (type) {
|
|
case useSelect.stateChangeTypes.ToggleButtonKeyDownEnter:
|
|
case useSelect.stateChangeTypes.ToggleButtonKeyDownSpaceButton:
|
|
case useSelect.stateChangeTypes.ItemClick:
|
|
return {
|
|
...changes,
|
|
isOpen: true, // keep the menu open after selection.
|
|
highlightedIndex: 0, // with the first option highlighted.
|
|
};
|
|
}
|
|
return changes;
|
|
},
|
|
onStateChange: ({ type, selectedItem: newSelectedItem }) => {
|
|
switch (type) {
|
|
case useSelect.stateChangeTypes.ToggleButtonKeyDownEnter:
|
|
case useSelect.stateChangeTypes.ToggleButtonKeyDownSpaceButton:
|
|
case useSelect.stateChangeTypes.ItemClick:
|
|
if (newSelectedItem) {
|
|
props.onSelectedItemsChange([
|
|
...props.selectedItems,
|
|
newSelectedItem,
|
|
]);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
},
|
|
isItemDisabled: (item) => !!item.disabled,
|
|
});
|
|
|
|
return (
|
|
<SelectMultiAux
|
|
{...props}
|
|
options={options}
|
|
labelAsPlaceholder={props.selectedItems.length === 0}
|
|
selectedItems={props.selectedItems}
|
|
downshiftReturn={{
|
|
...downshiftReturn,
|
|
wrapperProps: {
|
|
onClick: () => {
|
|
if (!props.disabled) {
|
|
downshiftReturn.toggleMenu();
|
|
}
|
|
},
|
|
},
|
|
toggleButtonProps: downshiftReturn.getToggleButtonProps({
|
|
...useMultipleSelectionReturn.getDropdownProps({
|
|
preventKeyAction: downshiftReturn.isOpen,
|
|
}),
|
|
disabled: props.disabled,
|
|
onClick: (e: React.MouseEvent): void => {
|
|
// As the wrapper also has an onClick handler, we need to stop the event propagation here on it will toggle
|
|
// twice the menu opening which will ... do nothing :).
|
|
e.stopPropagation();
|
|
},
|
|
}),
|
|
}}
|
|
useMultipleSelectionReturn={useMultipleSelectionReturn}
|
|
/>
|
|
);
|
|
};
|