From 24fa39f5124c9fc0b01590ad3f1e7960c54e5f35 Mon Sep 17 00:00:00 2001 From: Barsnes Date: Mon, 8 Apr 2024 09:41:39 +0200 Subject: [PATCH 01/47] fix(Combobox): Re-renders --- .../form/Combobox/Combobox.stories.tsx | 30 +++++++++++++++++++ .../components/form/Combobox/useCombobox.tsx | 4 +++ 2 files changed, 34 insertions(+) diff --git a/packages/react/src/components/form/Combobox/Combobox.stories.tsx b/packages/react/src/components/form/Combobox/Combobox.stories.tsx index 410ab2aaa6..33f34d9646 100644 --- a/packages/react/src/components/form/Combobox/Combobox.stories.tsx +++ b/packages/react/src/components/form/Combobox/Combobox.stories.tsx @@ -597,3 +597,33 @@ CustomNewValue.args = { size: 'medium', label: 'Hvor går reisen?', }; + +const items = Array.from({ length: 1000 }, (_, index) => ({ + name: `Option ${index}`, + value: `option-${index}`, +})); + +export const ThousandsOfOptions: StoryFn = (args) => { + const [value, setValue] = React.useState([]); + + return ( + { + setValue(value); + }} + virtual={true} + > + Fant ingen treff + {items.map((item, index) => ( + + {item.name} + + ))} + + ); +}; diff --git a/packages/react/src/components/form/Combobox/useCombobox.tsx b/packages/react/src/components/form/Combobox/useCombobox.tsx index 1787e9492d..01bbbec35e 100644 --- a/packages/react/src/components/form/Combobox/useCombobox.tsx +++ b/packages/react/src/components/form/Combobox/useCombobox.tsx @@ -50,6 +50,7 @@ export default function useCombobox({ initialValue, }: UseComboboxProps) { const options = useMemo(() => { + console.log('useMemo options ran'); const allOptions: Option[] = []; Children.forEach(children, (child) => { if (isComboboxOption(child)) { @@ -95,6 +96,7 @@ export default function useCombobox({ JSON.stringify(selectedOptions), ); const optionsChildren = useMemo(() => { + console.log('useMemo optionsChildren ran'); const valuesArray = Array.from(options); const children_ = Children.toArray(children).filter((child) => isComboboxOption(child), @@ -122,6 +124,7 @@ export default function useCombobox({ }, [options, children, multiple, inputValue, selectedOptions, filter]); const customIds = useMemo(() => { + console.log('useMemo customIds ran'); // find all custom components with `interactive=true` and generate random values for them const children_ = Children.toArray(children).filter((child) => { return isInteractiveComboboxCustom(child); @@ -147,6 +150,7 @@ export default function useCombobox({ }, [customIds, optionsChildren]); const restChildren = useMemo(() => { + console.log('useMemo restChildren ran'); return Children.toArray(children).filter((child) => { return !isComboboxOption(child); }); From 1f2a6b4305f6cdcb84c3f8f270c09b2935880050 Mon Sep 17 00:00:00 2001 From: Barsnes Date: Mon, 8 Apr 2024 11:32:30 +0200 Subject: [PATCH 02/47] some more optimizations --- .../form/Combobox/Combobox.stories.tsx | 3 +- .../components/form/Combobox/useCombobox.tsx | 50 +++++++++++++------ 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/packages/react/src/components/form/Combobox/Combobox.stories.tsx b/packages/react/src/components/form/Combobox/Combobox.stories.tsx index 33f34d9646..a6aa86ccfd 100644 --- a/packages/react/src/components/form/Combobox/Combobox.stories.tsx +++ b/packages/react/src/components/form/Combobox/Combobox.stories.tsx @@ -598,7 +598,7 @@ CustomNewValue.args = { label: 'Hvor går reisen?', }; -const items = Array.from({ length: 1000 }, (_, index) => ({ +const items = Array.from({ length: 5000 }, (_, index) => ({ name: `Option ${index}`, value: `option-${index}`, })); @@ -613,7 +613,6 @@ export const ThousandsOfOptions: StoryFn = (args) => { onValueChange={(value) => { setValue(value); }} - virtual={true} > Fant ingen treff {items.map((item, index) => ( diff --git a/packages/react/src/components/form/Combobox/useCombobox.tsx b/packages/react/src/components/form/Combobox/useCombobox.tsx index 01bbbec35e..5771c25fcc 100644 --- a/packages/react/src/components/form/Combobox/useCombobox.tsx +++ b/packages/react/src/components/form/Combobox/useCombobox.tsx @@ -95,8 +95,26 @@ export default function useCombobox({ const [prevSelectedHash, setPrevSelectedHash] = useState( JSON.stringify(selectedOptions), ); - const optionsChildren = useMemo(() => { - console.log('useMemo optionsChildren ran'); + + const selectedOptionsLookup = useMemo(() => { + const lookup: { + [key: string]: boolean; + } = {}; + selectedOptions.forEach((option) => { + lookup[option.value] = true; + }); + return lookup; + }, [selectedOptions]); + + const { optionsChildren, customIds } = useMemo(() => { + console.log('useMemo optionsChildren and customIds ran', { + options, + multiple, + inputValue, + selectedOptionsLookup, + }); + let optionsChildren; + const valuesArray = Array.from(options); const children_ = Children.toArray(children).filter((child) => isComboboxOption(child), @@ -104,40 +122,42 @@ export default function useCombobox({ const activeValue = valuesArray.find((item) => item.label === inputValue); - if (activeValue && !multiple) return children_; - if (inputValue === '' && !multiple) return children_; + if (activeValue && !multiple) { + optionsChildren = children_; + } + if (inputValue === '' && !multiple) { + optionsChildren = children_; + } - return children_.filter((child) => { + optionsChildren = children_.filter((child) => { const { value } = child.props; const option = valuesArray.find((item) => item.value === value); if (!option) return false; - const isSelected = selectedOptions.some( - (selectedOption) => selectedOption.value === value, - ); + const isSelected = selectedOptionsLookup[value]; // show what we search for, and all selected options return filter(inputValue, { ...option }) || isSelected; }); - }, [options, children, multiple, inputValue, selectedOptions, filter]); - - const customIds = useMemo(() => { - console.log('useMemo customIds ran'); // find all custom components with `interactive=true` and generate random values for them - const children_ = Children.toArray(children).filter((child) => { + const customChildren = children_.filter((child) => { return isInteractiveComboboxCustom(child); }) as ReactElement[]; // return all ids - return children_.map((child) => { + const customIds = customChildren.map((child) => { if (!child.props.id) throw new Error('If ComboboxCustom is interactive, it must have an id'); return child.props.id; }); - }, [children]); + + return { optionsChildren, customIds }; + + // ignore filter function in deps array, it causes a lot of re-renders + }, [options, multiple, inputValue, selectedOptionsLookup, children]); const optionValues = useMemo(() => { // create an index map of values from optionsChildren From 76a741cd8ea9edd840945e7a619e4794cd0c7d18 Mon Sep 17 00:00:00 2001 From: Barsnes Date: Mon, 8 Apr 2024 11:46:21 +0200 Subject: [PATCH 03/47] options as object to lookup faster --- .../src/components/form/Combobox/Combobox.tsx | 22 +++++++++---------- .../form/Combobox/internal/ComboboxInput.tsx | 2 +- .../components/form/Combobox/useCombobox.tsx | 12 +++++----- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/packages/react/src/components/form/Combobox/Combobox.tsx b/packages/react/src/components/form/Combobox/Combobox.tsx index b64062ad6c..1ad566e90f 100644 --- a/packages/react/src/components/form/Combobox/Combobox.tsx +++ b/packages/react/src/components/form/Combobox/Combobox.tsx @@ -239,7 +239,7 @@ export const Combobox = forwardRef( // if value is set, set input value to the label of the value useEffect(() => { if (value && value.length > 0 && !multiple) { - const option = options.find((option) => option.value === value[0]); + const option = options[value[0]]; setInputValue(option?.label || ''); } }, [multiple, value, options]); @@ -313,10 +313,10 @@ export const Combobox = forwardRef( }, [onValueChange, selectedOptions, prevSelectedHash, setPrevSelectedHash]); useEffect(() => { - if (value && options.length > 0) { + if (value && Object.keys(options).length > 0) { const updatedSelectedOptions = value.map((option) => { - const value = options.find((value) => value.value === option); - return value as Option; + const value = options[option]; + return value; }); setSelectedOptions(updatedSelectedOptions); @@ -419,9 +419,7 @@ export const Combobox = forwardRef( const child = optionsChildren[valueIndex]; if (isComboboxOption(child)) { const props = child.props; - const option = options.find( - (option) => option.value === props.value, - ); + const option = options[props.value]; if (!multiple) { // check if option is already selected, if so, deselect it @@ -432,7 +430,7 @@ export const Combobox = forwardRef( } } - debouncedHandleSelectOption(option as Option); + debouncedHandleSelectOption(option); } } break; @@ -505,8 +503,8 @@ export const Combobox = forwardRef( onOptionClick: (value: string) => { if (readOnly) return; if (disabled) return; - const option = options.find((option) => option.value === value); - debouncedHandleSelectOption(option as Option); + const option = options[value]; + debouncedHandleSelectOption(option); }, handleSelectOption: debouncedHandleSelectOption, chipSrLabel, @@ -637,7 +635,9 @@ type ComboboxContextType = { hideChips: NonNullable; clearButtonLabel: NonNullable; hideClearButton: NonNullable; - options: Option[]; + options: { + [key: string]: Option; + }; selectedOptions: Option[]; size: NonNullable; formFieldProps: ReturnType; diff --git a/packages/react/src/components/form/Combobox/internal/ComboboxInput.tsx b/packages/react/src/components/form/Combobox/internal/ComboboxInput.tsx index 2fe10f2c77..142596f84c 100644 --- a/packages/react/src/components/form/Combobox/internal/ComboboxInput.tsx +++ b/packages/react/src/components/form/Combobox/internal/ComboboxInput.tsx @@ -84,7 +84,7 @@ export const ComboboxInput = ({ } // check if input value is the same as a label, if so, select it - const option = options.find((option) => option.label === value); + const option = options[value]; if (!option) return; if ( selectedOptions.find( diff --git a/packages/react/src/components/form/Combobox/useCombobox.tsx b/packages/react/src/components/form/Combobox/useCombobox.tsx index 5771c25fcc..531cbd2062 100644 --- a/packages/react/src/components/form/Combobox/useCombobox.tsx +++ b/packages/react/src/components/form/Combobox/useCombobox.tsx @@ -51,7 +51,9 @@ export default function useCombobox({ }: UseComboboxProps) { const options = useMemo(() => { console.log('useMemo options ran'); - const allOptions: Option[] = []; + const allOptions: { + [key: string]: Option; + } = {}; Children.forEach(children, (child) => { if (isComboboxOption(child)) { const props = child.props; @@ -74,19 +76,19 @@ export default function useCombobox({ label = childrenLabel; } - allOptions.push({ + allOptions[props.value] = { value: props.value, label, displayValue: props.displayValue, description: props.description, - }); + }; } }); return allOptions; }, [children]); const preSelectedOptions = (initialValue || []) - .map((value) => options.find((option) => option.value === value)) + .map((value) => options[value]) .filter(isOption); const [selectedOptions, setSelectedOptions] = @@ -115,7 +117,7 @@ export default function useCombobox({ }); let optionsChildren; - const valuesArray = Array.from(options); + const valuesArray = Object.values(options); const children_ = Children.toArray(children).filter((child) => isComboboxOption(child), ) as ReactElement[]; From 2c9be2aa3a96ae2b665ac43581c876990bc06f67 Mon Sep 17 00:00:00 2001 From: Barsnes Date: Mon, 8 Apr 2024 12:03:50 +0200 Subject: [PATCH 04/47] update tests, some misc --- .../components/form/Combobox/Combobox.stories.tsx | 2 +- .../react/src/components/form/Combobox/Combobox.tsx | 4 ++-- .../components/form/Combobox/useCombobox.test.tsx | 12 ++++++------ .../src/components/form/Combobox/useCombobox.tsx | 9 +-------- 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/packages/react/src/components/form/Combobox/Combobox.stories.tsx b/packages/react/src/components/form/Combobox/Combobox.stories.tsx index a6aa86ccfd..90eb6b4bd2 100644 --- a/packages/react/src/components/form/Combobox/Combobox.stories.tsx +++ b/packages/react/src/components/form/Combobox/Combobox.stories.tsx @@ -598,7 +598,7 @@ CustomNewValue.args = { label: 'Hvor går reisen?', }; -const items = Array.from({ length: 5000 }, (_, index) => ({ +const items = Array.from({ length: 1500 }, (_, index) => ({ name: `Option ${index}`, value: `option-${index}`, })); diff --git a/packages/react/src/components/form/Combobox/Combobox.tsx b/packages/react/src/components/form/Combobox/Combobox.tsx index 1ad566e90f..564b951e94 100644 --- a/packages/react/src/components/form/Combobox/Combobox.tsx +++ b/packages/react/src/components/form/Combobox/Combobox.tsx @@ -357,7 +357,7 @@ export const Combobox = forwardRef( // handle keyboard navigation in the list const handleKeyDownFunc = (event: React.KeyboardEvent) => { - const navigateable = customIds.length + optionsChildren.length; + const navigateable = customIds.length + Object.keys(options).length; if (formFieldProps.readOnly || disabled) return; if (!event) return; @@ -453,7 +453,7 @@ export const Combobox = forwardRef( const handleKeyDown = useDebounce(handleKeyDownFunc, 20); const rowVirtualizer = useVirtualizer({ - count: optionsChildren.length, + count: Object.keys(options).length, getScrollElement: () => refs.floating.current, estimateSize: () => 70, measureElement: (elem) => { diff --git a/packages/react/src/components/form/Combobox/useCombobox.test.tsx b/packages/react/src/components/form/Combobox/useCombobox.test.tsx index 3fe29dc161..225855a8e4 100644 --- a/packages/react/src/components/form/Combobox/useCombobox.test.tsx +++ b/packages/react/src/components/form/Combobox/useCombobox.test.tsx @@ -58,7 +58,7 @@ describe('useCombobox', () => { multiple: false, }); - expect(result.current.options.length).toBe(3); + expect(Object.keys(result.current.options).length).toBe(3); expect(result.current.optionsChildren.length).toBe(3); expect(result.current.restChildren.length).toBe(1); }); @@ -69,7 +69,7 @@ describe('useCombobox', () => { multiple: false, }); - expect(result.current.options.length).toBe(3); + expect(Object.keys(result.current.options).length).toBe(3); expect(result.current.optionsChildren.length).toBe(0); expect(result.current.restChildren.length).toBe(1); }); @@ -81,7 +81,7 @@ describe('useCombobox', () => { initialValue: ['oslo'], }); - expect(result.current.options.length).toBe(3); + expect(Object.keys(result.current.options).length).toBe(3); expect(result.current.optionsChildren.length).toBe(1); expect(result.current.restChildren.length).toBe(1); }); @@ -93,7 +93,7 @@ describe('useCombobox', () => { initialValue: ['oslo'], }); - expect(result.current.options.length).toBe(3); + expect(Object.keys(result.current.options).length).toBe(3); expect(result.current.optionsChildren.length).toBe(1); expect(result.current.restChildren.length).toBe(1); }); @@ -104,7 +104,7 @@ describe('useCombobox', () => { multiple: false, }); - expect(result.current.options.length).toBe(3); + expect(Object.keys(result.current.options).length).toBe(3); expect(result.current.optionsChildren.length).toBe(1); expect(result.current.restChildren.length).toBe(1); }); @@ -116,7 +116,7 @@ describe('useCombobox', () => { initialValue: ['oslo'], }); - expect(result.current.options.length).toBe(3); + expect(Object.keys(result.current.options).length).toBe(3); expect(result.current.optionsChildren.length).toBe(2); expect(result.current.restChildren.length).toBe(1); }); diff --git a/packages/react/src/components/form/Combobox/useCombobox.tsx b/packages/react/src/components/form/Combobox/useCombobox.tsx index 531cbd2062..2871c801cc 100644 --- a/packages/react/src/components/form/Combobox/useCombobox.tsx +++ b/packages/react/src/components/form/Combobox/useCombobox.tsx @@ -50,7 +50,6 @@ export default function useCombobox({ initialValue, }: UseComboboxProps) { const options = useMemo(() => { - console.log('useMemo options ran'); const allOptions: { [key: string]: Option; } = {}; @@ -109,12 +108,6 @@ export default function useCombobox({ }, [selectedOptions]); const { optionsChildren, customIds } = useMemo(() => { - console.log('useMemo optionsChildren and customIds ran', { - options, - multiple, - inputValue, - selectedOptionsLookup, - }); let optionsChildren; const valuesArray = Object.values(options); @@ -159,6 +152,7 @@ export default function useCombobox({ return { optionsChildren, customIds }; // ignore filter function in deps array, it causes a lot of re-renders + // eslint-disable-next-line react-hooks/exhaustive-deps }, [options, multiple, inputValue, selectedOptionsLookup, children]); const optionValues = useMemo(() => { @@ -172,7 +166,6 @@ export default function useCombobox({ }, [customIds, optionsChildren]); const restChildren = useMemo(() => { - console.log('useMemo restChildren ran'); return Children.toArray(children).filter((child) => { return !isComboboxOption(child); }); From b5fdded71c823d69b543d3945b89d86e50b42036 Mon Sep 17 00:00:00 2001 From: Barsnes Date: Mon, 8 Apr 2024 12:31:11 +0200 Subject: [PATCH 05/47] `selectedOptions` is an array --- .../src/components/form/Combobox/Combobox.tsx | 59 ++++++++++++++----- .../form/Combobox/Option/Option.tsx | 2 +- .../form/Combobox/internal/ComboboxChips.tsx | 22 +++---- .../Combobox/internal/ComboboxClearButton.tsx | 4 +- .../form/Combobox/internal/ComboboxInput.tsx | 9 +-- .../form/Combobox/internal/ComboboxNative.tsx | 14 +++-- .../components/form/Combobox/useCombobox.tsx | 31 +++++----- 7 files changed, 84 insertions(+), 57 deletions(-) diff --git a/packages/react/src/components/form/Combobox/Combobox.tsx b/packages/react/src/components/form/Combobox/Combobox.tsx index 564b951e94..769edba975 100644 --- a/packages/react/src/components/form/Combobox/Combobox.tsx +++ b/packages/react/src/components/form/Combobox/Combobox.tsx @@ -307,7 +307,7 @@ export const Combobox = forwardRef( const selectedHash = JSON.stringify(selectedOptions); if (prevSelectedHash === selectedHash) return; - const values = selectedOptions.map((option) => option.value); + const values = Object.keys(selectedOptions); onValueChange?.(values); setPrevSelectedHash(selectedHash); }, [onValueChange, selectedOptions, prevSelectedHash, setPrevSelectedHash]); @@ -319,7 +319,14 @@ export const Combobox = forwardRef( return value; }); - setSelectedOptions(updatedSelectedOptions); + setSelectedOptions( + updatedSelectedOptions.reduce<{ + [key: string]: Option; + }>((acc, value) => { + acc[value.value] = value; + return acc; + }, {}), + ); } }, [multiple, prevSelectedHash, value, options, setSelectedOptions]); @@ -327,18 +334,27 @@ export const Combobox = forwardRef( const handleSelectOption = (option: Option) => { // if option is already selected, remove it if (value && value.includes(option.value)) { - setSelectedOptions((prev) => - prev.filter((i) => i.value !== option.value), - ); + setSelectedOptions((prev) => { + const updated = { ...prev }; + delete updated[option.value]; + return updated; + }); return; } if (multiple) { - setSelectedOptions([...selectedOptions, option]); + /* setSelectedOptions([...selectedOptions, option]); */ + setSelectedOptions((prev) => { + const updated = { ...prev }; + updated[option.value] = option; + return updated; + }); setInputValue(''); inputRef.current?.focus(); } else { - setSelectedOptions([option]); + setSelectedOptions({ + [option.value]: option, + }); setInputValue(option?.label || ''); // move cursor to the end of the input setTimeout(() => { @@ -423,8 +439,8 @@ export const Combobox = forwardRef( if (!multiple) { // check if option is already selected, if so, deselect it - if (selectedOptions.find((i) => i.value === option?.value)) { - setSelectedOptions([]); + if (selectedOptions[option?.value]) { + setSelectedOptions({}); setInputValue(''); return; } @@ -436,12 +452,21 @@ export const Combobox = forwardRef( break; case 'Backspace': - if (inputValue === '' && multiple && selectedOptions.length > 0) { - setSelectedOptions((prev) => prev.slice(0, prev.length - 1)); + if ( + inputValue === '' && + multiple && + Object.keys(selectedOptions).length > 0 + ) { + setSelectedOptions((prev) => { + const updated = { ...prev }; + const keys = Object.keys(updated); + delete updated[keys[keys.length - 1]]; + return updated; + }); } // if we are in single mode, we need to set activeValue to null if (!multiple) { - setSelectedOptions([]); + setSelectedOptions({}); } break; @@ -638,7 +663,9 @@ type ComboboxContextType = { options: { [key: string]: Option; }; - selectedOptions: Option[]; + selectedOptions: { + [key: string]: Option; + }; size: NonNullable; formFieldProps: ReturnType; refs: UseFloatingReturn['refs']; @@ -658,7 +685,11 @@ type ComboboxContextType = { props?: Record, ) => Record; onOptionClick: (value: string) => void; - setSelectedOptions: React.Dispatch>; + setSelectedOptions: React.Dispatch< + React.SetStateAction<{ + [key: string]: Option; + }> + >; chipSrLabel: NonNullable; handleSelectOption: (option: Option) => void; listRef: UseListNavigationProps['listRef']; diff --git a/packages/react/src/components/form/Combobox/Option/Option.tsx b/packages/react/src/components/form/Combobox/Option/Option.tsx index 4eb4f2306d..2df2e0d685 100644 --- a/packages/react/src/components/form/Combobox/Option/Option.tsx +++ b/packages/react/src/components/form/Combobox/Option/Option.tsx @@ -67,7 +67,7 @@ export const ComboboxOption = forwardRef< throw new Error('Internal error: ComboboxOption did not find index'); } - const selected = selectedOptions.find((option) => option.value === value); + const selected = selectedOptions[value]; useEffect(() => { if (activeIndex === index) setActiveOption(index, rest.id || generatedId); diff --git a/packages/react/src/components/form/Combobox/internal/ComboboxChips.tsx b/packages/react/src/components/form/Combobox/internal/ComboboxChips.tsx index 8d114a6505..5764a8a131 100644 --- a/packages/react/src/components/form/Combobox/internal/ComboboxChips.tsx +++ b/packages/react/src/components/form/Combobox/internal/ComboboxChips.tsx @@ -22,10 +22,10 @@ export const ComboboxChips = () => { return ( <> - {selectedOptions.map((option) => { + {Object.keys(selectedOptions).map((value) => { return ( { @@ -33,9 +33,10 @@ export const ComboboxChips = () => { if (disabled) return; if (e.key === 'Enter') { e.stopPropagation(); - setSelectedOptions( - selectedOptions.filter((i) => i.value !== option.value), - ); + setSelectedOptions((prev) => { + const { [value]: _, ...rest } = prev; + return rest; + }); inputRef.current?.focus(); } }} @@ -43,17 +44,18 @@ export const ComboboxChips = () => { if (readOnly) return; if (disabled) return; /* If we click a chip, filter the active values and remove the one we clicked */ - setSelectedOptions( - selectedOptions.filter((i) => i.value !== option.value), - ); + setSelectedOptions((prev) => { + const { [value]: _, ...rest } = prev; + return rest; + }); }} style={{ /* We already set the opacity on Combobox */ opacity: 1, }} - aria-label={chipSrLabel(option)} + aria-label={chipSrLabel(selectedOptions[value])} > - {option.label} + {selectedOptions[value].label} ); })} diff --git a/packages/react/src/components/form/Combobox/internal/ComboboxClearButton.tsx b/packages/react/src/components/form/Combobox/internal/ComboboxClearButton.tsx index 8ef749ad79..c957f8fa00 100644 --- a/packages/react/src/components/form/Combobox/internal/ComboboxClearButton.tsx +++ b/packages/react/src/components/form/Combobox/internal/ComboboxClearButton.tsx @@ -29,7 +29,7 @@ export const ComboboxClearButton = () => { onClick={() => { if (readOnly) return; if (disabled) return; - setSelectedOptions([]); + setSelectedOptions({}); setInputValue(''); }} onKeyDown={(e) => { @@ -37,7 +37,7 @@ export const ComboboxClearButton = () => { if (disabled) return; if (e.key === 'Enter') { e.stopPropagation(); - setSelectedOptions([]); + setSelectedOptions({}); setInputValue(''); inputRef.current?.focus(); } diff --git a/packages/react/src/components/form/Combobox/internal/ComboboxInput.tsx b/packages/react/src/components/form/Combobox/internal/ComboboxInput.tsx index 142596f84c..f1c4e5028f 100644 --- a/packages/react/src/components/form/Combobox/internal/ComboboxInput.tsx +++ b/packages/react/src/components/form/Combobox/internal/ComboboxInput.tsx @@ -86,12 +86,7 @@ export const ComboboxInput = ({ // check if input value is the same as a label, if so, select it const option = options[value]; if (!option) return; - if ( - selectedOptions.find( - (selectedOption) => selectedOption.value === option.value, - ) - ) - return; + if (selectedOptions[option.value]) return; handleSelectOption(option); @@ -109,7 +104,7 @@ export const ComboboxInput = ({ }; const showClearButton = - multiple && !hideClearButton && selectedOptions.length > 0; + multiple && !hideClearButton && Object.keys(selectedOptions).length > 0; return ( ; name: ComboboxProps['name']; }; @@ -19,15 +21,15 @@ export const ComboboxNative = ({ style={{ display: 'none' }} value={ multiple - ? selectedOptions.map((option) => option.value) - : selectedOptions[0]?.value + ? Object.keys(selectedOptions) + : Object.keys(selectedOptions)[0] } onChange={() => {}} > - {selectedOptions.map((option) => ( + {Object.keys(selectedOptions).map((value) => (