mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(stepper): don't handle enter/space when modifier key is pressed (#13827)
Along the same lines as #13790. Doesn't handle the prevent the default action for ENTER and SPACE when one of the modifier keys is pressed, in order to avoid interefering with the native keyboard shortcuts.
This commit is contained in:
committed by
Jeremy Elbourn
parent
a22a9fa3d7
commit
a9e550e5bf
@@ -442,19 +442,24 @@ export class CdkStepper implements AfterViewInit, OnDestroy {
|
||||
}
|
||||
|
||||
_onKeydown(event: KeyboardEvent) {
|
||||
// TODO(crisbeto): move into a CDK utility once
|
||||
// the similar PRs for other components are merged in.
|
||||
const hasModifier = event.altKey || event.shiftKey || event.ctrlKey || event.metaKey;
|
||||
const keyCode = event.keyCode;
|
||||
const manager = this._keyManager;
|
||||
|
||||
if (this._keyManager.activeItemIndex != null && (keyCode === SPACE || keyCode === ENTER)) {
|
||||
this.selectedIndex = this._keyManager.activeItemIndex;
|
||||
if (manager.activeItemIndex != null && !hasModifier &&
|
||||
(keyCode === SPACE || keyCode === ENTER)) {
|
||||
this.selectedIndex = manager.activeItemIndex;
|
||||
event.preventDefault();
|
||||
} else if (keyCode === HOME) {
|
||||
this._keyManager.setFirstItemActive();
|
||||
manager.setFirstItemActive();
|
||||
event.preventDefault();
|
||||
} else if (keyCode === END) {
|
||||
this._keyManager.setLastItemActive();
|
||||
manager.setLastItemActive();
|
||||
event.preventDefault();
|
||||
} else {
|
||||
this._keyManager.onKeydown(event);
|
||||
manager.onKeydown(event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
UP_ARROW,
|
||||
} from '@angular/cdk/keycodes';
|
||||
import {StepperOrientation, MAT_STEPPER_GLOBAL_OPTIONS, STEP_STATE} from '@angular/cdk/stepper';
|
||||
import {dispatchKeyboardEvent} from '@angular/cdk/testing';
|
||||
import {dispatchKeyboardEvent, createKeyboardEvent, dispatchEvent} from '@angular/cdk/testing';
|
||||
import {Component, DebugElement, EventEmitter, OnInit, Type, Provider} from '@angular/core';
|
||||
import {ComponentFixture, fakeAsync, flush, inject, TestBed} from '@angular/core/testing';
|
||||
import {
|
||||
@@ -345,6 +345,16 @@ describe('MatStepper', () => {
|
||||
|
||||
expect(stepperComponent.selectedIndex).toBe(1);
|
||||
});
|
||||
|
||||
it('should not do anything when pressing the ENTER key with a modifier', () => {
|
||||
const stepHeaders = fixture.debugElement.queryAll(By.css('.mat-vertical-stepper-header'));
|
||||
assertSelectKeyWithModifierInteraction(fixture, stepHeaders, 'vertical', ENTER);
|
||||
});
|
||||
|
||||
it('should not do anything when pressing the SPACE key with a modifier', () => {
|
||||
const stepHeaders = fixture.debugElement.queryAll(By.css('.mat-vertical-stepper-header'));
|
||||
assertSelectKeyWithModifierInteraction(fixture, stepHeaders, 'vertical', SPACE);
|
||||
});
|
||||
});
|
||||
|
||||
describe('basic stepper when attempting to set the selected step too early', () => {
|
||||
@@ -1063,6 +1073,38 @@ function assertArrowKeyInteractionInRtl(fixture: ComponentFixture<any>,
|
||||
expect(stepperComponent._getFocusIndex()).toBe(0);
|
||||
}
|
||||
|
||||
/** Asserts that keyboard interaction works correctly when the user is pressing a modifier key. */
|
||||
function assertSelectKeyWithModifierInteraction(fixture: ComponentFixture<any>,
|
||||
stepHeaders: DebugElement[],
|
||||
orientation: StepperOrientation,
|
||||
selectionKey: number) {
|
||||
const stepperComponent = fixture.debugElement.query(By.directive(MatStepper)).componentInstance;
|
||||
const modifiers = ['altKey', 'shiftKey', 'ctrlKey', 'metaKey'];
|
||||
|
||||
expect(stepperComponent._getFocusIndex()).toBe(0);
|
||||
expect(stepperComponent.selectedIndex).toBe(0);
|
||||
|
||||
dispatchKeyboardEvent(stepHeaders[0].nativeElement, 'keydown',
|
||||
orientation === 'vertical' ? DOWN_ARROW : RIGHT_ARROW);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(stepperComponent._getFocusIndex())
|
||||
.toBe(1, 'Expected index of focused step to increase by 1 after pressing the next key.');
|
||||
expect(stepperComponent.selectedIndex)
|
||||
.toBe(0, 'Expected index of selected step to remain unchanged after pressing the next key.');
|
||||
|
||||
modifiers.forEach(modifier => {
|
||||
const event: KeyboardEvent = createKeyboardEvent('keydown', selectionKey);
|
||||
Object.defineProperty(event, modifier, {get: () => true});
|
||||
dispatchEvent(stepHeaders[1].nativeElement, event);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(stepperComponent.selectedIndex).toBe(0, `Expected selected index to remain unchanged ` +
|
||||
`when pressing the selection key with ${modifier} modifier.`);
|
||||
expect(event.defaultPrevented).toBe(false);
|
||||
});
|
||||
}
|
||||
|
||||
function asyncValidator(minLength: number, validationTrigger: Subject<void>): AsyncValidatorFn {
|
||||
return (control: AbstractControl): Observable<ValidationErrors | null> => {
|
||||
return validationTrigger.pipe(
|
||||
|
||||
Reference in New Issue
Block a user