Skip to content

Commit 9af432d

Browse files
committed
deselect focused selected items on Enter
1 parent 29df804 commit 9af432d

File tree

2 files changed

+42
-10
lines changed

2 files changed

+42
-10
lines changed

packages/@react-stately/combobox/src/useComboBoxState.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ export function useComboBoxState<T extends object, M extends SelectionMode = 'si
400400
if (triggerState.isOpen && selectionManager.focusedKey != null) {
401401
// Reset inputValue and close menu here if the selected key is already the focused key. Otherwise
402402
// fire onSelectionChange to allow the application to control the closing.
403-
if (selectionManager.isSelected(selectionManager.focusedKey)) {
403+
if (selectionManager.isSelected(selectionManager.focusedKey) && selectionMode === 'single') {
404404
commitSelection();
405405
} else {
406406
selectionManager.select(selectionManager.focusedKey);

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

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -282,17 +282,17 @@ describe('ComboBox', () => {
282282
<input type="reset" />
283283
</form>
284284
);
285-
285+
286286
const comboboxTester = testUtilUser.createTester('ComboBox', {root: tree.container});
287287
const combobox = comboboxTester.combobox;
288-
288+
289289
expect(combobox).toHaveValue('Dog');
290290
await comboboxTester.open();
291-
291+
292292
const options = comboboxTester.options();
293293
await user.click(options[0]);
294294
expect(combobox).toHaveValue('Cat');
295-
295+
296296
await user.click(document.querySelector('input[type="reset"]'));
297297
expect(combobox).toHaveValue('Dog');
298298
expect(document.querySelector('input[name=combobox]')).toHaveValue('2');
@@ -588,7 +588,7 @@ describe('ComboBox', () => {
588588

589589
let comboboxTester = testUtilUser.createTester('ComboBox', {root: tree.container});
590590
let button = tree.getByRole('button');
591-
591+
592592
// Open the combobox
593593
await user.click(button);
594594
act(() => {
@@ -603,7 +603,7 @@ describe('ComboBox', () => {
603603
// Find and click on a section header
604604
let fruitHeader = tree.getByText('Fruit');
605605
expect(fruitHeader).toBeInTheDocument();
606-
606+
607607
await user.click(fruitHeader);
608608
act(() => {
609609
jest.runAllTimers();
@@ -617,13 +617,13 @@ describe('ComboBox', () => {
617617
// Verify we can still interact with options
618618
let options = comboboxTester.options();
619619
expect(options.length).toBeGreaterThan(0);
620-
620+
621621
// Click an option
622622
await user.click(options[0]);
623623
act(() => {
624624
jest.runAllTimers();
625625
});
626-
626+
627627
// Verify the combobox is closed and the value is updated
628628
expect(tree.queryByRole('listbox')).toBeNull();
629629
expect(comboboxTester.combobox).toHaveValue('Apple');
@@ -714,7 +714,7 @@ describe('ComboBox', () => {
714714

715715
expect(combobox).toHaveValue('C');
716716
expect(onChange).toHaveBeenCalledTimes(1);
717-
expect(onChange).toHaveBeenCalledWith(['2', '3']);
717+
expect(onChange).toHaveBeenCalledWith(['3']);
718718
});
719719

720720
it('should support multi-select with custom value', async () => {
@@ -729,4 +729,36 @@ describe('ComboBox', () => {
729729
await user.tab();
730730
expect(comboboxTester.combobox).toHaveValue('Test');
731731
});
732+
733+
it('should allow the user to deselect items with keyboard when multiselect (uncontrolled)', async () => {
734+
let onChange = jest.fn();
735+
let {container} = render(<TestComboBox defaultValue={['1', '2']} selectionMode="multiple" onChange={onChange} />);
736+
737+
let comboboxTester = testUtilUser.createTester('ComboBox', {root: container});
738+
await comboboxTester.open();
739+
740+
await user.keyboard('{Enter}');
741+
expect(onChange).toHaveBeenCalledTimes(1);
742+
expect(onChange).toHaveBeenLastCalledWith(['2']);
743+
744+
await user.keyboard('{ArrowDown}{Enter}');
745+
expect(onChange).toHaveBeenCalledTimes(2);
746+
expect(onChange).toHaveBeenLastCalledWith([]);
747+
});
748+
749+
it('should allow the user to deselect items with keyboard when multiselect (controlled)', async () => {
750+
let onChange = jest.fn();
751+
let {container} = render(<TestComboBox value={['1', '2']} selectionMode="multiple" onChange={onChange} />);
752+
753+
let comboboxTester = testUtilUser.createTester('ComboBox', {root: container});
754+
await comboboxTester.open();
755+
756+
await user.keyboard('{Enter}');
757+
expect(onChange).toHaveBeenCalledTimes(1);
758+
expect(onChange).toHaveBeenLastCalledWith(['2']);
759+
760+
await user.keyboard('{ArrowDown}{Enter}');
761+
expect(onChange).toHaveBeenCalledTimes(2);
762+
expect(onChange).toHaveBeenLastCalledWith(['1']);
763+
});
732764
});

0 commit comments

Comments
 (0)