Skip to content

Commit d8396f2

Browse files
authored
fix(material/autocomplete): don't prevent escape key actions with modifiers (#20706)
Doesn't handle escape key presses if the user is pressing a modifier key. This brings the autocomplete in line with most other components that were changed by #16202.
1 parent d93e16f commit d8396f2

File tree

3 files changed

+41
-4
lines changed

3 files changed

+41
-4
lines changed

src/material-experimental/mdc-autocomplete/autocomplete.spec.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,6 +1186,24 @@ describe('MDC-based MatAutocomplete', () => {
11861186
expect(escapeEvent.defaultPrevented).toBe(true);
11871187
}));
11881188

1189+
it('should not close the panel when pressing escape with a modifier', fakeAsync(() => {
1190+
const trigger = fixture.componentInstance.trigger;
1191+
1192+
input.focus();
1193+
flush();
1194+
fixture.detectChanges();
1195+
1196+
expect(document.activeElement).toBe(input, 'Expected input to be focused.');
1197+
expect(trigger.panelOpen).toBe(true, 'Expected panel to be open.');
1198+
1199+
const event = dispatchKeyboardEvent(document.body, 'keydown', ESCAPE, undefined, {alt: true});
1200+
fixture.detectChanges();
1201+
1202+
expect(document.activeElement).toBe(input, 'Expected input to continue to be focused.');
1203+
expect(trigger.panelOpen).toBe(true, 'Expected panel to stay open.');
1204+
expect(event.defaultPrevented).toBe(false, 'Expected default action not to be prevented.');
1205+
}));
1206+
11891207
it('should close the panel when pressing ALT + UP_ARROW', fakeAsync(() => {
11901208
const trigger = fixture.componentInstance.trigger;
11911209
const upArrowEvent = createKeyboardEvent('keydown', UP_ARROW, undefined, {alt: true});

src/material/autocomplete/autocomplete-trigger.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88
import {Directionality} from '@angular/cdk/bidi';
99
import {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion';
10-
import {DOWN_ARROW, ENTER, ESCAPE, TAB, UP_ARROW} from '@angular/cdk/keycodes';
10+
import {DOWN_ARROW, ENTER, ESCAPE, TAB, UP_ARROW, hasModifierKey} from '@angular/cdk/keycodes';
1111
import {
1212
FlexibleConnectedPositionStrategy,
1313
Overlay,
@@ -393,7 +393,7 @@ export abstract class _MatAutocompleteTriggerBase implements ControlValueAccesso
393393
// in line with other browsers. By default, pressing escape on IE will cause it to revert
394394
// the input value to the one that it had on focus, however it won't dispatch any events
395395
// which means that the model value will be out of sync with the view.
396-
if (keyCode === ESCAPE) {
396+
if (keyCode === ESCAPE && !hasModifierKey(event)) {
397397
event.preventDefault();
398398
}
399399

@@ -571,7 +571,7 @@ export abstract class _MatAutocompleteTriggerBase implements ControlValueAccesso
571571
*/
572572
private _clearPreviousSelectedOption(skip: MatOption) {
573573
this.autocomplete.options.forEach(option => {
574-
if (option != skip && option.selected) {
574+
if (option !== skip && option.selected) {
575575
option.deselect();
576576
}
577577
});
@@ -600,7 +600,8 @@ export abstract class _MatAutocompleteTriggerBase implements ControlValueAccesso
600600
overlayRef.keydownEvents().subscribe(event => {
601601
// Close when pressing ESCAPE or ALT + UP_ARROW, based on the a11y guidelines.
602602
// See: https://www.w3.org/TR/wai-aria-practices-1.1/#textbox-keyboard-interaction
603-
if (event.keyCode === ESCAPE || (event.keyCode === UP_ARROW && event.altKey)) {
603+
if ((event.keyCode === ESCAPE && !hasModifierKey(event)) ||
604+
(event.keyCode === UP_ARROW && hasModifierKey(event, 'altKey'))) {
604605
this._resetActiveItem();
605606
this._closeKeyEventStream.next();
606607

src/material/autocomplete/autocomplete.spec.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,6 +1183,24 @@ describe('MatAutocomplete', () => {
11831183
expect(escapeEvent.defaultPrevented).toBe(true);
11841184
}));
11851185

1186+
it('should not close the panel when pressing escape with a modifier', fakeAsync(() => {
1187+
const trigger = fixture.componentInstance.trigger;
1188+
1189+
input.focus();
1190+
flush();
1191+
fixture.detectChanges();
1192+
1193+
expect(document.activeElement).toBe(input, 'Expected input to be focused.');
1194+
expect(trigger.panelOpen).toBe(true, 'Expected panel to be open.');
1195+
1196+
const event = dispatchKeyboardEvent(document.body, 'keydown', ESCAPE, undefined, {alt: true});
1197+
fixture.detectChanges();
1198+
1199+
expect(document.activeElement).toBe(input, 'Expected input to continue to be focused.');
1200+
expect(trigger.panelOpen).toBe(true, 'Expected panel to stay open.');
1201+
expect(event.defaultPrevented).toBe(false, 'Expected default action not to be prevented.');
1202+
}));
1203+
11861204
it('should close the panel when pressing ALT + UP_ARROW', fakeAsync(() => {
11871205
const trigger = fixture.componentInstance.trigger;
11881206
const upArrowEvent = createKeyboardEvent('keydown', UP_ARROW, undefined, {alt: true});

0 commit comments

Comments
 (0)