Skip to content

Commit d02cc68

Browse files
authored
fix(material/datepicker): fix date picker shortcuts (#25951)
* fix(material/datepicker): fix date picker shortcuts Fixes a bug in the Angular Material `datepicker` component where the datepicker should open/close only on alt+down and alt+up respectively but using shift + ctrl + alt + down or ctrl + alt + down the datepicker was opening, and same happens for closing the date picker added a condition to check if ctrl, shift or meta keys are present and if it is present restricting datepicker to not to open/close. Fixes #25868 * fix(material/datepicker): fix date picker shortcuts  Fixes a bug in the Angular Material datepicker component where the datepicker should open/close only on alt+down and alt+up respectively but using shift + ctrl + alt + down or ctrl + alt + down the datepicker was opening, and same happens for closing the date picker added a condition to check if ctrl, shift or meta keys are present and if it is present restricting datepicker to not to open/close. Fixes #25868
1 parent 922d982 commit d02cc68

File tree

5 files changed

+57
-4
lines changed

5 files changed

+57
-4
lines changed

src/cdk/keycodes/modifiers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
type ModifierKey = 'altKey' | 'shiftKey' | 'ctrlKey' | 'metaKey';
9+
export type ModifierKey = 'altKey' | 'shiftKey' | 'ctrlKey' | 'metaKey';
1010

1111
/**
1212
* Checks whether a modifier key is pressed.

src/material/datepicker/datepicker-base.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
ESCAPE,
1414
hasModifierKey,
1515
LEFT_ARROW,
16+
ModifierKey,
1617
PAGE_DOWN,
1718
PAGE_UP,
1819
RIGHT_ARROW,
@@ -819,6 +820,7 @@ export abstract class MatDatepickerBase<
819820

820821
/** Gets an observable that will emit when the overlay is supposed to be closed. */
821822
private _getCloseStream(overlayRef: OverlayRef) {
823+
const ctrlShiftMetaModifiers: ModifierKey[] = ['ctrlKey', 'shiftKey', 'metaKey'];
822824
return merge(
823825
overlayRef.backdropClick(),
824826
overlayRef.detachments(),
@@ -827,7 +829,12 @@ export abstract class MatDatepickerBase<
827829
// Closing on alt + up is only valid when there's an input associated with the datepicker.
828830
return (
829831
(event.keyCode === ESCAPE && !hasModifierKey(event)) ||
830-
(this.datepickerInput && hasModifierKey(event, 'altKey') && event.keyCode === UP_ARROW)
832+
(this.datepickerInput &&
833+
hasModifierKey(event, 'altKey') &&
834+
event.keyCode === UP_ARROW &&
835+
ctrlShiftMetaModifiers.every(
836+
(modifier: ModifierKey) => !hasModifierKey(event, modifier),
837+
))
831838
);
832839
}),
833840
),

src/material/datepicker/datepicker-input-base.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88

99
import {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion';
10-
import {DOWN_ARROW} from '@angular/cdk/keycodes';
10+
import {DOWN_ARROW, hasModifierKey, ModifierKey} from '@angular/cdk/keycodes';
1111
import {
1212
Directive,
1313
ElementRef,
@@ -305,7 +305,11 @@ export abstract class MatDatepickerInputBase<S, D = ExtractDateTypeFromSelection
305305
}
306306

307307
_onKeydown(event: KeyboardEvent) {
308-
const isAltDownArrow = event.altKey && event.keyCode === DOWN_ARROW;
308+
const ctrlShiftMetaModifiers: ModifierKey[] = ['ctrlKey', 'shiftKey', 'metaKey'];
309+
const isAltDownArrow =
310+
hasModifierKey(event, 'altKey') &&
311+
event.keyCode === DOWN_ARROW &&
312+
ctrlShiftMetaModifiers.every((modifier: ModifierKey) => !hasModifierKey(event, modifier));
309313

310314
if (isAltDownArrow && !this._elementRef.nativeElement.readOnly) {
311315
this._openPopup();

src/material/datepicker/datepicker.spec.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,27 @@ describe('MatDatepicker', () => {
550550
expect(testComponent.datepicker.opened).toBe(false);
551551
}));
552552

553+
it('should not close the datepicker when using CTRL + SHIFT + ALT + UP_ARROW', fakeAsync(() => {
554+
testComponent.datepicker.open();
555+
fixture.detectChanges();
556+
tick();
557+
flush();
558+
559+
expect(testComponent.datepicker.opened).toBe(true);
560+
561+
const event = createKeyboardEvent('keydown', UP_ARROW, undefined, {
562+
alt: true,
563+
shift: true,
564+
control: true,
565+
});
566+
567+
dispatchEvent(document.body, event);
568+
fixture.detectChanges();
569+
flush();
570+
571+
expect(testComponent.datepicker.opened).toBe(true);
572+
}));
573+
553574
it('should open the datepicker using ALT + DOWN_ARROW', fakeAsync(() => {
554575
expect(testComponent.datepicker.opened).toBe(false);
555576

@@ -581,6 +602,24 @@ describe('MatDatepicker', () => {
581602
expect(event.defaultPrevented).toBe(false);
582603
}));
583604

605+
it('should not open the datepicker using SHIFT + CTRL + ALT + DOWN_ARROW', fakeAsync(() => {
606+
expect(testComponent.datepicker.opened).toBe(false);
607+
608+
const event = createKeyboardEvent('keydown', DOWN_ARROW, undefined, {
609+
alt: true,
610+
shift: true,
611+
control: true,
612+
});
613+
614+
dispatchEvent(fixture.nativeElement.querySelector('input'), event);
615+
fixture.detectChanges();
616+
tick();
617+
flush();
618+
619+
expect(testComponent.datepicker.opened).toBe(false);
620+
expect(event.defaultPrevented).toBe(false);
621+
}));
622+
584623
it('should show the invisible close button on focus', fakeAsync(() => {
585624
testComponent.opened = true;
586625
fixture.detectChanges();

tools/public_api_guard/cdk/keycodes.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,9 @@ export const MAC_WK_CMD_RIGHT = 93;
190190
// @public (undocumented)
191191
export const META = 91;
192192

193+
// @public
194+
export type ModifierKey = 'altKey' | 'shiftKey' | 'ctrlKey' | 'metaKey';
195+
193196
// @public (undocumented)
194197
export const MUTE = 173;
195198

0 commit comments

Comments
 (0)