diff --git a/src/material/datepicker/calendar-body.ts b/src/material/datepicker/calendar-body.ts index 1b6b7472cb44..6eb68156d31f 100644 --- a/src/material/datepicker/calendar-body.ts +++ b/src/material/datepicker/calendar-body.ts @@ -111,6 +111,7 @@ export class MatCalendarBody implements OnChanges, OnDestroy, AfterViewChecked { private _activeCell: number = 0; ngAfterViewChecked() { + console.log('ngAfterViewChecked', this._focusActiveCellAfterViewChecked); if (this._focusActiveCellAfterViewChecked) { this._focusActiveCell(); this._focusActiveCellAfterViewChecked = false; @@ -146,6 +147,8 @@ export class MatCalendarBody implements OnChanges, OnDestroy, AfterViewChecked { MatCalendarUserEvent >(); + @Output() readonly activeCellChange = new EventEmitter>(); + /** The number of blank cells to put at the beginning for the first row. */ _firstRowOffset: number; @@ -173,8 +176,9 @@ export class MatCalendarBody implements OnChanges, OnDestroy, AfterViewChecked { } _cellFocused(cell: MatCalendarCell, event: FocusEvent): void { + console.log('cellFocused', cell.value); if (cell.enabled) { - // TODO: make argument cell the active date + this.activeCellChange.emit({value: cell.value, event}); } } @@ -222,11 +226,13 @@ export class MatCalendarBody implements OnChanges, OnDestroy, AfterViewChecked { /** Focuses the active cell after the microtask queue is empty. */ _focusActiveCell(movePreview = true) { + console.log('_focusActiveCell', this.label); this._ngZone.runOutsideAngular(() => { this._ngZone.onStable.pipe(take(1)).subscribe(() => { const activeCell: HTMLElement | null = this._elementRef.nativeElement.querySelector( '.mat-calendar-body-active', ); + console.log('_focusActiveCell cb', activeCell?.innerText, this.label); if (activeCell) { if (!movePreview) { @@ -241,6 +247,7 @@ export class MatCalendarBody implements OnChanges, OnDestroy, AfterViewChecked { /** Focuses the active cell after change detection has run and the microtask queue is empty. */ _scheduleFocusActiveCellAfterViewChecked() { + console.log('_scheduleFocusActiveCellAfterViewChecked'); this._focusActiveCellAfterViewChecked = true; } diff --git a/src/material/datepicker/month-view.html b/src/material/datepicker/month-view.html index 35deaf2339c2..7688aa10cc20 100644 --- a/src/material/datepicker/month-view.html +++ b/src/material/datepicker/month-view.html @@ -25,6 +25,7 @@ [activeCell]="_dateAdapter.getDate(activeDate) - 1" (selectedValueChange)="_dateSelected($event)" (previewChange)="_previewChanged($event)" + (activeCellChange)="_dateBecomesActive($event)" (keyup)="_handleCalendarBodyKeyup($event)" (keydown)="_handleCalendarBodyKeydown($event)"> diff --git a/src/material/datepicker/month-view.ts b/src/material/datepicker/month-view.ts index 2f5a09c6e873..a7101d4452ff 100644 --- a/src/material/datepicker/month-view.ts +++ b/src/material/datepicker/month-view.ts @@ -230,9 +230,7 @@ export class MatMonthView implements AfterContentInit, OnChanges, OnDestroy { /** Handles when a new date is selected. */ _dateSelected(event: MatCalendarUserEvent) { const date = event.value; - const selectedYear = this._dateAdapter.getYear(this.activeDate); - const selectedMonth = this._dateAdapter.getMonth(this.activeDate); - const selectedDate = this._dateAdapter.createDate(selectedYear, selectedMonth, date); + const selectedDate = this._normalizeDate(date); let rangeStartDate: number | null; let rangeEndDate: number | null; @@ -252,8 +250,30 @@ export class MatMonthView implements AfterContentInit, OnChanges, OnDestroy { this._changeDetectorRef.markForCheck(); } + private _normalizeDate(date: number): D { + const normalizedYear = this._dateAdapter.getYear(this.activeDate); + const normalizedMonth = this._dateAdapter.getMonth(this.activeDate); + const normalizedDate = this._dateAdapter.createDate(normalizedYear, normalizedMonth, date); + return normalizedDate; + } + + /** Handles when a new date becomes active. */ + _dateBecomesActive(event: MatCalendarUserEvent) { + console.log('_dateBecomesActive', event.value); + const date = event.value; + const oldActiveDate = this.activeDate; + this.activeDate = this._normalizeDate(date); + + if (this._dateAdapter.compareDate(oldActiveDate, this.activeDate)) { + this.activeDateChange.emit(this._activeDate); + console.log('schedule in _dateBecomesActive', this._activeDate); + this._focusActiveCellAfterViewChecked(); + } + } + /** Handles keydown events on the calendar body when calendar is in month view. */ _handleCalendarBodyKeydown(event: KeyboardEvent): void { + console.log('_handleCalendarBodyKeydown', event.key); // TODO(mmalerba): We currently allow keyboard navigation to disabled dates, but just prevent // disabled ones from being selected. This may not be ideal, we should look into whether // navigation should skip over disabled dates, and if so, how to implement that efficiently. @@ -327,9 +347,10 @@ export class MatMonthView implements AfterContentInit, OnChanges, OnDestroy { if (this._dateAdapter.compareDate(oldActiveDate, this.activeDate)) { this.activeDateChange.emit(this.activeDate); + console.log('scheduling in keydown handler', this._activeDate); + this._focusActiveCellAfterViewChecked(); } - this._focusActiveCellAfterViewChecked(); // Prevent unexpected default actions such as form submission. event.preventDefault(); }