import { transition, trigger, useAnimation } from '@angular/animations';
import {
Component,
ContentChild,
forwardRef,
HostBinding,
HostListener,
Input,
ViewChild,
ElementRef,
AfterViewInit,
ViewChildren,
QueryList,
OnDestroy
} from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { fadeIn, scaleInCenter, slideInLeft, slideInRight } from '../animations/main';
import { IgxCalendarHeaderTemplateDirective, IgxCalendarSubheaderTemplateDirective, IgxCalendarScrollMonthDirective } from './calendar.directives';
import { ICalendarDate, IgxCalendarView, ScrollMonth, monthRange } from './calendar';
import { IgxMonthPickerBaseDirective } from './month-picker/month-picker-base';
import { IgxMonthsViewComponent } from './months-view/months-view.component';
import { IgxYearsViewComponent } from './years-view/years-view.component';
import { IgxDaysViewComponent } from './days-view/days-view.component';
import { interval, Subscription } from 'rxjs';
import { takeUntil, debounce, skipLast, switchMap } from 'rxjs/operators';
import { IViewChangingEventArgs } from './days-view/days-view.interface';
import { IgxMonthViewSlotsCalendar, IgxGetViewDateCalendar } from './months-view.pipe';
import { IgxIconComponent } from '../icon/icon.component';
import { NgIf, NgTemplateOutlet, NgStyle, NgFor, DatePipe } from '@angular/common';
let NEXT_ID = 0;
/**
* Calendar provides a way to display date information.
*
* @igxModule IgxCalendarModule
*
* @igxTheme igx-calendar-theme, igx-icon-theme
*
* @igxKeywords calendar, datepicker, schedule, date
*
* @igxGroup Scheduling
*
* @remarks
* The Ignite UI Calendar provides an easy way to display a calendar and allow users to select dates using single, multiple
* or range selection.
*
* @example:
* ```html
*
* ```
*/
@Component({
providers: [
{
multi: true,
provide: NG_VALUE_ACCESSOR,
useExisting: IgxCalendarComponent
}
],
animations: [
trigger('animateView', [
transition('void => 0', useAnimation(fadeIn)),
transition('void => *', useAnimation(scaleInCenter, {
params: {
duration: '.2s',
fromScale: .9
}
}))
]),
trigger('animateChange', [
transition('* => prev', useAnimation(slideInLeft, {
params: {
fromPosition: 'translateX(-30%)'
}
})),
transition('* => next', useAnimation(slideInRight, {
params: {
fromPosition: 'translateX(30%)'
}
}))
])
],
selector: 'igx-calendar',
templateUrl: 'calendar.component.html',
standalone: true,
imports: [NgIf, NgTemplateOutlet, IgxCalendarScrollMonthDirective, NgStyle, IgxIconComponent, NgFor, IgxDaysViewComponent, IgxMonthsViewComponent, IgxYearsViewComponent, DatePipe, IgxMonthViewSlotsCalendar, IgxGetViewDateCalendar]
})
export class IgxCalendarComponent extends IgxMonthPickerBaseDirective implements AfterViewInit, OnDestroy {
/**
* Sets/gets the `id` of the calendar.
*
* @remarks
* If not set, the `id` will have value `"igx-calendar-0"`.
*
* @example
* ```html
*
* ```
* @memberof IgxCalendarComponent
*/
@HostBinding('attr.id')
@Input()
public id = `igx-calendar-${NEXT_ID++}`;
/**
* Sets/gets whether the calendar has header.
* Default value is `true`.
*
* @example
* ```html
*
* ```
*/
@Input()
public hasHeader = true;
/**
* Sets/gets whether the calendar header will be in vertical position.
* Default value is `false`.
*
* @example
* ```html
*
* ```
*/
@Input()
public vertical = false;
/**
* Sets/gets the number of month views displayed.
* Default value is `1`.
*
* @example
* ```html
*
* ```
*/
@Input()
public get monthsViewNumber() {
return this._monthsViewNumber;
}
public set monthsViewNumber(val: number) {
if (val < 1 ) {
return;
}
this._monthsViewNumber = val;
}
/**
* Show/hide week numbers
*
* @example
* ```html
*
* ``
*/
@Input()
public showWeekNumbers = false;
/**
* Apply the different states for the transitions of animateChange
*
* @hidden
* @internal
*/
@Input()
public animationAction: any = '';
/**
* The default css class applied to the component.
*
* @hidden
* @internal
*/
@HostBinding('class.igx-calendar--vertical')
public get styleVerticalClass(): boolean {
return this.vertical;
}
/**
* The default css class applied to the component.
*
* @hidden
* @internal
*/
@HostBinding('class.igx-calendar')
public styleClass = true;
/**
* ViewChild that represents the months view.
*
* @hidden
* @internal
*/
@ViewChild('months', { read: IgxMonthsViewComponent })
public monthsView: IgxMonthsViewComponent;
/**
* Month button, that displays the months view.
*
* @hidden
* @internal
*/
@ViewChildren('monthsBtn')
public monthsBtns: QueryList;
/**
* ViewChild that represents the decade view.
*
* @hidden
* @internal
*/
@ViewChild('decade', { read: IgxYearsViewComponent })
public dacadeView: IgxYearsViewComponent;
/**
* ViewChild that represents the days view.
*
* @hidden
* @internal
*/
@ViewChild('days', { read: IgxDaysViewComponent })
public daysView: IgxDaysViewComponent;
/**
* ViewChildrenden representing all of the rendered days views.
*
* @hidden
* @internal
*/
@ViewChildren('days', { read: IgxDaysViewComponent })
public monthViews: QueryList;
/**
* Button for previous month.
*
* @hidden
* @internal
*/
@ViewChild('prevMonthBtn')
public prevMonthBtn: ElementRef;
/**
* Button for next month.
*
* @hidden
* @internal
*/
@ViewChild('nextMonthBtn')
public nextMonthBtn: ElementRef;
/**
* Denote if the year view is active.
*
* @hidden
* @internal
*/
public get isYearView(): boolean {
return this.activeView === IgxCalendarView.Year;
}
/**
* Gets the header template.
*
* @example
* ```typescript
* let headerTemplate = this.calendar.headerTeamplate;
* ```
* @memberof IgxCalendarComponent
*/
public get headerTemplate(): any {
if (this.headerTemplateDirective) {
return this.headerTemplateDirective.template;
}
return null;
}
/**
* Sets the header template.
*
* @example
* ```html
*
* ```
* @memberof IgxCalendarComponent
*/
public set headerTemplate(directive: any) {
this.headerTemplateDirective = directive;
}
/**
* Gets the subheader template.
*
* @example
* ```typescript
* let subheaderTemplate = this.calendar.subheaderTemplate;
* ```
*/
public get subheaderTemplate(): any {
if (this.subheaderTemplateDirective) {
return this.subheaderTemplateDirective.template;
}
return null;
}
/**
* Sets the subheader template.
*
* @example
* ```html
*
* ```
* @memberof IgxCalendarComponent
*/
public set subheaderTemplate(directive: any) {
this.subheaderTemplateDirective = directive;
}
/**
* Gets the context for the template marked with the `igxCalendarHeader` directive.
*
* @example
* ```typescript
* let headerContext = this.calendar.headerContext;
* ```
*/
public get headerContext() {
const date: Date = this.headerDate;
return this.generateContext(date);
}
/**
* Gets the context for the template marked with either `igxCalendarSubHeaderMonth`
* or `igxCalendarSubHeaderYear` directive.
*
* @example
* ```typescript
* let context = this.calendar.context;
* ```
*/
public get context() {
const date: Date = this.viewDate;
return this.generateContext(date);
}
/**
* Date displayed in header
*
* @hidden
* @internal
*/
public get headerDate(): Date {
return this.selectedDates ? this.selectedDates : new Date();
}
/**
* @hidden
* @internal
*/
@ContentChild(forwardRef(() => IgxCalendarHeaderTemplateDirective), { read: IgxCalendarHeaderTemplateDirective, static: true })
private headerTemplateDirective: IgxCalendarHeaderTemplateDirective;
/**
* @hidden
* @internal
*/
// eslint-disable-next-line max-len
@ContentChild(forwardRef(() => IgxCalendarSubheaderTemplateDirective), { read: IgxCalendarSubheaderTemplateDirective, static: true })
private subheaderTemplateDirective: IgxCalendarSubheaderTemplateDirective;
/**
* @hidden
* @internal
*/
public activeDate = new Date().toLocaleDateString();
/**
* Used to apply the active date when the calendar view is changed
*
* @hidden
* @internal
*/
public nextDate: Date;
/**
* Denote if the calendar view was changed with the keyboard
*
* @hidden
* @internal
*/
public isKeydownTrigger = false;
/**
* @hidden
* @internal
*/
public callback: (next) => void;
/**
* @hidden
* @internal
*/
private _monthsViewNumber = 1;
/**
* @hidden
* @internal
*/
private _monthViewsChanges$: Subscription;
/**
* Keyboard navigation of the calendar
*
* @hidden
* @internal
*/
@HostListener('keydown.pagedown', ['$event'])
@HostListener('keydown.pageup', ['$event'])
public onKeydownPageDown(event: KeyboardEvent) {
event.preventDefault();
if (!this.isDefaultView) {
return;
}
const isPageDown = event.key === 'PageDown';
const step = isPageDown ? 1 : -1;
let monthView = this.daysView as IgxDaysViewComponent;
let activeDate;
while (!activeDate && monthView) {
activeDate = monthView.dates.find((date) => date.nativeElement === document.activeElement);
monthView = monthView.nextMonthView;
}
if (activeDate) {
this.nextDate = new Date(activeDate.date.date);
let year = this.nextDate.getFullYear();
let month = this.nextDate.getMonth() + step;
if (isPageDown) {
if (month > 11) {
month = 0; year += step;
}
} else {
if (month < 0) {
month = 11; year += step;
}
}
const range = monthRange(this.nextDate.getFullYear(), month);
let day = this.nextDate.getDate();
if (day > range[1]) {
day = range[1];
}
this.nextDate.setDate(day);
this.nextDate.setMonth(month);
this.nextDate.setFullYear(year);
this.callback = (next) => {
monthView = this.daysView as IgxDaysViewComponent;
let dayItem;
while ((!dayItem && monthView) || (dayItem && !dayItem.isCurrentMonth)) {
dayItem = monthView.dates.find((d) => d.date.date.getTime() === next.getTime());
monthView = monthView.nextMonthView;
}
if (dayItem && dayItem.isFocusable) {
dayItem.nativeElement.focus();
}
};
}
if (isPageDown) {
if (event.repeat) {
requestAnimationFrame(() => this.nextMonth(true));
} else {
this.nextMonth(true);
}
} else {
if (event.repeat) {
requestAnimationFrame(() => this.previousMonth(true));
} else {
this.previousMonth(true);
}
}
}
/**
* Keyboard navigation of the calendar
*
* @hidden
* @internal
*/
@HostListener('keydown.shift.pageup', ['$event'])
@HostListener('keydown.shift.pagedown', ['$event'])
public onKeydownShiftPageUp(event: KeyboardEvent) {
event.preventDefault();
if (!this.isDefaultView) {
return;
}
const isPageDown = event.key === 'PageDown';
const step = isPageDown ? 1 : -1;
this.previousViewDate = this.viewDate;
this.viewDate = this.calendarModel.timedelta(this.viewDate, 'year', step);
this.animationAction = isPageDown ? ScrollMonth.NEXT : ScrollMonth.PREV;
this.isKeydownTrigger = true;
let monthView = this.daysView as IgxDaysViewComponent;
let activeDate;
while (!activeDate && monthView) {
activeDate = monthView.dates.find((date) => date.nativeElement === document.activeElement);
monthView = monthView.nextMonthView;
}
if (activeDate) {
this.nextDate = new Date(activeDate.date.date);
const year = this.nextDate.getFullYear() + step;
const range = monthRange(year, this.nextDate.getMonth());
let day = this.nextDate.getDate();
if (day > range[1]) {
day = range[1];
}
this.nextDate.setDate(day);
this.nextDate.setFullYear(year);
this.callback = (next) => {
monthView = this.daysView as IgxDaysViewComponent;
let dayItem;
while ((!dayItem && monthView) || (dayItem && !dayItem.isCurrentMonth)) {
dayItem = monthView.dates.find((d) => d.date.date.getTime() === next.getTime());
monthView = monthView.nextMonthView;
}
if (dayItem && dayItem.isFocusable) {
dayItem.nativeElement.focus();
}
};
}
}
/**
* Keyboard navigation of the calendar
*
* @hidden
* @internal
*/
@HostListener('keydown.home', ['$event'])
public onKeydownHome(event: KeyboardEvent) {
if (this.daysView) {
this.daysView.onKeydownHome(event);
}
}
/**
* Keyboard navigation of the calendar
*
* @hidden
* @internal
*/
@HostListener('keydown.end', ['$event'])
public onKeydownEnd(event: KeyboardEvent) {
if (this.daysView) {
this.daysView.onKeydownEnd(event);
}
}
/**
* Stop continuous navigation on mouseup event
*
* @hidden
* @internal
*/
@HostListener('document:mouseup', ['$event'])
public onMouseUp(event: KeyboardEvent) {
if (this.monthScrollDirection !== ScrollMonth.NONE) {
this.stopMonthScroll(event);
}
}
public ngAfterViewInit() {
this.setSiblingMonths(this.monthViews);
this._monthViewsChanges$ = this.monthViews.changes.subscribe(c => {
this.setSiblingMonths(c);
});
this.startMonthScroll$.pipe(
takeUntil(this.stopMonthScroll$),
switchMap(() => this.scrollMonth$.pipe(
skipLast(1),
debounce(() => interval(300)),
takeUntil(this.stopMonthScroll$)
))).subscribe(() => {
switch (this.monthScrollDirection) {
case ScrollMonth.PREV:
this.previousMonth();
break;
case ScrollMonth.NEXT:
this.nextMonth();
break;
case ScrollMonth.NONE:
default:
break;
}
});
}
/**
* Returns the locale representation of the month in the month view if enabled,
* otherwise returns the default `Date.getMonth()` value.
*
* @hidden
* @internal
*/
public formattedMonth(value: Date): string {
if (this.formatViews.month) {
return this.formatterMonth.format(value);
}
return `${value.getMonth()}`;
}
/**
* Change to previous month
*
* @hidden
* @internal
*/
public previousMonth(isKeydownTrigger = false) {
if (isKeydownTrigger && this.animationAction === ScrollMonth.NEXT) {
return;
}
this.previousViewDate = this.viewDate;
this.viewDate = this.calendarModel.getPrevMonth(this.viewDate);
this.animationAction = ScrollMonth.PREV;
this.isKeydownTrigger = isKeydownTrigger;
}
public suppressBlur() {
this.monthViews?.forEach(d => d.shouldResetDate = false);
if (this.daysView) {
this.daysView.shouldResetDate = false;
}
}
/**
* Change to next month
*
* @hidden
* @internal
*/
public nextMonth(isKeydownTrigger = false) {
if (isKeydownTrigger && this.animationAction === 'prev') {
return;
}
this.isKeydownTrigger = isKeydownTrigger;
this.previousViewDate = this.viewDate;
this.viewDate = this.calendarModel.getNextMonth(this.viewDate);
this.animationAction = ScrollMonth.NEXT;
}
/**
* Continious navigation through the previous months
*
* @hidden
* @internal
*/
public startPrevMonthScroll = (isKeydownTrigger = false) => {
this.startMonthScroll$.next();
this.monthScrollDirection = ScrollMonth.PREV;
this.animationAction = ScrollMonth.PREV;
this.previousMonth(isKeydownTrigger);
};
/**
* Continious navigation through the next months
*
* @hidden
* @internal
*/
public startNextMonthScroll = (isKeydownTrigger = false) => {
this.startMonthScroll$.next();
this.monthScrollDirection = ScrollMonth.NEXT;
this.animationAction = ScrollMonth.NEXT;
this.nextMonth(isKeydownTrigger);
};
/**
* Stop continuous navigation
*
* @hidden
* @internal
*/
public stopMonthScroll = (event: KeyboardEvent) => {
event.stopPropagation();
// generally the scrolling is built on the calendar component
// and all start/stop scrolling methods are called on the calendar
// if we change below lines to call stopMonthScroll$ on the calendar instead of on the views,
// strange bug is introduced --> after changing number of months, continuous scrolling on mouse click does not happen
this.daysView.stopMonthScroll$.next(true);
this.daysView.stopMonthScroll$.complete();
if (this.monthScrollDirection === ScrollMonth.PREV) {
this.prevMonthBtn.nativeElement.focus();
} else if (this.monthScrollDirection === ScrollMonth.NEXT) {
this.nextMonthBtn.nativeElement.focus();
}
if (this.platform.isActivationKey(event)) {
this.resetActiveDate();
}
this.monthScrollDirection = ScrollMonth.NONE;
};
/**
* @hidden
* @internal
*/
public onActiveViewDecade(args: Date, activeViewIdx: number) {
super.activeViewDecade(activeViewIdx);
requestAnimationFrame(() => {
if (this.dacadeView) {
this.dacadeView.date = args;
this.dacadeView.calendarDir.find(date => date.isCurrentYear).nativeElement.focus();
}
});
}
/**
* @hidden
* @internal
*/
public onActiveViewDecadeKB(event, args: Date, activeViewIdx: number) {
super.activeViewDecadeKB(event, activeViewIdx);
requestAnimationFrame(() => {
if (this.dacadeView) {
this.dacadeView.date = args;
this.dacadeView.calendarDir.find(date => date.isCurrentYear).nativeElement.focus();
}
});
}
/**
* @hidden
* @internal
*/
public getFormattedDate(): { weekday: string; monthday: string } {
const date = this.headerDate;
return {
monthday: this.formatterMonthday.format(date),
weekday: this.formatterWeekday.format(date),
};
}
/**
* Handles invoked on date selection
*
* @hidden
* @internal
*/
public childClicked(instance: ICalendarDate) {
if (instance.isPrevMonth) {
this.previousMonth();
}
if (instance.isNextMonth) {
this.nextMonth();
}
// selectDateFromClient is called both here and in days-view.component
// when multiple months are in view, 'shiftKey' and 'lastSelectedDate'
// should be set before and after selectDateFromClient
// in order all views to have the same values for these properties
this.monthViews.forEach(m => {
m.shiftKey = this.shiftKey;
m.lastSelectedDate = this.lastSelectedDate;
});
this.selectDateFromClient(instance.date);
if (this.selection === 'multi' && this._deselectDate) {
this.deselectDateInMonthViews(instance.date);
}
this.selected.emit(this.selectedDates);
this.monthViews.forEach(m => {
m.shiftKey = this.shiftKey;
m.lastSelectedDate = this.lastSelectedDate;
});
}
/**
* @hidden
* @internal
*/
public viewChanging(args: IViewChangingEventArgs) {
this.animationAction = args.monthAction;
this.isKeydownTrigger = true;
this.nextDate = args.nextDate;
this.callback = (next) => {
const day = this.daysView.dates.find((item) => item.date.date.getTime() === next.getTime());
if (day) {
this.daysView.daysNavService.focusNextDate(day.nativeElement, args.key, true);
}
};
this.previousViewDate = this.viewDate;
this.viewDate = this.nextDate;
}
/**
* @hidden
* @intenal
*/
public changeMonth(event: Date) {
this.previousViewDate = this.viewDate;
this.viewDate = this.calendarModel.getFirstViewDate(event, 'month', this.activeViewIdx);
this.activeView = IgxCalendarView.Month;
requestAnimationFrame(() => {
const elem = this.monthsBtns.find((e: ElementRef, idx: number) => idx === this.activeViewIdx);
if (elem) {
elem.nativeElement.focus();
}
});
}
/**
* @hidden
* @internal
*/
public onActiveViewYear(args: Date, activeViewIdx: number): void {
this.activeView = IgxCalendarView.Year;
this.activeViewIdx = activeViewIdx;
requestAnimationFrame(() => {
this.monthsView.date = args;
this.focusMonth();
});
}
/**
* @hidden
* @internal
*/
public onActiveViewYearKB(args: Date, event: KeyboardEvent, activeViewIdx: number): void {
if (this.platform.isActivationKey(event)) {
event.preventDefault();
this.onActiveViewYear(args, activeViewIdx);
}
}
/**
* Deselects date(s) (based on the selection type).
*
* @example
* ```typescript
* this.calendar.deselectDate(new Date(`2018-06-12`));
* ````
*/
public override deselectDate(value?: Date | Date[]) {
super.deselectDate(value);
this.monthViews.forEach((view) => {
view.selectedDates = this.selectedDates;
view.rangeStarted = false;
});
this._onChangeCallback(this.selectedDates);
}
/**
* @hidden
* @internal
*/
public getViewDate(i: number): Date {
const date = this.calendarModel.timedelta(this.viewDate, 'month', i);
return date;
}
/**
* Getter for the context object inside the calendar templates.
*
* @hidden
* @internal
*/
public getContext(i: number) {
const date = this.getViewDate(i);
return this.generateContext(date, i);
}
/**
* @hidden
* @internal
*/
public animationDone(event) {
if ((event.fromState === ScrollMonth.NONE && (event.toState === ScrollMonth.PREV || event.toState === ScrollMonth.NEXT)) ||
(event.fromState === 'void' && event.toState === ScrollMonth.NONE)) {
this.viewDateChanged.emit({ previousValue: this.previousViewDate, currentValue: this.viewDate });
}
if (!this.isKeydownTrigger) {
this.resetActiveDate();
}
if (this.monthScrollDirection !== ScrollMonth.NONE) {
this.scrollMonth$.next();
}
if (!this.isDefaultView) {
return;
}
let monthView = this.daysView as IgxDaysViewComponent;
let date = monthView?.dates.find((d) => d.selected);
while (!date && monthView?.nextMonthView) {
monthView = monthView.nextMonthView;
date = monthView.dates.find((d) => d.selected);
}
if (date && date.isFocusable && !this.isKeydownTrigger) {
setTimeout(() => {
date.nativeElement.focus();
}, parseInt(slideInRight.options.params.duration, 10));
} else if (this.callback && (event.toState === ScrollMonth.NEXT || event.toState === ScrollMonth.PREV)) {
this.callback(this.nextDate);
}
this.animationAction = ScrollMonth.NONE;
}
/**
* @hidden
* @internal
*/
public viewRendered(event) {
if (event.fromState !== 'void') {
this.activeViewChanged.emit(this.activeView);
if (this.isDefaultView) {
this.resetActiveDate();
}
}
}
/**
* @hidden
* @internal
*/
public resetActiveDate() {
if (!this.monthViews) {
return;
}
let dates = [];
this.monthViews.map(mv => mv.dates).forEach(days => {
dates = dates.concat(days.toArray());
});
const date = dates.find(day => day.selected && day.isCurrentMonth) || dates.find(day => day.isToday && day.isCurrentMonth)
|| dates.find(d => d.isFocusable);
if (date) {
this.activeDate = date.date.date.toLocaleDateString();
}
}
/**
* @hidden
* @internal
*/
public ngOnDestroy(): void {
if (this._monthViewsChanges$) {
this._monthViewsChanges$.unsubscribe();
}
}
/**
* @hidden
* @internal
*/
public getPrevMonth(date): Date {
return this.calendarModel.getPrevMonth(date);
}
/**
* @hidden
* @internal
*/
public getNextMonth(date, viewIndex): Date {
return this.calendarModel.getDateByView(date, 'Month', viewIndex);
}
/**
* Helper method building and returning the context object inside
* the calendar templates.
*
* @hidden
* @internal
*/
private generateContext(value: Date, i?: number) {
const formatObject = {
index: i,
monthView: () => this.onActiveViewYear(value, i),
yearView: () => this.onActiveViewDecade(value, i),
...this.calendarModel.formatToParts(value, this.locale, this.formatOptions,
['era', 'year', 'month', 'day', 'weekday'])
};
return { $implicit: formatObject };
}
/**
* Helper method that sets references for prev/next months for each month in the view
*
* @hidden
* @internal
*/
private setSiblingMonths(monthViews: QueryList) {
monthViews.forEach((item, index) => {
const prevMonthView = this.getMonthView(index - 1);
const nextMonthView = this.getMonthView(index + 1);
item.nextMonthView = nextMonthView;
item.prevMonthView = prevMonthView;
});
}
/**
* Helper method returning previous/next day views
*
* @hidden
* @internal
*/
private getMonthView(index: number): IgxDaysViewComponent {
if (index === -1 || index === this.monthViews.length ) {
return null;
} else {
return this.monthViews.toArray()[index];
}
}
/**
* Helper method that does deselection for all month views when selection is "multi"
* If not called, selection in other month views stays
*
* @hidden
* @internal
*/
private deselectDateInMonthViews(value: Date) {
this.monthViews.forEach(m => {
m.deselectMultipleInMonth(value);
});
}
private focusMonth() {
const month = this.monthsView.monthsRef.find((e) =>
e.index === this.monthsView.date.getMonth());
if (month) {
month.nativeElement.focus();
}
}
}