Skip to content

Commit 5825faf

Browse files
authored
fix(material/autocomplete): don't block default arrow keys when using modifiers (#11987)
Currently we hijack all up/down arrow key events, however this interferes with keyboard shortcuts such as shift + up arrow for marking all of the text. These changes stop intercepting the arrow keys, if they're used with a modifier. These changes also fix an issue where all the mocked out key events had the `metaKey` set to `true` on some browsers.
1 parent ca6b9fa commit 5825faf

File tree

3 files changed

+32
-3
lines changed

3 files changed

+32
-3
lines changed

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

+14
Original file line numberDiff line numberDiff line change
@@ -1470,6 +1470,20 @@ describe('MDC-based MatAutocomplete', () => {
14701470

14711471
expect(!!trigger.activeOption).withContext('Expected no active options.').toBe(false);
14721472
}));
1473+
1474+
it('should not prevent the default action when a modifier key is pressed', () => {
1475+
['metaKey', 'ctrlKey', 'altKey', 'shiftKey'].forEach(name => {
1476+
const event = createKeyboardEvent('keydown', DOWN_ARROW);
1477+
Object.defineProperty(event, name, {get: () => true});
1478+
1479+
fixture.componentInstance.trigger._handleKeydown(event);
1480+
fixture.detectChanges();
1481+
1482+
expect(event.defaultPrevented)
1483+
.withContext(`Expected autocompete not to block ${name} key`)
1484+
.toBe(false);
1485+
});
1486+
});
14731487
});
14741488

14751489
describe('option groups', () => {

src/material/autocomplete/autocomplete-trigger.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -390,24 +390,25 @@ export abstract class _MatAutocompleteTriggerBase
390390

391391
_handleKeydown(event: KeyboardEvent): void {
392392
const keyCode = event.keyCode;
393+
const hasModifier = hasModifierKey(event);
393394

394395
// Prevent the default action on all escape key presses. This is here primarily to bring IE
395396
// in line with other browsers. By default, pressing escape on IE will cause it to revert
396397
// the input value to the one that it had on focus, however it won't dispatch any events
397398
// which means that the model value will be out of sync with the view.
398-
if (keyCode === ESCAPE && !hasModifierKey(event)) {
399+
if (keyCode === ESCAPE && !hasModifier) {
399400
event.preventDefault();
400401
}
401402

402-
if (this.activeOption && keyCode === ENTER && this.panelOpen && !hasModifierKey(event)) {
403+
if (this.activeOption && keyCode === ENTER && this.panelOpen && !hasModifier) {
403404
this.activeOption._selectViaInteraction();
404405
this._resetActiveItem();
405406
event.preventDefault();
406407
} else if (this.autocomplete) {
407408
const prevActiveItem = this.autocomplete._keyManager.activeItem;
408409
const isArrowKey = keyCode === UP_ARROW || keyCode === DOWN_ARROW;
409410

410-
if (this.panelOpen || keyCode === TAB) {
411+
if (keyCode === TAB || (isArrowKey && !hasModifier && this.panelOpen)) {
411412
this.autocomplete._keyManager.onKeydown(event);
412413
} else if (isArrowKey && this._canOpen()) {
413414
this.openPanel();

src/material/autocomplete/autocomplete.spec.ts

+14
Original file line numberDiff line numberDiff line change
@@ -1453,6 +1453,20 @@ describe('MatAutocomplete', () => {
14531453

14541454
expect(!!trigger.activeOption).withContext('Expected no active options.').toBe(false);
14551455
}));
1456+
1457+
it('should not prevent the default action when a modifier key is pressed', () => {
1458+
['metaKey', 'ctrlKey', 'altKey', 'shiftKey'].forEach(name => {
1459+
const event = createKeyboardEvent('keydown', DOWN_ARROW);
1460+
Object.defineProperty(event, name, {get: () => true});
1461+
1462+
fixture.componentInstance.trigger._handleKeydown(event);
1463+
fixture.detectChanges();
1464+
1465+
expect(event.defaultPrevented)
1466+
.withContext(`Expected autocompete not to block ${name} key`)
1467+
.toBe(false);
1468+
});
1469+
});
14561470
});
14571471

14581472
describe('option groups', () => {

0 commit comments

Comments
 (0)