Skip to content

Commit 8a3e023

Browse files
crisbetojelbourn
authored andcommitted
fix(datepicker): calendar controls not being inverted in rtl (#9219)
Fixes the calendar left/right arrow keys not being inverted in RTL.
1 parent 9d152c0 commit 8a3e023

File tree

2 files changed

+79
-5
lines changed

2 files changed

+79
-5
lines changed

src/lib/datepicker/calendar.spec.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
SEP,
2828
} from '@angular/material/core';
2929
import {By} from '@angular/platform-browser';
30+
import {Direction, Directionality} from '@angular/cdk/bidi';
3031
import {MatButtonModule} from '../button/index';
3132
import {MatCalendar} from './calendar';
3233
import {MatCalendarBody} from './calendar-body';
@@ -37,6 +38,8 @@ import {MatYearView} from './year-view';
3738

3839

3940
describe('MatCalendar', () => {
41+
let dir: {value: Direction};
42+
4043
beforeEach(async(() => {
4144
TestBed.configureTestingModule({
4245
imports: [
@@ -57,6 +60,7 @@ describe('MatCalendar', () => {
5760
],
5861
providers: [
5962
MatDatepickerIntl,
63+
{provide: Directionality, useFactory: () => dir = {value: 'ltr'}}
6064
],
6165
});
6266

@@ -240,6 +244,20 @@ describe('MatCalendar', () => {
240244
expect(calendarInstance._activeDate).toEqual(new Date(2016, DEC, 31));
241245
});
242246

247+
it('should increment date on left arrow press in rtl', () => {
248+
dir.value = 'rtl';
249+
250+
dispatchKeyboardEvent(calendarBodyEl, 'keydown', LEFT_ARROW);
251+
fixture.detectChanges();
252+
253+
expect(calendarInstance._activeDate).toEqual(new Date(2017, FEB, 1));
254+
255+
dispatchKeyboardEvent(calendarBodyEl, 'keydown', LEFT_ARROW);
256+
fixture.detectChanges();
257+
258+
expect(calendarInstance._activeDate).toEqual(new Date(2017, FEB, 2));
259+
});
260+
243261
it('should increment date on right arrow press', () => {
244262
dispatchKeyboardEvent(calendarBodyEl, 'keydown', RIGHT_ARROW);
245263
fixture.detectChanges();
@@ -252,6 +270,23 @@ describe('MatCalendar', () => {
252270
expect(calendarInstance._activeDate).toEqual(new Date(2017, FEB, 2));
253271
});
254272

273+
it('should decrement date on right arrow press in rtl', () => {
274+
dir.value = 'rtl';
275+
276+
dispatchKeyboardEvent(calendarBodyEl, 'keydown', RIGHT_ARROW);
277+
fixture.detectChanges();
278+
279+
expect(calendarInstance._activeDate).toEqual(new Date(2017, JAN, 30));
280+
281+
calendarInstance._activeDate = new Date(2017, JAN, 1);
282+
fixture.detectChanges();
283+
284+
dispatchKeyboardEvent(calendarBodyEl, 'keydown', RIGHT_ARROW);
285+
fixture.detectChanges();
286+
287+
expect(calendarInstance._activeDate).toEqual(new Date(2016, DEC, 31));
288+
});
289+
255290
it('should go up a row on up arrow press', () => {
256291
dispatchKeyboardEvent(calendarBodyEl, 'keydown', UP_ARROW);
257292
fixture.detectChanges();
@@ -367,6 +402,20 @@ describe('MatCalendar', () => {
367402
expect(calendarInstance._activeDate).toEqual(new Date(2016, NOV, 30));
368403
});
369404

405+
it('should increment month on left arrow press in rtl', () => {
406+
dir.value = 'rtl';
407+
408+
dispatchKeyboardEvent(calendarBodyEl, 'keydown', LEFT_ARROW);
409+
fixture.detectChanges();
410+
411+
expect(calendarInstance._activeDate).toEqual(new Date(2017, FEB, 28));
412+
413+
dispatchKeyboardEvent(calendarBodyEl, 'keydown', LEFT_ARROW);
414+
fixture.detectChanges();
415+
416+
expect(calendarInstance._activeDate).toEqual(new Date(2017, MAR, 28));
417+
});
418+
370419
it('should increment month on right arrow press', () => {
371420
dispatchKeyboardEvent(calendarBodyEl, 'keydown', RIGHT_ARROW);
372421
fixture.detectChanges();
@@ -379,6 +428,20 @@ describe('MatCalendar', () => {
379428
expect(calendarInstance._activeDate).toEqual(new Date(2017, MAR, 28));
380429
});
381430

431+
it('should decrement month on right arrow press in rtl', () => {
432+
dir.value = 'rtl';
433+
434+
dispatchKeyboardEvent(calendarBodyEl, 'keydown', RIGHT_ARROW);
435+
fixture.detectChanges();
436+
437+
expect(calendarInstance._activeDate).toEqual(new Date(2016, DEC, 31));
438+
439+
dispatchKeyboardEvent(calendarBodyEl, 'keydown', RIGHT_ARROW);
440+
fixture.detectChanges();
441+
442+
expect(calendarInstance._activeDate).toEqual(new Date(2016, NOV, 30));
443+
});
444+
382445
it('should go up a row on up arrow press', () => {
383446
dispatchKeyboardEvent(calendarBodyEl, 'keydown', UP_ARROW);
384447
fixture.detectChanges();

src/lib/datepicker/calendar.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import {MatDatepickerIntl} from './datepicker-intl';
4343
import {MatMonthView} from './month-view';
4444
import {MatMultiYearView, yearsPerPage, yearsPerRow} from './multi-year-view';
4545
import {MatYearView} from './year-view';
46+
import {Directionality} from '@angular/cdk/bidi';
4647

4748

4849
/**
@@ -184,7 +185,8 @@ export class MatCalendar<D> implements AfterContentInit, OnDestroy, OnChanges {
184185
private _ngZone: NgZone,
185186
@Optional() private _dateAdapter: DateAdapter<D>,
186187
@Optional() @Inject(MAT_DATE_FORMATS) private _dateFormats: MatDateFormats,
187-
changeDetectorRef: ChangeDetectorRef) {
188+
changeDetectorRef: ChangeDetectorRef,
189+
@Optional() private _dir?: Directionality) {
188190

189191
if (!this._dateAdapter) {
190192
throw createMissingDateImplError('DateAdapter');
@@ -309,12 +311,14 @@ export class MatCalendar<D> implements AfterContentInit, OnDestroy, OnChanges {
309311

310312
/** Handles keydown events on the calendar body when calendar is in month view. */
311313
private _handleCalendarBodyKeydownInMonthView(event: KeyboardEvent): void {
314+
const isRtl = this._isRtl();
315+
312316
switch (event.keyCode) {
313317
case LEFT_ARROW:
314-
this._activeDate = this._dateAdapter.addCalendarDays(this._activeDate, -1);
318+
this._activeDate = this._dateAdapter.addCalendarDays(this._activeDate, isRtl ? 1 : -1);
315319
break;
316320
case RIGHT_ARROW:
317-
this._activeDate = this._dateAdapter.addCalendarDays(this._activeDate, 1);
321+
this._activeDate = this._dateAdapter.addCalendarDays(this._activeDate, isRtl ? -1 : 1);
318322
break;
319323
case UP_ARROW:
320324
this._activeDate = this._dateAdapter.addCalendarDays(this._activeDate, -7);
@@ -361,12 +365,14 @@ export class MatCalendar<D> implements AfterContentInit, OnDestroy, OnChanges {
361365

362366
/** Handles keydown events on the calendar body when calendar is in year view. */
363367
private _handleCalendarBodyKeydownInYearView(event: KeyboardEvent): void {
368+
const isRtl = this._isRtl();
369+
364370
switch (event.keyCode) {
365371
case LEFT_ARROW:
366-
this._activeDate = this._dateAdapter.addCalendarMonths(this._activeDate, -1);
372+
this._activeDate = this._dateAdapter.addCalendarMonths(this._activeDate, isRtl ? 1 : -1);
367373
break;
368374
case RIGHT_ARROW:
369-
this._activeDate = this._dateAdapter.addCalendarMonths(this._activeDate, 1);
375+
this._activeDate = this._dateAdapter.addCalendarMonths(this._activeDate, isRtl ? -1 : 1);
370376
break;
371377
case UP_ARROW:
372378
this._activeDate = this._dateAdapter.addCalendarMonths(this._activeDate, -4);
@@ -456,4 +462,9 @@ export class MatCalendar<D> implements AfterContentInit, OnDestroy, OnChanges {
456462
private _getValidDateOrNull(obj: any): D | null {
457463
return (this._dateAdapter.isDateInstance(obj) && this._dateAdapter.isValid(obj)) ? obj : null;
458464
}
465+
466+
/** Determines whether the user has the RTL layout direction. */
467+
private _isRtl() {
468+
return this._dir && this._dir.value === 'rtl';
469+
}
459470
}

0 commit comments

Comments
 (0)