@ng-matero/extensions
Version:
Angular Material Extensions
622 lines • 136 kB
JavaScript
import { DOWN_ARROW, END, ENTER, HOME, LEFT_ARROW, PAGE_DOWN, PAGE_UP, RIGHT_ARROW, UP_ARROW, } from '@angular/cdk/keycodes';
import { CdkPortalOutlet, ComponentPortal, } from '@angular/cdk/portal';
import { ChangeDetectionStrategy, Component, EventEmitter, Inject, Injector, Input, Optional, Output, ViewEncapsulation, afterNextRender, booleanAttribute, inject, } from '@angular/core';
import { MatButton, MatIconButton } from '@angular/material/button';
import { MTX_DATETIME_FORMATS, } from '@ng-matero/extensions/core';
import { MtxClock } from './clock';
import { mtxDatetimepickerAnimations } from './datetimepicker-animations';
import { createMissingDateImplError } from './datetimepicker-errors';
import { MtxDatetimepickerFilterType } from './datetimepicker-filtertype';
import { MtxMonthView } from './month-view';
import { MtxMultiYearView, getActiveOffset, isSameMultiYearView, yearsPerPage, yearsPerRow, } from './multi-year-view';
import { MtxTime } from './time';
import { MtxYearView } from './year-view';
import * as i0 from "@angular/core";
import * as i1 from "./datetimepicker-intl";
import * as i2 from "@ng-matero/extensions/core";
/**
* A calendar that is used as part of the datetimepicker.
* @docs-private
*/
export class MtxCalendar {
constructor(_elementRef, _intl, _ngZone, _adapter, _dateFormats, _changeDetectorRef) {
this._elementRef = _elementRef;
this._intl = _intl;
this._ngZone = _ngZone;
this._adapter = _adapter;
this._dateFormats = _dateFormats;
/** Whether to show multi-year view. */
this.multiYearSelector = false;
/** Whether the clock uses 12 hour format. */
this.twelvehour = false;
/** Whether the calendar should be started in month or year view. */
this.startView = 'month';
/** Step over minutes. */
this.timeInterval = 1;
/** Prevent user to select same date time */
this.preventSameDateTimeSelection = false;
/** Input for action buttons. */
this.actionsPortal = null;
/** Emits when the currently selected date changes. */
this.selectedChange = new EventEmitter();
/** Emits when the view has been changed. */
this.viewChanged = new EventEmitter();
this._userSelection = new EventEmitter();
this._clockView = 'hour';
this._injector = inject(Injector);
this._type = 'date';
/**
* Whether the calendar is in time mode. In time mode the calendar clock gets time input elements
* rather then just clock. When touchUi is enabled this will be disabled
*/
this.timeInput = false;
/** Date filter for the month and year views. */
this._dateFilterForViews = (date) => {
return (!!date &&
(!this.dateFilter || this.dateFilter(date, MtxDatetimepickerFilterType.DATE)) &&
(!this.minDate || this._adapter.compareDate(date, this.minDate) >= 0) &&
(!this.maxDate || this._adapter.compareDate(date, this.maxDate) <= 0));
};
if (!this._adapter) {
throw createMissingDateImplError('DatetimeAdapter');
}
if (!this._dateFormats) {
throw createMissingDateImplError('MTX_DATETIME_FORMATS');
}
this._intlChanges = _intl.changes.subscribe(() => _changeDetectorRef.markForCheck());
}
/** The display type of datetimepicker. */
get type() {
return this._type;
}
set type(value) {
this._type = value || 'date';
if (this.type === 'year') {
this.multiYearSelector = true;
}
}
/** A date representing the period (month or year) to start the calendar in. */
get startAt() {
return this._startAt;
}
set startAt(value) {
this._startAt = this._adapter.getValidDateOrNull(value);
}
/** The currently selected date. */
get selected() {
return this._selected;
}
set selected(value) {
this._selected = this._adapter.getValidDateOrNull(value);
}
/** The minimum selectable date. */
get minDate() {
return this._minDate;
}
set minDate(value) {
this._minDate = this._adapter.getValidDateOrNull(value);
}
/** The maximum selectable date. */
get maxDate() {
return this._maxDate;
}
set maxDate(value) {
this._maxDate = this._adapter.getValidDateOrNull(value);
}
/**
* The current active date. This determines which time period is shown and which date is
* highlighted when using keyboard navigation.
*/
get _activeDate() {
return this._clampedActiveDate;
}
set _activeDate(value) {
const oldActiveDate = this._clampedActiveDate;
this._clampedActiveDate = this._adapter.clampDate(value, this.minDate, this.maxDate);
// whenever active date changed, and possibly got clamped we should adjust the am/pm setting
this._selectAMPM(this._clampedActiveDate);
if (oldActiveDate &&
this._clampedActiveDate &&
this.currentView === 'month' &&
!this._adapter.sameMonthAndYear(oldActiveDate, this._clampedActiveDate)) {
if (this._adapter.isInNextMonth(oldActiveDate, this._clampedActiveDate)) {
this.calendarState('right');
}
else {
this.calendarState('left');
}
}
}
/** Whether the calendar is in month view. */
get currentView() {
return this._currentView;
}
set currentView(view) {
this._currentView = view;
this.viewChanged.emit(view);
}
get _yearPeriodText() {
if (this.currentView === 'multi-year') {
// The offset from the active year to the "slot" for the starting year is the
// *actual* first rendered year in the multi-year view, and the last year is
// just yearsPerPage - 1 away.
const activeYear = this._adapter.getYear(this._activeDate);
const minYearOfPage = activeYear - getActiveOffset(this._adapter, this._activeDate, this.minDate, this.maxDate);
const maxYearOfPage = minYearOfPage + yearsPerPage - 1;
const minYearName = this._adapter.getYearName(this._adapter.createDate(minYearOfPage, 0, 1));
const maxYearName = this._adapter.getYearName(this._adapter.createDate(maxYearOfPage, 0, 1));
return this._intl.formatYearRange(minYearName, maxYearName);
}
return this.currentView === 'month'
? this._adapter.getMonthNames('long')[this._adapter.getMonth(this._activeDate)]
: this._adapter.getYearName(this._activeDate);
}
get _yearButtonText() {
return this._adapter.getYearName(this._activeDate);
}
get _yearButtonLabel() {
return this.multiYearSelector
? this._intl.switchToMultiYearViewLabel
: this._intl.switchToYearViewLabel;
}
get _dateButtonText() {
switch (this.type) {
case 'month':
return this._adapter.getMonthNames('long')[this._adapter.getMonth(this._activeDate)];
default:
return this._adapter.format(this._activeDate, this._dateFormats.display.popupHeaderDateLabel);
}
}
get _dateButtonLabel() {
return this._intl.switchToMonthViewLabel;
}
get _hoursButtonText() {
let hour = this._adapter.getHour(this._activeDate);
if (this.twelvehour) {
if (hour === 0) {
hour = 24;
}
hour = hour > 12 ? hour - 12 : hour;
}
return this._2digit(hour);
}
get _hourButtonLabel() {
return this._intl.switchToClockHourViewLabel;
}
get _minutesButtonText() {
return this._2digit(this._adapter.getMinute(this._activeDate));
}
get _minuteButtonLabel() {
return this._intl.switchToClockMinuteViewLabel;
}
get _prevButtonLabel() {
switch (this._currentView) {
case 'month':
return this._intl.prevMonthLabel;
case 'year':
return this._intl.prevYearLabel;
case 'multi-year':
return this._intl.prevMultiYearLabel;
default:
return '';
}
}
get _nextButtonLabel() {
switch (this._currentView) {
case 'month':
return this._intl.nextMonthLabel;
case 'year':
return this._intl.nextYearLabel;
case 'multi-year':
return this._intl.nextMultiYearLabel;
default:
return '';
}
}
_userSelected() {
this._userSelection.emit();
}
ngAfterContentInit() {
if (this.headerComponent) {
this._calendarHeaderPortal = new ComponentPortal(this.headerComponent);
}
this._activeDate = this.startAt || this._adapter.today();
this._selectAMPM(this._activeDate);
if (this.type === 'year') {
this.currentView = 'multi-year';
}
else if (this.type === 'month') {
this.currentView = 'year';
}
else if (this.type === 'time') {
this.currentView = 'clock';
}
else {
this.currentView = this.startView || 'month';
}
}
ngOnDestroy() {
this._intlChanges.unsubscribe();
}
/** Handles date selection in the month view. */
_dateSelected(date) {
if (this.type === 'date') {
if (!this._adapter.sameDate(date, this.selected) || !this.preventSameDateTimeSelection) {
this.selectedChange.emit(date);
}
}
else {
this.selectedChange.emit(date);
this._activeDate = date;
this.currentView = 'clock';
}
}
/** Handles month selection in the year view. */
_monthSelected(month) {
if (this.type === 'month') {
if (!this._adapter.sameMonthAndYear(month, this.selected) ||
!this.preventSameDateTimeSelection) {
this.selectedChange.emit(this._adapter.getFirstDateOfMonth(month));
}
}
else {
this._activeDate = month;
this.currentView = 'month';
this._clockView = 'hour';
}
}
/** Handles year selection in the multi year view. */
_yearSelected(year) {
if (this.type === 'year') {
if (!this._adapter.sameYear(year, this.selected) || !this.preventSameDateTimeSelection) {
const normalizedDate = this._adapter.createDatetime(this._adapter.getYear(year), 0, 1, 0, 0);
this.selectedChange.emit(normalizedDate);
}
}
else {
this._activeDate = year;
this.currentView = 'year';
}
}
_timeSelected(date) {
this._activeDate = this._updateDate(date);
if (!this._adapter.sameDatetime(date, this.selected) || !this.preventSameDateTimeSelection) {
this.selectedChange.emit(date);
}
}
_dialTimeSelected(date) {
if (this._clockView !== 'minute') {
this._activeDate = this._updateDate(date);
this._clockView = 'minute';
}
else {
if (!this._adapter.sameDatetime(date, this.selected) || !this.preventSameDateTimeSelection) {
this.selectedChange.emit(date);
}
}
}
_onActiveDateChange(date) {
this._activeDate = date;
}
_updateDate(date) {
if (this.twelvehour) {
const HOUR = this._adapter.getHour(date);
if (HOUR === 12) {
if (this._AMPM === 'AM') {
return this._adapter.addCalendarHours(date, -12);
}
}
else if (this._AMPM === 'PM') {
return this._adapter.addCalendarHours(date, 12);
}
}
return date;
}
_selectAMPM(date) {
const hour = this._adapter.getHour(date);
if (hour > 11) {
this._AMPM = 'PM';
}
else {
this._AMPM = 'AM';
}
}
_ampmClicked(source) {
this._currentView = 'clock';
if (source === this._AMPM) {
return;
}
// if AMPM changed from PM to AM substract 12 hours
const currentHour = this._adapter.getHour(this._activeDate);
let newHourValue;
if (source === 'AM') {
newHourValue = currentHour >= 12 ? this._adapter.getHour(this._activeDate) - 12 : 12;
}
// otherwise add 12 hours
else {
newHourValue = (currentHour + 12) % 24;
}
const newActiveDate = this._adapter.clampDate(this._adapter.createDatetime(this._adapter.getYear(this._activeDate), this._adapter.getMonth(this._activeDate), this._adapter.getDate(this._activeDate), newHourValue, this._adapter.getMinute(this._activeDate)), this.minDate, this.maxDate);
// only if our clamped date is not changed, we know we can apply the newActiveDate to the
// activeDate
if (this._adapter.getHour(newActiveDate) === newHourValue) {
this._activeDate = newActiveDate;
this._AMPM = source;
}
}
_yearClicked() {
if (this.type === 'year' || this.multiYearSelector) {
this.currentView = 'multi-year';
return;
}
this.currentView = 'year';
}
_dateClicked() {
if (this.type !== 'month') {
this.currentView = 'month';
}
}
_hoursClicked() {
this.currentView = 'clock';
this._clockView = 'hour';
}
_minutesClicked() {
this.currentView = 'clock';
this._clockView = 'minute';
}
/** Handles user clicks on the previous button. */
_previousClicked() {
this._activeDate =
this.currentView === 'month'
? this._adapter.addCalendarMonths(this._activeDate, -1)
: this._adapter.addCalendarYears(this._activeDate, this.currentView === 'year' ? -1 : -yearsPerPage);
}
/** Handles user clicks on the next button. */
_nextClicked() {
this._activeDate =
this.currentView === 'month'
? this._adapter.addCalendarMonths(this._activeDate, 1)
: this._adapter.addCalendarYears(this._activeDate, this.currentView === 'year' ? 1 : yearsPerPage);
}
/** Whether the previous period button is enabled. */
_previousEnabled() {
if (!this.minDate) {
return true;
}
return !this.minDate || !this._isSameView(this._activeDate, this.minDate);
}
/** Whether the next period button is enabled. */
_nextEnabled() {
return !this.maxDate || !this._isSameView(this._activeDate, this.maxDate);
}
/** Handles keydown events on the calendar body. */
_handleCalendarBodyKeydown(event) {
// 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.
if (this.currentView === 'month') {
this._handleCalendarBodyKeydownInMonthView(event);
}
else if (this.currentView === 'year') {
this._handleCalendarBodyKeydownInYearView(event);
}
else if (this.currentView === 'multi-year') {
this._handleCalendarBodyKeydownInMultiYearView(event);
}
else {
this._handleCalendarBodyKeydownInClockView(event);
}
}
_focusActiveCell() {
afterNextRender(() => {
this._elementRef.nativeElement.focus();
}, { injector: this._injector });
}
_calendarStateDone() {
this._calendarState = '';
}
/** Whether the two dates represent the same view in the current view mode (month or year). */
_isSameView(date1, date2) {
if (this.currentView === 'month') {
return (this._adapter.getYear(date1) === this._adapter.getYear(date2) &&
this._adapter.getMonth(date1) === this._adapter.getMonth(date2));
}
if (this.currentView === 'year') {
return this._adapter.getYear(date1) === this._adapter.getYear(date2);
}
// Otherwise we are in 'multi-year' view.
return isSameMultiYearView(this._adapter, date1, date2, this.minDate, this.maxDate);
}
/** Handles keydown events on the calendar body when calendar is in month view. */
_handleCalendarBodyKeydownInMonthView(event) {
switch (event.keyCode) {
case LEFT_ARROW:
this._activeDate = this._adapter.addCalendarDays(this._activeDate, -1);
break;
case RIGHT_ARROW:
this._activeDate = this._adapter.addCalendarDays(this._activeDate, 1);
break;
case UP_ARROW:
this._activeDate = this._adapter.addCalendarDays(this._activeDate, -7);
break;
case DOWN_ARROW:
this._activeDate = this._adapter.addCalendarDays(this._activeDate, 7);
break;
case HOME:
this._activeDate = this._adapter.addCalendarDays(this._activeDate, 1 - this._adapter.getDate(this._activeDate));
break;
case END:
this._activeDate = this._adapter.addCalendarDays(this._activeDate, this._adapter.getNumDaysInMonth(this._activeDate) -
this._adapter.getDate(this._activeDate));
break;
case PAGE_UP:
this._activeDate = event.altKey
? this._adapter.addCalendarYears(this._activeDate, -1)
: this._adapter.addCalendarMonths(this._activeDate, -1);
break;
case PAGE_DOWN:
this._activeDate = event.altKey
? this._adapter.addCalendarYears(this._activeDate, 1)
: this._adapter.addCalendarMonths(this._activeDate, 1);
break;
case ENTER:
if (this._dateFilterForViews(this._activeDate)) {
this._dateSelected(this._activeDate);
// Prevent unexpected default actions such as form submission.
event.preventDefault();
}
return;
default:
// Don't prevent default or focus active cell on keys that we don't explicitly handle.
return;
}
// Prevent unexpected default actions such as form submission.
event.preventDefault();
}
/** Handles keydown events on the calendar body when calendar is in year view. */
_handleCalendarBodyKeydownInYearView(event) {
switch (event.keyCode) {
case LEFT_ARROW:
this._activeDate = this._adapter.addCalendarMonths(this._activeDate, -1);
break;
case RIGHT_ARROW:
this._activeDate = this._adapter.addCalendarMonths(this._activeDate, 1);
break;
case UP_ARROW:
this._activeDate = this._prevMonthInSameCol(this._activeDate);
break;
case DOWN_ARROW:
this._activeDate = this._nextMonthInSameCol(this._activeDate);
break;
case HOME:
this._activeDate = this._adapter.addCalendarMonths(this._activeDate, -this._adapter.getMonth(this._activeDate));
break;
case END:
this._activeDate = this._adapter.addCalendarMonths(this._activeDate, 11 - this._adapter.getMonth(this._activeDate));
break;
case PAGE_UP:
this._activeDate = this._adapter.addCalendarYears(this._activeDate, event.altKey ? -10 : -1);
break;
case PAGE_DOWN:
this._activeDate = this._adapter.addCalendarYears(this._activeDate, event.altKey ? 10 : 1);
break;
case ENTER:
this._monthSelected(this._activeDate);
break;
default:
// Don't prevent default or focus active cell on keys that we don't explicitly handle.
return;
}
// Prevent unexpected default actions such as form submission.
event.preventDefault();
}
/** Handles keydown events on the calendar body when calendar is in multi-year view. */
_handleCalendarBodyKeydownInMultiYearView(event) {
switch (event.keyCode) {
case LEFT_ARROW:
this._activeDate = this._adapter.addCalendarYears(this._activeDate, -1);
break;
case RIGHT_ARROW:
this._activeDate = this._adapter.addCalendarYears(this._activeDate, 1);
break;
case UP_ARROW:
this._activeDate = this._adapter.addCalendarYears(this._activeDate, -yearsPerRow);
break;
case DOWN_ARROW:
this._activeDate = this._adapter.addCalendarYears(this._activeDate, yearsPerRow);
break;
case HOME:
this._activeDate = this._adapter.addCalendarYears(this._activeDate, -getActiveOffset(this._adapter, this._activeDate, this.minDate, this.maxDate));
break;
case END:
this._activeDate = this._adapter.addCalendarYears(this._activeDate, yearsPerPage -
getActiveOffset(this._adapter, this._activeDate, this.minDate, this.maxDate) -
1);
break;
case PAGE_UP:
this._activeDate = this._adapter.addCalendarYears(this._activeDate, event.altKey ? -yearsPerPage * 10 : -yearsPerPage);
break;
case PAGE_DOWN:
this._activeDate = this._adapter.addCalendarYears(this._activeDate, event.altKey ? yearsPerPage * 10 : yearsPerPage);
break;
case ENTER:
this._yearSelected(this._activeDate);
break;
default:
// Don't prevent default or focus active cell on keys that we don't explicitly handle.
return;
}
}
/** Handles keydown events on the calendar body when calendar is in month view. */
_handleCalendarBodyKeydownInClockView(event) {
switch (event.keyCode) {
case UP_ARROW:
this._activeDate =
this._clockView === 'hour'
? this._adapter.addCalendarHours(this._activeDate, 1)
: this._adapter.addCalendarMinutes(this._activeDate, this.timeInterval);
break;
case DOWN_ARROW:
this._activeDate =
this._clockView === 'hour'
? this._adapter.addCalendarHours(this._activeDate, -1)
: this._adapter.addCalendarMinutes(this._activeDate, -this.timeInterval);
break;
case ENTER:
if (!this.timeInput) {
this._dialTimeSelected(this._activeDate);
}
return;
default:
// Don't prevent default or focus active cell on keys that we don't explicitly handle.
return;
}
// Prevent unexpected default actions such as form submission.
event.preventDefault();
}
/**
* Determine the date for the month that comes before the given month in the same column in the
* calendar table.
*/
_prevMonthInSameCol(date) {
// Determine how many months to jump forward given that there are 2 empty slots at the beginning
// of each year.
const increment = this._adapter.getMonth(date) <= 4 ? -5 : this._adapter.getMonth(date) >= 7 ? -7 : -12;
return this._adapter.addCalendarMonths(date, increment);
}
/**
* Determine the date for the month that comes after the given month in the same column in the
* calendar table.
*/
_nextMonthInSameCol(date) {
// Determine how many months to jump forward given that there are 2 empty slots at the beginning
// of each year.
const increment = this._adapter.getMonth(date) <= 4 ? 7 : this._adapter.getMonth(date) >= 7 ? 5 : 12;
return this._adapter.addCalendarMonths(date, increment);
}
calendarState(direction) {
this._calendarState = direction;
}
_2digit(n) {
return ('00' + n).slice(-2);
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.0", ngImport: i0, type: MtxCalendar, deps: [{ token: i0.ElementRef }, { token: i1.MtxDatetimepickerIntl }, { token: i0.NgZone }, { token: i2.DatetimeAdapter, optional: true }, { token: MTX_DATETIME_FORMATS, optional: true }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
/** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.0", type: MtxCalendar, isStandalone: true, selector: "mtx-calendar", inputs: { multiYearSelector: ["multiYearSelector", "multiYearSelector", booleanAttribute], twelvehour: ["twelvehour", "twelvehour", booleanAttribute], startView: "startView", timeInterval: "timeInterval", dateFilter: "dateFilter", preventSameDateTimeSelection: "preventSameDateTimeSelection", headerComponent: "headerComponent", actionsPortal: "actionsPortal", type: "type", startAt: "startAt", timeInput: ["timeInput", "timeInput", booleanAttribute], selected: "selected", minDate: "minDate", maxDate: "maxDate" }, outputs: { selectedChange: "selectedChange", viewChanged: "viewChanged", _userSelection: "_userSelection" }, host: { attributes: { "tabindex": "0" }, listeners: { "keydown": "_handleCalendarBodyKeydown($event)" }, properties: { "class.mtx-calendar-with-time-input": "timeInput" }, classAttribute: "mtx-calendar" }, exportAs: ["mtxCalendar"], ngImport: i0, template: "<div class=\"mtx-calendar-header\">\n @if (_calendarHeaderPortal) {\n <ng-template [cdkPortalOutlet]=\"_calendarHeaderPortal\"></ng-template>\n } @else {\n @if (type !== 'time') {\n <button\n mat-button type=\"button\" class=\"mtx-calendar-header-year\"\n [class.active]=\"currentView === 'year' || currentView === 'multi-year'\"\n [attr.aria-label]=\"_yearButtonLabel\"\n (click)=\"_yearClicked()\">\n <span>{{ _yearButtonText }}</span>\n @if (multiYearSelector || type === 'year') {\n <svg\n class=\"mtx-calendar-header-year-dropdown\" matButtonIcon iconPositionEnd\n width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M7,10L12,15L17,10H7Z\" />\n </svg>\n }\n </button>\n }\n @if (type !== 'year') {\n <div class=\"mtx-calendar-header-date-time\">\n @if (type !== 'time') {\n <button\n mat-button type=\"button\" class=\"mtx-calendar-header-date\"\n [class.active]=\"currentView === 'month'\"\n [class.not-clickable]=\"type === 'month'\"\n [attr.aria-label]=\"_dateButtonLabel\"\n (click)=\"_dateClicked()\">{{ _dateButtonText }}</button>\n }\n @if (type.endsWith('time')) {\n <span class=\"mtx-calendar-header-time\" [class.active]=\"currentView === 'clock'\">\n <span class=\"mtx-calendar-header-hour-minute-container\">\n <button mat-button type=\"button\" class=\"mtx-calendar-header-hours\"\n [class.active]=\"_clockView === 'hour'\"\n [attr.aria-label]=\"_hourButtonLabel\"\n (click)=\"_hoursClicked()\">{{ _hoursButtonText }}</button>\n <span class=\"mtx-calendar-header-hour-minute-separator\">:</span>\n <button mat-button type=\"button\" class=\"mtx-calendar-header-minutes\"\n [class.active]=\"_clockView === 'minute'\"\n [attr.aria-label]=\"_minuteButtonLabel\"\n (click)=\"_minutesClicked()\">{{ _minutesButtonText }}</button>\n </span>\n @if (twelvehour) {\n <span class=\"mtx-calendar-header-ampm-container\">\n <button mat-button type=\"button\" class=\"mtx-calendar-header-ampm\"\n [class.active]=\"_AMPM === 'AM'\" aria-label=\"AM\"\n (click)=\"_ampmClicked('AM')\">AM</button>\n <button mat-button type=\"button\" class=\"mtx-calendar-header-ampm\"\n [class.active]=\"_AMPM === 'PM'\" aria-label=\"PM\"\n (click)=\"_ampmClicked('PM')\">PM</button>\n </span>\n }\n </span>\n }\n </div>\n }\n }\n</div>\n\n<div class=\"mtx-calendar-content\">\n @if (currentView === 'month' || currentView === 'year' || currentView === 'multi-year') {\n <div class=\"mtx-month-content\">\n <div class=\"mtx-calendar-controls\">\n <button mat-icon-button type=\"button\"\n class=\"mtx-calendar-previous-button\"\n [class.disabled]=\"!_previousEnabled()\"\n [attr.aria-disabled]=\"!_previousEnabled()\"\n [attr.aria-label]=\"_prevButtonLabel\"\n (click)=\"_previousClicked()\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\">\n <path d=\"M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z\" />\n </svg>\n </button>\n <div class=\"mtx-calendar-period-button\"\n [@slideCalendar]=\"_calendarState\"\n (@slideCalendar.done)=\"_calendarStateDone()\">\n <strong>{{ _yearPeriodText }}</strong>\n </div>\n <button mat-icon-button type=\"button\"\n class=\"mtx-calendar-next-button\"\n [class.disabled]=\"!_nextEnabled()\"\n [attr.aria-disabled]=\"!_nextEnabled()\"\n [attr.aria-label]=\"_nextButtonLabel\"\n (click)=\"_nextClicked()\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\">\n <path d=\"M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z\" />\n </svg>\n </button>\n </div>\n </div>\n }\n\n @switch (currentView) {\n @case ('month') {\n <mtx-month-view\n (_userSelection)=\"_userSelected()\"\n (selectedChange)=\"_dateSelected($event)\"\n [activeDate]=\"_activeDate\"\n [dateFilter]=\"_dateFilterForViews\"\n [selected]=\"selected!\"\n [type]=\"type\">\n </mtx-month-view>\n }\n @case ('year') {\n <mtx-year-view\n (_userSelection)=\"_userSelected()\"\n (selectedChange)=\"_monthSelected($event)\"\n [activeDate]=\"_activeDate\"\n [dateFilter]=\"_dateFilterForViews\"\n [selected]=\"selected!\"\n [type]=\"type\">\n </mtx-year-view>\n }\n @case ('multi-year') {\n <mtx-multi-year-view\n (_userSelection)=\"_userSelected()\"\n (selectedChange)=\"_yearSelected($event)\"\n [activeDate]=\"_activeDate\"\n [dateFilter]=\"_dateFilterForViews\"\n [maxDate]=\"maxDate\"\n [minDate]=\"minDate\"\n [selected]=\"selected!\"\n [type]=\"type\">\n </mtx-multi-year-view>\n }\n @default {\n @if (timeInput) {\n <mtx-time\n (_userSelection)=\"_userSelected()\"\n (activeDateChange)=\"_onActiveDateChange($event)\"\n (selectedChange)=\"_timeSelected($event)\"\n [AMPM]=\"_AMPM\"\n (ampmChange)=\"_ampmClicked($event)\"\n [clockView]=\"_clockView\"\n (clockViewChange)=\"_clockView = $event\"\n [twelvehour]=\"twelvehour\"\n [dateFilter]=\"dateFilter\"\n [interval]=\"timeInterval\"\n [maxDate]=\"maxDate\"\n [minDate]=\"minDate\"\n [selected]=\"_activeDate\"\n [actionsPortal]=\"actionsPortal\">\n </mtx-time>\n } @else {\n <mtx-clock (_userSelection)=\"_userSelected()\"\n (activeDateChange)=\"_onActiveDateChange($event)\"\n (selectedChange)=\"_dialTimeSelected($event)\"\n [AMPM]=\"_AMPM\"\n [dateFilter]=\"dateFilter\"\n [interval]=\"timeInterval\"\n [maxDate]=\"maxDate\"\n [minDate]=\"minDate\"\n [selected]=\"_activeDate\"\n [startView]=\"_clockView\"\n [twelvehour]=\"twelvehour\">\n </mtx-clock>\n }\n }\n }\n</div>\n", styles: [".mtx-calendar{display:block;outline:none;font-family:var(--mtx-datetimepicker-calendar-text-font, var(--mat-app-body-large-font));font-size:var(--mtx-datetimepicker-calendar-text-size, var(--mat-app-body-large-size))}.mtx-calendar-header{box-sizing:border-box;padding:8px;border-bottom:1px solid var(--mtx-datetimepicker-calendar-header-divider-color, var(--mat-app-outline-variant));border-top-left-radius:var(--mtx-datetimepicker-container-shape, var(--mat-app-corner-large));border-top-right-radius:var(--mtx-datetimepicker-container-shape, var(--mat-app-corner-large));background-color:var(--mtx-datetimepicker-calendar-header-background-color);color:var(--mtx-datetimepicker-calendar-header-text-color, var(--mat-app-on-surface-variant));--mdc-text-button-container-shape: var(--mtx-datetimepicker-selector-container-shape, var(--mat-app-corner-small))}.mtx-calendar-header .mtx-calendar-header-year,.mtx-calendar-header .mtx-calendar-header-date,.mtx-calendar-header .mtx-calendar-header-hours,.mtx-calendar-header .mtx-calendar-header-minutes,.mtx-calendar-header .mtx-calendar-header-ampm{height:auto;min-width:auto;padding:0 4px;text-align:inherit;line-height:inherit;color:inherit;font-size:inherit;font-weight:inherit;letter-spacing:normal;white-space:normal;word-break:break-word}.mtx-calendar-header .mtx-calendar-header-year .mat-mdc-button-touch-target,.mtx-calendar-header .mtx-calendar-header-date .mat-mdc-button-touch-target,.mtx-calendar-header .mtx-calendar-header-hours .mat-mdc-button-touch-target,.mtx-calendar-header .mtx-calendar-header-minutes .mat-mdc-button-touch-target,.mtx-calendar-header .mtx-calendar-header-ampm .mat-mdc-button-touch-target{height:100%}.mtx-calendar-header .mtx-calendar-header-year{line-height:24px}.mtx-calendar-header-date-time{font-size:24px;line-height:36px}.mtx-calendar-header-year:not(.active),.mtx-calendar-header-date:not(.active),.mtx-calendar-header-hours:not(.active),.mtx-calendar-header-minutes:not(.active),.mtx-calendar-header-ampm:not(.active){opacity:.6}.mtx-calendar-header-year.not-clickable,.mtx-calendar-header-date.not-clickable,.mtx-calendar-header-hours.not-clickable,.mtx-calendar-header-minutes.not-clickable,.mtx-calendar-header-ampm.not-clickable{cursor:initial}.mtx-calendar-header-time{display:inline-flex}.mtx-calendar-header-time:not(.active){opacity:.6}.mtx-calendar-header-time:not(.active) .mtx-calendar-header-hours,.mtx-calendar-header-time:not(.active) .mtx-calendar-header-minutes,.mtx-calendar-header-time:not(.active) .mtx-calendar-header-ampm{opacity:1}.mtx-calendar-header-hour-minute-separator{display:inline-block;width:8px;text-align:center}.mtx-calendar-header-ampm-container{display:inline-flex;flex-direction:column;line-height:18px;font-size:12px}[mode=landscape] .mtx-calendar{display:flex}[mode=landscape] .mtx-calendar .mtx-calendar-header{width:144px;min-width:144px;padding:16px 8px;border-bottom-width:0;border-top-right-radius:0;border-bottom-right-radius:0;border-right:1px solid var(--mtx-datetimepicker-calendar-header-divider-color, var(--mat-app-outline-variant));border-top-left-radius:var(--mtx-datetimepicker-container-shape, var(--mat-app-corner-large));border-bottom-left-radius:var(--mtx-datetimepicker-container-shape, var(--mat-app-corner-large))}[dir=rtl] [mode=landscape] .mtx-calendar .mtx-calendar-header{border-top-left-radius:0;border-bottom-left-radius:0;border-right-width:0;border-left:1px solid var(--mtx-datetimepicker-calendar-header-divider-color, var(--mat-app-outline-variant));border-top-right-radius:var(--mtx-datetimepicker-container-shape, var(--mat-app-corner-large));border-bottom-right-radius:var(--mtx-datetimepicker-container-shape, var(--mat-app-corner-large))}[mode=landscape] .mtx-calendar .mtx-calendar-header-year+.mtx-calendar-header-date-time,[mode=landscape] .mtx-calendar .mtx-calendar-header-date+.mtx-calendar-header-time{margin-top:4px}[mode=landscape] .mtx-calendar .mtx-calendar-header-date-time{font-size:28px}[mode=landscape] .mtx-calendar .mtx-calendar-header-time{display:flex;flex-direction:column}[mode=landscape] .mtx-calendar .mtx-calendar-header-time .mtx-calendar-header-hours,[mode=landscape] .mtx-calendar .mtx-calendar-header-time .mtx-calendar-header-minutes,[mode=landscape] .mtx-calendar .mtx-calendar-header-time .mtx-calendar-header-ampm{width:40px;text-align:center}[mode=landscape] .mtx-calendar .mtx-calendar-header-ampm-container{flex-direction:row;font-size:20px}[mode=landscape] .mtx-calendar .mtx-calendar-header-ampm{padding:4px}[mode=landscape] .mtx-calendar .mtx-calendar-header-ampm+.mtx-calendar-header-ampm{margin:0 8px}[mode=landscape] .mtx-datetimepicker-content-container-with-actions .mtx-calendar .mtx-calendar-header{border-bottom-left-radius:0;border-bottom-right-radius:0}[mode=landscape] .mtx-datetimepicker-actions:before{position:absolute;top:0;left:0;box-sizing:border-box;width:144px;height:100%;content:\"\";border-right:1px solid var(--mtx-datetimepicker-calendar-header-divider-color, var(--mat-app-outline-variant));background-color:var(--mtx-datetimepicker-calendar-header-background-color);border-bottom-left-radius:var(--mtx-datetimepicker-container-shape, var(--mat-app-corner-large))}[dir=rtl] [mode=landscape] .mtx-datetimepicker-actions:before{left:auto;right:0;border-right-width:0;border-left:1px solid var(--mtx-datetimepicker-calendar-header-divider-color, var(--mat-app-outline-variant));border-bottom-left-radius:0;border-bottom-right-radius:var(--mtx-datetimepicker-container-shape, var(--mat-app-corner-large))}@media all and (orientation: landscape){[mode=auto] .mtx-calendar{display:flex}[mode=auto] .mtx-calendar .mtx-calendar-header{width:144px;min-width:144px;padding:16px 8px;border-bottom-width:0;border-top-right-radius:0;border-bottom-right-radius:0;border-right:1px solid var(--mtx-datetimepicker-calendar-header-divider-color, var(--mat-app-outline-variant));border-top-left-radius:var(--mtx-datetimepicker-container-shape, var(--mat-app-corner-large));border-bottom-left-radius:var(--mtx-datetimepicker-container-shape, var(--mat-app-corner-large))}[dir=rtl] [mode=auto] .mtx-calendar .mtx-calendar-header{border-top-left-radius:0;border-bottom-left-radius:0;border-right-width:0;border-left:1px solid var(--mtx-datetimepicker-calendar-header-divider-color, var(--mat-app-outline-variant));border-top-right-radius:var(--mtx-datetimepicker-container-shape, var(--mat-app-corner-large));border-bottom-right-radius:var(--mtx-datetimepicker-container-shape, var(--mat-app-corner-large))}[mode=auto] .mtx-calendar .mtx-calendar-header-year+.mtx-calendar-header-date-time,[mode=auto] .mtx-calendar .mtx-calendar-header-date+.mtx-calendar-header-time{margin-top:4px}[mode=auto] .mtx-calendar .mtx-calendar-header-date-time{font-size:28px}[mode=auto] .mtx-calendar .mtx-calendar-header-time{display:flex;flex-direction:column}[mode=auto] .mtx-calendar .mtx-calendar-header-time .mtx-calendar-header-hours,[mode=auto] .mtx-calendar .mtx-calendar-header-time .mtx-calendar-header-minutes,[mode=auto] .mtx-calendar .mtx-calendar-header-time .mtx-calendar-header-ampm{width:40px;text-align:center}[mode=auto] .mtx-calendar .mtx-calendar-header-ampm-container{flex-direction:row;font-size:20px}[mode=auto] .mtx-calendar .mtx-calendar-header-ampm{padding:4px}[mode=auto] .mtx-calendar .mtx-calendar-header-ampm+.mtx-calendar-header-ampm{margin:0 8px}[mode=auto] .mtx-datetimepicker-content-container-with-actions .mtx-calendar .mtx-calendar-header{border-bottom-left-radius:0;border-bottom-right-radius:0}[mode=auto] .mtx-datetimepicker-actions:before{position:absolute;top:0;left:0;box-sizing:border-box;width:144px;height:100%;content:\"\";border-right:1px solid var(--mtx-datetimepicker-calendar-header-divider-color, var(--mat-app-outline-variant));background-color:var(--mtx-datetimepicker-calendar-header-background-color);border-bottom-left-radius:var(--mtx-datetimepicker-container-shape, var(--mat-app-corner-large))}[dir=rtl] [mode=auto] .mtx-datetimepicker-actions:before{left:auto;right:0;border-right-width:0;border-left:1px solid var(--mtx-datetimepicker-calendar-header-divider-color, var(--mat-app-outline-variant));border-bottom-left-radius:0;border-bottom-right-radius:var(--mtx-datetimepicker-container-shape, var(--mat-app-corner-large))}}.mtx-calendar-content{width:100%;padding:8px;outline:none;box-sizing:border-box;overflow:hidden}.mtx-calendar-controls{display:flex;align-items:center;justify-content:space-between;margin:0 calc(4.7142857143% - 16px)}.mtx-calendar-controls .mat-icon-button:hover .mat-button-focus-overlay{opacity:.04}.mtx-calendar-period-button{display:inline-block;height:40px;line-height:40px;outline:none;border:0;background:transparent;box-sizing:border-box;font-size:var(--mtx-datetimepicker-calendar-period-button-text-size, var(--mat-app-title-small-size));font-weight:var(--mtx-datetimepicker-calendar-period-button-text-weight, var(--mat-app-title-small-weight))}.mtx-calendar-previous-button.disabled,.mtx-calendar-next-button.disabled{pointer-events:none;color:var(--mtx-datetimepicker-calendar-date-disabled-state-text-color)}.mtx-calendar-previous-button svg,.mtx-calendar-next-button svg{fill:currentColor;vertical-align:top}[dir=rtl] .mtx-calendar-previous-button svg,[dir=rtl] .mtx-calendar-next-button svg{transform:rotate(180deg)}.mtx-calendar-table{border-spacing:0;border-collapse:collapse;width:100%}.mtx-calendar-table-header th{text-align:center;padding:8px 0;color:var(--mtx-datetimepicker-calendar-table-header-text-color, var(--mat-app-on-surface));font-size:var(--mtx-datetimepicker-calendar-table-header-text-size);font-weight:var(--mtx-datetimepicker-calendar-table-header-text-weight)}\n"], dependencies: [{ kind: "directive", type: CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }, { kind: "component", type: MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: MtxMonthView, selector: "mtx-month-view", inputs: ["type", "dateFilter", "activeDate", "selected"], outputs: ["selectedChange", "_userSelection"], exportAs: ["mtxMonthView"] }, { kind: "component", type: MtxYearView, selector: "mtx-year-view", inputs: ["type", "dateFilter", "activeDate", "selected"], outputs: ["selectedChange", "_userSelection"], exportAs: ["mtxYearView"] }, { kind: "component", type: MtxMultiYearView, selector: "mtx-multi-year-view", inputs: ["type", "dateFilter", "activeDate", "selected", "minDate", "maxDate"], outputs: ["selectedChange", "_userSelection"], exportAs: ["mtxMultiYearView"] }, { kind: "component", type: MtxTime, selector: "mtx-time", inputs: ["dateFilter", "interval", "actionsPortal", "twelvehour", "AMPM", "activeDate", "selected", "minDate", "maxDate", "clockView"], outputs: ["selectedChange", "activeDateChange", "_userSelection", "ampmChange", "clockViewChange"], exportAs: ["mtxTime"] }, { kind: "component", type: MtxClock, selector: "mtx-clock", inputs: ["dateFilter", "interval", "twelvehour", "AMPM", "activeDate", "selected", "minDate", "maxDate", "startView"], outputs: ["selectedChange", "activeDateChange", "_userSelection"], exportAs: ["mtxClock"] }], animations: [mtxDatetimepickerAnimations.slideCalendar], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.0", ngImport: i0, type: MtxCalendar, decorators: [{
type: Component,
args: [{ selector: 'mtx-calendar', host: {
'class': 'mtx-calendar',
'[class.mtx-calendar-with-time-input]': 'timeInput',
'tabindex': '0',
'(keydown)': '_handleCalendarBodyKeydown($event)',
}, exportAs: 'mtxCalendar', animations: [mtxDatetimepickerAnimations.slideCalendar], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
CdkPortalOutlet,
MatButton,
MatIconButton,
MtxMonthView,
MtxYearView,
MtxMultiYearView,
MtxTime,
MtxClock,
], template: "<div class=\"mtx-calendar-header\">\n @if (_calendarHeaderPortal) {\n <ng-template [cdkPortalOutlet]=\"_calendarHeaderPortal\"></ng-template>\n } @else {\n @if (type !== 'time') {\n <button\n mat-button type=\"button\" class=\"mtx-calendar-header-year\"\n [class.active]=\"currentView === 'year' || currentView === 'multi-year'\"\n [attr.aria-label]=\"_yearButtonLabel\"\n (click)=\"_yearClicked()\">\n <span>{{ _yearButtonText }}</span>\n @if (multiYearSelector || type === 'year') {\n <svg\n class=\"mtx-calendar-header-year-dropdown\" matButtonIcon iconPositionEnd\n width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M7,10L12,15L17,10H7Z\" />\n </svg>\n }\n </button>\n }\n @if (type !== 'year') {\n <div class=\"mtx-calendar-header-date-time\">\n @if (type !== 'time') {\n <button\n mat-button type=\"button\" class=\"mtx-calendar-header-date\"\n [class.active]=\"currentView === 'month'\"\n [class.not-clickable]=\"type === 'month'\"\n [attr.aria-label]=\"_dateButtonLabel\"\n (click)=\"_dateClicked()\">{{ _dateButtonText }}</button>\n }\n @if (type.endsWith('time')) {\n <span class=\"mtx-calendar-header-time\" [class.active]=\"currentView === 'clock'\">\n <span class=\"mtx-calendar-header-hour-minute-container\">\n <button mat-button type=\"button\" class=\"mtx-calendar-header-hours\"\n [class.active]=\"_clockView === 'hour'\"\n [attr.aria-label]=\"_hourButtonLabel\"\n (click)=\"_hoursClicked()\">{{ _hoursButtonText }}</button>\n <span class=\"mtx-calendar-header-hour-minute-separator\">:</span>\n <button mat-button type=\"button\" class=\"mtx-calendar-header-minutes\"\n [class.active]=\"_clockView === 'minute'\"\n [attr.aria-label]=\"_minuteButtonLabel\"\n (click)=\"_minutesClicked()\">{{ _minutesButtonText }}</button>\n </span>\n @if (twelvehour) {\n <span class=\"mtx-calendar-header-ampm-container\">\n <button mat-button type=\"button\" class=\"mtx-calendar-header-ampm\"\n [class.active]=\"_AMPM === 'AM'\" aria-label=\"AM\"\n (click)=\"_ampmClicked('AM')\">AM</button>\n <button mat-button type=\"button\" class=\"mtx-calendar-header-ampm\"\n [class.active]=\"_AMPM === 'PM'\" aria-label=\"PM\"\n (click)=\"_ampmClicked('PM')\">PM</button>\n </span>\n }\n </span>\n }\n </div>\n }\n }\n</div>\n\n<div class=\"mtx-calendar-content\">\n @if (currentView === 'month' || currentView === 'year' || currentView === 'multi-year') {\n <div class=\"mtx-month-content\">\n <div class=\"mtx-calendar-controls\">\n <button mat-icon-button type=\"button\"\n class=\"mtx-calendar-previous-button\"\n [class.disabled]=\"!_previousEnabled()\"\n [attr.aria-disabled]=\"!_previousEnabled()\"\n [attr.aria-label]=\"_prevButtonLabel\"\n (click)=\"_previousClicked()\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\">\n <path d=\"M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z\" />\n </svg>\n </button>\n <div class=\"mtx-calendar-period-button\"\n [@slideCalendar]=\"_calendarState\"\n (@slideCalendar.done)=\"_calendarStateDone()\">\n <strong>{{ _yearPeriodText }}</strong>\n </div>\n <button mat-icon-button type=\"button\"\n class=\"mtx-calendar-next-button\"\n [class.disabled]=\"!_nextEnabled()\"\n [attr.aria-disabled]=\"!_nextEnabled()\"\n [attr.aria-label]=\"_nextButtonLabel\"\n (click)=\"_nextClicked()\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\">\n <path d=\"M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z\" />\n </svg>\n </button>\n </div>\n </div>\n }\n\n @switch (currentView) {\n @case ('month') {\n <mtx-month-view\n (_userSelection)=\"_userSelected()\"\n (selectedChange)=\"_dateSelected($event)\"\n [activeDate]=\"_activeDate\"\n [dateFilter]=\"_dateFilterForViews\"\n [selected]=\"selected!\"\n [type]=\"type\">\n </mtx-month-view>\n }\n @case ('