ngx-mat-datetime-picker-v2
Version:
Angular Material Datetime Picker
3,513 lines • 202 kB
JavaScript
import * as i1$1 from '@angular/material/core';
import { DateAdapter, MAT_DATE_LOCALE, MatRippleModule } from '@angular/material/core';
import * as i0 from '@angular/core';
import { InjectionToken, Optional, Inject, Injectable, NgModule, SkipSelf, EventEmitter, Output, Input, Directive, inject, ContentChild, Self, ViewEncapsulation, ChangeDetectionStrategy, Component, forwardRef, ViewChild, TemplateRef, Attribute } from '@angular/core';
import * as i1 from '@angular/cdk/platform';
import { PlatformModule, _getFocusedElementPierceShadowDom } from '@angular/cdk/platform';
import { Subject, Subscription, merge, of } from 'rxjs';
import * as i2$1 from '@angular/cdk/a11y';
import { A11yModule } from '@angular/cdk/a11y';
import * as i11 from '@angular/cdk/overlay';
import { Overlay, FlexibleConnectedPositionStrategy, OverlayConfig, OverlayModule } from '@angular/cdk/overlay';
import * as i7 from '@angular/cdk/portal';
import { ComponentPortal, TemplatePortal, PortalModule } from '@angular/cdk/portal';
import { CdkScrollableModule } from '@angular/cdk/scrolling';
import * as i4$1 from '@angular/material/button';
import { MatButtonModule } from '@angular/material/button';
import { coerceBooleanProperty, coerceStringArray } from '@angular/cdk/coercion';
import * as i2 from '@angular/forms';
import { NgControl, Validators, NgForm, FormGroupDirective, NG_VALUE_ACCESSOR, NG_VALIDATORS, ControlContainer, FormGroup, FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MAT_FORM_FIELD, MatFormFieldControl, MatFormFieldModule } from '@angular/material/form-field';
import * as i12 from '@angular/cdk/bidi';
import { Directionality } from '@angular/cdk/bidi';
import { hasModifierKey, DOWN_ARROW, RIGHT_ARROW, LEFT_ARROW, BACKSPACE, UP_ARROW, PAGE_UP, PAGE_DOWN, ESCAPE } from '@angular/cdk/keycodes';
import * as i4 from '@angular/common';
import { CommonModule, DOCUMENT } from '@angular/common';
import { takeUntil, debounceTime, take, filter } from 'rxjs/operators';
import { trigger, state, transition, style, animate, keyframes } from '@angular/animations';
import * as i10 from '@angular/material/datepicker';
import { DateRange, MatCalendar, MatDatepickerModule } from '@angular/material/datepicker';
import * as i3 from '@angular/material/input';
import { MatInputModule, MAT_INPUT_VALUE_ACCESSOR } from '@angular/material/input';
import * as i5 from '@angular/material/icon';
import { MatIconModule } from '@angular/material/icon';
import { MatSelectModule } from '@angular/material/select';
class NgxMatDateAdapter extends DateAdapter {
/**
* Check if two date have same time
* @param a Date 1
* @param b Date 2
*/
isSameTime(a, b) {
if (a == null || b == null)
return true;
return this.getHour(a) === this.getHour(b)
&& this.getMinute(a) === this.getMinute(b)
&& this.getSecond(a) === this.getSecond(b);
}
/**
* Copy time from a date to a another date
* @param toDate
* @param fromDate
*/
copyTime(toDate, fromDate) {
this.setHour(toDate, this.getHour(fromDate));
this.setMinute(toDate, this.getMinute(fromDate));
this.setSecond(toDate, this.getSecond(fromDate));
}
/**
* Compares two dates.
* @param first The first date to compare.
* @param second The second date to compare.
* @returns 0 if the dates are equal, a number less than 0 if the first date is earlier,
* a number greater than 0 if the first date is later.
*/
compareDateWithTime(first, second, showSeconds) {
let res = super.compareDate(first, second) ||
this.getHour(first) - this.getHour(second) ||
this.getMinute(first) - this.getMinute(second);
if (showSeconds) {
res = res || this.getSecond(first) - this.getSecond(second);
}
return res;
}
/**
* Set time by using default values
* @param defaultTime List default values [hour, minute, second]
*/
setTimeByDefaultValues(date, defaultTime) {
if (!Array.isArray(defaultTime)) {
throw Error('@Input DefaultTime should be an array');
}
this.setHour(date, defaultTime[0] || 0);
this.setMinute(date, defaultTime[1] || 0);
this.setSecond(date, defaultTime[2] || 0);
}
}
const NGX_MAT_DATE_FORMATS = new InjectionToken('ngx-mat-date-formats');
// TODO(mmalerba): Remove when we no longer support safari 9.
/** Whether the browser supports the Intl API. */
let SUPPORTS_INTL_API;
// We need a try/catch around the reference to `Intl`, because accessing it in some cases can
// cause IE to throw. These cases are tied to particular versions of Windows and can happen if
// the consumer is providing a polyfilled `Map`. See:
// https://github.com/Microsoft/ChakraCore/issues/3189
// https://github.com/angular/components/issues/15687
try {
SUPPORTS_INTL_API = typeof Intl != 'undefined';
}
catch {
SUPPORTS_INTL_API = false;
}
/** The default month names to use if Intl API is not available. */
const DEFAULT_MONTH_NAMES = {
'long': [
'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September',
'October', 'November', 'December'
],
'short': ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
'narrow': ['J', 'F', 'M', 'A', 'M', 'J', 'J', 'A', 'S', 'O', 'N', 'D']
};
/** The default date names to use if Intl API is not available. */
const DEFAULT_DATE_NAMES = range(31, i => String(i + 1));
/** The default day of the week names to use if Intl API is not available. */
const DEFAULT_DAY_OF_WEEK_NAMES = {
'long': ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
'short': ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
'narrow': ['S', 'M', 'T', 'W', 'T', 'F', 'S']
};
/**
* Matches strings that have the form of a valid RFC 3339 string
* (https://tools.ietf.org/html/rfc3339). Note that the string may not actually be a valid date
* because the regex will match strings an with out of bounds month, date, etc.
*/
const ISO_8601_REGEX = /^\d{4}-\d{2}-\d{2}(?:T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|(?:(?:\+|-)\d{2}:\d{2}))?)?$/;
/** Creates an array and fills it with values. */
function range(length, valueFunction) {
const valuesArray = Array(length);
for (let i = 0; i < length; i++) {
valuesArray[i] = valueFunction(i);
}
return valuesArray;
}
/** Adapts the native JS Date for use with cdk-based components that work with dates. */
class NgxMatNativeDateAdapter extends NgxMatDateAdapter {
constructor(matDateLocale, platform) {
super();
/**
* Whether to use `timeZone: 'utc'` with `Intl.DateTimeFormat` when formatting dates.
* Without this `Intl.DateTimeFormat` sometimes chooses the wrong timeZone, which can throw off
* the result. (e.g. in the en-US locale `new Date(1800, 7, 14).toLocaleDateString()`
* will produce `'8/13/1800'`.
*
* TODO(mmalerba): drop this variable. It's not being used in the code right now. We're now
* getting the string representation of a Date object from its utc representation. We're keeping
* it here for sometime, just for precaution, in case we decide to revert some of these changes
* though.
*/
this.useUtcForDisplay = true;
super.setLocale(matDateLocale);
// IE does its own time zone correction, so we disable this on IE.
this.useUtcForDisplay = !platform.TRIDENT;
this._clampDate = platform.TRIDENT || platform.EDGE;
}
getYear(date) {
return date.getFullYear();
}
getMonth(date) {
return date.getMonth();
}
getDate(date) {
return date.getDate();
}
getDayOfWeek(date) {
return date.getDay();
}
getMonthNames(style) {
if (SUPPORTS_INTL_API) {
const dtf = new Intl.DateTimeFormat(this.locale, { month: style, timeZone: 'utc' });
return range(12, i => this._stripDirectionalityCharacters(this._format(dtf, new Date(2017, i, 1))));
}
return DEFAULT_MONTH_NAMES[style];
}
getDateNames() {
if (SUPPORTS_INTL_API) {
const dtf = new Intl.DateTimeFormat(this.locale, { day: 'numeric', timeZone: 'utc' });
return range(31, i => this._stripDirectionalityCharacters(this._format(dtf, new Date(2017, 0, i + 1))));
}
return DEFAULT_DATE_NAMES;
}
getDayOfWeekNames(style) {
if (SUPPORTS_INTL_API) {
const dtf = new Intl.DateTimeFormat(this.locale, { weekday: style, timeZone: 'utc' });
return range(7, i => this._stripDirectionalityCharacters(this._format(dtf, new Date(2017, 0, i + 1))));
}
return DEFAULT_DAY_OF_WEEK_NAMES[style];
}
getYearName(date) {
if (SUPPORTS_INTL_API) {
const dtf = new Intl.DateTimeFormat(this.locale, { year: 'numeric', timeZone: 'utc' });
return this._stripDirectionalityCharacters(this._format(dtf, date));
}
return String(this.getYear(date));
}
getFirstDayOfWeek() {
// We can't tell using native JS Date what the first day of the week is, we default to Sunday.
return 0;
}
getNumDaysInMonth(date) {
return this.getDate(this._createDateWithOverflow(this.getYear(date), this.getMonth(date) + 1, 0));
}
clone(date) {
return new Date(date.getTime());
}
createDate(year, month, date) {
// Check for invalid month and date (except upper bound on date which we have to check after
// creating the Date).
if (month < 0 || month > 11) {
throw Error(`Invalid month index "${month}". Month index has to be between 0 and 11.`);
}
if (date < 1) {
throw Error(`Invalid date "${date}". Date has to be greater than 0.`);
}
let result = this._createDateWithOverflow(year, month, date);
// Check that the date wasn't above the upper bound for the month, causing the month to overflow
if (result.getMonth() != month) {
throw Error(`Invalid date "${date}" for month with index "${month}".`);
}
return result;
}
today() {
return new Date();
}
parse(value) {
// We have no way using the native JS Date to set the parse format or locale, so we ignore these
// parameters.
if (typeof value == 'number') {
return new Date(value);
}
return value ? new Date(Date.parse(value)) : null;
}
format(date, displayFormat) {
if (!this.isValid(date)) {
throw Error('NativeDateAdapter: Cannot format invalid date.');
}
if (SUPPORTS_INTL_API) {
// On IE and Edge the i18n API will throw a hard error that can crash the entire app
// if we attempt to format a date whose year is less than 1 or greater than 9999.
if (this._clampDate && (date.getFullYear() < 1 || date.getFullYear() > 9999)) {
date = this.clone(date);
date.setFullYear(Math.max(1, Math.min(9999, date.getFullYear())));
}
displayFormat = { ...displayFormat, timeZone: 'utc' };
const dtf = new Intl.DateTimeFormat(this.locale, displayFormat);
return this._stripDirectionalityCharacters(this._format(dtf, date));
}
return this._stripDirectionalityCharacters(date.toDateString());
}
addCalendarYears(date, years) {
return this.addCalendarMonths(date, years * 12);
}
addCalendarMonths(date, months) {
let newDate = this._createDateWithOverflow(this.getYear(date), this.getMonth(date) + months, this.getDate(date));
// It's possible to wind up in the wrong month if the original month has more days than the new
// month. In this case we want to go to the last day of the desired month.
// Note: the additional + 12 % 12 ensures we end up with a positive number, since JS % doesn't
// guarantee this.
if (this.getMonth(newDate) != ((this.getMonth(date) + months) % 12 + 12) % 12) {
newDate = this._createDateWithOverflow(this.getYear(newDate), this.getMonth(newDate), 0);
}
return newDate;
}
addCalendarDays(date, days) {
return this._createDateWithOverflow(this.getYear(date), this.getMonth(date), this.getDate(date) + days);
}
toIso8601(date) {
return [
date.getUTCFullYear(),
this._2digit(date.getUTCMonth() + 1),
this._2digit(date.getUTCDate())
].join('-');
}
/**
* Returns the given value if given a valid Date or null. Deserializes valid ISO 8601 strings
* (https://www.ietf.org/rfc/rfc3339.txt) into valid Dates and empty string into null. Returns an
* invalid date for all other values.
*/
deserialize(value) {
if (typeof value === 'string') {
if (!value) {
return null;
}
// The `Date` constructor accepts formats other than ISO 8601, so we need to make sure the
// string is the right format first.
if (ISO_8601_REGEX.test(value)) {
let date = new Date(value);
if (this.isValid(date)) {
return date;
}
}
}
return super.deserialize(value);
}
isDateInstance(obj) {
return obj instanceof Date;
}
isValid(date) {
return !isNaN(date.getTime());
}
invalid() {
return new Date(NaN);
}
getHour(date) {
return date.getHours();
}
getMinute(date) {
return date.getMinutes();
}
getSecond(date) {
return date.getSeconds();
}
setHour(date, value) {
date.setHours(value);
}
setMinute(date, value) {
date.setMinutes(value);
}
setSecond(date, value) {
date.setSeconds(value);
}
/** Creates a date but allows the month and date to overflow. */
_createDateWithOverflow(year, month, date) {
const result = new Date(year, month, date);
// We need to correct for the fact that JS native Date treats years in range [0, 99] as
// abbreviations for 19xx.
if (year >= 0 && year < 100) {
result.setFullYear(this.getYear(result) - 1900);
}
return result;
}
/**
* Pads a number to make it two digits.
* @param n The number to pad.
* @returns The padded number.
*/
_2digit(n) {
return ('00' + n).slice(-2);
}
/**
* Strip out unicode LTR and RTL characters. Edge and IE insert these into formatted dates while
* other browsers do not. We remove them to make output consistent and because they interfere with
* date parsing.
* @param str The string to strip direction characters from.
* @returns The stripped string.
*/
_stripDirectionalityCharacters(str) {
return str.replace(/[\u200e\u200f]/g, '');
}
/**
* When converting Date object to string, javascript built-in functions may return wrong
* results because it applies its internal DST rules. The DST rules around the world change
* very frequently, and the current valid rule is not always valid in previous years though.
* We work around this problem building a new Date object which has its internal UTC
* representation with the local date and time.
* @param dtf Intl.DateTimeFormat object, containg the desired string format. It must have
* timeZone set to 'utc' to work fine.
* @param date Date from which we want to get the string representation according to dtf
* @returns A Date object with its UTC representation based on the passed in date info
*/
_format(dtf, date) {
// Passing the year to the constructor causes year numbers <100 to be converted to 19xx.
// To work around this we use `setUTCFullYear` and `setUTCHours` instead.
const d = new Date();
d.setUTCFullYear(date.getFullYear(), date.getMonth(), date.getDate());
d.setUTCHours(date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());
return dtf.format(d);
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatNativeDateAdapter, deps: [{ token: MAT_DATE_LOCALE, optional: true }, { token: i1.Platform }], target: i0.ɵɵFactoryTarget.Injectable }); }
/** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatNativeDateAdapter }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatNativeDateAdapter, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: [MAT_DATE_LOCALE]
}] }, { type: i1.Platform }] });
const DEFAULT_DATE_INPUT = {
year: 'numeric', month: 'numeric', day: 'numeric',
hour12: false, hour: "2-digit", minute: "2-digit", second: "2-digit"
};
const NGX_MAT_NATIVE_DATE_FORMATS = {
parse: {
dateInput: DEFAULT_DATE_INPUT,
},
display: {
dateInput: DEFAULT_DATE_INPUT,
monthYearLabel: { year: 'numeric', month: 'short' },
dateA11yLabel: { year: 'numeric', month: 'long', day: 'numeric' },
monthYearA11yLabel: { year: 'numeric', month: 'long' },
}
};
class NgxNativeDateModule {
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxNativeDateModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
/** @nocollapse */ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.10", ngImport: i0, type: NgxNativeDateModule, imports: [PlatformModule] }); }
/** @nocollapse */ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxNativeDateModule, providers: [
{ provide: NgxMatDateAdapter, useClass: NgxMatNativeDateAdapter },
], imports: [PlatformModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxNativeDateModule, decorators: [{
type: NgModule,
args: [{
imports: [PlatformModule],
providers: [
{ provide: NgxMatDateAdapter, useClass: NgxMatNativeDateAdapter },
],
}]
}] });
class NgxMatNativeDateModule {
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatNativeDateModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
/** @nocollapse */ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.10", ngImport: i0, type: NgxMatNativeDateModule, imports: [NgxNativeDateModule] }); }
/** @nocollapse */ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatNativeDateModule, providers: [{ provide: NGX_MAT_DATE_FORMATS, useValue: NGX_MAT_NATIVE_DATE_FORMATS }], imports: [NgxNativeDateModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatNativeDateModule, decorators: [{
type: NgModule,
args: [{
imports: [NgxNativeDateModule],
providers: [{ provide: NGX_MAT_DATE_FORMATS, useValue: NGX_MAT_NATIVE_DATE_FORMATS }],
}]
}] });
/** A class representing a range of dates. */
class NgxDateRange {
constructor(
/** The start date of the range. */
start,
/** The end date of the range. */
end) {
this.start = start;
this.end = end;
}
}
/**
* A selection model containing a date selection.
* @docs-private
*/
class NgxMatDateSelectionModel {
constructor(
/** The current selection. */
selection, _adapter) {
this.selection = selection;
this._adapter = _adapter;
this._selectionChanged = new Subject();
/** Emits when the selection has changed. */
this.selectionChanged = this._selectionChanged;
this.selection = selection;
}
/**
* Updates the current selection in the model.
* @param value New selection that should be assigned.
* @param source Object that triggered the selection change.
*/
updateSelection(value, source) {
const oldValue = this.selection;
this.selection = value;
this._selectionChanged.next({ selection: value, source, oldValue });
}
ngOnDestroy() {
this._selectionChanged.complete();
}
_isValidDateInstance(date) {
return this._adapter.isDateInstance(date) && this._adapter.isValid(date);
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDateSelectionModel, deps: "invalid", target: i0.ɵɵFactoryTarget.Injectable }); }
/** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDateSelectionModel }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDateSelectionModel, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: undefined }, { type: NgxMatDateAdapter }] });
/**
* A selection model that contains a single date.
* @docs-private
*/
class NgxMatSingleDateSelectionModel extends NgxMatDateSelectionModel {
constructor(adapter) {
super(null, adapter);
}
/**
* Adds a date to the current selection. In the case of a single date selection, the added date
* simply overwrites the previous selection
*/
add(date) {
super.updateSelection(date, this);
}
/** Checks whether the current selection is valid. */
isValid() {
return this.selection != null && this._isValidDateInstance(this.selection);
}
/**
* Checks whether the current selection is complete. In the case of a single date selection, this
* is true if the current selection is not null.
*/
isComplete() {
return this.selection != null;
}
/** Clones the selection model. */
clone() {
const clone = new NgxMatSingleDateSelectionModel(this._adapter);
clone.updateSelection(this.selection, this);
return clone;
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatSingleDateSelectionModel, deps: [{ token: NgxMatDateAdapter }], target: i0.ɵɵFactoryTarget.Injectable }); }
/** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatSingleDateSelectionModel }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatSingleDateSelectionModel, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: NgxMatDateAdapter }] });
/**
* A selection model that contains a date range.
* @docs-private
*/
class NgxMatRangeDateSelectionModel extends NgxMatDateSelectionModel {
constructor(adapter) {
super(new NgxDateRange(null, null), adapter);
}
/**
* Adds a date to the current selection. In the case of a date range selection, the added date
* fills in the next `null` value in the range. If both the start and the end already have a date,
* the selection is reset so that the given date is the new `start` and the `end` is null.
*/
add(date) {
let { start, end } = this.selection;
if (start == null) {
start = date;
}
else if (end == null) {
end = date;
}
else {
start = date;
end = null;
}
super.updateSelection(new NgxDateRange(start, end), this);
}
/** Checks whether the current selection is valid. */
isValid() {
const { start, end } = this.selection;
// Empty ranges are valid.
if (start == null && end == null) {
return true;
}
// Complete ranges are only valid if both dates are valid and the start is before the end.
if (start != null && end != null) {
return (this._isValidDateInstance(start) &&
this._isValidDateInstance(end) &&
this._adapter.compareDate(start, end) <= 0);
}
// Partial ranges are valid if the start/end is valid.
return ((start == null || this._isValidDateInstance(start)) &&
(end == null || this._isValidDateInstance(end)));
}
/**
* Checks whether the current selection is complete. In the case of a date range selection, this
* is true if the current selection has a non-null `start` and `end`.
*/
isComplete() {
return this.selection.start != null && this.selection.end != null;
}
/** Clones the selection model. */
clone() {
const clone = new NgxMatRangeDateSelectionModel(this._adapter);
clone.updateSelection(this.selection, this);
return clone;
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatRangeDateSelectionModel, deps: [{ token: NgxMatDateAdapter }], target: i0.ɵɵFactoryTarget.Injectable }); }
/** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatRangeDateSelectionModel }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatRangeDateSelectionModel, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: NgxMatDateAdapter }] });
/** @docs-private */
function NGX_MAT_SINGLE_DATE_SELECTION_MODEL_FACTORY(parent, adapter) {
return parent || new NgxMatSingleDateSelectionModel(adapter);
}
/**
* Used to provide a single selection model to a component.
* @docs-private
*/
const NGX_MAT_SINGLE_DATE_SELECTION_MODEL_PROVIDER = {
provide: NgxMatDateSelectionModel,
deps: [[new Optional(), new SkipSelf(), NgxMatDateSelectionModel], NgxMatDateAdapter],
useFactory: NGX_MAT_SINGLE_DATE_SELECTION_MODEL_FACTORY,
};
/** @docs-private */
function NGX_MAT_RANGE_DATE_SELECTION_MODEL_FACTORY(parent, adapter) {
return parent || new NgxMatRangeDateSelectionModel(adapter);
}
/**
* Used to provide a range selection model to a component.
* @docs-private
*/
const NGX_MAT_RANGE_DATE_SELECTION_MODEL_PROVIDER = {
provide: NgxMatDateSelectionModel,
deps: [[new Optional(), new SkipSelf(), NgxMatDateSelectionModel], NgxMatDateAdapter],
useFactory: NGX_MAT_RANGE_DATE_SELECTION_MODEL_FACTORY,
};
/** Injection token used to customize the date range selection behavior. */
const NGX_MAT_DATE_RANGE_SELECTION_STRATEGY = new InjectionToken('NGX_MAT_DATE_RANGE_SELECTION_STRATEGY');
/** Provides the default date range selection behavior. */
class DefaultNgxMatCalendarRangeStrategy {
constructor(_dateAdapter) {
this._dateAdapter = _dateAdapter;
}
selectionFinished(date, currentRange) {
let { start, end } = currentRange;
if (start == null) {
start = date;
}
else if (end == null && date && this._dateAdapter.compareDate(date, start) >= 0) {
end = date;
}
else {
start = date;
end = null;
}
return new NgxDateRange(start, end);
}
createPreview(activeDate, currentRange) {
let start = null;
let end = null;
if (currentRange.start && !currentRange.end && activeDate) {
start = currentRange.start;
end = activeDate;
}
return new NgxDateRange(start, end);
}
createDrag(dragOrigin, originalRange, newDate) {
let start = originalRange.start;
let end = originalRange.end;
if (!start || !end) {
// Can't drag from an incomplete range.
return null;
}
const adapter = this._dateAdapter;
const isRange = adapter.compareDate(start, end) !== 0;
const diffYears = adapter.getYear(newDate) - adapter.getYear(dragOrigin);
const diffMonths = adapter.getMonth(newDate) - adapter.getMonth(dragOrigin);
const diffDays = adapter.getDate(newDate) - adapter.getDate(dragOrigin);
if (isRange && adapter.sameDate(dragOrigin, originalRange.start)) {
start = newDate;
if (adapter.compareDate(newDate, end) > 0) {
end = adapter.addCalendarYears(end, diffYears);
end = adapter.addCalendarMonths(end, diffMonths);
end = adapter.addCalendarDays(end, diffDays);
}
}
else if (isRange && adapter.sameDate(dragOrigin, originalRange.end)) {
end = newDate;
if (adapter.compareDate(newDate, start) < 0) {
start = adapter.addCalendarYears(start, diffYears);
start = adapter.addCalendarMonths(start, diffMonths);
start = adapter.addCalendarDays(start, diffDays);
}
}
else {
start = adapter.addCalendarYears(start, diffYears);
start = adapter.addCalendarMonths(start, diffMonths);
start = adapter.addCalendarDays(start, diffDays);
end = adapter.addCalendarYears(end, diffYears);
end = adapter.addCalendarMonths(end, diffMonths);
end = adapter.addCalendarDays(end, diffDays);
}
return new NgxDateRange(start, end);
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: DefaultNgxMatCalendarRangeStrategy, deps: [{ token: NgxMatDateAdapter }], target: i0.ɵɵFactoryTarget.Injectable }); }
/** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: DefaultNgxMatCalendarRangeStrategy }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: DefaultNgxMatCalendarRangeStrategy, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: NgxMatDateAdapter }] });
/** @docs-private */
function NGX_MAT_CALENDAR_RANGE_STRATEGY_PROVIDER_FACTORY(parent, adapter) {
return parent || new DefaultNgxMatCalendarRangeStrategy(adapter);
}
const NGX_MAT_CALENDAR_RANGE_STRATEGY_PROVIDER = {
provide: NGX_MAT_DATE_RANGE_SELECTION_STRATEGY,
deps: [[new Optional(), new SkipSelf(), NGX_MAT_DATE_RANGE_SELECTION_STRATEGY], NgxMatDateAdapter],
useFactory: NGX_MAT_CALENDAR_RANGE_STRATEGY_PROVIDER_FACTORY,
};
// This file contains the `_computeAriaAccessibleName` function, which computes what the *expected*
// ARIA accessible name would be for a given element. Implements a subset of ARIA specification
// [Accessible Name and Description Computation 1.2](https://www.w3.org/TR/accname-1.2/).
//
// Specification accname-1.2 can be summarized by returning the result of the first method
// available.
//
// 1. `aria-labelledby` attribute
// ```
// <!-- example using aria-labelledby-->
// <label id='label-id'>Start Date</label>
// <input aria-labelledby='label-id'/>
// ```
// 2. `aria-label` attribute (e.g. `<input aria-label="Departure"/>`)
// 3. Label with `for`/`id`
// ```
// <!-- example using for/id -->
// <label for="current-node">Label</label>
// <input id="current-node"/>
// ```
// 4. `placeholder` attribute (e.g. `<input placeholder="06/03/1990"/>`)
// 5. `title` attribute (e.g. `<input title="Check-In"/>`)
// 6. text content
// ```
// <!-- example using text content -->
// <label for="current-node"><span>Departure</span> Date</label>
// <input id="current-node"/>
// ```
/**
* Computes the *expected* ARIA accessible name for argument element based on [accname-1.2
* specification](https://www.w3.org/TR/accname-1.2/). Implements a subset of accname-1.2,
* and should only be used for the Datepicker's specific use case.
*
* Intended use:
* This is not a general use implementation. Only implements the parts of accname-1.2 that are
* required for the Datepicker's specific use case. This function is not intended for any other
* use.
*
* Limitations:
* - Only covers the needs of `matStartDate` and `matEndDate`. Does not support other use cases.
* - See NOTES's in implementation for specific details on what parts of the accname-1.2
* specification are not implemented.
*
* @param element {HTMLInputElement} native <input/> element of `matStartDate` or
* `matEndDate` component. Corresponds to the 'Root Element' from accname-1.2
*
* @return expected ARIA accessible name of argument <input/>
*/
function _computeAriaAccessibleName(element) {
return _computeAriaAccessibleNameInternal(element, true);
}
/**
* Determine if argument node is an Element based on `nodeType` property. This function is safe to
* use with server-side rendering.
*/
function ssrSafeIsElement(node) {
return node.nodeType === Node.ELEMENT_NODE;
}
/**
* Determine if argument node is an HTMLInputElement based on `nodeName` property. This funciton is
* safe to use with server-side rendering.
*/
function ssrSafeIsHTMLInputElement(node) {
return node.nodeName === 'INPUT';
}
/**
* Determine if argument node is an HTMLTextAreaElement based on `nodeName` property. This
* funciton is safe to use with server-side rendering.
*/
function ssrSafeIsHTMLTextAreaElement(node) {
return node.nodeName === 'TEXTAREA';
}
/**
* Calculate the expected ARIA accessible name for given DOM Node. Given DOM Node may be either the
* "Root node" passed to `_computeAriaAccessibleName` or "Current node" as result of recursion.
*
* @return the accessible name of argument DOM Node
*
* @param currentNode node to determine accessible name of
* @param isDirectlyReferenced true if `currentNode` is the root node to calculate ARIA accessible
* name of. False if it is a result of recursion.
*/
function _computeAriaAccessibleNameInternal(currentNode, isDirectlyReferenced) {
// NOTE: this differs from accname-1.2 specification.
// - Does not implement Step 1. of accname-1.2: '''If `currentNode`'s role prohibits naming,
// return the empty string ("")'''.
// - Does not implement Step 2.A. of accname-1.2: '''if current node is hidden and not directly
// referenced by aria-labelledby... return the empty string.'''
// acc-name-1.2 Step 2.B.: aria-labelledby
if (ssrSafeIsElement(currentNode) && isDirectlyReferenced) {
const labelledbyIds = currentNode.getAttribute?.('aria-labelledby')?.split(/\s+/g) || [];
const validIdRefs = labelledbyIds.reduce((validIds, id) => {
const elem = document.getElementById(id);
if (elem) {
validIds.push(elem);
}
return validIds;
}, []);
if (validIdRefs.length) {
return validIdRefs
.map(idRef => {
return _computeAriaAccessibleNameInternal(idRef, false);
})
.join(' ');
}
}
// acc-name-1.2 Step 2.C.: aria-label
if (ssrSafeIsElement(currentNode)) {
const ariaLabel = currentNode.getAttribute('aria-label')?.trim();
if (ariaLabel) {
return ariaLabel;
}
}
// acc-name-1.2 Step 2.D. attribute or element that defines a text alternative
//
// NOTE: this differs from accname-1.2 specification.
// Only implements Step 2.D. for `<label>`,`<input/>`, and `<textarea/>` element. Does not
// implement other elements that have an attribute or element that defines a text alternative.
if (ssrSafeIsHTMLInputElement(currentNode) || ssrSafeIsHTMLTextAreaElement(currentNode)) {
// use label with a `for` attribute referencing the current node
if (currentNode.labels?.length) {
return Array.from(currentNode.labels)
.map(x => _computeAriaAccessibleNameInternal(x, false))
.join(' ');
}
// use placeholder if available
const placeholder = currentNode.getAttribute('placeholder')?.trim();
if (placeholder) {
return placeholder;
}
// use title if available
const title = currentNode.getAttribute('title')?.trim();
if (title) {
return title;
}
}
// NOTE: this differs from accname-1.2 specification.
// - does not implement acc-name-1.2 Step 2.E.: '''if the current node is a control embedded
// within the label... then include the embedded control as part of the text alternative in
// the following manner...'''. Step 2E applies to embedded controls such as textbox, listbox,
// range, etc.
// - does not implement acc-name-1.2 step 2.F.: check that '''role allows name from content''',
// which applies to `currentNode` and its children.
// - does not implement acc-name-1.2 Step 2.F.ii.: '''Check for CSS generated textual content'''
// (e.g. :before and :after).
// - does not implement acc-name-1.2 Step 2.I.: '''if the current node has a Tooltip attribute,
// return its value'''
// Return text content with whitespace collapsed into a single space character. Accomplish
// acc-name-1.2 steps 2F, 2G, and 2H.
return (currentNode.textContent || '').replace(/\s+/g, ' ').trim();
}
/** @docs-private */
function createMissingDateImplError$1(provider) {
return Error(`NgxMatDatetimePicker: No provider found for ${provider}. You must import one of the following ` +
`modules at your application root: NgxMatNativeDateModule, NgxMatMomentDateModule, or provide a ` +
`custom implementation.`);
}
/**
* An event used for datepicker input and change events. We don't always have access to a native
* input or change event because the event may have been triggered by the user clicking on the
* calendar popup. For consistency, we always use MatDatepickerInputEvent instead.
*/
class NgxMatDatepickerInputEvent {
constructor(
/** Reference to the datepicker input component that emitted the event. */
target,
/** Reference to the native input element associated with the datepicker input. */
targetElement) {
this.target = target;
this.targetElement = targetElement;
this.value = this.target.value;
}
}
/** Base class for datepicker inputs. */
class NgxMatDatepickerInputBase {
/** The value of the input. */
get value() {
return this._model ? this._getValueFromModel(this._model.selection) : this._pendingValue;
}
set value(value) {
this._assignValueProgrammatically(value);
}
/** Whether the datepicker-input is disabled. */
get disabled() {
return !!this._disabled || this._parentDisabled();
}
set disabled(value) {
const newValue = coerceBooleanProperty(value);
const element = this._elementRef.nativeElement;
if (this._disabled !== newValue) {
this._disabled = newValue;
this.stateChanges.next(undefined);
}
// We need to null check the `blur` method, because it's undefined during SSR.
// In Ivy static bindings are invoked earlier, before the element is attached to the DOM.
// This can cause an error to be thrown in some browsers (IE/Edge) which assert that the
// element has been inserted.
if (newValue && this._isInitialized && element.blur) {
// Normally, native input elements automatically blur if they turn disabled. This behavior
// is problematic, because it would mean that it triggers another change detection cycle,
// which then causes a changed after checked error if the input element was focused before.
element.blur();
}
}
/** Gets the base validator functions. */
_getValidators() {
return [this._parseValidator, this._minValidator, this._maxValidator, this._filterValidator];
}
/** Registers a date selection model with the input. */
_registerModel(model) {
this._model = model;
this._valueChangesSubscription.unsubscribe();
if (this._pendingValue) {
this._assignValue(this._pendingValue);
}
this._valueChangesSubscription = this._model.selectionChanged.subscribe(event => {
if (this._shouldHandleChangeEvent(event)) {
const value = this._getValueFromModel(event.selection);
this._lastValueValid = this._isValidValue(value);
this._cvaOnChange(value);
this._onTouched();
this._formatValue(value);
this.dateInput.emit(new NgxMatDatepickerInputEvent(this, this._elementRef.nativeElement));
this.dateChange.emit(new NgxMatDatepickerInputEvent(this, this._elementRef.nativeElement));
}
});
}
constructor(_elementRef, _dateAdapter, _dateFormats) {
this._elementRef = _elementRef;
this._dateAdapter = _dateAdapter;
this._dateFormats = _dateFormats;
/** Emits when a `change` event is fired on this `<input>`. */
this.dateChange = new EventEmitter();
/** Emits when an `input` event is fired on this `<input>`. */
this.dateInput = new EventEmitter();
/** Emits when the internal state has changed */
this.stateChanges = new Subject();
this._onTouched = () => { };
this._validatorOnChange = () => { };
this._cvaOnChange = () => { };
this._valueChangesSubscription = Subscription.EMPTY;
this._localeSubscription = Subscription.EMPTY;
/** The form control validator for whether the input parses. */
this._parseValidator = () => {
return this._lastValueValid
? null
: { 'matDatepickerParse': { 'text': this._elementRef.nativeElement.value } };
};
/** The form control validator for the date filter. */
this._filterValidator = (control) => {
const controlValue = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(control.value));
return !controlValue || this._matchesFilter(controlValue)
? null
: { 'matDatepickerFilter': true };
};
/** The form control validator for the min date. */
this._minValidator = (control) => {
const controlValue = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(control.value));
const min = this._getMinDate();
return !min || !controlValue || this._dateAdapter.compareDateWithTime(min, controlValue) <= 0
? null
: { 'matDatetimePickerMin': { 'min': min, 'actual': controlValue } };
};
/** The form control validator for the max date. */
this._maxValidator = (control) => {
const controlValue = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(control.value));
const max = this._getMaxDate();
return !max || !controlValue || this._dateAdapter.compareDateWithTime(max, controlValue) >= 0
? null
: { 'matDatetimePickerMax': { 'max': max, 'actual': controlValue } };
};
/** Whether the last value set on the input was valid. */
this._lastValueValid = false;
if (!this._dateAdapter) {
throw createMissingDateImplError$1('NgxMatDateAdapter');
}
if (!this._dateFormats) {
throw createMissingDateImplError$1('NGX_MAT_DATE_FORMATS');
}
// Update the displayed date when the locale changes.
this._localeSubscription = _dateAdapter.localeChanges.subscribe(() => {
this._assignValueProgrammatically(this.value);
});
}
ngAfterViewInit() {
this._isInitialized = true;
}
ngOnChanges(changes) {
if (dateInputsHaveChanged(changes, this._dateAdapter)) {
this.stateChanges.next(undefined);
}
}
ngOnDestroy() {
this._valueChangesSubscription.unsubscribe();
this._localeSubscription.unsubscribe();
this.stateChanges.complete();
}
/** @docs-private */
registerOnValidatorChange(fn) {
this._validatorOnChange = fn;
}
/** @docs-private */
validate(c) {
return this._validator ? this._validator(c) : null;
}
// Implemented as part of ControlValueAccessor.
writeValue(value) {
this._assignValueProgrammatically(value);
}
// Implemented as part of ControlValueAccessor.
registerOnChange(fn) {
this._cvaOnChange = fn;
}
// Implemented as part of ControlValueAccessor.
registerOnTouched(fn) {
this._onTouched = fn;
}
// Implemented as part of ControlValueAccessor.
setDisabledState(isDisabled) {
this.disabled = isDisabled;
}
_onKeydown(event) {
const ctrlShiftMetaModifiers = ['ctrlKey', 'shiftKey', 'metaKey'];
const isAltDownArrow = hasModifierKey(event, 'altKey') &&
event.keyCode === DOWN_ARROW &&
ctrlShiftMetaModifiers.every((modifier) => !hasModifierKey(event, modifier));
if (isAltDownArrow && !this._elementRef.nativeElement.readOnly) {
this._openPopup();
event.preventDefault();
}
}
_onInput(value) {
const lastValueWasValid = this._lastValueValid;
let date = this._dateAdapter.parse(value, this._dateFormats.parse.dateInput);
this._lastValueValid = this._isValidValue(date);
date = this._dateAdapter.getValidDateOrNull(date);
const isSameTime = this._dateAdapter.isSameTime(date, this.value);
const isSameDate = this._dateAdapter.sameDate(date, this.value);
const isSame = isSameDate && isSameTime;
const hasChanged = !isSame;
// We need to fire the CVA change event for all
// nulls, otherwise the validators won't run.
if (!date || hasChanged) {
this._cvaOnChange(date);
}
else {
// Call the CVA change handler for invalid values
// since this is what marks the control as dirty.
if (value && !this.value) {
this._cvaOnChange(date);
}
if (lastValueWasValid !== this._lastValueValid) {
this._validatorOnChange();
}
}
if (hasChanged) {
this._assignValue(date);
this.dateInput.emit(new NgxMatDatepickerInputEvent(this, this._elementRef.nativeElement));
}
}
_onChange() {
this.dateChange.emit(new NgxMatDatepickerInputEvent(this, this._elementRef.nativeElement));
}
/** Handles blur events on the input. */
_onBlur() {
// Reformat the input only if we have a valid value.
if (this.value) {
this._formatValue(this.value);
}
this._onTouched();
}
/** Formats a value and sets it on the input element. */
_formatValue(value) {
this._elementRef.nativeElement.value =
value != null ? this._dateAdapter.format(value, this._dateFormats.display.dateInput) : '';
}
/** Assigns a value to the model. */
_assignValue(value) {
// We may get some incoming values before the model was
// assigned. Save the value so that we can assign it later.
if (this._model) {
this._assignValueToModel(value);
this._pendingValue = null;
}
else {
this._pendingValue = value;
}
}
/** Whether a value is considered valid. */
_isValidValue(value) {
return !value || this._dateAdapter.isValid(value);
}
/**
* Checks whether a parent control is disabled. This is in place so that it can be overridden
* by inputs extending this one which can be placed inside of a group that can be disabled.
*/
_parentDisabled() {
return false;
}
/** Programmatically assigns a value to the input. */
_assignValueProgrammatically(value) {
value = this._dateAdapter.deserialize(value);
this._lastValueValid = this._isValidValue(value);
value = this._dateAdapter.getValidDateOrNull(value);
this._assignValue(value);
this._formatValue(value);
}
/** Gets whether a value matches the current date filter. */
_matchesFilter(value) {
const filter = this._getDateFilter();
return !filter || filter(value);
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDatepickerInputBase, deps: [{ token: i0.ElementRef }, { token: NgxMatDateAdapter, optional: true }, { token: NGX_MAT_DATE_FORMATS, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
/** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.10", type: NgxMatDatepickerInputBase, isStandalone: true, inputs: { value: "value", disabled: "disabled" }, outputs: { dateChange: "dateChange", dateInput: "dateInput" }, usesOnChanges: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDatepickerInputBase, decorators: [{
type: Directive
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: NgxMatDateAdapter, decorators: [{
type: Optional
}] }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: [NGX_MAT_DATE_FORMATS]
}] }], propDecorators: { value: [{
type: Input
}], disabled: [{
type: Input
}], dateChange: [{
type: Output
}], dateInput: [{
type: Output
}] } });
/**
* Checks whether the `SimpleChanges` object from an `ngOnChanges`
* callback has any changes, accounting for date objects.
*/
function dateInputsHaveChanged(changes, adapter) {
const keys = Object.keys(changes);
for (let key of keys) {
const { previousValue, currentValue } = changes[key];
if (adapter.isDateInstance(previousValue) && adapter.isDateInstance(currentValue)) {
if (!adapter.sameDate(previousValue, currentValue)) {
return true;
}
}
else {
return true;
}
}
return false;
}
/**
* Used to provide the date range input wrapper component
* to the parts without circular dependencies.
*/
const NGX_MAT_DATE_RANGE_INPUT_PARENT = new InjectionToken("NGX_MAT_DATE_RANGE_INPUT_PARENT");
/**
* Base class for the individual inputs that can be projected inside a `mat-date-range-input`.
*/
class NgxMatDateRangeInputPartBase extends NgxMatDatepickerInputBase {
constructor(_rangeInput, _elementRef, _defaultErrorStateMatcher, _injector, _parentForm, _parentFormGroup, dateAdapter, dateFormats) {
super(_elementRef, dateAdapter, dateFormats);
this._rangeInput = _rangeInput;
this._elementRef = _elementRef;
this._defaultErrorStateMatcher = _defaultErrorStateMatcher;
this._injector = _injector;
this._parentForm = _parentForm;
this._parentFormGroup = _parentFormGroup;
this._dir = inject(Directionality, { optional: true });
this._errorState = false;
}
ngOnInit() {
// We need the date input to provide itself as a `ControlValueAccessor` and a `Validator`, while
// injecting its `NgControl` so that the error state is handled correctly. This introduces a
// circular dependency, because both `ControlValueAccessor` and `Validator` depend on the input
// itself. Usually we can work around it for the CVA, but there's no API to do it for the
// validator. We work around it here by injecting the `NgControl` in `ngOnInit`, after
// everything has been resolved.
// tslint:disable-next-line:no-bitwise
const ngControl = this._injector.get(NgControl, null, {
optional: true,
self: true,
});
if (ngControl) {
this.ngControl = ngControl;
}
}
ngDoCheck() {
if (this.ngControl) {
// We need to re-evaluate this on every change detection cycle, because there are some
// error triggers that we can't subscribe to (e.g. parent form submissions). This means
// that whatever logic is in here has to be super lean or we risk destroying the performance.
this.updateErrorState();
}
}
/** Whether the component is in an error state. */
get errorState() {
return this._errorState;
}
/** Sets the error state of the component. */
set errorState(value) {
this._errorState = value;
this._elementRef.nativeElement.classList.toggle("mat-error", value);
}
/** Updates the error state of the component. */
updateErrorState() {
const isInvalid = this._defaultErrorStateMatcher.isErrorState(this.ngControl, this._elementRef);
this._errorState = isInvalid;
this._elementRef.nativeElement.classList.toggle("mat-error", isInvalid);
}
/** Gets whether the input is empty. */
isEmpty() {
return this._elementRef.nativeElement.value.length === 0;
}
/** Gets the placeholder of the input. */
_getPlaceholder() {
return this._elementRef.nativeElement.placeholder;
}
/** Focuses the input. */
focus() {
this._elementRef.nativeElement.focus();
}
/** Gets the value that should be used when mirroring the input's size. */
getMirrorValue() {
const element = this._elementRef.nativeElement;
const value = element.value;
return value.length > 0 ? value : element.placeholder;
}
/** Handles `input` events on the input element. */
_onInput(value) {
super._onInput(value);
this._rangeInput._handleChildValueChange();
}
/** Opens the datepicker associated with the input. */
_openPopup() {
this._rangeInput._openDatepicker();
}
/** Gets the minimum date from the range input. */
_getMinDate() {
return this._rangeInput.min;
}
/** Gets the maximum date from the range input. */
_getMaxDate() {
return this._rangeInput.max;
}
/** Gets the date filter function from the range input. */
_getDateFilter() {
return this._rangeInput.dateFilter;
}
_parentDisabled() {
return this._rangeInput._groupDisabled;
}
_shouldHandleChangeEvent({ source, }) {
return (source !== this._rangeInput._startInput &&
source !== this._rangeInput._endInput);
}
_assignValueProgrammatically(value) {
super._assignValueProgrammatically(value);
const opposite = (this === this._rangeInput._startInput
? this._rangeInput._endInput
: this._rangeInput._startInput);
opposite?._validatorOnChange();
}
/** return the ARIA accessible name of the input element */
_getAccessibleName() {
return _computeAriaAccessibleName(this._elementRef.nativeElement);
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDateRangeInputPartBase, deps: [{ token: NGX_MAT_DATE_RANGE_INPUT_PARENT }, { token: i0.ElementRef }, { token: i1$1.ErrorStateMatcher }, { token: i0.Injector }, { token: i2.NgForm, optional: true }, { token: i2.FormGroupDirective, optional: true }, { token: NgxMatDateAdapter, optional: true }, { token: NGX_MAT_DATE_FORMATS, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
/** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.10", type: NgxMatDateRangeInputPartBase, isStandalone: true, usesInheritance: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDateRangeInputPartBase, decorators: [{
type: Directive
}], ctorParameters: () => [{ type: undefined, decorators: [{
type: Inject,
args: [NGX_MAT_DATE_RANGE_INPUT_PARENT]
}] }, { type: i0.ElementRef }, { type: i1$1.ErrorStateMatcher }, { type: i0.Injector }, { type: i2.NgForm, decorators: [{
type: Optional
}] }, { type: i2.FormGroupDirective, decorators: [{
type: Optional
}] }, { type: NgxMatDateAdapter, decorators: [{
type: Optional
}] }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: [NGX_MAT_DATE_FORMATS]
}] }] });
/** Input for entering the start date in a `mat-date-range-input`. */
class NgxMatStartDate extends NgxMatDateRangeInputPartBase {
constructor(rangeInput, elementRef, defaultErrorStateMatcher, injector, parentForm, parentFormGroup, dateAdapter, dateFormats) {
super(rangeInput, elementRef, defaultErrorStateMatcher, injector, parentForm, parentFormGroup, dateAdapter, dateFormats);
/** Validator that checks that the start date isn't after the end date. */
this._startValidator = (control) => {
const start = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(control.value));
const end = this._model ? this._model.selection.end : null;
return !start || !end || this._dateAdapter.compareDate(start, end) <= 0
? null
: { matStartDateInvalid: { end: end, actual: start } };
};
this._validator = Validators.compose([
...super._getValidators(),
this._startValidator,
]);
}
_getValueFromModel(modelValue) {
return modelValue.start;
}
_shouldHandleChangeEvent(change) {
if (!super._shouldHandleChangeEvent(change)) {
return false;
}
else {
return !change.oldValue?.start
? !!change.selection.start
: !change.selection.start ||
!!this._dateAdapter.compareDate(change.oldValue.start, change.selection.start);
}
}
_assignValueToModel(value) {
if (this._model) {
const range = new NgxDateRange(value, this._model.selection.end);
this._model.updateSelection(range, this);
}
}
_formatValue(value) {
super._formatValue(value);
// Any time the input value is reformatted we need to tell the parent.
this._rangeInput._handleChildValueChange();
}
_onKeydown(event) {
const endInput = this._rangeInput._endInput;
const element = this._elementRef.nativeElement;
const isLtr = this._dir?.value !== "rtl";
// If the user hits RIGHT (LTR) when at the end of the input (and no
// selection), move the cursor to the start of the end input.
if (((event.keyCode === RIGHT_ARROW && isLtr) ||
(event.keyCode === LEFT_ARROW && !isLtr)) &&
element.selectionStart === element.value.length &&
element.selectionEnd === element.value.length) {
event.preventDefault();
endInput._elementRef.nativeElement.setSelectionRange(0, 0);
endInput.focus();
}
else {
super._onKeydown(event);
}
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatStartDate, deps: [{ token: NGX_MAT_DATE_RANGE_INPUT_PARENT }, { token: i0.ElementRef }, { token: i1$1.ErrorStateMatcher }, { token: i0.Injector }, { token: NgForm, optional: true }, { token: FormGroupDirective, optional: true }, { token: NgxMatDateAdapter, optional: true }, { token: NGX_MAT_DATE_FORMATS, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
/** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.10", type: NgxMatStartDate, isStandalone: false, selector: "input[ngxMatStartDate]", inputs: { errorStateMatcher: "errorStateMatcher" }, outputs: { dateChange: "dateChange", dateInput: "dateInput" }, host: { attributes: { "type": "text" }, listeners: { "input": "_onInput($event.target.value)", "change": "_onChange()", "keydown": "_onKeydown($event)", "blur": "_onBlur()" }, properties: { "disabled": "disabled", "attr.aria-haspopup": "_rangeInput.rangePicker ? \"dialog\" : null", "attr.aria-owns": "(_rangeInput.rangePicker?.opened && _rangeInput.rangePicker.id) || null", "attr.min": "_getMinDate() ? _dateAdapter.toIso8601(_getMinDate()) : null", "attr.max": "_getMaxDate() ? _dateAdapter.toIso8601(_getMaxDate()) : null" }, classAttribute: "mat-start-date mat-date-range-input-inner" }, providers: [
{ provide: NG_VALUE_ACCESSOR, useExisting: NgxMatStartDate, multi: true },
{ provide: NG_VALIDATORS, useExisting: NgxMatStartDate, multi: true },
], usesInheritance: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatStartDate, decorators: [{
type: Directive,
args: [{
selector: "input[ngxMatStartDate]",
host: {
class: "mat-start-date mat-date-range-input-inner",
"[disabled]": "disabled",
"(input)": "_onInput($event.target.value)",
"(change)": "_onChange()",
"(keydown)": "_onKeydown($event)",
"[attr.aria-haspopup]": '_rangeInput.rangePicker ? "dialog" : null',
"[attr.aria-owns]": "(_rangeInput.rangePicker?.opened && _rangeInput.rangePicker.id) || null",
"[attr.min]": "_getMinDate() ? _dateAdapter.toIso8601(_getMinDate()) : null",
"[attr.max]": "_getMaxDate() ? _dateAdapter.toIso8601(_getMaxDate()) : null",
"(blur)": "_onBlur()",
type: "text",
},
providers: [
{ provide: NG_VALUE_ACCESSOR, useExisting: NgxMatStartDate, multi: true },
{ provide: NG_VALIDATORS, useExisting: NgxMatStartDate, multi: true },
],
// These need to be specified explicitly, because some tooling doesn't
// seem to pick them up from the base class. See #20932.
outputs: ["dateChange", "dateInput"],
inputs: ["errorStateMatcher"],
standalone: false,
}]
}], ctorParameters: () => [{ type: undefined, decorators: [{
type: Inject,
args: [NGX_MAT_DATE_RANGE_INPUT_PARENT]
}] }, { type: i0.ElementRef }, { type: i1$1.ErrorStateMatcher }, { type: i0.Injector }, { type: i2.NgForm, decorators: [{
type: Optional
}, {
type: Inject,
args: [NgForm]
}] }, { type: i2.FormGroupDirective, decorators: [{
type: Optional
}, {
type: Inject,
args: [FormGroupDirective]
}] }, { type: NgxMatDateAdapter, decorators: [{
type: Optional
}] }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: [NGX_MAT_DATE_FORMATS]
}] }] });
/** Input for entering the end date in a `mat-date-range-input`. */
class NgxMatEndDate extends NgxMatDateRangeInputPartBase {
constructor(rangeInput, elementRef, defaultErrorStateMatcher, injector, parentForm, parentFormGroup, dateAdapter, dateFormats) {
super(rangeInput, elementRef, defaultErrorStateMatcher, injector, parentForm, parentFormGroup, dateAdapter, dateFormats);
/** Validator that checks that the end date isn't before the start date. */
this._endValidator = (control) => {
const end = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(control.value));
const start = this._model ? this._model.selection.start : null;
return !end || !start || this._dateAdapter.compareDate(end, start) >= 0
? null
: { matEndDateInvalid: { start: start, actual: end } };
};
this._validator = Validators.compose([
...super._getValidators(),
this._endValidator,
]);
}
_getValueFromModel(modelValue) {
return modelValue.end;
}
_shouldHandleChangeEvent(change) {
if (!super._shouldHandleChangeEvent(change)) {
return false;
}
else {
return !change.oldValue?.end
? !!change.selection.end
: !change.selection.end ||
!!super._dateAdapter.compareDate(change.oldValue.end, change.selection.end);
}
}
_assignValueToModel(value) {
if (this._model) {
const range = new NgxDateRange(this._model.selection.start, value);
this._model.updateSelection(range, this);
}
}
_onKeydown(event) {
const startInput = this._rangeInput._startInput;
const element = this._elementRef.nativeElement;
const isLtr = this._dir?.value !== "rtl";
// If the user is pressing backspace on an empty end input, move focus back to the start.
if (event.keyCode === BACKSPACE && !element.value) {
startInput.focus();
}
// If the user hits LEFT (LTR) when at the start of the input (and no
// selection), move the cursor to the end of the start input.
else if (((event.keyCode === LEFT_ARROW && isLtr) ||
(event.keyCode === RIGHT_ARROW && !isLtr)) &&
element.selectionStart === 0 &&
element.selectionEnd === 0) {
event.preventDefault();
const endPosition = startInput._elementRef.nativeElement.value.length;
startInput._elementRef.nativeElement.setSelectionRange(endPosition, endPosition);
startInput.focus();
}
else {
super._onKeydown(event);
}
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatEndDate, deps: [{ token: NGX_MAT_DATE_RANGE_INPUT_PARENT }, { token: i0.ElementRef }, { token: i1$1.ErrorStateMatcher }, { token: i0.Injector }, { token: NgForm, optional: true }, { token: FormGroupDirective, optional: true }, { token: NgxMatDateAdapter, optional: true }, { token: NGX_MAT_DATE_FORMATS, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
/** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.10", type: NgxMatEndDate, isStandalone: false, selector: "input[ngxMatEndDate]", inputs: { errorStateMatcher: "errorStateMatcher" }, outputs: { dateChange: "dateChange", dateInput: "dateInput" }, host: { attributes: { "type": "text" }, listeners: { "input": "_onInput($event.target.value)", "change": "_onChange()", "keydown": "_onKeydown($event)", "blur": "_onBlur()" }, properties: { "disabled": "disabled", "attr.aria-haspopup": "_rangeInput.rangePicker ? \"dialog\" : null", "attr.aria-owns": "(_rangeInput.rangePicker?.opened && _rangeInput.rangePicker.id) || null", "attr.min": "_getMinDate() ? _dateAdapter.toIso8601(_getMinDate()) : null", "attr.max": "_getMaxDate() ? _dateAdapter.toIso8601(_getMaxDate()) : null" }, classAttribute: "mat-end-date mat-date-range-input-inner" }, providers: [
{ provide: NG_VALUE_ACCESSOR, useExisting: NgxMatEndDate, multi: true },
{ provide: NG_VALIDATORS, useExisting: NgxMatEndDate, multi: true },
], usesInheritance: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatEndDate, decorators: [{
type: Directive,
args: [{
selector: "input[ngxMatEndDate]",
host: {
class: "mat-end-date mat-date-range-input-inner",
"[disabled]": "disabled",
"(input)": "_onInput($event.target.value)",
"(change)": "_onChange()",
"(keydown)": "_onKeydown($event)",
"[attr.aria-haspopup]": '_rangeInput.rangePicker ? "dialog" : null',
"[attr.aria-owns]": "(_rangeInput.rangePicker?.opened && _rangeInput.rangePicker.id) || null",
"[attr.min]": "_getMinDate() ? _dateAdapter.toIso8601(_getMinDate()) : null",
"[attr.max]": "_getMaxDate() ? _dateAdapter.toIso8601(_getMaxDate()) : null",
"(blur)": "_onBlur()",
type: "text",
},
providers: [
{ provide: NG_VALUE_ACCESSOR, useExisting: NgxMatEndDate, multi: true },
{ provide: NG_VALIDATORS, useExisting: NgxMatEndDate, multi: true },
],
// These need to be specified explicitly, because some tooling doesn't
// seem to pick them up from the base class. See #20932.
outputs: ["dateChange", "dateInput"],
inputs: ["errorStateMatcher"],
standalone: false,
}]
}], ctorParameters: () => [{ type: undefined, decorators: [{
type: Inject,
args: [NGX_MAT_DATE_RANGE_INPUT_PARENT]
}] }, { type: i0.ElementRef }, { type: i1$1.ErrorStateMatcher }, { type: i0.Injector }, { type: i2.NgForm, decorators: [{
type: Optional
}, {
type: Inject,
args: [NgForm]
}] }, { type: i2.FormGroupDirective, decorators: [{
type: Optional
}, {
type: Inject,
args: [FormGroupDirective]
}] }, { type: NgxMatDateAdapter, decorators: [{
type: Optional
}] }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: [NGX_MAT_DATE_FORMATS]
}] }] });
let nextUniqueId = 0;
class NgxMatDateRangeInput {
/** Current value of the range input. */
get value() {
return this._model ? this._model.selection : null;
}
/** Whether the control's label should float. */
get shouldLabelFloat() {
return this.focused || !this.empty;
}
/**
* Implemented as a part of `MatFormFieldControl`.
* Set the placeholder attribute on `matStartDate` and `matEndDate`.
* @docs-private
*/
get placeholder() {
const start = this._startInput?._getPlaceholder() || "";
const end = this._endInput?._getPlaceholder() || "";
return start || end ? `${start} ${this.separator} ${end}` : "";
}
/** The range picker that this input is associated with. */
get rangePicker() {
return this._rangePicker;
}
set rangePicker(rangePicker) {
if (rangePicker) {
this._model = rangePicker.registerInput(this);
this._rangePicker = rangePicker;
this._closedSubscription.unsubscribe();
this._closedSubscription = rangePicker.closedStream.subscribe(() => {
this._startInput?._onTouched();
this._endInput?._onTouched();
});
this._registerModel(this._model);
}
}
/** Whether the input is required. */
get required() {
return (this._required ??
(this._isTargetRequired(this) ||
this._isTargetRequired(this._startInput) ||
this._isTargetRequired(this._endInput)) ??
false);
}
set required(value) {
this._required = coerceBooleanProperty(value);
}
/** Function that can be used to filter out dates within the date range picker. */
get dateFilter() {
return this._dateFilter;
}
set dateFilter(value) {
const start = this._startInput;
const end = this._endInput;
const wasMatchingStart = start && start._matchesFilter(start.value);
const wasMatchingEnd = end && end._matchesFilter(start.value);
this._dateFilter = value;
if (start && start._matchesFilter(start.value) !== wasMatchingStart) {
start._validatorOnChange();
}
if (end && end._matchesFilter(end.value) !== wasMatchingEnd) {
end._validatorOnChange();
}
}
/** The minimum valid date. */
get min() {
return this._min;
}
set min(value) {
const validValue = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value));
if (!this._dateAdapter.sameDate(validValue, this._min)) {
this._min = validValue;
this._revalidate();
}
}
/** The maximum valid date. */
get max() {
return this._max;
}
set max(value) {
const validValue = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value));
if (!this._dateAdapter.sameDate(validValue, this._max)) {
this._max = validValue;
this._revalidate();
}
}
/** Whether the input is disabled. */
get disabled() {
return this._startInput && this._endInput
? this._startInput.disabled && this._endInput.disabled
: this._groupDisabled;
}
set disabled(value) {
const newValue = coerceBooleanProperty(value);
if (newValue !== this._groupDisabled) {
this._groupDisabled = newValue;
this.stateChanges.next(undefined);
}
}
/** Whether the input is in an error state. */
get errorState() {
if (this._startInput && this._endInput) {
return this._startInput.errorState || this._endInput.errorState;
}
return false;
}
/** Whether the datepicker input is empty. */
get empty() {
const startEmpty = this._startInput ? this._startInput.isEmpty() : false;
const endEmpty = this._endInput ? this._endInput.isEmpty() : false;
return startEmpty && endEmpty;
}
constructor(_changeDetectorRef, _elementRef, control, _dateAdapter, _formField) {
this._changeDetectorRef = _changeDetectorRef;
this._elementRef = _elementRef;
this._dateAdapter = _dateAdapter;
this._formField = _formField;
this._closedSubscription = Subscription.EMPTY;
/** Unique ID for the group. */
this.id = `mat-date-range-input-${nextUniqueId++}`;
/** Whether the control is focused. */
this.focused = false;
/** Name of the form control. */
this.controlType = "mat-date-range-input";
this._groupDisabled = false;
/** Value for the `aria-describedby` attribute of the inputs. */
this._ariaDescribedBy = null;
/** Separator text to be shown between the inputs. */
this.separator = "–";
/** Start of the comparison range that should be shown in the calendar. */
this.comparisonStart = null;
/** End of the comparison range that should be shown in the calendar. */
this.comparisonEnd = null;
/** Emits when the input's state has changed. */
this.stateChanges = new Subject();
if (!_dateAdapter) {
throw createMissingDateImplError$1("NgxMatDateAdapter");
}
// The datepicker module can be used both with MDC and non-MDC form fields. We have
// to conditionally add the MDC input class so that the range picker looks correctly.
if (_formField?._elementRef.nativeElement.classList.contains("mat-mdc-form-field")) {
_elementRef.nativeElement.classList.add("mat-mdc-input-element", "mat-mdc-form-field-input-control", "mdc-text-field__input");
}
// TODO(crisbeto): remove `as any` after #18206 lands.
this.ngControl = control;
}
/**
* Implemented as a part of `MatFormFieldControl`.
* @docs-private
*/
setDescribedByIds(ids) {
this._ariaDescribedBy = ids.length ? ids.join(" ") : null;
}
/**
* Implemented as a part of `MatFormFieldControl`.
* @docs-private
*/
onContainerClick() {
if (!this.focused && !this.disabled) {
if (!this._model || !this._model.selection.start) {
this._startInput.focus();
}
else {
this._endInput.focus();
}
}
}
ngAfterContentInit() {
if (!this._startInput) {
throw Error("mat-date-range-input must contain a matStartDate input");
}
if (!this._endInput) {
throw Error("mat-date-range-input must contain a matEndDate input");
}
if (this._model) {
this._registerModel(this._model);
}
// We don't need to unsubscribe from this, because we
// know that the input streams will be completed on destroy.
merge(this._startInput.stateChanges, this._endInput.stateChanges).subscribe(() => {
this.stateChanges.next(undefined);
});
}
ngOnChanges(changes) {
if (dateInputsHaveChanged(changes, this._dateAdapter)) {
this.stateChanges.next(undefined);
}
}
ngOnDestroy() {
this._closedSubscription.unsubscribe();
this.stateChanges.complete();
}
/** Gets the date at which the calendar should start. */
getStartValue() {
return this.value ? this.value.start : null;
}
/** Gets the input's theme palette. */
getThemePalette() {
return this._formField ? this._formField.color : undefined;
}
/** Gets the element to which the calendar overlay should be attached. */
getConnectedOverlayOrigin() {
return this._formField
? this._formField.getConnectedOverlayOrigin()
: this._elementRef;
}
/** Gets the ID of an element that should be used a description for the calendar overlay. */
getOverlayLabelId() {
return this._formField ? this._formField.getLabelId() : null;
}
/** Gets the value that is used to mirror the state input. */
_getInputMirrorValue(part) {
const input = part === "start" ? this._startInput : this._endInput;
return input ? input.getMirrorValue() : "";
}
/** Whether the input placeholders should be hidden. */
_shouldHidePlaceholders() {
return this._startInput ? !this._startInput.isEmpty() : false;
}
/** Handles the value in one of the child inputs changing. */
_handleChildValueChange() {
this.stateChanges.next(undefined);
this._changeDetectorRef.markForCheck();
}
/** Opens the date range picker associated with the input. */
_openDatepicker() {
if (this._rangePicker) {
this._rangePicker.open();
}
}
/** Whether the separate text should be hidden. */
_shouldHideSeparator() {
return ((!this._formField ||
(this._formField.getLabelId() &&
!this._formField._shouldLabelFloat())) &&
this.empty);
}
/** Gets the value for the `aria-labelledby` attribute of the inputs. */
_getAriaLabelledby() {
const formField = this._formField;
return formField && formField._hasFloatingLabel()
? formField._labelId
: null;
}
_getStartDateAccessibleName() {
return this._startInput._getAccessibleName();
}
_getEndDateAccessibleName() {
return this._endInput._getAccessibleName();
}
/** Updates the focused state of the range input. */
_updateFocus(origin) {
this.focused = origin !== null;
this.stateChanges.next();
}
/** Re-runs the validators on the start/end inputs. */
_revalidate() {
if (this._startInput) {
this._startInput._validatorOnChange();
}
if (this._endInput) {
this._endInput._validatorOnChange();
}
}
/** Registers the current date selection model with the start/end inputs. */
_registerModel(model) {
if (this._startInput) {
this._startInput._registerModel(model);
}
if (this._endInput) {
this._endInput._registerModel(model);
}
}
/** Checks whether a specific range input directive is required. */
_isTargetRequired(target) {
return target?.ngControl?.control?.hasValidator(Validators.required);
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDateRangeInput, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: ControlContainer, optional: true, self: true }, { token: NgxMatDateAdapter, optional: true }, { token: MAT_FORM_FIELD, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
/** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.10", type: NgxMatDateRangeInput, isStandalone: false, selector: "ngx-mat-date-range-input", inputs: { rangePicker: "rangePicker", required: "required", dateFilter: "dateFilter", min: "min", max: "max", disabled: "disabled", separator: "separator", comparisonStart: "comparisonStart", comparisonEnd: "comparisonEnd" }, host: { attributes: { "role": "group" }, properties: { "class.mat-date-range-input-hide-placeholders": "_shouldHidePlaceholders()", "class.mat-date-range-input-required": "required", "attr.id": "id", "attr.aria-labelledby": "_getAriaLabelledby()", "attr.aria-describedby": "_ariaDescribedBy", "attr.data-mat-calendar": "rangePicker ? rangePicker.id : null" }, classAttribute: "mat-date-range-input" }, providers: [
{ provide: MatFormFieldControl, useExisting: NgxMatDateRangeInput },
{
provide: NGX_MAT_DATE_RANGE_INPUT_PARENT,
useExisting: NgxMatDateRangeInput,
},
], queries: [{ propertyName: "_startInput", first: true, predicate: NgxMatStartDate, descendants: true }, { propertyName: "_endInput", first: true, predicate: NgxMatEndDate, descendants: true }], exportAs: ["ngxMatDateRangeInput"], usesOnChanges: true, ngImport: i0, template: "<div\r\n class=\"mat-date-range-input-container\"\r\n cdkMonitorSubtreeFocus\r\n (cdkFocusChange)=\"_updateFocus($event)\"\r\n>\r\n <div class=\"mat-date-range-input-wrapper\">\r\n <ng-content select=\"input[matStartDate]\"></ng-content>\r\n <span class=\"mat-date-range-input-mirror\" aria-hidden=\"true\"\r\n >{{_getInputMirrorValue('start')}}</span\r\n >\r\n </div>\r\n\r\n <span\r\n class=\"mat-date-range-input-separator\"\r\n [class.mat-date-range-input-separator-hidden]=\"_shouldHideSeparator()\"\r\n >{{separator}}</span\r\n >\r\n\r\n <div class=\"mat-date-range-input-wrapper mat-date-range-input-end-wrapper\">\r\n <ng-content select=\"input[matEndDate]\"></ng-content>\r\n <span class=\"mat-date-range-input-mirror\" aria-hidden=\"true\"\r\n >{{_getInputMirrorValue('end')}}</span\r\n >\r\n </div>\r\n</div>\r\n", styles: [".mat-date-range-input{display:block;width:100%}.mat-date-range-input-container{display:flex;align-items:center}.mat-date-range-input-separator{transition:opacity .4s .1333333333333s cubic-bezier(.25,.8,.25,1);margin:0 4px}._mat-animation-noopable .mat-date-range-input-separator{transition:none}.mat-date-range-input-separator-hidden{-webkit-user-select:none;user-select:none;opacity:0;transition:none}.mat-date-range-input-wrapper{position:relative;overflow:hidden;max-width:calc(50% - 4px)}.mat-date-range-input-end-wrapper{flex-grow:1}.mat-date-range-input-inner{position:absolute;top:0;left:0;font:inherit;background:transparent;color:currentColor;border:none;outline:none;padding:0;margin:0;vertical-align:bottom;text-align:inherit;width:100%;height:100%}.mat-date-range-input-inner:-moz-ui-invalid{box-shadow:none}.mat-form-field-hide-placeholder .mat-date-range-input-inner::placeholder,.mat-date-range-input-hide-placeholders .mat-date-range-input-inner::placeholder{-webkit-user-select:none;user-select:none;color:transparent!important;-webkit-text-fill-color:transparent;transition:none}@media (forced-colors: active){.mat-form-field-hide-placeholder .mat-date-range-input-inner::placeholder,.mat-date-range-input-hide-placeholders .mat-date-range-input-inner::placeholder{opacity:0}}.mat-form-field-hide-placeholder .mat-date-range-input-inner::-moz-placeholder,.mat-date-range-input-hide-placeholders .mat-date-range-input-inner::-moz-placeholder{-webkit-user-select:none;user-select:none;color:transparent!important;-webkit-text-fill-color:transparent;transition:none}@media (forced-colors: active){.mat-form-field-hide-placeholder .mat-date-range-input-inner::-moz-placeholder,.mat-date-range-input-hide-placeholders .mat-date-range-input-inner::-moz-placeholder{opacity:0}}.mat-form-field-hide-placeholder .mat-date-range-input-inner::-webkit-input-placeholder,.mat-date-range-input-hide-placeholders .mat-date-range-input-inner::-webkit-input-placeholder{-webkit-user-select:none;user-select:none;color:transparent!important;-webkit-text-fill-color:transparent;transition:none}@media (forced-colors: active){.mat-form-field-hide-placeholder .mat-date-range-input-inner::-webkit-input-placeholder,.mat-date-range-input-hide-placeholders .mat-date-range-input-inner::-webkit-input-placeholder{opacity:0}}.mat-form-field-hide-placeholder .mat-date-range-input-inner:-ms-input-placeholder,.mat-date-range-input-hide-placeholders .mat-date-range-input-inner:-ms-input-placeholder{-webkit-user-select:none;user-select:none;color:transparent!important;-webkit-text-fill-color:transparent;transition:none}@media (forced-colors: active){.mat-form-field-hide-placeholder .mat-date-range-input-inner:-ms-input-placeholder,.mat-date-range-input-hide-placeholders .mat-date-range-input-inner:-ms-input-placeholder{opacity:0}}._mat-animation-noopable .mat-date-range-input-inner::placeholder{transition:none}._mat-animation-noopable .mat-date-range-input-inner::-moz-placeholder{transition:none}._mat-animation-noopable .mat-date-range-input-inner::-webkit-input-placeholder{transition:none}._mat-animation-noopable .mat-date-range-input-inner:-ms-input-placeholder{transition:none}.mat-date-range-input-mirror{-webkit-user-select:none;user-select:none;visibility:hidden;white-space:nowrap;display:inline-block;min-width:2px}.mat-mdc-form-field-type-mat-date-range-input .mat-mdc-form-field-infix{width:200px}\n"], dependencies: [{ kind: "directive", type: i2$1.CdkMonitorFocus, selector: "[cdkMonitorElementFocus], [cdkMonitorSubtreeFocus]", outputs: ["cdkFocusChange"], exportAs: ["cdkMonitorFocus"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDateRangeInput, decorators: [{
type: Component,
args: [{ selector: "ngx-mat-date-range-input", exportAs: "ngxMatDateRangeInput", host: {
class: "mat-date-range-input",
"[class.mat-date-range-input-hide-placeholders]": "_shouldHidePlaceholders()",
"[class.mat-date-range-input-required]": "required",
"[attr.id]": "id",
role: "group",
"[attr.aria-labelledby]": "_getAriaLabelledby()",
"[attr.aria-describedby]": "_ariaDescribedBy",
// Used by the test harness to tie this input to its calendar. We can't depend on
// `aria-owns` for this, because it's only defined while the calendar is open.
"[attr.data-mat-calendar]": "rangePicker ? rangePicker.id : null",
}, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, providers: [
{ provide: MatFormFieldControl, useExisting: NgxMatDateRangeInput },
{
provide: NGX_MAT_DATE_RANGE_INPUT_PARENT,
useExisting: NgxMatDateRangeInput,
},
], standalone: false, template: "<div\r\n class=\"mat-date-range-input-container\"\r\n cdkMonitorSubtreeFocus\r\n (cdkFocusChange)=\"_updateFocus($event)\"\r\n>\r\n <div class=\"mat-date-range-input-wrapper\">\r\n <ng-content select=\"input[matStartDate]\"></ng-content>\r\n <span class=\"mat-date-range-input-mirror\" aria-hidden=\"true\"\r\n >{{_getInputMirrorValue('start')}}</span\r\n >\r\n </div>\r\n\r\n <span\r\n class=\"mat-date-range-input-separator\"\r\n [class.mat-date-range-input-separator-hidden]=\"_shouldHideSeparator()\"\r\n >{{separator}}</span\r\n >\r\n\r\n <div class=\"mat-date-range-input-wrapper mat-date-range-input-end-wrapper\">\r\n <ng-content select=\"input[matEndDate]\"></ng-content>\r\n <span class=\"mat-date-range-input-mirror\" aria-hidden=\"true\"\r\n >{{_getInputMirrorValue('end')}}</span\r\n >\r\n </div>\r\n</div>\r\n", styles: [".mat-date-range-input{display:block;width:100%}.mat-date-range-input-container{display:flex;align-items:center}.mat-date-range-input-separator{transition:opacity .4s .1333333333333s cubic-bezier(.25,.8,.25,1);margin:0 4px}._mat-animation-noopable .mat-date-range-input-separator{transition:none}.mat-date-range-input-separator-hidden{-webkit-user-select:none;user-select:none;opacity:0;transition:none}.mat-date-range-input-wrapper{position:relative;overflow:hidden;max-width:calc(50% - 4px)}.mat-date-range-input-end-wrapper{flex-grow:1}.mat-date-range-input-inner{position:absolute;top:0;left:0;font:inherit;background:transparent;color:currentColor;border:none;outline:none;padding:0;margin:0;vertical-align:bottom;text-align:inherit;width:100%;height:100%}.mat-date-range-input-inner:-moz-ui-invalid{box-shadow:none}.mat-form-field-hide-placeholder .mat-date-range-input-inner::placeholder,.mat-date-range-input-hide-placeholders .mat-date-range-input-inner::placeholder{-webkit-user-select:none;user-select:none;color:transparent!important;-webkit-text-fill-color:transparent;transition:none}@media (forced-colors: active){.mat-form-field-hide-placeholder .mat-date-range-input-inner::placeholder,.mat-date-range-input-hide-placeholders .mat-date-range-input-inner::placeholder{opacity:0}}.mat-form-field-hide-placeholder .mat-date-range-input-inner::-moz-placeholder,.mat-date-range-input-hide-placeholders .mat-date-range-input-inner::-moz-placeholder{-webkit-user-select:none;user-select:none;color:transparent!important;-webkit-text-fill-color:transparent;transition:none}@media (forced-colors: active){.mat-form-field-hide-placeholder .mat-date-range-input-inner::-moz-placeholder,.mat-date-range-input-hide-placeholders .mat-date-range-input-inner::-moz-placeholder{opacity:0}}.mat-form-field-hide-placeholder .mat-date-range-input-inner::-webkit-input-placeholder,.mat-date-range-input-hide-placeholders .mat-date-range-input-inner::-webkit-input-placeholder{-webkit-user-select:none;user-select:none;color:transparent!important;-webkit-text-fill-color:transparent;transition:none}@media (forced-colors: active){.mat-form-field-hide-placeholder .mat-date-range-input-inner::-webkit-input-placeholder,.mat-date-range-input-hide-placeholders .mat-date-range-input-inner::-webkit-input-placeholder{opacity:0}}.mat-form-field-hide-placeholder .mat-date-range-input-inner:-ms-input-placeholder,.mat-date-range-input-hide-placeholders .mat-date-range-input-inner:-ms-input-placeholder{-webkit-user-select:none;user-select:none;color:transparent!important;-webkit-text-fill-color:transparent;transition:none}@media (forced-colors: active){.mat-form-field-hide-placeholder .mat-date-range-input-inner:-ms-input-placeholder,.mat-date-range-input-hide-placeholders .mat-date-range-input-inner:-ms-input-placeholder{opacity:0}}._mat-animation-noopable .mat-date-range-input-inner::placeholder{transition:none}._mat-animation-noopable .mat-date-range-input-inner::-moz-placeholder{transition:none}._mat-animation-noopable .mat-date-range-input-inner::-webkit-input-placeholder{transition:none}._mat-animation-noopable .mat-date-range-input-inner:-ms-input-placeholder{transition:none}.mat-date-range-input-mirror{-webkit-user-select:none;user-select:none;visibility:hidden;white-space:nowrap;display:inline-block;min-width:2px}.mat-mdc-form-field-type-mat-date-range-input .mat-mdc-form-field-infix{width:200px}\n"] }]
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i2.ControlContainer, decorators: [{
type: Optional
}, {
type: Self
}, {
type: Inject,
args: [ControlContainer]
}] }, { type: NgxMatDateAdapter, decorators: [{
type: Optional
}] }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: [MAT_FORM_FIELD]
}] }], propDecorators: { rangePicker: [{
type: Input
}], required: [{
type: Input
}], dateFilter: [{
type: Input
}], min: [{
type: Input
}], max: [{
type: Input
}], disabled: [{
type: Input
}], separator: [{
type: Input
}], comparisonStart: [{
type: Input
}], comparisonEnd: [{
type: Input
}], _startInput: [{
type: ContentChild,
args: [NgxMatStartDate]
}], _endInput: [{
type: ContentChild,
args: [NgxMatEndDate]
}] } });
/**
* Animations used by the Material datepicker.
* @docs-private
*/
const ngxMatDatepickerAnimations = {
/** Transforms the height of the datepicker's calendar. */
transformPanel: trigger('transformPanel', [
transition('void => enter-dropdown', animate('120ms cubic-bezier(0, 0, 0.2, 1)', keyframes([
style({ opacity: 0, transform: 'scale(1, 0.8)' }),
style({ opacity: 1, transform: 'scale(1, 1)' }),
]))),
transition('void => enter-dialog', animate('150ms cubic-bezier(0, 0, 0.2, 1)', keyframes([
style({ opacity: 0, transform: 'scale(0.7)' }),
style({ transform: 'none', opacity: 1 }),
]))),
transition('* => void', animate('100ms linear', style({ opacity: 0 }))),
]),
/** Fades in the content of the calendar. */
fadeInCalendar: trigger('fadeInCalendar', [
state('void', style({ opacity: 0 })),
state('enter', style({ opacity: 1 })),
// TODO(crisbeto): this animation should be removed since it isn't quite on spec, but we
// need to keep it until #12440 gets in, otherwise the exit animation will look glitchy.
transition('void => *', animate('120ms 100ms cubic-bezier(0.55, 0, 0.55, 0.2)')),
]),
};
const LIMIT_TIMES = {
minHour: 0,
maxHour: 24,
minMinute: 0,
maxMinute: 60,
minSecond: 0,
maxSecond: 60,
meridian: 12
};
const MERIDIANS = {
AM: 'AM',
PM: 'PM'
};
const DEFAULT_STEP = 1;
const NUMERIC_REGEX = /[^0-9]/g;
const PATTERN_INPUT_HOUR = /^(2[0-3]|[0-1][0-9]|[0-9])$/;
const PATTERN_INPUT_MINUTE = /^([0-5][0-9]|[0-9])$/;
const PATTERN_INPUT_SECOND = /^([0-5][0-9]|[0-9])$/;
function formatTwoDigitTimeValue(val) {
const txt = val.toString();
return txt.length > 1 ? txt : `0${txt}`;
}
function createMissingDateImplError(provider) {
return Error(`NgxMatDatetimePicker: No provider found for ${provider}. You must import one of the following ` +
`modules at your application root: NgxMatNativeDateModule, NgxMatMomentModule, or provide a ` +
`custom implementation.`);
}
/** Formats a range of years. */
function formatYearRange(start, end) {
return `${start} \u2013 ${end}`;
}
/** Datepicker data that requires internationalization. */
class NgxMatDatepickerIntl {
constructor() {
/**
* Stream that emits whenever the labels here are changed. Use this to notify
* components if the labels have changed after initialization.
*/
this.changes = new Subject();
/** A label for the calendar popup (used by screen readers). */
this.calendarLabel = 'Calendar';
/** A label for the button used to open the calendar popup (used by screen readers). */
this.openCalendarLabel = 'Open calendar';
/** Label for the button used to close the calendar popup. */
this.closeCalendarLabel = 'Close calendar';
/** A label for the previous month button (used by screen readers). */
this.prevMonthLabel = 'Previous month';
/** A label for the next month button (used by screen readers). */
this.nextMonthLabel = 'Next month';
/** A label for the previous year button (used by screen readers). */
this.prevYearLabel = 'Previous year';
/** A label for the next year button (used by screen readers). */
this.nextYearLabel = 'Next year';
/** A label for the previous multi-year button (used by screen readers). */
this.prevMultiYearLabel = 'Previous 24 years';
/** A label for the next multi-year button (used by screen readers). */
this.nextMultiYearLabel = 'Next 24 years';
/** A label for the 'switch to month view' button (used by screen readers). */
this.switchToMonthViewLabel = 'Choose date';
/** A label for the 'switch to year view' button (used by screen readers). */
this.switchToMultiYearViewLabel = 'Choose month and year';
/**
* A label for the first date of a range of dates (used by screen readers).
* @deprecated Provide your own internationalization string.
* @breaking-change 17.0.0
*/
this.startDateLabel = 'Start date';
/**
* A label for the last date of a range of dates (used by screen readers).
* @deprecated Provide your own internationalization string.
* @breaking-change 17.0.0
*/
this.endDateLabel = 'End date';
}
/** Formats a range of years (used for visuals). */
formatYearRange(start, end) {
return `${start} \u2013 ${end}`;
}
/** Formats a label for a range of years (used by screen readers). */
formatYearRangeLabel(start, end) {
return `${start} to ${end}`;
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDatepickerIntl, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
/** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDatepickerIntl, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDatepickerIntl, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}] });
class NgxMatTimepickerComponent {
/** Hour */
get hour() {
let val = Number(this.form.controls["hour"].value);
return isNaN(val) ? 0 : val;
}
get minute() {
let val = Number(this.form.controls["minute"].value);
return isNaN(val) ? 0 : val;
}
get second() {
let val = Number(this.form.controls["second"].value);
return isNaN(val) ? 0 : val;
}
/** Whether or not the form is valid */
get valid() {
return this.form.valid;
}
constructor(cd, _dateAdapter) {
this.cd = cd;
this._dateAdapter = _dateAdapter;
this.disabled = false;
this.showSpinners = true;
this.stepHour = DEFAULT_STEP;
this.stepMinute = DEFAULT_STEP;
this.stepSecond = DEFAULT_STEP;
this.showSeconds = false;
this.disableMinute = false;
this.enableMeridian = false;
this.color = "primary";
this.meridian = MERIDIANS.AM;
this._onChange = () => { };
this._onTouched = () => { };
this._destroyed = new Subject();
this.pattern = PATTERN_INPUT_HOUR;
if (!this._dateAdapter) {
throw createMissingDateImplError("NgxMatDateAdapter");
}
this.form = new FormGroup({
hour: new FormControl(null, [
Validators.required,
Validators.pattern(PATTERN_INPUT_HOUR),
]),
minute: new FormControl(null, [
Validators.required,
Validators.pattern(PATTERN_INPUT_MINUTE),
]),
second: new FormControl(null, [
Validators.required,
Validators.pattern(PATTERN_INPUT_SECOND),
]),
});
}
ngOnInit() {
this.form.valueChanges
.pipe(takeUntil(this._destroyed), debounceTime(400))
.subscribe((val) => {
this._updateModel();
});
}
ngOnChanges(changes) {
if (changes.disabled || changes.disableMinute) {
this._setDisableStates();
}
}
ngOnDestroy() {
this._destroyed.next();
this._destroyed.complete();
}
/**
* Writes a new value to the element.
* @param obj
*/
writeValue(val) {
if (val != null) {
this._model = val;
this._updateHourMinuteSecond();
}
}
/** Registers a callback function that is called when the control's value changes in the UI. */
registerOnChange(fn) {
this._onChange = fn;
}
/**
* Set the function to be called when the control receives a touch event.
*/
registerOnTouched(fn) {
this._onTouched = fn;
}
/** Enables or disables the appropriate DOM element */
setDisabledState(isDisabled) {
this._disabled = isDisabled;
this.cd.markForCheck();
}
/**
* Format input
* @param input
*/
formatInput(input) {
input.value = input.value.replace(NUMERIC_REGEX, "");
}
/** Toggle meridian */
toggleMeridian() {
this.meridian =
this.meridian === MERIDIANS.AM ? MERIDIANS.PM : MERIDIANS.AM;
this.change("hour");
}
/** Change property of time */
change(prop, up) {
const next = this._getNextValueByProp(prop, up);
this.form.controls[prop].setValue(formatTwoDigitTimeValue(next), {
onlySelf: false,
emitEvent: false,
});
this._updateModel();
}
/** Update controls of form by model */
_updateHourMinuteSecond() {
let _hour = this._dateAdapter.getHour(this._model);
const _minute = this._dateAdapter.getMinute(this._model);
const _second = this._dateAdapter.getSecond(this._model);
if (this.enableMeridian) {
if (_hour >= LIMIT_TIMES.meridian) {
_hour = _hour - LIMIT_TIMES.meridian;
this.meridian = MERIDIANS.PM;
}
else {
this.meridian = MERIDIANS.AM;
}
if (_hour === 0) {
_hour = LIMIT_TIMES.meridian;
}
}
this.form.patchValue({
hour: formatTwoDigitTimeValue(_hour),
minute: formatTwoDigitTimeValue(_minute),
second: formatTwoDigitTimeValue(_second),
}, {
emitEvent: false,
});
}
/** Update model */
_updateModel() {
let _hour = this.hour;
if (this.enableMeridian) {
if (this.meridian === MERIDIANS.AM && _hour === LIMIT_TIMES.meridian) {
_hour = 0;
}
else if (this.meridian === MERIDIANS.PM &&
_hour !== LIMIT_TIMES.meridian) {
_hour = _hour + LIMIT_TIMES.meridian;
}
}
if (this._model) {
const clonedModel = this._dateAdapter.clone(this._model);
this._dateAdapter.setHour(clonedModel, _hour);
this._dateAdapter.setMinute(clonedModel, this.minute);
this._dateAdapter.setSecond(clonedModel, this.second);
this._onChange(clonedModel);
}
}
/**
* Get next value by property
* @param prop
* @param up
*/
_getNextValueByProp(prop, up) {
const keyProp = prop[0].toUpperCase() + prop.slice(1);
const min = LIMIT_TIMES[`min${keyProp}`];
let max = LIMIT_TIMES[`max${keyProp}`];
if (prop === "hour" && this.enableMeridian) {
max = LIMIT_TIMES.meridian;
}
let next;
if (up == null) {
next = this[prop] % max;
if (prop === "hour" && this.enableMeridian) {
if (next === 0)
next = max;
}
}
else {
next = up
? this[prop] + this[`step${keyProp}`]
: this[prop] - this[`step${keyProp}`];
if (prop === "hour" && this.enableMeridian) {
next = next % (max + 1);
if (next === 0)
next = up ? 1 : max;
}
else {
next = next % max;
}
if (up) {
next = next > max ? next - max + min : next;
}
else {
next = next < min ? next - min + max : next;
}
}
return next;
}
/**
* Set disable states
*/
_setDisableStates() {
if (this.disabled) {
this.form.disable();
}
else {
this.form.enable();
if (this.disableMinute) {
this.form.get("minute").disable();
if (this.showSeconds) {
this.form.get("second").disable();
}
}
}
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatTimepickerComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: NgxMatDateAdapter, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
/** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.10", type: NgxMatTimepickerComponent, isStandalone: true, selector: "ngx-mat-timepicker", inputs: { disabled: "disabled", showSpinners: "showSpinners", stepHour: "stepHour", stepMinute: "stepMinute", stepSecond: "stepSecond", showSeconds: "showSeconds", disableMinute: "disableMinute", enableMeridian: "enableMeridian", defaultTime: "defaultTime", color: "color" }, host: { classAttribute: "ngx-mat-timepicker" }, providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef((() => NgxMatTimepickerComponent)),
multi: true,
},
], exportAs: ["ngxMatTimepicker"], usesOnChanges: true, ngImport: i0, template: "<form [formGroup]=\"form\">\r\n <table class=\"ngx-mat-timepicker-table\">\r\n <tbody class=\"ngx-mat-timepicker-tbody\">\r\n <tr *ngIf=\"showSpinners\">\r\n <td>\r\n <button type=\"button\" mat-icon-button aria-label=\"expand_less icon\" (click)=\"change('hour', true)\"\r\n [disabled]=\"disabled\">\r\n <mat-icon>expand_less</mat-icon>\r\n </button>\r\n </td>\r\n <td></td>\r\n <td>\r\n <button type=\"button\" mat-icon-button aria-label=\"expand_less icon\" (click)=\"change('minute', true)\"\r\n [disabled]=\"disabled || disableMinute\">\r\n <mat-icon>expand_less</mat-icon>\r\n </button> </td>\r\n <td></td>\r\n <td *ngIf=\"showSeconds\">\r\n <button type=\"button\" mat-icon-button aria-label=\"expand_less icon\" (click)=\"change('second', true)\"\r\n [disabled]=\"disabled || disableMinute\">\r\n <mat-icon>expand_less</mat-icon>\r\n </button>\r\n </td>\r\n <td *ngIf=\"enableMeridian\" class=\"ngx-mat-timepicker-spacer\"></td>\r\n <td *ngIf=\"enableMeridian\"></td>\r\n </tr>\r\n\r\n <tr>\r\n <td>\r\n <mat-form-field appearance=\"fill\" [color]=\"color\">\r\n <input type=\"text\" matInput (input)=\"formatInput($any($event).target)\" maxlength=\"2\" formControlName=\"hour\"\r\n (keydown.ArrowUp)=\"change('hour', true); $event.preventDefault()\"\r\n (keydown.ArrowDown)=\"change('hour', false); $event.preventDefault()\" (blur)=\"change('hour')\">\r\n </mat-form-field>\r\n </td>\r\n <td class=\"ngx-mat-timepicker-spacer\">:</td>\r\n <td>\r\n <mat-form-field appearance=\"fill\" [color]=\"color\">\r\n <input type=\"text\" matInput (input)=\"formatInput($any($event).target)\" maxlength=\"2\"\r\n formControlName=\"minute\" (keydown.ArrowUp)=\"change('minute', true); $event.preventDefault()\"\r\n (keydown.ArrowDown)=\"change('minute', false); $event.preventDefault()\" (blur)=\"change('minute')\">\r\n </mat-form-field>\r\n </td>\r\n <td *ngIf=\"showSeconds\" class=\"ngx-mat-timepicker-spacer\">:</td>\r\n <td *ngIf=\"showSeconds\">\r\n <mat-form-field appearance=\"fill\" [color]=\"color\">\r\n <input type=\"text\" matInput (input)=\"formatInput($any($event).target)\" maxlength=\"2\"\r\n formControlName=\"second\" (keydown.ArrowUp)=\"change('second', true); $event.preventDefault()\"\r\n (keydown.ArrowDown)=\"change('second', false); $event.preventDefault()\" (blur)=\"change('second')\">\r\n </mat-form-field>\r\n </td>\r\n\r\n <td *ngIf=\"enableMeridian\" class=\"ngx-mat-timepicker-spacer\"></td>\r\n <td *ngIf=\"enableMeridian\" class=\"ngx-mat-timepicker-meridian\">\r\n <button mat-button (click)=\"toggleMeridian()\" mat-stroked-button [color]=\"color\" [disabled]=\"disabled\">\r\n {{meridian}}\r\n </button>\r\n </td>\r\n </tr>\r\n\r\n <tr *ngIf=\"showSpinners\">\r\n <td>\r\n <button type=\"button\" mat-icon-button aria-label=\"expand_more icon\" (click)=\"change('hour', false)\"\r\n [disabled]=\"disabled\">\r\n <mat-icon>expand_more</mat-icon>\r\n </button> </td>\r\n <td></td>\r\n <td>\r\n <button type=\"button\" mat-icon-button aria-label=\"expand_more icon\" (click)=\"change('minute', false)\"\r\n [disabled]=\"disabled || disableMinute\">\r\n <mat-icon>expand_more</mat-icon>\r\n </button> </td>\r\n <td *ngIf=\"showSeconds\"></td>\r\n <td *ngIf=\"showSeconds\">\r\n <button type=\"button\" mat-icon-button aria-label=\"expand_more icon\" (click)=\"change('second', false)\"\r\n [disabled]=\"disabled || disableMinute\">\r\n <mat-icon>expand_more</mat-icon>\r\n </button>\r\n </td>\r\n <td *ngIf=\"enableMeridian\" class=\"ngx-mat-timepicker-spacer\"></td>\r\n <td *ngIf=\"enableMeridian\"></td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n</form>", styles: [".ngx-mat-timepicker form .ngx-mat-timepicker-table .ngx-mat-timepicker-tbody tr td{text-align:center}.ngx-mat-timepicker form .ngx-mat-timepicker-table .ngx-mat-timepicker-tbody tr td.ngx-mat-timepicker-spacer{font-weight:700}.ngx-mat-timepicker form .ngx-mat-timepicker-table .ngx-mat-timepicker-tbody tr td.ngx-mat-timepicker-meridian .mdc-button{min-width:64px;line-height:36px;min-width:0;border-radius:50%;width:36px;height:36px;padding:0;flex-shrink:0}.ngx-mat-timepicker form .ngx-mat-timepicker-table .ngx-mat-timepicker-tbody tr td .mat-mdc-icon-button{height:24px;width:24px;line-height:24px;padding:0}.ngx-mat-timepicker form .ngx-mat-timepicker-table .ngx-mat-timepicker-tbody tr td .mat-mdc-icon-button .mat-icon{font-size:24px}.ngx-mat-timepicker form .ngx-mat-timepicker-table .ngx-mat-timepicker-tbody tr td .mat-mdc-form-field{width:24px;max-width:24px;text-align:center}.ngx-mat-timepicker form .ngx-mat-timepicker-table .ngx-mat-timepicker-tbody tr td .mat-mdc-form-field.mat-focused .mdc-text-field--filled .mat-mdc-form-field-focus-overlay,.ngx-mat-timepicker form .ngx-mat-timepicker-table .ngx-mat-timepicker-tbody tr td .mat-mdc-form-field:hover .mdc-text-field--filled .mat-mdc-form-field-focus-overlay{background-color:transparent}.ngx-mat-timepicker form .ngx-mat-timepicker-table .ngx-mat-timepicker-tbody tr td .mat-mdc-form-field .mdc-text-field--filled{background-color:transparent!important;padding:0!important}.ngx-mat-timepicker form .ngx-mat-timepicker-table .ngx-mat-timepicker-tbody tr td .mat-mdc-form-field .mdc-text-field--filled .mat-mdc-form-field-infix{padding:4px 0;min-height:1px!important}.ngx-mat-timepicker form .ngx-mat-timepicker-table .ngx-mat-timepicker-tbody tr td .mat-mdc-form-field .mdc-text-field--filled .mat-mdc-form-field-infix input{text-align:center;font-size:14px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i4$1.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "ngmodule", type: MatFormFieldModule }], encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatTimepickerComponent, decorators: [{
type: Component,
args: [{ selector: "ngx-mat-timepicker", host: {
class: "ngx-mat-timepicker",
}, providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef((() => NgxMatTimepickerComponent)),
multi: true,
},
], exportAs: "ngxMatTimepicker", encapsulation: ViewEncapsulation.None, standalone: true, imports: [
CommonModule,
MatInputModule,
MatButtonModule,
MatIconModule,
FormsModule,
ReactiveFormsModule,
MatSelectModule,
MatFormFieldModule,
], template: "<form [formGroup]=\"form\">\r\n <table class=\"ngx-mat-timepicker-table\">\r\n <tbody class=\"ngx-mat-timepicker-tbody\">\r\n <tr *ngIf=\"showSpinners\">\r\n <td>\r\n <button type=\"button\" mat-icon-button aria-label=\"expand_less icon\" (click)=\"change('hour', true)\"\r\n [disabled]=\"disabled\">\r\n <mat-icon>expand_less</mat-icon>\r\n </button>\r\n </td>\r\n <td></td>\r\n <td>\r\n <button type=\"button\" mat-icon-button aria-label=\"expand_less icon\" (click)=\"change('minute', true)\"\r\n [disabled]=\"disabled || disableMinute\">\r\n <mat-icon>expand_less</mat-icon>\r\n </button> </td>\r\n <td></td>\r\n <td *ngIf=\"showSeconds\">\r\n <button type=\"button\" mat-icon-button aria-label=\"expand_less icon\" (click)=\"change('second', true)\"\r\n [disabled]=\"disabled || disableMinute\">\r\n <mat-icon>expand_less</mat-icon>\r\n </button>\r\n </td>\r\n <td *ngIf=\"enableMeridian\" class=\"ngx-mat-timepicker-spacer\"></td>\r\n <td *ngIf=\"enableMeridian\"></td>\r\n </tr>\r\n\r\n <tr>\r\n <td>\r\n <mat-form-field appearance=\"fill\" [color]=\"color\">\r\n <input type=\"text\" matInput (input)=\"formatInput($any($event).target)\" maxlength=\"2\" formControlName=\"hour\"\r\n (keydown.ArrowUp)=\"change('hour', true); $event.preventDefault()\"\r\n (keydown.ArrowDown)=\"change('hour', false); $event.preventDefault()\" (blur)=\"change('hour')\">\r\n </mat-form-field>\r\n </td>\r\n <td class=\"ngx-mat-timepicker-spacer\">:</td>\r\n <td>\r\n <mat-form-field appearance=\"fill\" [color]=\"color\">\r\n <input type=\"text\" matInput (input)=\"formatInput($any($event).target)\" maxlength=\"2\"\r\n formControlName=\"minute\" (keydown.ArrowUp)=\"change('minute', true); $event.preventDefault()\"\r\n (keydown.ArrowDown)=\"change('minute', false); $event.preventDefault()\" (blur)=\"change('minute')\">\r\n </mat-form-field>\r\n </td>\r\n <td *ngIf=\"showSeconds\" class=\"ngx-mat-timepicker-spacer\">:</td>\r\n <td *ngIf=\"showSeconds\">\r\n <mat-form-field appearance=\"fill\" [color]=\"color\">\r\n <input type=\"text\" matInput (input)=\"formatInput($any($event).target)\" maxlength=\"2\"\r\n formControlName=\"second\" (keydown.ArrowUp)=\"change('second', true); $event.preventDefault()\"\r\n (keydown.ArrowDown)=\"change('second', false); $event.preventDefault()\" (blur)=\"change('second')\">\r\n </mat-form-field>\r\n </td>\r\n\r\n <td *ngIf=\"enableMeridian\" class=\"ngx-mat-timepicker-spacer\"></td>\r\n <td *ngIf=\"enableMeridian\" class=\"ngx-mat-timepicker-meridian\">\r\n <button mat-button (click)=\"toggleMeridian()\" mat-stroked-button [color]=\"color\" [disabled]=\"disabled\">\r\n {{meridian}}\r\n </button>\r\n </td>\r\n </tr>\r\n\r\n <tr *ngIf=\"showSpinners\">\r\n <td>\r\n <button type=\"button\" mat-icon-button aria-label=\"expand_more icon\" (click)=\"change('hour', false)\"\r\n [disabled]=\"disabled\">\r\n <mat-icon>expand_more</mat-icon>\r\n </button> </td>\r\n <td></td>\r\n <td>\r\n <button type=\"button\" mat-icon-button aria-label=\"expand_more icon\" (click)=\"change('minute', false)\"\r\n [disabled]=\"disabled || disableMinute\">\r\n <mat-icon>expand_more</mat-icon>\r\n </button> </td>\r\n <td *ngIf=\"showSeconds\"></td>\r\n <td *ngIf=\"showSeconds\">\r\n <button type=\"button\" mat-icon-button aria-label=\"expand_more icon\" (click)=\"change('second', false)\"\r\n [disabled]=\"disabled || disableMinute\">\r\n <mat-icon>expand_more</mat-icon>\r\n </button>\r\n </td>\r\n <td *ngIf=\"enableMeridian\" class=\"ngx-mat-timepicker-spacer\"></td>\r\n <td *ngIf=\"enableMeridian\"></td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n</form>", styles: [".ngx-mat-timepicker form .ngx-mat-timepicker-table .ngx-mat-timepicker-tbody tr td{text-align:center}.ngx-mat-timepicker form .ngx-mat-timepicker-table .ngx-mat-timepicker-tbody tr td.ngx-mat-timepicker-spacer{font-weight:700}.ngx-mat-timepicker form .ngx-mat-timepicker-table .ngx-mat-timepicker-tbody tr td.ngx-mat-timepicker-meridian .mdc-button{min-width:64px;line-height:36px;min-width:0;border-radius:50%;width:36px;height:36px;padding:0;flex-shrink:0}.ngx-mat-timepicker form .ngx-mat-timepicker-table .ngx-mat-timepicker-tbody tr td .mat-mdc-icon-button{height:24px;width:24px;line-height:24px;padding:0}.ngx-mat-timepicker form .ngx-mat-timepicker-table .ngx-mat-timepicker-tbody tr td .mat-mdc-icon-button .mat-icon{font-size:24px}.ngx-mat-timepicker form .ngx-mat-timepicker-table .ngx-mat-timepicker-tbody tr td .mat-mdc-form-field{width:24px;max-width:24px;text-align:center}.ngx-mat-timepicker form .ngx-mat-timepicker-table .ngx-mat-timepicker-tbody tr td .mat-mdc-form-field.mat-focused .mdc-text-field--filled .mat-mdc-form-field-focus-overlay,.ngx-mat-timepicker form .ngx-mat-timepicker-table .ngx-mat-timepicker-tbody tr td .mat-mdc-form-field:hover .mdc-text-field--filled .mat-mdc-form-field-focus-overlay{background-color:transparent}.ngx-mat-timepicker form .ngx-mat-timepicker-table .ngx-mat-timepicker-tbody tr td .mat-mdc-form-field .mdc-text-field--filled{background-color:transparent!important;padding:0!important}.ngx-mat-timepicker form .ngx-mat-timepicker-table .ngx-mat-timepicker-tbody tr td .mat-mdc-form-field .mdc-text-field--filled .mat-mdc-form-field-infix{padding:4px 0;min-height:1px!important}.ngx-mat-timepicker form .ngx-mat-timepicker-table .ngx-mat-timepicker-tbody tr td .mat-mdc-form-field .mdc-text-field--filled .mat-mdc-form-field-infix input{text-align:center;font-size:14px}\n"] }]
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: NgxMatDateAdapter, decorators: [{
type: Optional
}] }], propDecorators: { disabled: [{
type: Input
}], showSpinners: [{
type: Input
}], stepHour: [{
type: Input
}], stepMinute: [{
type: Input
}], stepSecond: [{
type: Input
}], showSeconds: [{
type: Input
}], disableMinute: [{
type: Input
}], enableMeridian: [{
type: Input
}], defaultTime: [{
type: Input
}], color: [{
type: Input
}] } });
/** Used to generate a unique ID for each datepicker instance. */
let datepickerUid = 0;
/** Injection token that determines the scroll handling while the calendar is open. */
const NGX_MAT_DATEPICKER_SCROLL_STRATEGY = new InjectionToken("ngx-mat-datepicker-scroll-strategy");
/** @docs-private */
function NGX_MAT_DATEPICKER_SCROLL_STRATEGY_FACTORY(overlay) {
return () => overlay.scrollStrategies.reposition();
}
/** @docs-private */
const NGX_MAT_DATEPICKER_SCROLL_STRATEGY_FACTORY_PROVIDER = {
provide: NGX_MAT_DATEPICKER_SCROLL_STRATEGY,
deps: [Overlay],
useFactory: NGX_MAT_DATEPICKER_SCROLL_STRATEGY_FACTORY,
};
/**
* Component used as the content for the datepicker overlay. We use this instead of using
* MatCalendar directly as the content so we can control the initial focus. This also gives us a
* place to put additional features of the overlay that are not part of the calendar itself in the
* future. (e.g. confirmation buttons).
* @docs-private
*/
class NgxMatDatepickerContent {
get isViewMonth() {
if (!this._calendar || this._calendar.currentView == null)
return true;
return this._calendar.currentView == "month";
}
constructor(elementRef, _changeDetectorRef, _globalModel, _dateAdapter, _rangeSelectionStrategy, intl) {
this.elementRef = elementRef;
this._changeDetectorRef = _changeDetectorRef;
this._globalModel = _globalModel;
this._dateAdapter = _dateAdapter;
this._rangeSelectionStrategy = _rangeSelectionStrategy;
this._subscriptions = new Subscription();
// Add color property with default value
this.color = "primary";
this.defaultColor = "primary";
/** Emits when an animation has finished. */
this._animationDone = new Subject();
/** Whether there is an in-progress animation. */
this._isAnimating = false;
/** Portal with projected action buttons. */
this._actionsPortal = null;
// super(elementRef);
this._closeButtonText = intl.closeCalendarLabel;
}
// Helper getter that returns the current color or default
get _color() {
return this.color || this.defaultColor;
}
// Update the color and apply the appropriate classes
_updateColor(newColor) {
const color = newColor || this.defaultColor;
const element = this.elementRef.nativeElement;
// Remove old color class
element.classList.remove(`mat-${this._color}`);
// Add new color class
if (color) {
element.classList.add(`mat-${color}`);
}
// Update the color property
this.color = color;
}
ngOnInit() {
this._animationState = this.datepicker.touchUi
? "enter-dialog"
: "enter-dropdown";
}
ngOnChanges(changes) {
if (changes["color"]) {
this._updateColor(changes["color"].currentValue);
}
}
ngAfterViewInit() {
this._subscriptions.add(this.datepicker.stateChanges.subscribe(() => {
this._changeDetectorRef.markForCheck();
}));
// this._calendar.color = this.color;
this._calendar.focusActiveCell();
}
ngOnDestroy() {
this._subscriptions.unsubscribe();
this._animationDone.complete();
}
onTimeChanged(selectedDateWithTime) {
const userEvent = {
value: selectedDateWithTime,
event: null,
};
this._updateUserSelectionWithCalendarUserEvent(userEvent);
}
_handleUserSelection(event) {
this._updateUserSelectionWithCalendarUserEvent(event);
// Delegate closing the overlay to the actions.
if (this.datepicker.hideTime) {
if ((!this._model || this._model.isComplete()) && !this._actionsPortal) {
this.datepicker.close();
}
}
}
_updateUserSelectionWithCalendarUserEvent(event) {
const selection = this._model.selection;
const value = event.value;
const isRange = selection instanceof DateRange;
// If we're selecting a range and we have a selection strategy, always pass the value through
// there. Otherwise don't assign null values to the model, unless we're selecting a range.
// A null value when picking a range means that the user cancelled the selection (e.g. by
// pressing escape), whereas when selecting a single value it means that the value didn't
// change. This isn't very intuitive, but it's here for backwards-compatibility.
if (isRange && this._rangeSelectionStrategy) {
const newSelection = this._rangeSelectionStrategy.selectionFinished(value, selection, event.event);
this._model.updateSelection(newSelection, this);
}
else {
const isSameTime = this._dateAdapter.isSameTime(selection, value);
const isSameDate = this._dateAdapter.sameDate(value, selection);
const isSame = isSameDate && isSameTime;
if (value && (isRange || !isSame)) {
this._model.add(value);
}
}
}
_handleUserDragDrop(event) {
this._model.updateSelection(event.value, this);
}
_startExitAnimation() {
this._animationState = "void";
this._changeDetectorRef.markForCheck();
}
_handleAnimationEvent(event) {
this._isAnimating = event.phaseName === "start";
if (!this._isAnimating) {
this._animationDone.next();
}
}
_getSelected() {
this._modelTime = this._model.selection;
return this._model.selection;
}
/** Applies the current pending selection to the global model. */
_applyPendingSelection() {
if (this._model !== this._globalModel) {
this._globalModel.updateSelection(this._model.selection, this);
}
}
/**
* Assigns a new portal containing the datepicker actions.
* @param portal Portal with the actions to be assigned.
* @param forceRerender Whether a re-render of the portal should be triggered. This isn't
* necessary if the portal is assigned during initialization, but it may be required if it's
* added at a later point.
*/
_assignActions(portal, forceRerender) {
// If we have actions, clone the model so that we have the ability to cancel the selection,
// otherwise update the global model directly. Note that we want to assign this as soon as
// possible, but `_actionsPortal` isn't available in the constructor so we do it in `ngOnInit`.
this._model = portal ? this._globalModel.clone() : this._globalModel;
this._actionsPortal = portal;
if (forceRerender) {
this._changeDetectorRef.detectChanges();
}
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDatepickerContent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }, { token: NgxMatDateSelectionModel }, { token: NgxMatDateAdapter }, { token: NGX_MAT_DATE_RANGE_SELECTION_STRATEGY, optional: true }, { token: NgxMatDatepickerIntl }], target: i0.ɵɵFactoryTarget.Component }); }
/** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.10", type: NgxMatDatepickerContent, isStandalone: false, selector: "ngx-mat-datepicker-content", inputs: { color: "color" }, host: { listeners: { "@transformPanel.start": "_handleAnimationEvent($event)", "@transformPanel.done": "_handleAnimationEvent($event)" }, properties: { "class.mat-primary": "color === \"primary\"", "class.mat-accent": "color === \"accent\"", "class.mat-warn": "color === \"warn\"", "class.app-background": "true", "@transformPanel": "_animationState", "class.mat-datepicker-content-touch": "datepicker.touchUi", "class.mat-datepicker-content-touch-with-time": "!datepicker.hideTime" }, classAttribute: "mat-datepicker-content" }, viewQueries: [{ propertyName: "_calendar", first: true, predicate: MatCalendar, descendants: true }], exportAs: ["ngxMatDatepickerContent"], usesOnChanges: true, ngImport: i0, template: "<div\r\n cdkTrapFocus\r\n role=\"dialog\"\r\n [attr.aria-modal]=\"true\"\r\n [attr.aria-labelledby]=\"_dialogLabelId ?? undefined\"\r\n class=\"mat-datepicker-content-container\"\r\n [class.mat-datepicker-content-container-with-custom-header]=\"datepicker.calendarHeaderComponent\"\r\n [class.mat-datepicker-content-container-with-actions]=\"_actionsPortal\"\r\n [class.mat-datepicker-content-container-with-time]=\"!datepicker._hideTime\"\r\n>\r\n <mat-calendar\r\n [id]=\"datepicker.id\"\r\n [ngClass]=\"datepicker.panelClass\"\r\n [startAt]=\"datepicker.startAt\"\r\n [startView]=\"datepicker.startView\"\r\n [minDate]=\"datepicker._getMinDate()\"\r\n [maxDate]=\"datepicker._getMaxDate()\"\r\n [dateFilter]=\"datepicker._getDateFilter()\"\r\n [headerComponent]=\"datepicker.calendarHeaderComponent\"\r\n [selected]=\"_getSelected()\"\r\n [dateClass]=\"datepicker.dateClass\"\r\n [comparisonStart]=\"comparisonStart\"\r\n [comparisonEnd]=\"comparisonEnd\"\r\n [@fadeInCalendar]=\"'enter'\"\r\n [startDateAccessibleName]=\"startDateAccessibleName\"\r\n [endDateAccessibleName]=\"endDateAccessibleName\"\r\n (yearSelected)=\"datepicker._selectYear($event)\"\r\n (monthSelected)=\"datepicker._selectMonth($event)\"\r\n (viewChanged)=\"datepicker._viewChanged($event)\"\r\n (_userSelection)=\"_handleUserSelection($event)\"\r\n (_userDragDrop)=\"_handleUserDragDrop($event)\"\r\n ></mat-calendar>\r\n\r\n <ng-container *ngIf=\"isViewMonth\">\r\n <div\r\n *ngIf=\"!datepicker._hideTime\"\r\n class=\"time-container\"\r\n [class.disable-seconds]=\"!datepicker._showSeconds\"\r\n >\r\n <ngx-mat-timepicker\r\n [showSpinners]=\"datepicker._showSpinners\"\r\n [showSeconds]=\"datepicker._showSeconds\"\r\n [disabled]=\"datepicker._disabled || !_modelTime\"\r\n [stepHour]=\"datepicker._stepHour\"\r\n [stepMinute]=\"datepicker._stepMinute\"\r\n [stepSecond]=\"datepicker._stepSecond\"\r\n [(ngModel)]=\"_modelTime\"\r\n [color]=\"_color\"\r\n [enableMeridian]=\"datepicker._enableMeridian\"\r\n [disableMinute]=\"datepicker._disableMinute\"\r\n (ngModelChange)=\"onTimeChanged($event)\"\r\n >\r\n </ngx-mat-timepicker>\r\n </div>\r\n </ng-container>\r\n\r\n <ng-template [cdkPortalOutlet]=\"_actionsPortal\"></ng-template>\r\n\r\n <!-- Invisible close button for screen reader users. -->\r\n <button\r\n type=\"button\"\r\n mat-raised-button\r\n [color]=\"_color\"\r\n class=\"mat-datepicker-close-button\"\r\n [class.cdk-visually-hidden]=\"!_closeButtonFocused\"\r\n (focus)=\"_closeButtonFocused = true\"\r\n (blur)=\"_closeButtonFocused = false\"\r\n (click)=\"datepicker.close()\"\r\n >\r\n {{ _closeButtonText }}\r\n </button>\r\n</div>\r\n", styles: [".mat-datepicker-content{display:block;border-radius:4px;background:var(--mat-menu-container-color, white);color:var(--mat-menu-container-text-color, rgba(0, 0, 0, .87));box-shadow:0 2px 4px -1px #0003,0 4px 5px #00000024,0 1px 10px #0000001f}.mat-datepicker-content .mat-calendar{width:296px;height:354px}.mat-datepicker-content .mat-datepicker-content-container-with-custom-header .mat-calendar{height:auto}.mat-datepicker-content .mat-datepicker-close-button{position:absolute;top:100%;left:0;margin-top:8px}.ng-animating .mat-datepicker-content .mat-datepicker-close-button{display:none}.mat-datepicker-content-container{display:flex;flex-direction:column;justify-content:space-between;border-radius:6px;margin-top:.2rem}.time-container{display:flex;position:relative;padding-top:5px;justify-content:center}.time-container.disable-seconds .ngx-mat-timepicker .table{margin-left:9px}.time-container:before{content:\"\";position:absolute;top:0;left:0;right:0;height:1px;background-color:#0000001f}.mat-datepicker-content-touch{display:block;max-height:90vh;position:relative;overflow:visible}.mat-datepicker-content-touch .mat-datepicker-content-container{min-height:312px;max-height:815px;min-width:250px;max-width:750px}.mat-datepicker-content-touch .mat-calendar{width:100%;height:auto}@media all and (orientation: landscape){.mat-datepicker-content-touch .mat-datepicker-content-container{width:64vh;height:90vh}.mat-datepicker-content-touch .mat-datepicker-content-container.mat-datepicker-content-container-with-time{height:auto}}@media all and (orientation: portrait){.mat-datepicker-content-touch{max-height:100vh}.mat-datepicker-content-touch .mat-datepicker-content-container{width:80vw;height:100vw}.mat-datepicker-content-touch .mat-datepicker-content-container.mat-datepicker-content-container-with-time{height:auto;max-height:870px}.mat-datepicker-content-touch .mat-datepicker-content-container.mat-datepicker-content-container-with-time.mat-datepicker-content-container-with-actions{max-height:none!important}.mat-datepicker-content-touch .mat-datepicker-content-container-with-actions{height:115vw}}\n"], dependencies: [{ kind: "directive", type: i4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i4$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "directive", type: i2$1.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "directive", type: i7.CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: NgxMatTimepickerComponent, selector: "ngx-mat-timepicker", inputs: ["disabled", "showSpinners", "stepHour", "stepMinute", "stepSecond", "showSeconds", "disableMinute", "enableMeridian", "defaultTime", "color"], exportAs: ["ngxMatTimepicker"] }, { kind: "component", type: i10.MatCalendar, selector: "mat-calendar", inputs: ["headerComponent", "startAt", "startView", "selected", "minDate", "maxDate", "dateFilter", "dateClass", "comparisonStart", "comparisonEnd", "startDateAccessibleName", "endDateAccessibleName"], outputs: ["selectedChange", "yearSelected", "monthSelected", "viewChanged", "_userSelection", "_userDragDrop"], exportAs: ["matCalendar"] }], animations: [
ngxMatDatepickerAnimations.transformPanel,
ngxMatDatepickerAnimations.fadeInCalendar,
], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDatepickerContent, decorators: [{
type: Component,
args: [{ selector: "ngx-mat-datepicker-content", host: {
class: "mat-datepicker-content",
"[class.mat-primary]": 'color === "primary"',
"[class.mat-accent]": 'color === "accent"',
"[class.mat-warn]": 'color === "warn"',
"[class.app-background]": "true",
"[@transformPanel]": "_animationState",
"(@transformPanel.start)": "_handleAnimationEvent($event)",
"(@transformPanel.done)": "_handleAnimationEvent($event)",
"[class.mat-datepicker-content-touch]": "datepicker.touchUi",
"[class.mat-datepicker-content-touch-with-time]": "!datepicker.hideTime",
}, animations: [
ngxMatDatepickerAnimations.transformPanel,
ngxMatDatepickerAnimations.fadeInCalendar,
], exportAs: "ngxMatDatepickerContent", encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, inputs: ["color"], standalone: false, template: "<div\r\n cdkTrapFocus\r\n role=\"dialog\"\r\n [attr.aria-modal]=\"true\"\r\n [attr.aria-labelledby]=\"_dialogLabelId ?? undefined\"\r\n class=\"mat-datepicker-content-container\"\r\n [class.mat-datepicker-content-container-with-custom-header]=\"datepicker.calendarHeaderComponent\"\r\n [class.mat-datepicker-content-container-with-actions]=\"_actionsPortal\"\r\n [class.mat-datepicker-content-container-with-time]=\"!datepicker._hideTime\"\r\n>\r\n <mat-calendar\r\n [id]=\"datepicker.id\"\r\n [ngClass]=\"datepicker.panelClass\"\r\n [startAt]=\"datepicker.startAt\"\r\n [startView]=\"datepicker.startView\"\r\n [minDate]=\"datepicker._getMinDate()\"\r\n [maxDate]=\"datepicker._getMaxDate()\"\r\n [dateFilter]=\"datepicker._getDateFilter()\"\r\n [headerComponent]=\"datepicker.calendarHeaderComponent\"\r\n [selected]=\"_getSelected()\"\r\n [dateClass]=\"datepicker.dateClass\"\r\n [comparisonStart]=\"comparisonStart\"\r\n [comparisonEnd]=\"comparisonEnd\"\r\n [@fadeInCalendar]=\"'enter'\"\r\n [startDateAccessibleName]=\"startDateAccessibleName\"\r\n [endDateAccessibleName]=\"endDateAccessibleName\"\r\n (yearSelected)=\"datepicker._selectYear($event)\"\r\n (monthSelected)=\"datepicker._selectMonth($event)\"\r\n (viewChanged)=\"datepicker._viewChanged($event)\"\r\n (_userSelection)=\"_handleUserSelection($event)\"\r\n (_userDragDrop)=\"_handleUserDragDrop($event)\"\r\n ></mat-calendar>\r\n\r\n <ng-container *ngIf=\"isViewMonth\">\r\n <div\r\n *ngIf=\"!datepicker._hideTime\"\r\n class=\"time-container\"\r\n [class.disable-seconds]=\"!datepicker._showSeconds\"\r\n >\r\n <ngx-mat-timepicker\r\n [showSpinners]=\"datepicker._showSpinners\"\r\n [showSeconds]=\"datepicker._showSeconds\"\r\n [disabled]=\"datepicker._disabled || !_modelTime\"\r\n [stepHour]=\"datepicker._stepHour\"\r\n [stepMinute]=\"datepicker._stepMinute\"\r\n [stepSecond]=\"datepicker._stepSecond\"\r\n [(ngModel)]=\"_modelTime\"\r\n [color]=\"_color\"\r\n [enableMeridian]=\"datepicker._enableMeridian\"\r\n [disableMinute]=\"datepicker._disableMinute\"\r\n (ngModelChange)=\"onTimeChanged($event)\"\r\n >\r\n </ngx-mat-timepicker>\r\n </div>\r\n </ng-container>\r\n\r\n <ng-template [cdkPortalOutlet]=\"_actionsPortal\"></ng-template>\r\n\r\n <!-- Invisible close button for screen reader users. -->\r\n <button\r\n type=\"button\"\r\n mat-raised-button\r\n [color]=\"_color\"\r\n class=\"mat-datepicker-close-button\"\r\n [class.cdk-visually-hidden]=\"!_closeButtonFocused\"\r\n (focus)=\"_closeButtonFocused = true\"\r\n (blur)=\"_closeButtonFocused = false\"\r\n (click)=\"datepicker.close()\"\r\n >\r\n {{ _closeButtonText }}\r\n </button>\r\n</div>\r\n", styles: [".mat-datepicker-content{display:block;border-radius:4px;background:var(--mat-menu-container-color, white);color:var(--mat-menu-container-text-color, rgba(0, 0, 0, .87));box-shadow:0 2px 4px -1px #0003,0 4px 5px #00000024,0 1px 10px #0000001f}.mat-datepicker-content .mat-calendar{width:296px;height:354px}.mat-datepicker-content .mat-datepicker-content-container-with-custom-header .mat-calendar{height:auto}.mat-datepicker-content .mat-datepicker-close-button{position:absolute;top:100%;left:0;margin-top:8px}.ng-animating .mat-datepicker-content .mat-datepicker-close-button{display:none}.mat-datepicker-content-container{display:flex;flex-direction:column;justify-content:space-between;border-radius:6px;margin-top:.2rem}.time-container{display:flex;position:relative;padding-top:5px;justify-content:center}.time-container.disable-seconds .ngx-mat-timepicker .table{margin-left:9px}.time-container:before{content:\"\";position:absolute;top:0;left:0;right:0;height:1px;background-color:#0000001f}.mat-datepicker-content-touch{display:block;max-height:90vh;position:relative;overflow:visible}.mat-datepicker-content-touch .mat-datepicker-content-container{min-height:312px;max-height:815px;min-width:250px;max-width:750px}.mat-datepicker-content-touch .mat-calendar{width:100%;height:auto}@media all and (orientation: landscape){.mat-datepicker-content-touch .mat-datepicker-content-container{width:64vh;height:90vh}.mat-datepicker-content-touch .mat-datepicker-content-container.mat-datepicker-content-container-with-time{height:auto}}@media all and (orientation: portrait){.mat-datepicker-content-touch{max-height:100vh}.mat-datepicker-content-touch .mat-datepicker-content-container{width:80vw;height:100vw}.mat-datepicker-content-touch .mat-datepicker-content-container.mat-datepicker-content-container-with-time{height:auto;max-height:870px}.mat-datepicker-content-touch .mat-datepicker-content-container.mat-datepicker-content-container-with-time.mat-datepicker-content-container-with-actions{max-height:none!important}.mat-datepicker-content-touch .mat-datepicker-content-container-with-actions{height:115vw}}\n"] }]
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }, { type: NgxMatDateSelectionModel }, { type: NgxMatDateAdapter }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: [NGX_MAT_DATE_RANGE_SELECTION_STRATEGY]
}] }, { type: NgxMatDatepickerIntl }], propDecorators: { _calendar: [{
type: ViewChild,
args: [MatCalendar]
}], color: [{
type: Input
}] } });
/** Base class for a datepicker. */
class NgxMatDatepickerBase {
/** The date to open the calendar to initially. */
get startAt() {
// If an explicit startAt is set we start there, otherwise we start at whatever the currently
// selected value is.
return (this._startAt ||
(this.datepickerInput ? this.datepickerInput.getStartValue() : null));
}
set startAt(value) {
this._startAt = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value));
}
/** Color palette to use on the datepicker's calendar. */
get color() {
return (this._color ||
(this.datepickerInput
? this.datepickerInput.getThemePalette()
: "primary"));
}
set color(value) {
this._color = value;
}
/**
* Whether the calendar UI is in touch mode. In touch mode the calendar opens in a dialog rather
* than a dropdown and elements have more padding to allow for bigger touch targets.
*/
get touchUi() {
return this._touchUi;
}
set touchUi(value) {
this._touchUi = coerceBooleanProperty(value);
}
get hideTime() {
return this._hideTime;
}
set hideTime(value) {
this._hideTime = coerceBooleanProperty(value);
}
/** Whether the datepicker pop-up should be disabled. */
get disabled() {
return this._disabled === undefined && this.datepickerInput
? this.datepickerInput.disabled
: !!this._disabled;
}
set disabled(value) {
const newValue = coerceBooleanProperty(value);
if (newValue !== this._disabled) {
this._disabled = newValue;
this.stateChanges.next(undefined);
}
}
/**
* Whether to restore focus to the previously-focused element when the calendar is closed.
* Note that automatic focus restoration is an accessibility feature and it is recommended that
* you provide your own equivalent, if you decide to turn it off.
*/
get restoreFocus() {
return this._restoreFocus;
}
set restoreFocus(value) {
this._restoreFocus = coerceBooleanProperty(value);
}
/**
* Classes to be passed to the date picker panel.
* Supports string and string array values, similar to `ngClass`.
*/
get panelClass() {
return this._panelClass;
}
set panelClass(value) {
this._panelClass = coerceStringArray(value);
}
/** Whether the calendar is open. */
get opened() {
return this._opened;
}
set opened(value) {
coerceBooleanProperty(value) ? this.open() : this.close();
}
/** Whether the timepicker'spinners is shown. */
get showSpinners() {
return this._showSpinners;
}
set showSpinners(value) {
this._showSpinners = value;
}
/** Whether the second part is disabled. */
get showSeconds() {
return this._showSeconds;
}
set showSeconds(value) {
this._showSeconds = value;
}
/** Step hour */
get stepHour() {
return this._stepHour;
}
set stepHour(value) {
this._stepHour = value;
}
/** Step minute */
get stepMinute() {
return this._stepMinute;
}
set stepMinute(value) {
this._stepMinute = value;
}
/** Step second */
get stepSecond() {
return this._stepSecond;
}
set stepSecond(value) {
this._stepSecond = value;
}
/** Enable meridian */
get enableMeridian() {
return this._enableMeridian;
}
set enableMeridian(value) {
this._enableMeridian = value;
}
/** disable minute */
get disableMinute() {
return this._disableMinute;
}
set disableMinute(value) {
this._disableMinute = value;
}
/** Step second */
get defaultTime() {
return this._defaultTime;
}
set defaultTime(value) {
this._defaultTime = value;
}
/** The minimum selectable date. */
_getMinDate() {
return this.datepickerInput && this.datepickerInput.min;
}
/** The maximum selectable date. */
_getMaxDate() {
return this.datepickerInput && this.datepickerInput.max;
}
_getDateFilter() {
return this.datepickerInput && this.datepickerInput.dateFilter;
}
constructor(_overlay, _ngZone, _viewContainerRef, scrollStrategy, _dateAdapter, _dir, _model) {
this._overlay = _overlay;
this._ngZone = _ngZone;
this._viewContainerRef = _viewContainerRef;
this._dateAdapter = _dateAdapter;
this._dir = _dir;
this._model = _model;
this._inputStateChanges = Subscription.EMPTY;
this._document = inject(DOCUMENT);
/** The view that the calendar should start in. */
this.startView = "month";
this._touchUi = false;
this._hideTime = false;
/** Preferred position of the datepicker in the X axis. */
this.xPosition = "start";
/** Preferred position of the datepicker in the Y axis. */
this.yPosition = "below";
this._restoreFocus = true;
/**
* Emits selected year in multiyear view.
* This doesn't imply a change on the selected date.
*/
this.yearSelected = new EventEmitter();
/**
* Emits selected month in year view.
* This doesn't imply a change on the selected date.
*/
this.monthSelected = new EventEmitter();
/**
* Emits when the current view changes.
*/
this.viewChanged = new EventEmitter(true);
/** Emits when the datepicker has been opened. */
this.openedStream = new EventEmitter();
/** Emits when the datepicker has been closed. */
this.closedStream = new EventEmitter();
this._opened = false;
this._showSpinners = true;
this._showSeconds = false;
this._stepHour = DEFAULT_STEP;
this._stepMinute = DEFAULT_STEP;
this._stepSecond = DEFAULT_STEP;
this._enableMeridian = false;
/** The id for the datepicker calendar. */
this.id = `mat-datepicker-${datepickerUid++}`;
/** The element that was focused before the datepicker was opened. */
this._focusedElementBeforeOpen = null;
/** Unique class that will be added to the backdrop so that the test harnesses can look it up. */
this._backdropHarnessClass = `${this.id}-backdrop`;
/** Emits when the datepicker's state changes. */
this.stateChanges = new Subject();
if (!this._dateAdapter) {
throw createMissingDateImplError$1("NgxMatDateAdapter");
}
this._scrollStrategy = scrollStrategy;
}
ngOnChanges(changes) {
const positionChange = changes["xPosition"] || changes["yPosition"];
if (positionChange && !positionChange.firstChange && this._overlayRef) {
const positionStrategy = this._overlayRef.getConfig().positionStrategy;
if (positionStrategy instanceof FlexibleConnectedPositionStrategy) {
this._setConnectedPositions(positionStrategy);
if (this.opened) {
this._overlayRef.updatePosition();
}
}
}
this.stateChanges.next(undefined);
}
ngOnDestroy() {
this._destroyOverlay();
this.close();
this._inputStateChanges.unsubscribe();
this.stateChanges.complete();
}
/** Selects the given date */
select(date) {
this._model.add(date);
}
/** Emits the selected year in multiyear view */
_selectYear(normalizedYear) {
this.yearSelected.emit(normalizedYear);
}
/** Emits selected month in year view */
_selectMonth(normalizedMonth) {
this.monthSelected.emit(normalizedMonth);
}
/** Emits changed view */
_viewChanged(view) {
this.viewChanged.emit(view);
}
/**
* Register an input with this datepicker.
* @param input The datepicker input to register with this datepicker.
* @returns Selection model that the input should hook itself up to.
*/
registerInput(input) {
if (this.datepickerInput) {
throw Error("A MatDatepicker can only be associated with a single input.");
}
this._inputStateChanges.unsubscribe();
this.datepickerInput = input;
this._inputStateChanges = input.stateChanges.subscribe(() => this.stateChanges.next(undefined));
return this._model;
}
/**
* Registers a portal containing action buttons with the datepicker.
* @param portal Portal to be registered.
*/
registerActions(portal) {
if (this._actionsPortal) {
throw Error("A MatDatepicker can only be associated with a single actions row.");
}
this._actionsPortal = portal;
this._componentRef?.instance._assignActions(portal, true);
}
/**
* Removes a portal containing action buttons from the datepicker.
* @param portal Portal to be removed.
*/
removeActions(portal) {
if (portal === this._actionsPortal) {
this._actionsPortal = null;
this._componentRef?.instance._assignActions(null, true);
}
}
/** Open the calendar. */
open() {
// Skip reopening if there's an in-progress animation to avoid overlapping
// sequences which can cause "changed after checked" errors. See #25837.
if (this._opened ||
this.disabled ||
this._componentRef?.instance._isAnimating) {
return;
}
if (!this.datepickerInput) {
throw Error("Attempted to open an MatDatepicker with no associated input.");
}
this._focusedElementBeforeOpen = _getFocusedElementPierceShadowDom();
this._openOverlay();
this._opened = true;
this.openedStream.emit();
}
/** Close the calendar. */
close() {
// Skip reopening if there's an in-progress animation to avoid overlapping
// sequences which can cause "changed after checked" errors. See #25837.
if (!this._opened || this._componentRef?.instance._isAnimating) {
return;
}
const canRestoreFocus = this._restoreFocus &&
this._focusedElementBeforeOpen &&
typeof this._focusedElementBeforeOpen.focus === "function";
const completeClose = () => {
// The `_opened` could've been reset already if
// we got two events in quick succession.
if (this._opened) {
this._opened = false;
this.closedStream.emit();
}
};
if (this._componentRef) {
const { instance, location } = this._componentRef;
instance._startExitAnimation();
instance._animationDone.pipe(take(1)).subscribe(() => {
const activeElement = this._document.activeElement;
// Since we restore focus after the exit animation, we have to check that
// the user didn't move focus themselves inside the `close` handler.
if (canRestoreFocus &&
(!activeElement ||
activeElement === this._document.activeElement ||
location.nativeElement.contains(activeElement))) {
this._focusedElementBeforeOpen.focus();
}
this._focusedElementBeforeOpen = null;
this._destroyOverlay();
});
}
if (canRestoreFocus) {
// Because IE moves focus asynchronously, we can't count on it being restored before we've
// marked the datepicker as closed. If the event fires out of sequence and the element that
// we're refocusing opens the datepicker on focus, the user could be stuck with not being
// able to close the calendar at all. We work around it by making the logic, that marks
// the datepicker as closed, async as well.
setTimeout(completeClose);
}
else {
completeClose();
}
}
/** Applies the current pending selection on the overlay to the model. */
_applyPendingSelection() {
this._componentRef?.instance?._applyPendingSelection();
}
/** Forwards relevant values from the datepicker to the datepicker content inside the overlay. */
_forwardContentValues(instance) {
instance.datepicker = this;
instance.color = this._color;
instance._dialogLabelId = this.datepickerInput.getOverlayLabelId();
instance._assignActions(this._actionsPortal, false);
}
/** Opens the overlay with the calendar. */
_openOverlay() {
this._destroyOverlay();
const isDialog = this.touchUi;
const portal = new ComponentPortal(NgxMatDatepickerContent, this._viewContainerRef);
const overlayRef = (this._overlayRef = this._overlay.create(new OverlayConfig({
positionStrategy: isDialog
? this._getDialogStrategy()
: this._getDropdownStrategy(),
hasBackdrop: true,
backdropClass: [
isDialog
? "cdk-overlay-dark-backdrop"
: "mat-overlay-transparent-backdrop",
this._backdropHarnessClass,
],
direction: this._dir,
scrollStrategy: isDialog
? this._overlay.scrollStrategies.block()
: this._scrollStrategy(),
panelClass: `mat-datepicker-${isDialog ? "dialog" : "popup"}`,
})));
this._getCloseStream(overlayRef).subscribe((event) => {
if (event) {
event.preventDefault();
}
this.close();
});
// The `preventDefault` call happens inside the calendar as well, however focus moves into
// it inside a timeout which can give browsers a chance to fire off a keyboard event in-between
// that can scroll the page (see #24969). Always block default actions of arrow keys for the
// entire overlay so the page doesn't get scrolled by accident.
overlayRef.keydownEvents().subscribe((event) => {
const keyCode = event.keyCode;
if (keyCode === UP_ARROW ||
keyCode === DOWN_ARROW ||
keyCode === LEFT_ARROW ||
keyCode === RIGHT_ARROW ||
keyCode === PAGE_UP ||
keyCode === PAGE_DOWN) {
event.preventDefault();
}
});
this._componentRef = overlayRef.attach(portal);
this._forwardContentValues(this._componentRef.instance);
// Update the position once the calendar has rendered. Only relevant in dropdown mode.
if (!isDialog) {
this._ngZone.onStable
.pipe(take(1))
.subscribe(() => overlayRef.updatePosition());
}
}
/** Destroys the current overlay. */
_destroyOverlay() {
if (this._overlayRef) {
this._overlayRef.dispose();
this._overlayRef = this._componentRef = null;
}
}
/** Gets a position strategy that will open the calendar as a dropdown. */
_getDialogStrategy() {
return this._overlay
.position()
.global()
.centerHorizontally()
.centerVertically();
}
/** Gets a position strategy that will open the calendar as a dropdown. */
_getDropdownStrategy() {
const strategy = this._overlay
.position()
.flexibleConnectedTo(this.datepickerInput.getConnectedOverlayOrigin())
.withTransformOriginOn(".mat-datepicker-content")
.withFlexibleDimensions(false)
.withViewportMargin(8)
.withLockedPosition();
return this._setConnectedPositions(strategy);
}
/** Sets the positions of the datepicker in dropdown mode based on the current configuration. */
_setConnectedPositions(strategy) {
const primaryX = this.xPosition === "end" ? "end" : "start";
const secondaryX = primaryX === "start" ? "end" : "start";
const primaryY = this.yPosition === "above" ? "bottom" : "top";
const secondaryY = primaryY === "top" ? "bottom" : "top";
return strategy.withPositions([
{
originX: primaryX,
originY: secondaryY,
overlayX: primaryX,
overlayY: primaryY,
},
{
originX: primaryX,
originY: primaryY,
overlayX: primaryX,
overlayY: secondaryY,
},
{
originX: secondaryX,
originY: secondaryY,
overlayX: secondaryX,
overlayY: primaryY,
},
{
originX: secondaryX,
originY: primaryY,
overlayX: secondaryX,
overlayY: secondaryY,
},
]);
}
/** Gets an observable that will emit when the overlay is supposed to be closed. */
_getCloseStream(overlayRef) {
const ctrlShiftMetaModifiers = [
"ctrlKey",
"shiftKey",
"metaKey",
];
return merge(overlayRef.backdropClick(), overlayRef.detachments(), overlayRef.keydownEvents().pipe(filter((event) => {
// Closing on alt + up is only valid when there's an input associated with the datepicker.
return ((event.keyCode === ESCAPE && !hasModifierKey(event)) ||
(this.datepickerInput &&
hasModifierKey(event, "altKey") &&
event.keyCode === UP_ARROW &&
ctrlShiftMetaModifiers.every((modifier) => !hasModifierKey(event, modifier))));
})));
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDatepickerBase, deps: [{ token: i11.Overlay }, { token: i0.NgZone }, { token: i0.ViewContainerRef }, { token: NGX_MAT_DATEPICKER_SCROLL_STRATEGY }, { token: NgxMatDateAdapter, optional: true }, { token: i12.Directionality, optional: true }, { token: NgxMatDateSelectionModel }], target: i0.ɵɵFactoryTarget.Directive }); }
/** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.10", type: NgxMatDatepickerBase, isStandalone: true, inputs: { calendarHeaderComponent: "calendarHeaderComponent", startAt: "startAt", startView: "startView", color: "color", touchUi: "touchUi", hideTime: "hideTime", disabled: "disabled", xPosition: "xPosition", yPosition: "yPosition", restoreFocus: "restoreFocus", dateClass: "dateClass", panelClass: "panelClass", opened: "opened", showSpinners: "showSpinners", showSeconds: "showSeconds", stepHour: "stepHour", stepMinute: "stepMinute", stepSecond: "stepSecond", enableMeridian: "enableMeridian", disableMinute: "disableMinute", defaultTime: "defaultTime" }, outputs: { yearSelected: "yearSelected", monthSelected: "monthSelected", viewChanged: "viewChanged", openedStream: "opened", closedStream: "closed" }, usesOnChanges: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDatepickerBase, decorators: [{
type: Directive
}], ctorParameters: () => [{ type: i11.Overlay }, { type: i0.NgZone }, { type: i0.ViewContainerRef }, { type: undefined, decorators: [{
type: Inject,
args: [NGX_MAT_DATEPICKER_SCROLL_STRATEGY]
}] }, { type: NgxMatDateAdapter, decorators: [{
type: Optional
}] }, { type: i12.Directionality, decorators: [{
type: Optional
}] }, { type: NgxMatDateSelectionModel }], propDecorators: { calendarHeaderComponent: [{
type: Input
}], startAt: [{
type: Input
}], startView: [{
type: Input
}], color: [{
type: Input
}], touchUi: [{
type: Input
}], hideTime: [{
type: Input
}], disabled: [{
type: Input
}], xPosition: [{
type: Input
}], yPosition: [{
type: Input
}], restoreFocus: [{
type: Input
}], yearSelected: [{
type: Output
}], monthSelected: [{
type: Output
}], viewChanged: [{
type: Output
}], dateClass: [{
type: Input
}], openedStream: [{
type: Output,
args: ["opened"]
}], closedStream: [{
type: Output,
args: ["closed"]
}], panelClass: [{
type: Input
}], opened: [{
type: Input
}], showSpinners: [{
type: Input
}], showSeconds: [{
type: Input
}], stepHour: [{
type: Input
}], stepMinute: [{
type: Input
}], stepSecond: [{
type: Input
}], enableMeridian: [{
type: Input
}], disableMinute: [{
type: Input
}], defaultTime: [{
type: Input
}] } });
// TODO(mmalerba): We use a component instead of a directive here so the user can use implicit
// template reference variables (e.g. #d vs #d="matDateRangePicker"). We can change this to a
// directive if angular adds support for `exportAs: '$implicit'` on directives.
/** Component responsible for managing the date range picker popup/dialog. */
class NgxMatDateRangePicker extends NgxMatDatepickerBase {
_forwardContentValues(instance) {
super._forwardContentValues(instance);
const input = this.datepickerInput;
if (input) {
instance.comparisonStart = input.comparisonStart;
instance.comparisonEnd = input.comparisonEnd;
instance.startDateAccessibleName = input._getStartDateAccessibleName();
instance.endDateAccessibleName = input._getEndDateAccessibleName();
}
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDateRangePicker, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
/** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.10", type: NgxMatDateRangePicker, isStandalone: false, selector: "ngx-mat-date-range-picker", providers: [
NGX_MAT_RANGE_DATE_SELECTION_MODEL_PROVIDER,
NGX_MAT_CALENDAR_RANGE_STRATEGY_PROVIDER,
{ provide: NgxMatDatepickerBase, useExisting: NgxMatDateRangePicker },
], exportAs: ["ngxMatDateRangePicker"], usesInheritance: true, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDateRangePicker, decorators: [{
type: Component,
args: [{
selector: 'ngx-mat-date-range-picker',
template: '',
exportAs: 'ngxMatDateRangePicker',
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
providers: [
NGX_MAT_RANGE_DATE_SELECTION_MODEL_PROVIDER,
NGX_MAT_CALENDAR_RANGE_STRATEGY_PROVIDER,
{ provide: NgxMatDatepickerBase, useExisting: NgxMatDateRangePicker },
],
standalone: false
}]
}] });
// TODO(mmalerba): We use a component instead of a directive here so the user can use implicit
// template reference variables (e.g. #d vs #d="matDatepicker"). We can change this to a directive
// if angular adds support for `exportAs: '$implicit'` on directives.
/** Component responsible for managing the datepicker popup/dialog. */
class NgxMatDatetimepicker extends NgxMatDatepickerBase {
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDatetimepicker, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
/** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.10", type: NgxMatDatetimepicker, isStandalone: false, selector: "ngx-mat-datetime-picker", providers: [
NGX_MAT_SINGLE_DATE_SELECTION_MODEL_PROVIDER,
{ provide: NgxMatDatepickerBase, useExisting: NgxMatDatetimepicker },
], exportAs: ["ngxMatDatetimePicker"], usesInheritance: true, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDatetimepicker, decorators: [{
type: Component,
args: [{
selector: 'ngx-mat-datetime-picker',
template: '',
exportAs: 'ngxMatDatetimePicker',
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
providers: [
NGX_MAT_SINGLE_DATE_SELECTION_MODEL_PROVIDER,
{ provide: NgxMatDatepickerBase, useExisting: NgxMatDatetimepicker },
],
standalone: false
}]
}] });
/** Button that will close the datepicker and assign the current selection to the data model. */
class NgxMatDatepickerApply {
constructor(_datepicker) {
this._datepicker = _datepicker;
}
_applySelection() {
this._datepicker._applyPendingSelection();
this._datepicker.close();
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDatepickerApply, deps: [{ token: NgxMatDatepickerBase }], target: i0.ɵɵFactoryTarget.Directive }); }
/** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.10", type: NgxMatDatepickerApply, isStandalone: false, selector: "[ngxMatDatepickerApply], [ngxMatDateRangePickerApply]", host: { listeners: { "click": "_applySelection()" } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDatepickerApply, decorators: [{
type: Directive,
args: [{
selector: '[ngxMatDatepickerApply], [ngxMatDateRangePickerApply]',
host: { '(click)': '_applySelection()' },
standalone: false
}]
}], ctorParameters: () => [{ type: NgxMatDatepickerBase }] });
/** Button that will close the datepicker and discard the current selection. */
class NgxMatDatepickerCancel {
constructor(_datepicker) {
this._datepicker = _datepicker;
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDatepickerCancel, deps: [{ token: NgxMatDatepickerBase }], target: i0.ɵɵFactoryTarget.Directive }); }
/** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.10", type: NgxMatDatepickerCancel, isStandalone: false, selector: "[ngxMatDatepickerCancel], [ngxMatDateRangePickerCancel]", host: { listeners: { "click": "_datepicker.close()" } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDatepickerCancel, decorators: [{
type: Directive,
args: [{
selector: '[ngxMatDatepickerCancel], [ngxMatDateRangePickerCancel]',
host: { '(click)': '_datepicker.close()' },
standalone: false
}]
}], ctorParameters: () => [{ type: NgxMatDatepickerBase }] });
/**
* Container that can be used to project a row of action buttons
* to the bottom of a datepicker or date range picker.
*/
class NgxMatDatepickerActions {
constructor(_datepicker, _viewContainerRef) {
this._datepicker = _datepicker;
this._viewContainerRef = _viewContainerRef;
}
ngAfterViewInit() {
this._portal = new TemplatePortal(this._template, this._viewContainerRef);
this._datepicker.registerActions(this._portal);
}
ngOnDestroy() {
this._datepicker.removeActions(this._portal);
// Needs to be null checked since we initialize it in `ngAfterViewInit`.
if (this._portal && this._portal.isAttached) {
this._portal?.detach();
}
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDatepickerActions, deps: [{ token: NgxMatDatepickerBase }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Component }); }
/** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.10", type: NgxMatDatepickerActions, isStandalone: false, selector: "ngx-mat-datepicker-actions, ngx-mat-date-range-picker-actions", viewQueries: [{ propertyName: "_template", first: true, predicate: TemplateRef, descendants: true }], ngImport: i0, template: `
<ng-template>
<div class="mat-datepicker-actions">
<ng-content></ng-content>
</div>
</ng-template>
`, isInline: true, styles: [".mat-datepicker-actions{display:flex;justify-content:flex-end;align-items:center;padding:8px}.mat-datepicker-actions .mat-mdc-button-base+.mat-mdc-button-base{margin-left:8px}[dir=rtl] .mat-datepicker-actions .mat-mdc-button-base+.mat-mdc-button-base{margin-left:0;margin-right:8px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDatepickerActions, decorators: [{
type: Component,
args: [{ selector: 'ngx-mat-datepicker-actions, ngx-mat-date-range-picker-actions', template: `
<ng-template>
<div class="mat-datepicker-actions">
<ng-content></ng-content>
</div>
</ng-template>
`, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, standalone: false, styles: [".mat-datepicker-actions{display:flex;justify-content:flex-end;align-items:center;padding:8px}.mat-datepicker-actions .mat-mdc-button-base+.mat-mdc-button-base{margin-left:8px}[dir=rtl] .mat-datepicker-actions .mat-mdc-button-base+.mat-mdc-button-base{margin-left:0;margin-right:8px}\n"] }]
}], ctorParameters: () => [{ type: NgxMatDatepickerBase }, { type: i0.ViewContainerRef }], propDecorators: { _template: [{
type: ViewChild,
args: [TemplateRef]
}] } });
/** @docs-private */
const NGX_MAT_DATEPICKER_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => NgxMatDatepickerInput),
multi: true,
};
/** @docs-private */
const NGX_MAT_DATEPICKER_VALIDATORS = {
provide: NG_VALIDATORS,
useExisting: forwardRef(() => NgxMatDatepickerInput),
multi: true,
};
/** Directive used to connect an input to a MatDatepicker. */
class NgxMatDatepickerInput extends NgxMatDatepickerInputBase {
/** The datepicker that this input is associated with. */
set ngxMatDatetimePicker(datepicker) {
if (datepicker) {
this._datepicker = datepicker;
this._closedSubscription = datepicker.closedStream.subscribe(() => this._onTouched());
this._registerModel(datepicker.registerInput(this));
}
}
/** The minimum valid date. */
get min() {
return this._min;
}
set min(value) {
const validValue = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value));
if (!this._dateAdapter.sameDate(validValue, this._min)) {
this._min = validValue;
this._validatorOnChange();
}
}
/** The maximum valid date. */
get max() {
return this._max;
}
set max(value) {
const validValue = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value));
if (!this._dateAdapter.sameDate(validValue, this._max)) {
this._max = validValue;
this._validatorOnChange();
}
}
/** Function that can be used to filter out dates within the datepicker. */
get dateFilter() {
return this._dateFilter;
}
set dateFilter(value) {
const wasMatchingValue = this._matchesFilter(this.value);
this._dateFilter = value;
if (this._matchesFilter(this.value) !== wasMatchingValue) {
this._validatorOnChange();
}
}
constructor(elementRef, dateAdapter, dateFormats, _formField) {
super(elementRef, dateAdapter, dateFormats);
this._formField = _formField;
this._closedSubscription = Subscription.EMPTY;
this._validator = Validators.compose(super._getValidators());
}
/**
* Gets the element that the datepicker popup should be connected to.
* @return The element to connect the popup to.
*/
getConnectedOverlayOrigin() {
return this._formField ? this._formField.getConnectedOverlayOrigin() : this._elementRef;
}
/** Gets the ID of an element that should be used a description for the calendar overlay. */
getOverlayLabelId() {
if (this._formField) {
return this._formField.getLabelId();
}
return this._elementRef.nativeElement.getAttribute('aria-labelledby');
}
/** Returns the palette used by the input's form field, if any. */
getThemePalette() {
return this._formField ? this._formField.color : undefined;
}
/** Gets the value at which the calendar should start. */
getStartValue() {
return this.value;
}
ngOnDestroy() {
super.ngOnDestroy();
this._closedSubscription.unsubscribe();
}
/** Opens the associated datepicker. */
_openPopup() {
if (this._datepicker) {
this._datepicker.open();
}
}
_getValueFromModel(modelValue) {
return modelValue;
}
_assignValueToModel(value) {
if (this._model) {
this._model.updateSelection(value, this);
}
}
/** Gets the input's minimum date. */
_getMinDate() {
return this._min;
}
/** Gets the input's maximum date. */
_getMaxDate() {
return this._max;
}
/** Gets the input's date filtering function. */
_getDateFilter() {
return this._dateFilter;
}
_shouldHandleChangeEvent(event) {
return event.source !== this;
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDatepickerInput, deps: [{ token: i0.ElementRef }, { token: NgxMatDateAdapter, optional: true }, { token: NGX_MAT_DATE_FORMATS, optional: true }, { token: MAT_FORM_FIELD, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
/** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.10", type: NgxMatDatepickerInput, isStandalone: false, selector: "input[ngxMatDatetimePicker]", inputs: { ngxMatDatetimePicker: "ngxMatDatetimePicker", min: "min", max: "max", dateFilter: ["matDatepickerFilter", "dateFilter"] }, host: { listeners: { "input": "_onInput($event.target.value)", "change": "_onChange()", "blur": "_onBlur()", "keydown": "_onKeydown($event)" }, properties: { "attr.aria-haspopup": "_datepicker ? \"dialog\" : null", "attr.aria-owns": "(_datepicker?.opened && _datepicker.id) || null", "attr.min": "min ? _dateAdapter.toIso8601(min) : null", "attr.max": "max ? _dateAdapter.toIso8601(max) : null", "attr.data-mat-calendar": "_datepicker ? _datepicker.id : null", "disabled": "disabled" }, classAttribute: "mat-datepicker-input" }, providers: [
NGX_MAT_DATEPICKER_VALUE_ACCESSOR,
NGX_MAT_DATEPICKER_VALIDATORS,
{ provide: MAT_INPUT_VALUE_ACCESSOR, useExisting: NgxMatDatepickerInput },
], exportAs: ["ngxMatDatepickerInput"], usesInheritance: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDatepickerInput, decorators: [{
type: Directive,
args: [{
selector: 'input[ngxMatDatetimePicker]',
providers: [
NGX_MAT_DATEPICKER_VALUE_ACCESSOR,
NGX_MAT_DATEPICKER_VALIDATORS,
{ provide: MAT_INPUT_VALUE_ACCESSOR, useExisting: NgxMatDatepickerInput },
],
host: {
'class': 'mat-datepicker-input',
'[attr.aria-haspopup]': '_datepicker ? "dialog" : null',
'[attr.aria-owns]': '(_datepicker?.opened && _datepicker.id) || null',
'[attr.min]': 'min ? _dateAdapter.toIso8601(min) : null',
'[attr.max]': 'max ? _dateAdapter.toIso8601(max) : null',
// Used by the test harness to tie this input to its calendar. We can't depend on
// `aria-owns` for this, because it's only defined while the calendar is open.
'[attr.data-mat-calendar]': '_datepicker ? _datepicker.id : null',
'[disabled]': 'disabled',
'(input)': '_onInput($event.target.value)',
'(change)': '_onChange()',
'(blur)': '_onBlur()',
'(keydown)': '_onKeydown($event)',
},
exportAs: 'ngxMatDatepickerInput',
standalone: false
}]
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: NgxMatDateAdapter, decorators: [{
type: Optional
}] }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: [NGX_MAT_DATE_FORMATS]
}] }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: [MAT_FORM_FIELD]
}] }], propDecorators: { ngxMatDatetimePicker: [{
type: Input
}], min: [{
type: Input
}], max: [{
type: Input
}], dateFilter: [{
type: Input,
args: ['matDatepickerFilter']
}] } });
/** Can be used to override the icon of a `matDatepickerToggle`. */
class NgxMatDatepickerToggleIcon {
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDatepickerToggleIcon, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
/** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.10", type: NgxMatDatepickerToggleIcon, isStandalone: false, selector: "[ngxMatDatepickerToggleIcon]", ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDatepickerToggleIcon, decorators: [{
type: Directive,
args: [{
selector: "[ngxMatDatepickerToggleIcon]",
standalone: false,
}]
}] });
class NgxMatDatepickerToggle {
/** Whether the toggle button is disabled. */
get disabled() {
if (this._disabled === undefined && this.datepicker) {
return this.datepicker.disabled;
}
return !!this._disabled;
}
set disabled(value) {
this._disabled = coerceBooleanProperty(value);
}
constructor(_intl, _changeDetectorRef, defaultTabIndex) {
this._intl = _intl;
this._changeDetectorRef = _changeDetectorRef;
this._stateChanges = Subscription.EMPTY;
const parsedTabIndex = Number(defaultTabIndex);
this.tabIndex =
parsedTabIndex || parsedTabIndex === 0 ? parsedTabIndex : null;
}
ngOnChanges(changes) {
if (changes["datepicker"]) {
this._watchStateChanges();
}
}
ngOnDestroy() {
this._stateChanges.unsubscribe();
}
ngAfterContentInit() {
this._watchStateChanges();
}
_open(event) {
if (this.datepicker && !this.disabled) {
this.datepicker.open();
event.stopPropagation();
}
}
_watchStateChanges() {
const datepickerStateChanged = this.datepicker
? this.datepicker.stateChanges
: of();
const inputStateChanged = this.datepicker && this.datepicker.datepickerInput
? this.datepicker.datepickerInput.stateChanges
: of();
const datepickerToggled = this.datepicker
? merge(this.datepicker.openedStream, this.datepicker.closedStream)
: of();
this._stateChanges.unsubscribe();
this._stateChanges = merge(this._intl.changes, datepickerStateChanged, inputStateChanged, datepickerToggled).subscribe(() => this._changeDetectorRef.markForCheck());
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDatepickerToggle, deps: [{ token: NgxMatDatepickerIntl }, { token: i0.ChangeDetectorRef }, { token: "tabindex", attribute: true }], target: i0.ɵɵFactoryTarget.Component }); }
/** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.10", type: NgxMatDatepickerToggle, isStandalone: false, selector: "ngx-mat-datepicker-toggle", inputs: { datepicker: ["for", "datepicker"], tabIndex: "tabIndex", ariaLabel: ["aria-label", "ariaLabel"], disabled: "disabled", disableRipple: "disableRipple" }, host: { listeners: { "click": "_open($event)" }, properties: { "attr.tabindex": "null", "class.mat-datepicker-toggle-active": "datepicker && datepicker.opened", "class.mat-accent": "datepicker && datepicker.color === \"accent\"", "class.mat-warn": "datepicker && datepicker.color === \"warn\"", "attr.data-mat-calendar": "datepicker ? datepicker.id : null" }, classAttribute: "mat-datepicker-toggle" }, queries: [{ propertyName: "_customIcon", first: true, predicate: NgxMatDatepickerToggleIcon, descendants: true }], viewQueries: [{ propertyName: "_button", first: true, predicate: ["button"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<button\r\n #button\r\n mat-icon-button\r\n type=\"button\"\r\n [attr.aria-haspopup]=\"datepicker ? 'dialog' : null\"\r\n [attr.aria-label]=\"ariaLabel || _intl.openCalendarLabel\"\r\n [attr.tabindex]=\"disabled ? -1 : tabIndex\"\r\n [disabled]=\"disabled\"\r\n>\r\n <svg\r\n *ngIf=\"!_customIcon\"\r\n class=\"mat-datepicker-toggle-default-icon\"\r\n viewBox=\"0 0 24 24\"\r\n width=\"24px\"\r\n height=\"24px\"\r\n fill=\"currentColor\"\r\n focusable=\"false\"\r\n >\r\n <path\r\n d=\"M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11zM7 10h5v5H7z\"\r\n />\r\n </svg>\r\n\r\n <ng-content select=\"[ngxMatDatepickerToggleIcon]\"></ng-content>\r\n</button>\r\n", styles: [".mat-datepicker-toggle{pointer-events:auto}@media (forced-colors: active){.mat-datepicker-toggle-default-icon{color:CanvasText}}\n"], dependencies: [{ kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i4$1.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDatepickerToggle, decorators: [{
type: Component,
args: [{ selector: "ngx-mat-datepicker-toggle", host: {
class: "mat-datepicker-toggle",
"[attr.tabindex]": "null",
"[class.mat-datepicker-toggle-active]": "datepicker && datepicker.opened",
"[class.mat-accent]": 'datepicker && datepicker.color === "accent"',
"[class.mat-warn]": 'datepicker && datepicker.color === "warn"',
// Used by the test harness to tie this toggle to its datepicker.
"[attr.data-mat-calendar]": "datepicker ? datepicker.id : null",
// Bind the `click` on the host, rather than the inner `button`, so that we can call
// `stopPropagation` on it without affecting the user's `click` handlers. We need to stop
// it so that the input doesn't get focused automatically by the form field (See #21836).
"(click)": "_open($event)",
}, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, standalone: false, template: "<button\r\n #button\r\n mat-icon-button\r\n type=\"button\"\r\n [attr.aria-haspopup]=\"datepicker ? 'dialog' : null\"\r\n [attr.aria-label]=\"ariaLabel || _intl.openCalendarLabel\"\r\n [attr.tabindex]=\"disabled ? -1 : tabIndex\"\r\n [disabled]=\"disabled\"\r\n>\r\n <svg\r\n *ngIf=\"!_customIcon\"\r\n class=\"mat-datepicker-toggle-default-icon\"\r\n viewBox=\"0 0 24 24\"\r\n width=\"24px\"\r\n height=\"24px\"\r\n fill=\"currentColor\"\r\n focusable=\"false\"\r\n >\r\n <path\r\n d=\"M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11zM7 10h5v5H7z\"\r\n />\r\n </svg>\r\n\r\n <ng-content select=\"[ngxMatDatepickerToggleIcon]\"></ng-content>\r\n</button>\r\n", styles: [".mat-datepicker-toggle{pointer-events:auto}@media (forced-colors: active){.mat-datepicker-toggle-default-icon{color:CanvasText}}\n"] }]
}], ctorParameters: () => [{ type: NgxMatDatepickerIntl }, { type: i0.ChangeDetectorRef }, { type: undefined, decorators: [{
type: Attribute,
args: ["tabindex"]
}] }], propDecorators: { datepicker: [{
type: Input,
args: ["for"]
}], tabIndex: [{
type: Input
}], ariaLabel: [{
type: Input,
args: ["aria-label"]
}], disabled: [{
type: Input
}], disableRipple: [{
type: Input
}], _customIcon: [{
type: ContentChild,
args: [NgxMatDatepickerToggleIcon]
}], _button: [{
type: ViewChild,
args: ["button"]
}] } });
class NgxMatDatetimePickerModule {
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDatetimePickerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
/** @nocollapse */ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDatetimePickerModule, declarations: [NgxMatDatetimepicker,
NgxMatDatepickerContent,
NgxMatDatepickerInput,
NgxMatDatepickerToggle,
NgxMatDatepickerToggleIcon,
NgxMatDateRangeInput,
NgxMatStartDate,
NgxMatEndDate,
NgxMatDateRangePicker,
NgxMatDatepickerActions,
NgxMatDatepickerCancel,
NgxMatDatepickerApply], imports: [CommonModule,
MatButtonModule,
OverlayModule,
A11yModule,
PortalModule,
FormsModule,
ReactiveFormsModule,
NgxMatTimepickerComponent,
MatRippleModule,
MatDatepickerModule], exports: [CdkScrollableModule,
NgxMatDatetimepicker,
NgxMatDatepickerContent,
NgxMatDatepickerInput,
NgxMatDatepickerToggle,
NgxMatDatepickerToggleIcon,
NgxMatDateRangeInput,
NgxMatStartDate,
NgxMatEndDate,
NgxMatDateRangePicker,
NgxMatDatepickerActions,
NgxMatDatepickerCancel,
NgxMatDatepickerApply,
NgxMatTimepickerComponent] }); }
/** @nocollapse */ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDatetimePickerModule, providers: [
NgxMatDatepickerIntl,
NGX_MAT_DATEPICKER_SCROLL_STRATEGY_FACTORY_PROVIDER,
], imports: [CommonModule,
MatButtonModule,
OverlayModule,
A11yModule,
PortalModule,
FormsModule,
ReactiveFormsModule,
NgxMatTimepickerComponent,
MatRippleModule,
MatDatepickerModule, CdkScrollableModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: NgxMatDatetimePickerModule, decorators: [{
type: NgModule,
args: [{
imports: [
CommonModule,
MatButtonModule,
OverlayModule,
A11yModule,
PortalModule,
FormsModule,
ReactiveFormsModule,
NgxMatTimepickerComponent,
MatRippleModule,
MatDatepickerModule,
],
exports: [
CdkScrollableModule,
NgxMatDatetimepicker,
NgxMatDatepickerContent,
NgxMatDatepickerInput,
NgxMatDatepickerToggle,
NgxMatDatepickerToggleIcon,
NgxMatDateRangeInput,
NgxMatStartDate,
NgxMatEndDate,
NgxMatDateRangePicker,
NgxMatDatepickerActions,
NgxMatDatepickerCancel,
NgxMatDatepickerApply,
NgxMatTimepickerComponent,
],
declarations: [
NgxMatDatetimepicker,
NgxMatDatepickerContent,
NgxMatDatepickerInput,
NgxMatDatepickerToggle,
NgxMatDatepickerToggleIcon,
NgxMatDateRangeInput,
NgxMatStartDate,
NgxMatEndDate,
NgxMatDateRangePicker,
NgxMatDatepickerActions,
NgxMatDatepickerCancel,
NgxMatDatepickerApply,
],
providers: [
NgxMatDatepickerIntl,
NGX_MAT_DATEPICKER_SCROLL_STRATEGY_FACTORY_PROVIDER,
],
}]
}] });
/*
* Public API Surface of ngx-mat-datetime-picker
*/
/**
* Generated bundle index. Do not edit.
*/
export { DefaultNgxMatCalendarRangeStrategy, NGX_MAT_CALENDAR_RANGE_STRATEGY_PROVIDER, NGX_MAT_CALENDAR_RANGE_STRATEGY_PROVIDER_FACTORY, NGX_MAT_DATEPICKER_SCROLL_STRATEGY, NGX_MAT_DATEPICKER_SCROLL_STRATEGY_FACTORY, NGX_MAT_DATEPICKER_SCROLL_STRATEGY_FACTORY_PROVIDER, NGX_MAT_DATEPICKER_VALIDATORS, NGX_MAT_DATEPICKER_VALUE_ACCESSOR, NGX_MAT_DATE_FORMATS, NGX_MAT_DATE_RANGE_INPUT_PARENT, NGX_MAT_DATE_RANGE_SELECTION_STRATEGY, NGX_MAT_NATIVE_DATE_FORMATS, NgxMatDateAdapter, NgxMatDateRangeInput, NgxMatDateRangePicker, NgxMatDatepickerActions, NgxMatDatepickerApply, NgxMatDatepickerBase, NgxMatDatepickerCancel, NgxMatDatepickerContent, NgxMatDatepickerInput, NgxMatDatepickerToggle, NgxMatDatepickerToggleIcon, NgxMatDatetimePickerModule, NgxMatDatetimepicker, NgxMatEndDate, NgxMatNativeDateAdapter, NgxMatNativeDateModule, NgxMatStartDate, NgxMatTimepickerComponent, NgxNativeDateModule };
//# sourceMappingURL=ngx-mat-datetime-picker-v2.mjs.map