Skip to content

Commit 9980c23

Browse files
heloiseluiGururajj77tay1orjones
authored
fix(ComboBox): mark selected option after reopening with custom value (#20983)
* fix(ComboBox): mark selected option after reopening with custom value * Update packages/react/src/components/ComboBox/ComboBox.stories.js --------- Co-authored-by: Gururaj J <89023023+Gururajj77@users.noreply.github.com> Co-authored-by: Taylor Jones <tay1orjones@users.noreply.github.com>
1 parent 2b9c45c commit 9980c23

File tree

3 files changed

+46
-8
lines changed

3 files changed

+46
-8
lines changed

packages/react/src/components/ComboBox/ComboBox-test.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,28 @@ describe('ComboBox', () => {
377377
);
378378
});
379379

380+
it('should keep the selected item active after blur when allowCustomValue is set', async () => {
381+
const user = userEvent.setup();
382+
383+
render(
384+
<>
385+
<ComboBox {...mockProps} allowCustomValue />
386+
<button type="button">Move focus</button>
387+
</>
388+
);
389+
390+
await openMenu();
391+
await user.click(screen.getByRole('option', { name: 'Item 1' }));
392+
expect(mockProps.onChange).toHaveBeenCalledTimes(1);
393+
394+
await user.click(screen.getByRole('button', { name: 'Move focus' }));
395+
396+
await openMenu();
397+
const activeOption = screen.getByRole('option', { name: 'Item 1' });
398+
expect(activeOption).toHaveClass(`${prefix}--list-box__menu-item--active`);
399+
expect(mockProps.onChange).toHaveBeenCalledTimes(1);
400+
});
401+
380402
it('should yield highlighted item as `selectedItem` when pressing Enter with an unmodified input value', async () => {
381403
render(<ControlledComboBox controlledItem={null} />);
382404

packages/react/src/components/ComboBox/ComboBox.stories.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8-
import React, { useState, useRef } from 'react';
9-
import { Locked } from '@carbon/react/icons';
8+
import React from 'react';
109
import { WithLayer } from '../../../.storybook/templates/WithLayer';
1110
import ComboBox from '../ComboBox';
1211
import Button from '../Button';

packages/react/src/components/ComboBox/ComboBox.tsx

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -585,15 +585,32 @@ const ComboBox = forwardRef(
585585
// If custom values are allowed, treat whatever the user typed as
586586
// the value.
587587
if (allowCustomValue && highlightedIndex === -1) {
588-
const { inputValue } = state;
589-
590-
changes.selectedItem = inputValue;
588+
const inputValue = state.inputValue ?? '';
589+
const currentSelectedItem =
590+
typeof changes.selectedItem === 'undefined'
591+
? state.selectedItem
592+
: changes.selectedItem;
593+
const isMatchingSelection =
594+
currentSelectedItem !== null &&
595+
typeof currentSelectedItem !== 'undefined' &&
596+
itemToString(currentSelectedItem) === inputValue &&
597+
items.some((item) => isEqual(item, currentSelectedItem));
598+
599+
if (isMatchingSelection) {
600+
return changes;
601+
}
602+
const nextSelectedItem =
603+
items.find((item) => itemToString(item) === inputValue) ??
604+
inputValue;
591605

592-
if (onChange) {
593-
onChange({ selectedItem: inputValue, inputValue });
606+
if (!isEqual(currentSelectedItem, nextSelectedItem) && onChange) {
607+
onChange({ selectedItem: nextSelectedItem, inputValue });
594608
}
595609

596-
return changes;
610+
return {
611+
...changes,
612+
selectedItem: nextSelectedItem,
613+
};
597614
}
598615

599616
// If a new item was selected, keep its label in the input.

0 commit comments

Comments
 (0)