From e8c79fc16c38e8df0d546168bcaf3cdf3b241923 Mon Sep 17 00:00:00 2001 From: Ronnie Laugen Date: Wed, 22 May 2024 14:15:10 +0200 Subject: [PATCH] feat(autocomplete): Possible solution for object-checking References issue #3259 --- .../Autocomplete/Autocomplete.stories.tsx | 14 ++++++- .../components/Autocomplete/Autocomplete.tsx | 41 ++++++++++++++++--- 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/packages/eds-core-react/src/components/Autocomplete/Autocomplete.stories.tsx b/packages/eds-core-react/src/components/Autocomplete/Autocomplete.stories.tsx index 7fbffb6f9a..f6f9cf5a12 100644 --- a/packages/eds-core-react/src/components/Autocomplete/Autocomplete.stories.tsx +++ b/packages/eds-core-react/src/components/Autocomplete/Autocomplete.stories.tsx @@ -243,7 +243,12 @@ export const OptionComponent: StoryFn> = ( options={options} optionLabel={(opt) => `${opt.trend} ${opt.label} (${opt.symbol})`} optionComponent={CustomItem} - initialSelectedOptions={[options[1]]} + initialSelectedOptions={ + [JSON.parse(JSON.stringify(options[1]))] as MyOptionType[] + } + itemCompare={(item, compare) => { + return item.label === compare.label + }} multiline /> > = ( options={options} optionLabel={(opt) => `${opt.trend} ${opt.label} (${opt.symbol})`} optionComponent={CustomItem} - initialSelectedOptions={[options[1]]} + initialSelectedOptions={ + JSON.parse(JSON.stringify([options[1], options[2]])) as MyOptionType[] + } + itemCompare={(item, compare) => { + return item.label === compare.label + }} multiline multiple /> diff --git a/packages/eds-core-react/src/components/Autocomplete/Autocomplete.tsx b/packages/eds-core-react/src/components/Autocomplete/Autocomplete.tsx index 65a50de433..d75aa32d46 100644 --- a/packages/eds-core-react/src/components/Autocomplete/Autocomplete.tsx +++ b/packages/eds-core-react/src/components/Autocomplete/Autocomplete.tsx @@ -223,7 +223,8 @@ const handleListFocus = (e: FocusEvent) => { const defaultOptionDisabled = () => false -type OptionLabelProps = T extends string | number +// prettier-ignore +type OptionLabelProps = T extends string | number ? { /** Custom option label */ optionLabel?: (option: T) => string @@ -325,6 +326,10 @@ export type AutocompleteProps = { * @default 300 */ dropdownHeight?: number + /** + * Method that is used to compare objects by value. If omitted, objects are matched by reference. + */ + itemCompare?: (value: T, compare: T) => boolean } & HTMLAttributes & OptionLabelProps @@ -344,10 +349,11 @@ function AutocompleteInner( hideClearButton = false, onOptionsChange, onInputChange, - selectedOptions, + selectedOptions: _selectedOptions, multiple, + itemCompare, allowSelectAll, - initialSelectedOptions = [], + initialSelectedOptions: _initialSelectedOptions = [], disablePortal, optionDisabled = defaultOptionDisabled, optionsFilter, @@ -365,6 +371,21 @@ function AutocompleteInner( ...other } = props + const selectedOptions = _selectedOptions + ? itemCompare + ? options.filter((item) => + _selectedOptions.some((compare) => itemCompare(item, compare)), + ) + : _selectedOptions + : undefined + const initialSelectedOptions = _initialSelectedOptions + ? itemCompare + ? options.filter((item) => + _initialSelectedOptions.some((compare) => itemCompare(item, compare)), + ) + : _initialSelectedOptions + : undefined + if (disablePortal) { console.warn( 'Autocomplete "disablePortal" prop has been deprecated. Autocomplete now uses the native popover api', @@ -423,9 +444,14 @@ function AutocompleteInner( ...multipleSelectionProps, onSelectedItemsChange: (changes) => { if (onOptionsChange) { - const selectedItems = changes.selectedItems.filter( + let selectedItems = changes.selectedItems.filter( (item) => item !== AllSymbol, ) + if (itemCompare) { + selectedItems = inputOptions.filter((item) => + selectedItems.some((compare) => itemCompare(item, compare)), + ) + } onOptionsChange({ selectedItems }) } }, @@ -607,7 +633,12 @@ function AutocompleteInner( ...comboBoxProps, onSelectedItemChange: (changes) => { if (onOptionsChange) { - const { selectedItem } = changes + let { selectedItem } = changes + if (itemCompare) { + selectedItem = inputOptions.find((item) => + itemCompare(item, selectedItem), + ) + } onOptionsChange({ selectedItems: selectedItem ? [selectedItem] : [], })