From 4ff1c4f930930b2e907deb2fbc5e7eb63b9bd0a0 Mon Sep 17 00:00:00 2001 From: MonikaKirkova Date: Thu, 2 Oct 2025 13:45:33 +0300 Subject: [PATCH] feat(combo): update Tab and Escape key behavior --- src/components/combo/combo.spec.ts | 79 +++++++++++++++++++ src/components/combo/combo.ts | 10 +++ .../combo/controllers/navigation.ts | 14 +++- 3 files changed, 99 insertions(+), 4 deletions(-) diff --git a/src/components/combo/combo.spec.ts b/src/components/combo/combo.spec.ts index 0a12bc7da..a4d2ec521 100644 --- a/src/components/combo/combo.spec.ts +++ b/src/components/combo/combo.spec.ts @@ -714,6 +714,85 @@ describe('Combo', () => { expect(combo.open).to.be.true; }); + it('should close the menu by pressing the Tab key', async () => { + await combo.show(); + await list.layoutComplete; + + pressKey(options, 'Tab', 1, { altKey: false }); + await elementUpdated(combo); + expect(combo.open).to.be.false; + + await combo.show(); + pressKey(searchInput, 'Tab', 1, { altKey: false }); + await elementUpdated(combo); + + expect(combo.open).to.be.false; + + await combo.show(); + pressKey(input, 'Tab', 1, { altKey: false }); + await elementUpdated(combo); + + expect(combo.open).to.be.false; + }); + + it('should clear the selection by pressing the Escape key when the combo is closed', async () => { + combo.autofocusList = true; + combo.select(['BG01', 'BG02']); + await elementUpdated(combo); + + await combo.show(); + await list.layoutComplete; + + pressKey(options, 'Escape', 1, { altKey: false }); + await elementUpdated(combo); + + expect(combo.open).to.be.false; + expect(combo.value.length).to.equal(2); + + pressKey(input, 'Escape', 1, { altKey: false }); + await elementUpdated(combo); + + expect(combo.open).to.be.false; + expect(combo.value.length).to.equal(0); + }); + + it('should close the menu by pressing the Tab key in single selection', async () => { + await combo.show(); + await list.layoutComplete; + + pressKey(options, 'Tab', 1, { altKey: false }); + await elementUpdated(combo); + + expect(combo.open).to.be.false; + + await combo.show(); + pressKey(input, 'Tab', 1, { altKey: false }); + await elementUpdated(combo); + + expect(combo.open).to.be.false; + }); + + it('should clear the selection by pressing the Escape key in single selection', async () => { + combo.singleSelect = true; + combo.select('BG01'); + await elementUpdated(combo); + + await combo.show(); + await list.layoutComplete; + + pressKey(options, 'Escape', 1, { altKey: false }); + await elementUpdated(combo); + + expect(combo.open).to.be.false; + expect(combo.value.length).to.equal(1); + + pressKey(input, 'Escape', 1, { altKey: false }); + await elementUpdated(combo); + + expect(combo.open).to.be.false; + expect(combo.value.length).to.equal(0); + }); + it('should select the active item and close the menu by pressing Enter in single selection', async () => { combo.singleSelect = true; await elementUpdated(combo); diff --git a/src/components/combo/combo.ts b/src/components/combo/combo.ts index 87518e363..f8849af80 100644 --- a/src/components/combo/combo.ts +++ b/src/components/combo/combo.ts @@ -701,6 +701,7 @@ export default class IgcComboComponent< this.emitEvent('igcClosed'); } this._navigation.active = -1; + this._input.focus(); return true; } @@ -841,6 +842,15 @@ export default class IgcComboComponent< protected handleMainInputKeydown(e: KeyboardEvent) { this._setTouchedState(); + if (e.key === 'Escape' && !this.open) { + if (this.singleSelect) { + this.resetSearchTerm(); + this.clearSingleSelection(); + } else { + this._selection.deselect([], true); + } + this.updateValue(); + } this._navigation.navigateMainInput(e, this._list); } diff --git a/src/components/combo/controllers/navigation.ts b/src/components/combo/controllers/navigation.ts index 54c23369b..fb195cbde 100644 --- a/src/components/combo/controllers/navigation.ts +++ b/src/components/combo/controllers/navigation.ts @@ -35,7 +35,7 @@ export class NavigationController Escape: this.escape, ArrowUp: this.escape, ArrowDown: this.inputArrowDown, - Tab: this.inputArrowDown, + Tab: this.tab, }) ); @@ -252,7 +252,9 @@ export class NavigationController event.stopPropagation(); if (this.mainInputHandlers.has(event.key)) { - event.preventDefault(); + if (event.key.toLowerCase() !== 'tab') { + event.preventDefault(); + } this.mainInputHandlers.get(event.key)!.call(this, container); } } @@ -264,7 +266,9 @@ export class NavigationController event.stopPropagation(); if (this.searchInputHandlers.has(event.key)) { - event.preventDefault(); + if (event.key.toLowerCase() !== 'tab') { + event.preventDefault(); + } this.searchInputHandlers.get(event.key)!.call(this, container); } } @@ -273,7 +277,9 @@ export class NavigationController event.stopPropagation(); if (this.listHandlers.has(event.key)) { - event.preventDefault(); + if (event.key.toLowerCase() !== 'tab') { + event.preventDefault(); + } this.listHandlers.get(event.key)!.call(this, container); } }