UNPKG

258 kBJavaScriptView Raw
1import * as i5 from '@angular/cdk/a11y';
2import { A11yModule } from '@angular/cdk/a11y';
3import * as i9 from '@angular/cdk/overlay';
4import { Overlay, FlexibleConnectedPositionStrategy, OverlayConfig, OverlayModule } from '@angular/cdk/overlay';
5import * as i6 from '@angular/cdk/portal';
6import { ComponentPortal, TemplatePortal, PortalModule } from '@angular/cdk/portal';
7import * as i1 from '@angular/common';
8import { CommonModule } from '@angular/common';
9import * as i0 from '@angular/core';
10import { EventEmitter, Component, ViewEncapsulation, ChangeDetectionStrategy, Input, Output, Injectable, Optional, SkipSelf, InjectionToken, Inject, ViewChild, forwardRef, Directive, Attribute, ContentChild, InjectFlags, Self, TemplateRef, NgModule } from '@angular/core';
11import * as i3 from '@angular/material/button';
12import { MatButtonModule } from '@angular/material/button';
13import { CdkScrollableModule } from '@angular/cdk/scrolling';
14import * as i1$1 from '@angular/material/core';
15import { DateAdapter, MAT_DATE_FORMATS, mixinColor, mixinErrorState, MatCommonModule } from '@angular/material/core';
16import { Subject, Subscription, merge, of } from 'rxjs';
17import { ESCAPE, hasModifierKey, SPACE, ENTER, PAGE_DOWN, PAGE_UP, END, HOME, DOWN_ARROW, UP_ARROW, RIGHT_ARROW, LEFT_ARROW, BACKSPACE } from '@angular/cdk/keycodes';
18import { take, startWith, filter } from 'rxjs/operators';
19import * as i2 from '@angular/cdk/bidi';
20import { coerceBooleanProperty, coerceStringArray } from '@angular/cdk/coercion';
21import { _getFocusedElementPierceShadowDom } from '@angular/cdk/platform';
22import { trigger, transition, animate, keyframes, style, state } from '@angular/animations';
23import * as i2$2 from '@angular/forms';
24import { NG_VALUE_ACCESSOR, NG_VALIDATORS, Validators, NgControl } from '@angular/forms';
25import * as i2$1 from '@angular/material/form-field';
26import { MAT_FORM_FIELD, MatFormFieldControl } from '@angular/material/form-field';
27import { MAT_INPUT_VALUE_ACCESSOR } from '@angular/material/input';
28
29/**
30 * @license
31 * Copyright Google LLC All Rights Reserved.
32 *
33 * Use of this source code is governed by an MIT-style license that can be
34 * found in the LICENSE file at https://angular.io/license
35 */
36/** @docs-private */
37function createMissingDateImplError(provider) {
38 return Error(`MatDatepicker: No provider found for ${provider}. You must import one of the following ` +
39 `modules at your application root: MatNativeDateModule, MatMomentDateModule, or provide a ` +
40 `custom implementation.`);
41}
42
43/**
44 * @license
45 * Copyright Google LLC All Rights Reserved.
46 *
47 * Use of this source code is governed by an MIT-style license that can be
48 * found in the LICENSE file at https://angular.io/license
49 */
50/**
51 * An internal class that represents the data corresponding to a single calendar cell.
52 * @docs-private
53 */
54class MatCalendarCell {
55 constructor(value, displayValue, ariaLabel, enabled, cssClasses = {}, compareValue = value, rawValue) {
56 this.value = value;
57 this.displayValue = displayValue;
58 this.ariaLabel = ariaLabel;
59 this.enabled = enabled;
60 this.cssClasses = cssClasses;
61 this.compareValue = compareValue;
62 this.rawValue = rawValue;
63 }
64}
65/**
66 * An internal component used to display calendar data in a table.
67 * @docs-private
68 */
69class MatCalendarBody {
70 constructor(_elementRef, _ngZone) {
71 this._elementRef = _elementRef;
72 this._ngZone = _ngZone;
73 /**
74 * Used to focus the active cell after change detection has run.
75 */
76 this._focusActiveCellAfterViewChecked = false;
77 /** The number of columns in the table. */
78 this.numCols = 7;
79 /** The cell number of the active cell in the table. */
80 this.activeCell = 0;
81 /** Whether a range is being selected. */
82 this.isRange = false;
83 /**
84 * The aspect ratio (width / height) to use for the cells in the table. This aspect ratio will be
85 * maintained even as the table resizes.
86 */
87 this.cellAspectRatio = 1;
88 /** Start of the preview range. */
89 this.previewStart = null;
90 /** End of the preview range. */
91 this.previewEnd = null;
92 /** Emits when a new value is selected. */
93 this.selectedValueChange = new EventEmitter();
94 /** Emits when the preview has changed as a result of a user action. */
95 this.previewChange = new EventEmitter();
96 this.activeDateChange = new EventEmitter();
97 /**
98 * Event handler for when the user enters an element
99 * inside the calendar body (e.g. by hovering in or focus).
100 */
101 this._enterHandler = (event) => {
102 if (this._skipNextFocus && event.type === 'focus') {
103 this._skipNextFocus = false;
104 return;
105 }
106 // We only need to hit the zone when we're selecting a range.
107 if (event.target && this.isRange) {
108 const cell = this._getCellFromElement(event.target);
109 if (cell) {
110 this._ngZone.run(() => this.previewChange.emit({ value: cell.enabled ? cell : null, event }));
111 }
112 }
113 };
114 /**
115 * Event handler for when the user's pointer leaves an element
116 * inside the calendar body (e.g. by hovering out or blurring).
117 */
118 this._leaveHandler = (event) => {
119 // We only need to hit the zone when we're selecting a range.
120 if (this.previewEnd !== null && this.isRange) {
121 // Only reset the preview end value when leaving cells. This looks better, because
122 // we have a gap between the cells and the rows and we don't want to remove the
123 // range just for it to show up again when the user moves a few pixels to the side.
124 if (event.target && this._getCellFromElement(event.target)) {
125 this._ngZone.run(() => this.previewChange.emit({ value: null, event }));
126 }
127 }
128 };
129 _ngZone.runOutsideAngular(() => {
130 const element = _elementRef.nativeElement;
131 element.addEventListener('mouseenter', this._enterHandler, true);
132 element.addEventListener('focus', this._enterHandler, true);
133 element.addEventListener('mouseleave', this._leaveHandler, true);
134 element.addEventListener('blur', this._leaveHandler, true);
135 });
136 }
137 ngAfterViewChecked() {
138 if (this._focusActiveCellAfterViewChecked) {
139 this._focusActiveCell();
140 this._focusActiveCellAfterViewChecked = false;
141 }
142 }
143 /** Called when a cell is clicked. */
144 _cellClicked(cell, event) {
145 if (cell.enabled) {
146 this.selectedValueChange.emit({ value: cell.value, event });
147 }
148 }
149 _emitActiveDateChange(cell, event) {
150 if (cell.enabled) {
151 this.activeDateChange.emit({ value: cell.value, event });
152 }
153 }
154 /** Returns whether a cell should be marked as selected. */
155 _isSelected(value) {
156 return this.startValue === value || this.endValue === value;
157 }
158 ngOnChanges(changes) {
159 const columnChanges = changes['numCols'];
160 const { rows, numCols } = this;
161 if (changes['rows'] || columnChanges) {
162 this._firstRowOffset = rows && rows.length && rows[0].length ? numCols - rows[0].length : 0;
163 }
164 if (changes['cellAspectRatio'] || columnChanges || !this._cellPadding) {
165 this._cellPadding = `${(50 * this.cellAspectRatio) / numCols}%`;
166 }
167 if (columnChanges || !this._cellWidth) {
168 this._cellWidth = `${100 / numCols}%`;
169 }
170 }
171 ngOnDestroy() {
172 const element = this._elementRef.nativeElement;
173 element.removeEventListener('mouseenter', this._enterHandler, true);
174 element.removeEventListener('focus', this._enterHandler, true);
175 element.removeEventListener('mouseleave', this._leaveHandler, true);
176 element.removeEventListener('blur', this._leaveHandler, true);
177 }
178 /** Returns whether a cell is active. */
179 _isActiveCell(rowIndex, colIndex) {
180 let cellNumber = rowIndex * this.numCols + colIndex;
181 // Account for the fact that the first row may not have as many cells.
182 if (rowIndex) {
183 cellNumber -= this._firstRowOffset;
184 }
185 return cellNumber == this.activeCell;
186 }
187 /**
188 * Focuses the active cell after the microtask queue is empty.
189 *
190 * Adding a 0ms setTimeout seems to fix Voiceover losing focus when pressing PageUp/PageDown
191 * (issue #24330).
192 *
193 * Determined a 0ms by gradually increasing duration from 0 and testing two use cases with screen
194 * reader enabled:
195 *
196 * 1. Pressing PageUp/PageDown repeatedly with pausing between each key press.
197 * 2. Pressing and holding the PageDown key with repeated keys enabled.
198 *
199 * Test 1 worked roughly 95-99% of the time with 0ms and got a little bit better as the duration
200 * increased. Test 2 got slightly better until the duration was long enough to interfere with
201 * repeated keys. If the repeated key speed was faster than the timeout duration, then pressing
202 * and holding pagedown caused the entire page to scroll.
203 *
204 * Since repeated key speed can verify across machines, determined that any duration could
205 * potentially interfere with repeated keys. 0ms would be best because it almost entirely
206 * eliminates the focus being lost in Voiceover (#24330) without causing unintended side effects.
207 * Adding delay also complicates writing tests.
208 */
209 _focusActiveCell(movePreview = true) {
210 this._ngZone.runOutsideAngular(() => {
211 this._ngZone.onStable.pipe(take(1)).subscribe(() => {
212 setTimeout(() => {
213 const activeCell = this._elementRef.nativeElement.querySelector('.mat-calendar-body-active');
214 if (activeCell) {
215 if (!movePreview) {
216 this._skipNextFocus = true;
217 }
218 activeCell.focus();
219 }
220 });
221 });
222 });
223 }
224 /** Focuses the active cell after change detection has run and the microtask queue is empty. */
225 _scheduleFocusActiveCellAfterViewChecked() {
226 this._focusActiveCellAfterViewChecked = true;
227 }
228 /** Gets whether a value is the start of the main range. */
229 _isRangeStart(value) {
230 return isStart(value, this.startValue, this.endValue);
231 }
232 /** Gets whether a value is the end of the main range. */
233 _isRangeEnd(value) {
234 return isEnd(value, this.startValue, this.endValue);
235 }
236 /** Gets whether a value is within the currently-selected range. */
237 _isInRange(value) {
238 return isInRange(value, this.startValue, this.endValue, this.isRange);
239 }
240 /** Gets whether a value is the start of the comparison range. */
241 _isComparisonStart(value) {
242 return isStart(value, this.comparisonStart, this.comparisonEnd);
243 }
244 /** Whether the cell is a start bridge cell between the main and comparison ranges. */
245 _isComparisonBridgeStart(value, rowIndex, colIndex) {
246 if (!this._isComparisonStart(value) || this._isRangeStart(value) || !this._isInRange(value)) {
247 return false;
248 }
249 let previousCell = this.rows[rowIndex][colIndex - 1];
250 if (!previousCell) {
251 const previousRow = this.rows[rowIndex - 1];
252 previousCell = previousRow && previousRow[previousRow.length - 1];
253 }
254 return previousCell && !this._isRangeEnd(previousCell.compareValue);
255 }
256 /** Whether the cell is an end bridge cell between the main and comparison ranges. */
257 _isComparisonBridgeEnd(value, rowIndex, colIndex) {
258 if (!this._isComparisonEnd(value) || this._isRangeEnd(value) || !this._isInRange(value)) {
259 return false;
260 }
261 let nextCell = this.rows[rowIndex][colIndex + 1];
262 if (!nextCell) {
263 const nextRow = this.rows[rowIndex + 1];
264 nextCell = nextRow && nextRow[0];
265 }
266 return nextCell && !this._isRangeStart(nextCell.compareValue);
267 }
268 /** Gets whether a value is the end of the comparison range. */
269 _isComparisonEnd(value) {
270 return isEnd(value, this.comparisonStart, this.comparisonEnd);
271 }
272 /** Gets whether a value is within the current comparison range. */
273 _isInComparisonRange(value) {
274 return isInRange(value, this.comparisonStart, this.comparisonEnd, this.isRange);
275 }
276 /**
277 * Gets whether a value is the same as the start and end of the comparison range.
278 * For context, the functions that we use to determine whether something is the start/end of
279 * a range don't allow for the start and end to be on the same day, because we'd have to use
280 * much more specific CSS selectors to style them correctly in all scenarios. This is fine for
281 * the regular range, because when it happens, the selected styles take over and still show where
282 * the range would've been, however we don't have these selected styles for a comparison range.
283 * This function is used to apply a class that serves the same purpose as the one for selected
284 * dates, but it only applies in the context of a comparison range.
285 */
286 _isComparisonIdentical(value) {
287 // Note that we don't need to null check the start/end
288 // here, because the `value` will always be defined.
289 return this.comparisonStart === this.comparisonEnd && value === this.comparisonStart;
290 }
291 /** Gets whether a value is the start of the preview range. */
292 _isPreviewStart(value) {
293 return isStart(value, this.previewStart, this.previewEnd);
294 }
295 /** Gets whether a value is the end of the preview range. */
296 _isPreviewEnd(value) {
297 return isEnd(value, this.previewStart, this.previewEnd);
298 }
299 /** Gets whether a value is inside the preview range. */
300 _isInPreview(value) {
301 return isInRange(value, this.previewStart, this.previewEnd, this.isRange);
302 }
303 /** Finds the MatCalendarCell that corresponds to a DOM node. */
304 _getCellFromElement(element) {
305 let cell;
306 if (isTableCell(element)) {
307 cell = element;
308 }
309 else if (isTableCell(element.parentNode)) {
310 cell = element.parentNode;
311 }
312 if (cell) {
313 const row = cell.getAttribute('data-mat-row');
314 const col = cell.getAttribute('data-mat-col');
315 if (row && col) {
316 return this.rows[parseInt(row)][parseInt(col)];
317 }
318 }
319 return null;
320 }
321}
322MatCalendarBody.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatCalendarBody, deps: [{ token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
323MatCalendarBody.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.1", type: MatCalendarBody, selector: "[mat-calendar-body]", inputs: { label: "label", rows: "rows", todayValue: "todayValue", startValue: "startValue", endValue: "endValue", labelMinRequiredCells: "labelMinRequiredCells", numCols: "numCols", activeCell: "activeCell", isRange: "isRange", cellAspectRatio: "cellAspectRatio", comparisonStart: "comparisonStart", comparisonEnd: "comparisonEnd", previewStart: "previewStart", previewEnd: "previewEnd" }, outputs: { selectedValueChange: "selectedValueChange", previewChange: "previewChange", activeDateChange: "activeDateChange" }, host: { classAttribute: "mat-calendar-body" }, exportAs: ["matCalendarBody"], usesOnChanges: true, ngImport: i0, template: "<!--\n If there's not enough space in the first row, create a separate label row. We mark this row as\n aria-hidden because we don't want it to be read out as one of the weeks in the month.\n-->\n<tr *ngIf=\"_firstRowOffset < labelMinRequiredCells\" aria-hidden=\"true\">\n <td class=\"mat-calendar-body-label\"\n [attr.colspan]=\"numCols\"\n [style.paddingTop]=\"_cellPadding\"\n [style.paddingBottom]=\"_cellPadding\">\n {{label}}\n </td>\n</tr>\n\n<!-- Create the first row separately so we can include a special spacer cell. -->\n<tr *ngFor=\"let row of rows; let rowIndex = index\" role=\"row\">\n <!--\n This cell is purely decorative, but we can't put `aria-hidden` or `role=\"presentation\"` on it,\n because it throws off the week days for the rest of the row on NVDA. The aspect ratio of the\n table cells is maintained by setting the top and bottom padding as a percentage of the width\n (a variant of the trick described here: https://www.w3schools.com/howto/howto_css_aspect_ratio.asp).\n -->\n <td *ngIf=\"rowIndex === 0 && _firstRowOffset\"\n class=\"mat-calendar-body-label\"\n [attr.colspan]=\"_firstRowOffset\"\n [style.paddingTop]=\"_cellPadding\"\n [style.paddingBottom]=\"_cellPadding\">\n {{_firstRowOffset >= labelMinRequiredCells ? label : ''}}\n </td>\n <!--\n Each gridcell in the calendar contains a button, which signals to assistive technology that the\n cell is interactable, as well as the selection state via `aria-pressed`. See #23476 for\n background.\n -->\n <td\n *ngFor=\"let item of row; let colIndex = index\"\n role=\"gridcell\"\n class=\"mat-calendar-body-cell-container\"\n [style.width]=\"_cellWidth\"\n [style.paddingTop]=\"_cellPadding\"\n [style.paddingBottom]=\"_cellPadding\"\n [attr.data-mat-row]=\"rowIndex\"\n [attr.data-mat-col]=\"colIndex\"\n >\n <button\n type=\"button\"\n class=\"mat-calendar-body-cell\"\n [ngClass]=\"item.cssClasses\"\n [tabindex]=\"_isActiveCell(rowIndex, colIndex) ? 0 : -1\"\n [class.mat-calendar-body-disabled]=\"!item.enabled\"\n [class.mat-calendar-body-active]=\"_isActiveCell(rowIndex, colIndex)\"\n [class.mat-calendar-body-range-start]=\"_isRangeStart(item.compareValue)\"\n [class.mat-calendar-body-range-end]=\"_isRangeEnd(item.compareValue)\"\n [class.mat-calendar-body-in-range]=\"_isInRange(item.compareValue)\"\n [class.mat-calendar-body-comparison-bridge-start]=\"_isComparisonBridgeStart(item.compareValue, rowIndex, colIndex)\"\n [class.mat-calendar-body-comparison-bridge-end]=\"_isComparisonBridgeEnd(item.compareValue, rowIndex, colIndex)\"\n [class.mat-calendar-body-comparison-start]=\"_isComparisonStart(item.compareValue)\"\n [class.mat-calendar-body-comparison-end]=\"_isComparisonEnd(item.compareValue)\"\n [class.mat-calendar-body-in-comparison-range]=\"_isInComparisonRange(item.compareValue)\"\n [class.mat-calendar-body-preview-start]=\"_isPreviewStart(item.compareValue)\"\n [class.mat-calendar-body-preview-end]=\"_isPreviewEnd(item.compareValue)\"\n [class.mat-calendar-body-in-preview]=\"_isInPreview(item.compareValue)\"\n [attr.aria-label]=\"item.ariaLabel\"\n [attr.aria-disabled]=\"!item.enabled || null\"\n [attr.aria-pressed]=\"_isSelected(item.compareValue)\"\n [attr.aria-current]=\"todayValue === item.compareValue ? 'date' : null\"\n (click)=\"_cellClicked(item, $event)\"\n (focus)=\"_emitActiveDateChange(item, $event)\">\n <div class=\"mat-calendar-body-cell-content mat-focus-indicator\"\n [class.mat-calendar-body-selected]=\"_isSelected(item.compareValue)\"\n [class.mat-calendar-body-comparison-identical]=\"_isComparisonIdentical(item.compareValue)\"\n [class.mat-calendar-body-today]=\"todayValue === item.compareValue\">\n {{item.displayValue}}\n </div>\n <div class=\"mat-calendar-body-cell-preview\" aria-hidden=\"true\"></div>\n </button>\n </td>\n</tr>\n", styles: [".mat-calendar-body{min-width:224px}.mat-calendar-body-label{height:0;line-height:0;text-align:left;padding-left:4.7142857143%;padding-right:4.7142857143%}.mat-calendar-body-cell-container{position:relative;height:0;line-height:0}.mat-calendar-body-cell{-webkit-user-select:none;user-select:none;cursor:pointer;outline:none;border:none;-webkit-tap-highlight-color:rgba(0,0,0,0);position:absolute;top:0;left:0;width:100%;height:100%;background:none;text-align:center;outline:none;font-family:inherit;margin:0}.mat-calendar-body-cell::-moz-focus-inner{border:0}.mat-calendar-body-cell::before,.mat-calendar-body-cell::after,.mat-calendar-body-cell-preview{content:\"\";position:absolute;top:5%;left:0;z-index:0;box-sizing:border-box;height:90%;width:100%}.mat-calendar-body-range-start:not(.mat-calendar-body-in-comparison-range)::before,.mat-calendar-body-range-start::after,.mat-calendar-body-comparison-start:not(.mat-calendar-body-comparison-bridge-start)::before,.mat-calendar-body-comparison-start::after,.mat-calendar-body-preview-start .mat-calendar-body-cell-preview{left:5%;width:95%;border-top-left-radius:999px;border-bottom-left-radius:999px}[dir=rtl] .mat-calendar-body-range-start:not(.mat-calendar-body-in-comparison-range)::before,[dir=rtl] .mat-calendar-body-range-start::after,[dir=rtl] .mat-calendar-body-comparison-start:not(.mat-calendar-body-comparison-bridge-start)::before,[dir=rtl] .mat-calendar-body-comparison-start::after,[dir=rtl] .mat-calendar-body-preview-start .mat-calendar-body-cell-preview{left:0;border-radius:0;border-top-right-radius:999px;border-bottom-right-radius:999px}.mat-calendar-body-range-end:not(.mat-calendar-body-in-comparison-range)::before,.mat-calendar-body-range-end::after,.mat-calendar-body-comparison-end:not(.mat-calendar-body-comparison-bridge-end)::before,.mat-calendar-body-comparison-end::after,.mat-calendar-body-preview-end .mat-calendar-body-cell-preview{width:95%;border-top-right-radius:999px;border-bottom-right-radius:999px}[dir=rtl] .mat-calendar-body-range-end:not(.mat-calendar-body-in-comparison-range)::before,[dir=rtl] .mat-calendar-body-range-end::after,[dir=rtl] .mat-calendar-body-comparison-end:not(.mat-calendar-body-comparison-bridge-end)::before,[dir=rtl] .mat-calendar-body-comparison-end::after,[dir=rtl] .mat-calendar-body-preview-end .mat-calendar-body-cell-preview{left:5%;border-radius:0;border-top-left-radius:999px;border-bottom-left-radius:999px}[dir=rtl] .mat-calendar-body-comparison-bridge-start.mat-calendar-body-range-end::after,[dir=rtl] .mat-calendar-body-comparison-bridge-end.mat-calendar-body-range-start::after{width:95%;border-top-right-radius:999px;border-bottom-right-radius:999px}.mat-calendar-body-comparison-start.mat-calendar-body-range-end::after,[dir=rtl] .mat-calendar-body-comparison-start.mat-calendar-body-range-end::after,.mat-calendar-body-comparison-end.mat-calendar-body-range-start::after,[dir=rtl] .mat-calendar-body-comparison-end.mat-calendar-body-range-start::after{width:90%}.mat-calendar-body-in-preview .mat-calendar-body-cell-preview{border-top:dashed 1px;border-bottom:dashed 1px}.mat-calendar-body-preview-start .mat-calendar-body-cell-preview{border-left:dashed 1px}[dir=rtl] .mat-calendar-body-preview-start .mat-calendar-body-cell-preview{border-left:0;border-right:dashed 1px}.mat-calendar-body-preview-end .mat-calendar-body-cell-preview{border-right:dashed 1px}[dir=rtl] .mat-calendar-body-preview-end .mat-calendar-body-cell-preview{border-right:0;border-left:dashed 1px}.mat-calendar-body-disabled{cursor:default}.cdk-high-contrast-active .mat-calendar-body-disabled{opacity:.5}.mat-calendar-body-cell-content{top:5%;left:5%;z-index:1;display:flex;align-items:center;justify-content:center;box-sizing:border-box;width:90%;height:90%;line-height:1;border-width:1px;border-style:solid;border-radius:999px}.mat-calendar-body-cell-content.mat-focus-indicator{position:absolute}.cdk-high-contrast-active .mat-calendar-body-cell-content{border:none}.cdk-high-contrast-active .mat-datepicker-popup:not(:empty),.cdk-high-contrast-active .mat-calendar-body-cell:not(.mat-calendar-body-in-range) .mat-calendar-body-selected{outline:solid 1px}.cdk-high-contrast-active .mat-calendar-body-today{outline:dotted 1px}.cdk-high-contrast-active .cdk-keyboard-focused .mat-calendar-body-active>.mat-calendar-body-cell-content,.cdk-high-contrast-active .cdk-program-focused .mat-calendar-body-active>.mat-calendar-body-cell-content{outline:dotted 2px}.cdk-high-contrast-active .cdk-keyboard-focused .mat-calendar-body-active>.mat-calendar-body-cell-content.mat-calendar-body-selected,.cdk-high-contrast-active .cdk-program-focused .mat-calendar-body-active>.mat-calendar-body-cell-content.mat-calendar-body-selected{outline:solid 3px}.cdk-high-contrast-active .mat-calendar-body-cell::before,.cdk-high-contrast-active .mat-calendar-body-cell::after,.cdk-high-contrast-active .mat-calendar-body-selected{background:none}.cdk-high-contrast-active .mat-calendar-body-in-range::before,.cdk-high-contrast-active .mat-calendar-body-comparison-bridge-start::before,.cdk-high-contrast-active .mat-calendar-body-comparison-bridge-end::before{border-top:solid 1px;border-bottom:solid 1px}.cdk-high-contrast-active .mat-calendar-body-range-start::before{border-left:solid 1px}[dir=rtl] .cdk-high-contrast-active .mat-calendar-body-range-start::before{border-left:0;border-right:solid 1px}.cdk-high-contrast-active .mat-calendar-body-range-end::before{border-right:solid 1px}[dir=rtl] .cdk-high-contrast-active .mat-calendar-body-range-end::before{border-right:0;border-left:solid 1px}.cdk-high-contrast-active .mat-calendar-body-in-comparison-range::before{border-top:dashed 1px;border-bottom:dashed 1px}.cdk-high-contrast-active .mat-calendar-body-comparison-start::before{border-left:dashed 1px}[dir=rtl] .cdk-high-contrast-active .mat-calendar-body-comparison-start::before{border-left:0;border-right:dashed 1px}.cdk-high-contrast-active .mat-calendar-body-comparison-end::before{border-right:dashed 1px}[dir=rtl] .cdk-high-contrast-active .mat-calendar-body-comparison-end::before{border-right:0;border-left:dashed 1px}[dir=rtl] .mat-calendar-body-label{text-align:right}"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
324i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatCalendarBody, decorators: [{
325 type: Component,
326 args: [{ selector: '[mat-calendar-body]', host: {
327 'class': 'mat-calendar-body',
328 }, exportAs: 'matCalendarBody', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: "<!--\n If there's not enough space in the first row, create a separate label row. We mark this row as\n aria-hidden because we don't want it to be read out as one of the weeks in the month.\n-->\n<tr *ngIf=\"_firstRowOffset < labelMinRequiredCells\" aria-hidden=\"true\">\n <td class=\"mat-calendar-body-label\"\n [attr.colspan]=\"numCols\"\n [style.paddingTop]=\"_cellPadding\"\n [style.paddingBottom]=\"_cellPadding\">\n {{label}}\n </td>\n</tr>\n\n<!-- Create the first row separately so we can include a special spacer cell. -->\n<tr *ngFor=\"let row of rows; let rowIndex = index\" role=\"row\">\n <!--\n This cell is purely decorative, but we can't put `aria-hidden` or `role=\"presentation\"` on it,\n because it throws off the week days for the rest of the row on NVDA. The aspect ratio of the\n table cells is maintained by setting the top and bottom padding as a percentage of the width\n (a variant of the trick described here: https://www.w3schools.com/howto/howto_css_aspect_ratio.asp).\n -->\n <td *ngIf=\"rowIndex === 0 && _firstRowOffset\"\n class=\"mat-calendar-body-label\"\n [attr.colspan]=\"_firstRowOffset\"\n [style.paddingTop]=\"_cellPadding\"\n [style.paddingBottom]=\"_cellPadding\">\n {{_firstRowOffset >= labelMinRequiredCells ? label : ''}}\n </td>\n <!--\n Each gridcell in the calendar contains a button, which signals to assistive technology that the\n cell is interactable, as well as the selection state via `aria-pressed`. See #23476 for\n background.\n -->\n <td\n *ngFor=\"let item of row; let colIndex = index\"\n role=\"gridcell\"\n class=\"mat-calendar-body-cell-container\"\n [style.width]=\"_cellWidth\"\n [style.paddingTop]=\"_cellPadding\"\n [style.paddingBottom]=\"_cellPadding\"\n [attr.data-mat-row]=\"rowIndex\"\n [attr.data-mat-col]=\"colIndex\"\n >\n <button\n type=\"button\"\n class=\"mat-calendar-body-cell\"\n [ngClass]=\"item.cssClasses\"\n [tabindex]=\"_isActiveCell(rowIndex, colIndex) ? 0 : -1\"\n [class.mat-calendar-body-disabled]=\"!item.enabled\"\n [class.mat-calendar-body-active]=\"_isActiveCell(rowIndex, colIndex)\"\n [class.mat-calendar-body-range-start]=\"_isRangeStart(item.compareValue)\"\n [class.mat-calendar-body-range-end]=\"_isRangeEnd(item.compareValue)\"\n [class.mat-calendar-body-in-range]=\"_isInRange(item.compareValue)\"\n [class.mat-calendar-body-comparison-bridge-start]=\"_isComparisonBridgeStart(item.compareValue, rowIndex, colIndex)\"\n [class.mat-calendar-body-comparison-bridge-end]=\"_isComparisonBridgeEnd(item.compareValue, rowIndex, colIndex)\"\n [class.mat-calendar-body-comparison-start]=\"_isComparisonStart(item.compareValue)\"\n [class.mat-calendar-body-comparison-end]=\"_isComparisonEnd(item.compareValue)\"\n [class.mat-calendar-body-in-comparison-range]=\"_isInComparisonRange(item.compareValue)\"\n [class.mat-calendar-body-preview-start]=\"_isPreviewStart(item.compareValue)\"\n [class.mat-calendar-body-preview-end]=\"_isPreviewEnd(item.compareValue)\"\n [class.mat-calendar-body-in-preview]=\"_isInPreview(item.compareValue)\"\n [attr.aria-label]=\"item.ariaLabel\"\n [attr.aria-disabled]=\"!item.enabled || null\"\n [attr.aria-pressed]=\"_isSelected(item.compareValue)\"\n [attr.aria-current]=\"todayValue === item.compareValue ? 'date' : null\"\n (click)=\"_cellClicked(item, $event)\"\n (focus)=\"_emitActiveDateChange(item, $event)\">\n <div class=\"mat-calendar-body-cell-content mat-focus-indicator\"\n [class.mat-calendar-body-selected]=\"_isSelected(item.compareValue)\"\n [class.mat-calendar-body-comparison-identical]=\"_isComparisonIdentical(item.compareValue)\"\n [class.mat-calendar-body-today]=\"todayValue === item.compareValue\">\n {{item.displayValue}}\n </div>\n <div class=\"mat-calendar-body-cell-preview\" aria-hidden=\"true\"></div>\n </button>\n </td>\n</tr>\n", styles: [".mat-calendar-body{min-width:224px}.mat-calendar-body-label{height:0;line-height:0;text-align:left;padding-left:4.7142857143%;padding-right:4.7142857143%}.mat-calendar-body-cell-container{position:relative;height:0;line-height:0}.mat-calendar-body-cell{-webkit-user-select:none;user-select:none;cursor:pointer;outline:none;border:none;-webkit-tap-highlight-color:rgba(0,0,0,0);position:absolute;top:0;left:0;width:100%;height:100%;background:none;text-align:center;outline:none;font-family:inherit;margin:0}.mat-calendar-body-cell::-moz-focus-inner{border:0}.mat-calendar-body-cell::before,.mat-calendar-body-cell::after,.mat-calendar-body-cell-preview{content:\"\";position:absolute;top:5%;left:0;z-index:0;box-sizing:border-box;height:90%;width:100%}.mat-calendar-body-range-start:not(.mat-calendar-body-in-comparison-range)::before,.mat-calendar-body-range-start::after,.mat-calendar-body-comparison-start:not(.mat-calendar-body-comparison-bridge-start)::before,.mat-calendar-body-comparison-start::after,.mat-calendar-body-preview-start .mat-calendar-body-cell-preview{left:5%;width:95%;border-top-left-radius:999px;border-bottom-left-radius:999px}[dir=rtl] .mat-calendar-body-range-start:not(.mat-calendar-body-in-comparison-range)::before,[dir=rtl] .mat-calendar-body-range-start::after,[dir=rtl] .mat-calendar-body-comparison-start:not(.mat-calendar-body-comparison-bridge-start)::before,[dir=rtl] .mat-calendar-body-comparison-start::after,[dir=rtl] .mat-calendar-body-preview-start .mat-calendar-body-cell-preview{left:0;border-radius:0;border-top-right-radius:999px;border-bottom-right-radius:999px}.mat-calendar-body-range-end:not(.mat-calendar-body-in-comparison-range)::before,.mat-calendar-body-range-end::after,.mat-calendar-body-comparison-end:not(.mat-calendar-body-comparison-bridge-end)::before,.mat-calendar-body-comparison-end::after,.mat-calendar-body-preview-end .mat-calendar-body-cell-preview{width:95%;border-top-right-radius:999px;border-bottom-right-radius:999px}[dir=rtl] .mat-calendar-body-range-end:not(.mat-calendar-body-in-comparison-range)::before,[dir=rtl] .mat-calendar-body-range-end::after,[dir=rtl] .mat-calendar-body-comparison-end:not(.mat-calendar-body-comparison-bridge-end)::before,[dir=rtl] .mat-calendar-body-comparison-end::after,[dir=rtl] .mat-calendar-body-preview-end .mat-calendar-body-cell-preview{left:5%;border-radius:0;border-top-left-radius:999px;border-bottom-left-radius:999px}[dir=rtl] .mat-calendar-body-comparison-bridge-start.mat-calendar-body-range-end::after,[dir=rtl] .mat-calendar-body-comparison-bridge-end.mat-calendar-body-range-start::after{width:95%;border-top-right-radius:999px;border-bottom-right-radius:999px}.mat-calendar-body-comparison-start.mat-calendar-body-range-end::after,[dir=rtl] .mat-calendar-body-comparison-start.mat-calendar-body-range-end::after,.mat-calendar-body-comparison-end.mat-calendar-body-range-start::after,[dir=rtl] .mat-calendar-body-comparison-end.mat-calendar-body-range-start::after{width:90%}.mat-calendar-body-in-preview .mat-calendar-body-cell-preview{border-top:dashed 1px;border-bottom:dashed 1px}.mat-calendar-body-preview-start .mat-calendar-body-cell-preview{border-left:dashed 1px}[dir=rtl] .mat-calendar-body-preview-start .mat-calendar-body-cell-preview{border-left:0;border-right:dashed 1px}.mat-calendar-body-preview-end .mat-calendar-body-cell-preview{border-right:dashed 1px}[dir=rtl] .mat-calendar-body-preview-end .mat-calendar-body-cell-preview{border-right:0;border-left:dashed 1px}.mat-calendar-body-disabled{cursor:default}.cdk-high-contrast-active .mat-calendar-body-disabled{opacity:.5}.mat-calendar-body-cell-content{top:5%;left:5%;z-index:1;display:flex;align-items:center;justify-content:center;box-sizing:border-box;width:90%;height:90%;line-height:1;border-width:1px;border-style:solid;border-radius:999px}.mat-calendar-body-cell-content.mat-focus-indicator{position:absolute}.cdk-high-contrast-active .mat-calendar-body-cell-content{border:none}.cdk-high-contrast-active .mat-datepicker-popup:not(:empty),.cdk-high-contrast-active .mat-calendar-body-cell:not(.mat-calendar-body-in-range) .mat-calendar-body-selected{outline:solid 1px}.cdk-high-contrast-active .mat-calendar-body-today{outline:dotted 1px}.cdk-high-contrast-active .cdk-keyboard-focused .mat-calendar-body-active>.mat-calendar-body-cell-content,.cdk-high-contrast-active .cdk-program-focused .mat-calendar-body-active>.mat-calendar-body-cell-content{outline:dotted 2px}.cdk-high-contrast-active .cdk-keyboard-focused .mat-calendar-body-active>.mat-calendar-body-cell-content.mat-calendar-body-selected,.cdk-high-contrast-active .cdk-program-focused .mat-calendar-body-active>.mat-calendar-body-cell-content.mat-calendar-body-selected{outline:solid 3px}.cdk-high-contrast-active .mat-calendar-body-cell::before,.cdk-high-contrast-active .mat-calendar-body-cell::after,.cdk-high-contrast-active .mat-calendar-body-selected{background:none}.cdk-high-contrast-active .mat-calendar-body-in-range::before,.cdk-high-contrast-active .mat-calendar-body-comparison-bridge-start::before,.cdk-high-contrast-active .mat-calendar-body-comparison-bridge-end::before{border-top:solid 1px;border-bottom:solid 1px}.cdk-high-contrast-active .mat-calendar-body-range-start::before{border-left:solid 1px}[dir=rtl] .cdk-high-contrast-active .mat-calendar-body-range-start::before{border-left:0;border-right:solid 1px}.cdk-high-contrast-active .mat-calendar-body-range-end::before{border-right:solid 1px}[dir=rtl] .cdk-high-contrast-active .mat-calendar-body-range-end::before{border-right:0;border-left:solid 1px}.cdk-high-contrast-active .mat-calendar-body-in-comparison-range::before{border-top:dashed 1px;border-bottom:dashed 1px}.cdk-high-contrast-active .mat-calendar-body-comparison-start::before{border-left:dashed 1px}[dir=rtl] .cdk-high-contrast-active .mat-calendar-body-comparison-start::before{border-left:0;border-right:dashed 1px}.cdk-high-contrast-active .mat-calendar-body-comparison-end::before{border-right:dashed 1px}[dir=rtl] .cdk-high-contrast-active .mat-calendar-body-comparison-end::before{border-right:0;border-left:dashed 1px}[dir=rtl] .mat-calendar-body-label{text-align:right}"] }]
329 }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.NgZone }]; }, propDecorators: { label: [{
330 type: Input
331 }], rows: [{
332 type: Input
333 }], todayValue: [{
334 type: Input
335 }], startValue: [{
336 type: Input
337 }], endValue: [{
338 type: Input
339 }], labelMinRequiredCells: [{
340 type: Input
341 }], numCols: [{
342 type: Input
343 }], activeCell: [{
344 type: Input
345 }], isRange: [{
346 type: Input
347 }], cellAspectRatio: [{
348 type: Input
349 }], comparisonStart: [{
350 type: Input
351 }], comparisonEnd: [{
352 type: Input
353 }], previewStart: [{
354 type: Input
355 }], previewEnd: [{
356 type: Input
357 }], selectedValueChange: [{
358 type: Output
359 }], previewChange: [{
360 type: Output
361 }], activeDateChange: [{
362 type: Output
363 }] } });
364/** Checks whether a node is a table cell element. */
365function isTableCell(node) {
366 return node.nodeName === 'TD';
367}
368/** Checks whether a value is the start of a range. */
369function isStart(value, start, end) {
370 return end !== null && start !== end && value < end && value === start;
371}
372/** Checks whether a value is the end of a range. */
373function isEnd(value, start, end) {
374 return start !== null && start !== end && value >= start && value === end;
375}
376/** Checks whether a value is inside of a range. */
377function isInRange(value, start, end, rangeEnabled) {
378 return (rangeEnabled &&
379 start !== null &&
380 end !== null &&
381 start !== end &&
382 value >= start &&
383 value <= end);
384}
385
386/**
387 * @license
388 * Copyright Google LLC All Rights Reserved.
389 *
390 * Use of this source code is governed by an MIT-style license that can be
391 * found in the LICENSE file at https://angular.io/license
392 */
393/** A class representing a range of dates. */
394class DateRange {
395 constructor(
396 /** The start date of the range. */
397 start,
398 /** The end date of the range. */
399 end) {
400 this.start = start;
401 this.end = end;
402 }
403}
404/**
405 * A selection model containing a date selection.
406 * @docs-private
407 */
408class MatDateSelectionModel {
409 constructor(
410 /** The current selection. */
411 selection, _adapter) {
412 this.selection = selection;
413 this._adapter = _adapter;
414 this._selectionChanged = new Subject();
415 /** Emits when the selection has changed. */
416 this.selectionChanged = this._selectionChanged;
417 this.selection = selection;
418 }
419 /**
420 * Updates the current selection in the model.
421 * @param value New selection that should be assigned.
422 * @param source Object that triggered the selection change.
423 */
424 updateSelection(value, source) {
425 const oldValue = this.selection;
426 this.selection = value;
427 this._selectionChanged.next({ selection: value, source, oldValue });
428 }
429 ngOnDestroy() {
430 this._selectionChanged.complete();
431 }
432 _isValidDateInstance(date) {
433 return this._adapter.isDateInstance(date) && this._adapter.isValid(date);
434 }
435}
436MatDateSelectionModel.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDateSelectionModel, deps: "invalid", target: i0.ɵɵFactoryTarget.Injectable });
437MatDateSelectionModel.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDateSelectionModel });
438i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDateSelectionModel, decorators: [{
439 type: Injectable
440 }], ctorParameters: function () { return [{ type: undefined }, { type: i1$1.DateAdapter }]; } });
441/**
442 * A selection model that contains a single date.
443 * @docs-private
444 */
445class MatSingleDateSelectionModel extends MatDateSelectionModel {
446 constructor(adapter) {
447 super(null, adapter);
448 }
449 /**
450 * Adds a date to the current selection. In the case of a single date selection, the added date
451 * simply overwrites the previous selection
452 */
453 add(date) {
454 super.updateSelection(date, this);
455 }
456 /** Checks whether the current selection is valid. */
457 isValid() {
458 return this.selection != null && this._isValidDateInstance(this.selection);
459 }
460 /**
461 * Checks whether the current selection is complete. In the case of a single date selection, this
462 * is true if the current selection is not null.
463 */
464 isComplete() {
465 return this.selection != null;
466 }
467 /** Clones the selection model. */
468 clone() {
469 const clone = new MatSingleDateSelectionModel(this._adapter);
470 clone.updateSelection(this.selection, this);
471 return clone;
472 }
473}
474MatSingleDateSelectionModel.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatSingleDateSelectionModel, deps: [{ token: i1$1.DateAdapter }], target: i0.ɵɵFactoryTarget.Injectable });
475MatSingleDateSelectionModel.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatSingleDateSelectionModel });
476i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatSingleDateSelectionModel, decorators: [{
477 type: Injectable
478 }], ctorParameters: function () { return [{ type: i1$1.DateAdapter }]; } });
479/**
480 * A selection model that contains a date range.
481 * @docs-private
482 */
483class MatRangeDateSelectionModel extends MatDateSelectionModel {
484 constructor(adapter) {
485 super(new DateRange(null, null), adapter);
486 }
487 /**
488 * Adds a date to the current selection. In the case of a date range selection, the added date
489 * fills in the next `null` value in the range. If both the start and the end already have a date,
490 * the selection is reset so that the given date is the new `start` and the `end` is null.
491 */
492 add(date) {
493 let { start, end } = this.selection;
494 if (start == null) {
495 start = date;
496 }
497 else if (end == null) {
498 end = date;
499 }
500 else {
501 start = date;
502 end = null;
503 }
504 super.updateSelection(new DateRange(start, end), this);
505 }
506 /** Checks whether the current selection is valid. */
507 isValid() {
508 const { start, end } = this.selection;
509 // Empty ranges are valid.
510 if (start == null && end == null) {
511 return true;
512 }
513 // Complete ranges are only valid if both dates are valid and the start is before the end.
514 if (start != null && end != null) {
515 return (this._isValidDateInstance(start) &&
516 this._isValidDateInstance(end) &&
517 this._adapter.compareDate(start, end) <= 0);
518 }
519 // Partial ranges are valid if the start/end is valid.
520 return ((start == null || this._isValidDateInstance(start)) &&
521 (end == null || this._isValidDateInstance(end)));
522 }
523 /**
524 * Checks whether the current selection is complete. In the case of a date range selection, this
525 * is true if the current selection has a non-null `start` and `end`.
526 */
527 isComplete() {
528 return this.selection.start != null && this.selection.end != null;
529 }
530 /** Clones the selection model. */
531 clone() {
532 const clone = new MatRangeDateSelectionModel(this._adapter);
533 clone.updateSelection(this.selection, this);
534 return clone;
535 }
536}
537MatRangeDateSelectionModel.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatRangeDateSelectionModel, deps: [{ token: i1$1.DateAdapter }], target: i0.ɵɵFactoryTarget.Injectable });
538MatRangeDateSelectionModel.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatRangeDateSelectionModel });
539i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatRangeDateSelectionModel, decorators: [{
540 type: Injectable
541 }], ctorParameters: function () { return [{ type: i1$1.DateAdapter }]; } });
542/** @docs-private */
543function MAT_SINGLE_DATE_SELECTION_MODEL_FACTORY(parent, adapter) {
544 return parent || new MatSingleDateSelectionModel(adapter);
545}
546/**
547 * Used to provide a single selection model to a component.
548 * @docs-private
549 */
550const MAT_SINGLE_DATE_SELECTION_MODEL_PROVIDER = {
551 provide: MatDateSelectionModel,
552 deps: [[new Optional(), new SkipSelf(), MatDateSelectionModel], DateAdapter],
553 useFactory: MAT_SINGLE_DATE_SELECTION_MODEL_FACTORY,
554};
555/** @docs-private */
556function MAT_RANGE_DATE_SELECTION_MODEL_FACTORY(parent, adapter) {
557 return parent || new MatRangeDateSelectionModel(adapter);
558}
559/**
560 * Used to provide a range selection model to a component.
561 * @docs-private
562 */
563const MAT_RANGE_DATE_SELECTION_MODEL_PROVIDER = {
564 provide: MatDateSelectionModel,
565 deps: [[new Optional(), new SkipSelf(), MatDateSelectionModel], DateAdapter],
566 useFactory: MAT_RANGE_DATE_SELECTION_MODEL_FACTORY,
567};
568
569/**
570 * @license
571 * Copyright Google LLC All Rights Reserved.
572 *
573 * Use of this source code is governed by an MIT-style license that can be
574 * found in the LICENSE file at https://angular.io/license
575 */
576/** Injection token used to customize the date range selection behavior. */
577const MAT_DATE_RANGE_SELECTION_STRATEGY = new InjectionToken('MAT_DATE_RANGE_SELECTION_STRATEGY');
578/** Provides the default date range selection behavior. */
579class DefaultMatCalendarRangeStrategy {
580 constructor(_dateAdapter) {
581 this._dateAdapter = _dateAdapter;
582 }
583 selectionFinished(date, currentRange) {
584 let { start, end } = currentRange;
585 if (start == null) {
586 start = date;
587 }
588 else if (end == null && date && this._dateAdapter.compareDate(date, start) >= 0) {
589 end = date;
590 }
591 else {
592 start = date;
593 end = null;
594 }
595 return new DateRange(start, end);
596 }
597 createPreview(activeDate, currentRange) {
598 let start = null;
599 let end = null;
600 if (currentRange.start && !currentRange.end && activeDate) {
601 start = currentRange.start;
602 end = activeDate;
603 }
604 return new DateRange(start, end);
605 }
606}
607DefaultMatCalendarRangeStrategy.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: DefaultMatCalendarRangeStrategy, deps: [{ token: i1$1.DateAdapter }], target: i0.ɵɵFactoryTarget.Injectable });
608DefaultMatCalendarRangeStrategy.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: DefaultMatCalendarRangeStrategy });
609i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: DefaultMatCalendarRangeStrategy, decorators: [{
610 type: Injectable
611 }], ctorParameters: function () { return [{ type: i1$1.DateAdapter }]; } });
612/** @docs-private */
613function MAT_CALENDAR_RANGE_STRATEGY_PROVIDER_FACTORY(parent, adapter) {
614 return parent || new DefaultMatCalendarRangeStrategy(adapter);
615}
616/** @docs-private */
617const MAT_CALENDAR_RANGE_STRATEGY_PROVIDER = {
618 provide: MAT_DATE_RANGE_SELECTION_STRATEGY,
619 deps: [[new Optional(), new SkipSelf(), MAT_DATE_RANGE_SELECTION_STRATEGY], DateAdapter],
620 useFactory: MAT_CALENDAR_RANGE_STRATEGY_PROVIDER_FACTORY,
621};
622
623/**
624 * @license
625 * Copyright Google LLC All Rights Reserved.
626 *
627 * Use of this source code is governed by an MIT-style license that can be
628 * found in the LICENSE file at https://angular.io/license
629 */
630const DAYS_PER_WEEK = 7;
631/**
632 * An internal component used to display a single month in the datepicker.
633 * @docs-private
634 */
635class MatMonthView {
636 constructor(_changeDetectorRef, _dateFormats, _dateAdapter, _dir, _rangeStrategy) {
637 this._changeDetectorRef = _changeDetectorRef;
638 this._dateFormats = _dateFormats;
639 this._dateAdapter = _dateAdapter;
640 this._dir = _dir;
641 this._rangeStrategy = _rangeStrategy;
642 this._rerenderSubscription = Subscription.EMPTY;
643 /** Emits when a new date is selected. */
644 this.selectedChange = new EventEmitter();
645 /** Emits when any date is selected. */
646 this._userSelection = new EventEmitter();
647 /** Emits when any date is activated. */
648 this.activeDateChange = new EventEmitter();
649 if (typeof ngDevMode === 'undefined' || ngDevMode) {
650 if (!this._dateAdapter) {
651 throw createMissingDateImplError('DateAdapter');
652 }
653 if (!this._dateFormats) {
654 throw createMissingDateImplError('MAT_DATE_FORMATS');
655 }
656 }
657 this._activeDate = this._dateAdapter.today();
658 }
659 /**
660 * The date to display in this month view (everything other than the month and year is ignored).
661 */
662 get activeDate() {
663 return this._activeDate;
664 }
665 set activeDate(value) {
666 const oldActiveDate = this._activeDate;
667 const validDate = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value)) ||
668 this._dateAdapter.today();
669 this._activeDate = this._dateAdapter.clampDate(validDate, this.minDate, this.maxDate);
670 if (!this._hasSameMonthAndYear(oldActiveDate, this._activeDate)) {
671 this._init();
672 }
673 }
674 /** The currently selected date. */
675 get selected() {
676 return this._selected;
677 }
678 set selected(value) {
679 if (value instanceof DateRange) {
680 this._selected = value;
681 }
682 else {
683 this._selected = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value));
684 }
685 this._setRanges(this._selected);
686 }
687 /** The minimum selectable date. */
688 get minDate() {
689 return this._minDate;
690 }
691 set minDate(value) {
692 this._minDate = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value));
693 }
694 /** The maximum selectable date. */
695 get maxDate() {
696 return this._maxDate;
697 }
698 set maxDate(value) {
699 this._maxDate = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value));
700 }
701 ngAfterContentInit() {
702 this._rerenderSubscription = this._dateAdapter.localeChanges
703 .pipe(startWith(null))
704 .subscribe(() => this._init());
705 }
706 ngOnChanges(changes) {
707 const comparisonChange = changes['comparisonStart'] || changes['comparisonEnd'];
708 if (comparisonChange && !comparisonChange.firstChange) {
709 this._setRanges(this.selected);
710 }
711 }
712 ngOnDestroy() {
713 this._rerenderSubscription.unsubscribe();
714 }
715 /** Handles when a new date is selected. */
716 _dateSelected(event) {
717 const date = event.value;
718 const selectedDate = this._getDateFromDayOfMonth(date);
719 let rangeStartDate;
720 let rangeEndDate;
721 if (this._selected instanceof DateRange) {
722 rangeStartDate = this._getDateInCurrentMonth(this._selected.start);
723 rangeEndDate = this._getDateInCurrentMonth(this._selected.end);
724 }
725 else {
726 rangeStartDate = rangeEndDate = this._getDateInCurrentMonth(this._selected);
727 }
728 if (rangeStartDate !== date || rangeEndDate !== date) {
729 this.selectedChange.emit(selectedDate);
730 }
731 this._userSelection.emit({ value: selectedDate, event: event.event });
732 this._previewStart = this._previewEnd = null;
733 this._changeDetectorRef.markForCheck();
734 }
735 /**
736 * Takes the index of a calendar body cell wrapped in in an event as argument. For the date that
737 * corresponds to the given cell, set `activeDate` to that date and fire `activeDateChange` with
738 * that date.
739 *
740 * This fucntion is used to match each component's model of the active date with the calendar
741 * body cell that was focused. It updates its value of `activeDate` synchronously and updates the
742 * parent's value asynchonously via the `activeDateChange` event. The child component receives an
743 * updated value asynchronously via the `activeCell` Input.
744 */
745 _updateActiveDate(event) {
746 const month = event.value;
747 const oldActiveDate = this._activeDate;
748 this.activeDate = this._getDateFromDayOfMonth(month);
749 if (this._dateAdapter.compareDate(oldActiveDate, this.activeDate)) {
750 this.activeDateChange.emit(this._activeDate);
751 }
752 }
753 /** Handles keydown events on the calendar body when calendar is in month view. */
754 _handleCalendarBodyKeydown(event) {
755 // TODO(mmalerba): We currently allow keyboard navigation to disabled dates, but just prevent
756 // disabled ones from being selected. This may not be ideal, we should look into whether
757 // navigation should skip over disabled dates, and if so, how to implement that efficiently.
758 const oldActiveDate = this._activeDate;
759 const isRtl = this._isRtl();
760 switch (event.keyCode) {
761 case LEFT_ARROW:
762 this.activeDate = this._dateAdapter.addCalendarDays(this._activeDate, isRtl ? 1 : -1);
763 break;
764 case RIGHT_ARROW:
765 this.activeDate = this._dateAdapter.addCalendarDays(this._activeDate, isRtl ? -1 : 1);
766 break;
767 case UP_ARROW:
768 this.activeDate = this._dateAdapter.addCalendarDays(this._activeDate, -7);
769 break;
770 case DOWN_ARROW:
771 this.activeDate = this._dateAdapter.addCalendarDays(this._activeDate, 7);
772 break;
773 case HOME:
774 this.activeDate = this._dateAdapter.addCalendarDays(this._activeDate, 1 - this._dateAdapter.getDate(this._activeDate));
775 break;
776 case END:
777 this.activeDate = this._dateAdapter.addCalendarDays(this._activeDate, this._dateAdapter.getNumDaysInMonth(this._activeDate) -
778 this._dateAdapter.getDate(this._activeDate));
779 break;
780 case PAGE_UP:
781 this.activeDate = event.altKey
782 ? this._dateAdapter.addCalendarYears(this._activeDate, -1)
783 : this._dateAdapter.addCalendarMonths(this._activeDate, -1);
784 break;
785 case PAGE_DOWN:
786 this.activeDate = event.altKey
787 ? this._dateAdapter.addCalendarYears(this._activeDate, 1)
788 : this._dateAdapter.addCalendarMonths(this._activeDate, 1);
789 break;
790 case ENTER:
791 case SPACE:
792 this._selectionKeyPressed = true;
793 if (this._canSelect(this._activeDate)) {
794 // Prevent unexpected default actions such as form submission.
795 // Note that we only prevent the default action here while the selection happens in
796 // `keyup` below. We can't do the selection here, because it can cause the calendar to
797 // reopen if focus is restored immediately. We also can't call `preventDefault` on `keyup`
798 // because it's too late (see #23305).
799 event.preventDefault();
800 }
801 return;
802 case ESCAPE:
803 // Abort the current range selection if the user presses escape mid-selection.
804 if (this._previewEnd != null && !hasModifierKey(event)) {
805 this._previewStart = this._previewEnd = null;
806 this.selectedChange.emit(null);
807 this._userSelection.emit({ value: null, event });
808 event.preventDefault();
809 event.stopPropagation(); // Prevents the overlay from closing.
810 }
811 return;
812 default:
813 // Don't prevent default or focus active cell on keys that we don't explicitly handle.
814 return;
815 }
816 if (this._dateAdapter.compareDate(oldActiveDate, this.activeDate)) {
817 this.activeDateChange.emit(this.activeDate);
818 this._focusActiveCellAfterViewChecked();
819 }
820 // Prevent unexpected default actions such as form submission.
821 event.preventDefault();
822 }
823 /** Handles keyup events on the calendar body when calendar is in month view. */
824 _handleCalendarBodyKeyup(event) {
825 if (event.keyCode === SPACE || event.keyCode === ENTER) {
826 if (this._selectionKeyPressed && this._canSelect(this._activeDate)) {
827 this._dateSelected({ value: this._dateAdapter.getDate(this._activeDate), event });
828 }
829 this._selectionKeyPressed = false;
830 }
831 }
832 /** Initializes this month view. */
833 _init() {
834 this._setRanges(this.selected);
835 this._todayDate = this._getCellCompareValue(this._dateAdapter.today());
836 this._monthLabel = this._dateFormats.display.monthLabel
837 ? this._dateAdapter.format(this.activeDate, this._dateFormats.display.monthLabel)
838 : this._dateAdapter
839 .getMonthNames('short')[this._dateAdapter.getMonth(this.activeDate)].toLocaleUpperCase();
840 let firstOfMonth = this._dateAdapter.createDate(this._dateAdapter.getYear(this.activeDate), this._dateAdapter.getMonth(this.activeDate), 1);
841 this._firstWeekOffset =
842 (DAYS_PER_WEEK +
843 this._dateAdapter.getDayOfWeek(firstOfMonth) -
844 this._dateAdapter.getFirstDayOfWeek()) %
845 DAYS_PER_WEEK;
846 this._initWeekdays();
847 this._createWeekCells();
848 this._changeDetectorRef.markForCheck();
849 }
850 /** Focuses the active cell after the microtask queue is empty. */
851 _focusActiveCell(movePreview) {
852 this._matCalendarBody._focusActiveCell(movePreview);
853 }
854 /** Focuses the active cell after change detection has run and the microtask queue is empty. */
855 _focusActiveCellAfterViewChecked() {
856 this._matCalendarBody._scheduleFocusActiveCellAfterViewChecked();
857 }
858 /** Called when the user has activated a new cell and the preview needs to be updated. */
859 _previewChanged({ event, value: cell }) {
860 if (this._rangeStrategy) {
861 // We can assume that this will be a range, because preview
862 // events aren't fired for single date selections.
863 const value = cell ? cell.rawValue : null;
864 const previewRange = this._rangeStrategy.createPreview(value, this.selected, event);
865 this._previewStart = this._getCellCompareValue(previewRange.start);
866 this._previewEnd = this._getCellCompareValue(previewRange.end);
867 // Note that here we need to use `detectChanges`, rather than `markForCheck`, because
868 // the way `_focusActiveCell` is set up at the moment makes it fire at the wrong time
869 // when navigating one month back using the keyboard which will cause this handler
870 // to throw a "changed after checked" error when updating the preview state.
871 this._changeDetectorRef.detectChanges();
872 }
873 }
874 /**
875 * Takes a day of the month and returns a new date in the same month and year as the currently
876 * active date. The returned date will have the same day of the month as the argument date.
877 */
878 _getDateFromDayOfMonth(dayOfMonth) {
879 return this._dateAdapter.createDate(this._dateAdapter.getYear(this.activeDate), this._dateAdapter.getMonth(this.activeDate), dayOfMonth);
880 }
881 /** Initializes the weekdays. */
882 _initWeekdays() {
883 const firstDayOfWeek = this._dateAdapter.getFirstDayOfWeek();
884 const narrowWeekdays = this._dateAdapter.getDayOfWeekNames('narrow');
885 const longWeekdays = this._dateAdapter.getDayOfWeekNames('long');
886 // Rotate the labels for days of the week based on the configured first day of the week.
887 let weekdays = longWeekdays.map((long, i) => {
888 return { long, narrow: narrowWeekdays[i] };
889 });
890 this._weekdays = weekdays.slice(firstDayOfWeek).concat(weekdays.slice(0, firstDayOfWeek));
891 }
892 /** Creates MatCalendarCells for the dates in this month. */
893 _createWeekCells() {
894 const daysInMonth = this._dateAdapter.getNumDaysInMonth(this.activeDate);
895 const dateNames = this._dateAdapter.getDateNames();
896 this._weeks = [[]];
897 for (let i = 0, cell = this._firstWeekOffset; i < daysInMonth; i++, cell++) {
898 if (cell == DAYS_PER_WEEK) {
899 this._weeks.push([]);
900 cell = 0;
901 }
902 const date = this._dateAdapter.createDate(this._dateAdapter.getYear(this.activeDate), this._dateAdapter.getMonth(this.activeDate), i + 1);
903 const enabled = this._shouldEnableDate(date);
904 const ariaLabel = this._dateAdapter.format(date, this._dateFormats.display.dateA11yLabel);
905 const cellClasses = this.dateClass ? this.dateClass(date, 'month') : undefined;
906 this._weeks[this._weeks.length - 1].push(new MatCalendarCell(i + 1, dateNames[i], ariaLabel, enabled, cellClasses, this._getCellCompareValue(date), date));
907 }
908 }
909 /** Date filter for the month */
910 _shouldEnableDate(date) {
911 return (!!date &&
912 (!this.minDate || this._dateAdapter.compareDate(date, this.minDate) >= 0) &&
913 (!this.maxDate || this._dateAdapter.compareDate(date, this.maxDate) <= 0) &&
914 (!this.dateFilter || this.dateFilter(date)));
915 }
916 /**
917 * Gets the date in this month that the given Date falls on.
918 * Returns null if the given Date is in another month.
919 */
920 _getDateInCurrentMonth(date) {
921 return date && this._hasSameMonthAndYear(date, this.activeDate)
922 ? this._dateAdapter.getDate(date)
923 : null;
924 }
925 /** Checks whether the 2 dates are non-null and fall within the same month of the same year. */
926 _hasSameMonthAndYear(d1, d2) {
927 return !!(d1 &&
928 d2 &&
929 this._dateAdapter.getMonth(d1) == this._dateAdapter.getMonth(d2) &&
930 this._dateAdapter.getYear(d1) == this._dateAdapter.getYear(d2));
931 }
932 /** Gets the value that will be used to one cell to another. */
933 _getCellCompareValue(date) {
934 if (date) {
935 // We use the time since the Unix epoch to compare dates in this view, rather than the
936 // cell values, because we need to support ranges that span across multiple months/years.
937 const year = this._dateAdapter.getYear(date);
938 const month = this._dateAdapter.getMonth(date);
939 const day = this._dateAdapter.getDate(date);
940 return new Date(year, month, day).getTime();
941 }
942 return null;
943 }
944 /** Determines whether the user has the RTL layout direction. */
945 _isRtl() {
946 return this._dir && this._dir.value === 'rtl';
947 }
948 /** Sets the current range based on a model value. */
949 _setRanges(selectedValue) {
950 if (selectedValue instanceof DateRange) {
951 this._rangeStart = this._getCellCompareValue(selectedValue.start);
952 this._rangeEnd = this._getCellCompareValue(selectedValue.end);
953 this._isRange = true;
954 }
955 else {
956 this._rangeStart = this._rangeEnd = this._getCellCompareValue(selectedValue);
957 this._isRange = false;
958 }
959 this._comparisonRangeStart = this._getCellCompareValue(this.comparisonStart);
960 this._comparisonRangeEnd = this._getCellCompareValue(this.comparisonEnd);
961 }
962 /** Gets whether a date can be selected in the month view. */
963 _canSelect(date) {
964 return !this.dateFilter || this.dateFilter(date);
965 }
966}
967MatMonthView.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatMonthView, deps: [{ token: i0.ChangeDetectorRef }, { token: MAT_DATE_FORMATS, optional: true }, { token: i1$1.DateAdapter, optional: true }, { token: i2.Directionality, optional: true }, { token: MAT_DATE_RANGE_SELECTION_STRATEGY, optional: true }], target: i0.ɵɵFactoryTarget.Component });
968MatMonthView.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.1", type: MatMonthView, selector: "mat-month-view", inputs: { activeDate: "activeDate", selected: "selected", minDate: "minDate", maxDate: "maxDate", dateFilter: "dateFilter", dateClass: "dateClass", comparisonStart: "comparisonStart", comparisonEnd: "comparisonEnd" }, outputs: { selectedChange: "selectedChange", _userSelection: "_userSelection", activeDateChange: "activeDateChange" }, viewQueries: [{ propertyName: "_matCalendarBody", first: true, predicate: MatCalendarBody, descendants: true }], exportAs: ["matMonthView"], usesOnChanges: true, ngImport: i0, template: "<table class=\"mat-calendar-table\" role=\"grid\">\n <thead class=\"mat-calendar-table-header\">\n <tr>\n <th scope=\"col\" *ngFor=\"let day of _weekdays\">\n <span class=\"cdk-visually-hidden\">{{day.long}}</span>\n <span aria-hidden=\"true\">{{day.narrow}}</span>\n </th>\n </tr>\n <tr><th aria-hidden=\"true\" class=\"mat-calendar-table-header-divider\" colspan=\"7\"></th></tr>\n </thead>\n <tbody mat-calendar-body\n [label]=\"_monthLabel\"\n [rows]=\"_weeks\"\n [todayValue]=\"_todayDate!\"\n [startValue]=\"_rangeStart!\"\n [endValue]=\"_rangeEnd!\"\n [comparisonStart]=\"_comparisonRangeStart\"\n [comparisonEnd]=\"_comparisonRangeEnd\"\n [previewStart]=\"_previewStart\"\n [previewEnd]=\"_previewEnd\"\n [isRange]=\"_isRange\"\n [labelMinRequiredCells]=\"3\"\n [activeCell]=\"_dateAdapter.getDate(activeDate) - 1\"\n (selectedValueChange)=\"_dateSelected($event)\"\n (activeDateChange)=\"_updateActiveDate($event)\"\n (previewChange)=\"_previewChanged($event)\"\n (keyup)=\"_handleCalendarBodyKeyup($event)\"\n (keydown)=\"_handleCalendarBodyKeydown($event)\">\n </tbody>\n</table>\n", dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: MatCalendarBody, selector: "[mat-calendar-body]", inputs: ["label", "rows", "todayValue", "startValue", "endValue", "labelMinRequiredCells", "numCols", "activeCell", "isRange", "cellAspectRatio", "comparisonStart", "comparisonEnd", "previewStart", "previewEnd"], outputs: ["selectedValueChange", "previewChange", "activeDateChange"], exportAs: ["matCalendarBody"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
969i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatMonthView, decorators: [{
970 type: Component,
971 args: [{ selector: 'mat-month-view', exportAs: 'matMonthView', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: "<table class=\"mat-calendar-table\" role=\"grid\">\n <thead class=\"mat-calendar-table-header\">\n <tr>\n <th scope=\"col\" *ngFor=\"let day of _weekdays\">\n <span class=\"cdk-visually-hidden\">{{day.long}}</span>\n <span aria-hidden=\"true\">{{day.narrow}}</span>\n </th>\n </tr>\n <tr><th aria-hidden=\"true\" class=\"mat-calendar-table-header-divider\" colspan=\"7\"></th></tr>\n </thead>\n <tbody mat-calendar-body\n [label]=\"_monthLabel\"\n [rows]=\"_weeks\"\n [todayValue]=\"_todayDate!\"\n [startValue]=\"_rangeStart!\"\n [endValue]=\"_rangeEnd!\"\n [comparisonStart]=\"_comparisonRangeStart\"\n [comparisonEnd]=\"_comparisonRangeEnd\"\n [previewStart]=\"_previewStart\"\n [previewEnd]=\"_previewEnd\"\n [isRange]=\"_isRange\"\n [labelMinRequiredCells]=\"3\"\n [activeCell]=\"_dateAdapter.getDate(activeDate) - 1\"\n (selectedValueChange)=\"_dateSelected($event)\"\n (activeDateChange)=\"_updateActiveDate($event)\"\n (previewChange)=\"_previewChanged($event)\"\n (keyup)=\"_handleCalendarBodyKeyup($event)\"\n (keydown)=\"_handleCalendarBodyKeydown($event)\">\n </tbody>\n</table>\n" }]
972 }], ctorParameters: function () {
973 return [{ type: i0.ChangeDetectorRef }, { type: undefined, decorators: [{
974 type: Optional
975 }, {
976 type: Inject,
977 args: [MAT_DATE_FORMATS]
978 }] }, { type: i1$1.DateAdapter, decorators: [{
979 type: Optional
980 }] }, { type: i2.Directionality, decorators: [{
981 type: Optional
982 }] }, { type: undefined, decorators: [{
983 type: Inject,
984 args: [MAT_DATE_RANGE_SELECTION_STRATEGY]
985 }, {
986 type: Optional
987 }] }];
988 }, propDecorators: { activeDate: [{
989 type: Input
990 }], selected: [{
991 type: Input
992 }], minDate: [{
993 type: Input
994 }], maxDate: [{
995 type: Input
996 }], dateFilter: [{
997 type: Input
998 }], dateClass: [{
999 type: Input
1000 }], comparisonStart: [{
1001 type: Input
1002 }], comparisonEnd: [{
1003 type: Input
1004 }], selectedChange: [{
1005 type: Output
1006 }], _userSelection: [{
1007 type: Output
1008 }], activeDateChange: [{
1009 type: Output
1010 }], _matCalendarBody: [{
1011 type: ViewChild,
1012 args: [MatCalendarBody]
1013 }] } });
1014
1015/**
1016 * @license
1017 * Copyright Google LLC All Rights Reserved.
1018 *
1019 * Use of this source code is governed by an MIT-style license that can be
1020 * found in the LICENSE file at https://angular.io/license
1021 */
1022const yearsPerPage = 24;
1023const yearsPerRow = 4;
1024/**
1025 * An internal component used to display a year selector in the datepicker.
1026 * @docs-private
1027 */
1028class MatMultiYearView {
1029 constructor(_changeDetectorRef, _dateAdapter, _dir) {
1030 this._changeDetectorRef = _changeDetectorRef;
1031 this._dateAdapter = _dateAdapter;
1032 this._dir = _dir;
1033 this._rerenderSubscription = Subscription.EMPTY;
1034 /** Emits when a new year is selected. */
1035 this.selectedChange = new EventEmitter();
1036 /** Emits the selected year. This doesn't imply a change on the selected date */
1037 this.yearSelected = new EventEmitter();
1038 /** Emits when any date is activated. */
1039 this.activeDateChange = new EventEmitter();
1040 if (!this._dateAdapter && (typeof ngDevMode === 'undefined' || ngDevMode)) {
1041 throw createMissingDateImplError('DateAdapter');
1042 }
1043 this._activeDate = this._dateAdapter.today();
1044 }
1045 /** The date to display in this multi-year view (everything other than the year is ignored). */
1046 get activeDate() {
1047 return this._activeDate;
1048 }
1049 set activeDate(value) {
1050 let oldActiveDate = this._activeDate;
1051 const validDate = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value)) ||
1052 this._dateAdapter.today();
1053 this._activeDate = this._dateAdapter.clampDate(validDate, this.minDate, this.maxDate);
1054 if (!isSameMultiYearView(this._dateAdapter, oldActiveDate, this._activeDate, this.minDate, this.maxDate)) {
1055 this._init();
1056 }
1057 }
1058 /** The currently selected date. */
1059 get selected() {
1060 return this._selected;
1061 }
1062 set selected(value) {
1063 if (value instanceof DateRange) {
1064 this._selected = value;
1065 }
1066 else {
1067 this._selected = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value));
1068 }
1069 this._setSelectedYear(value);
1070 }
1071 /** The minimum selectable date. */
1072 get minDate() {
1073 return this._minDate;
1074 }
1075 set minDate(value) {
1076 this._minDate = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value));
1077 }
1078 /** The maximum selectable date. */
1079 get maxDate() {
1080 return this._maxDate;
1081 }
1082 set maxDate(value) {
1083 this._maxDate = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value));
1084 }
1085 ngAfterContentInit() {
1086 this._rerenderSubscription = this._dateAdapter.localeChanges
1087 .pipe(startWith(null))
1088 .subscribe(() => this._init());
1089 }
1090 ngOnDestroy() {
1091 this._rerenderSubscription.unsubscribe();
1092 }
1093 /** Initializes this multi-year view. */
1094 _init() {
1095 this._todayYear = this._dateAdapter.getYear(this._dateAdapter.today());
1096 // We want a range years such that we maximize the number of
1097 // enabled dates visible at once. This prevents issues where the minimum year
1098 // is the last item of a page OR the maximum year is the first item of a page.
1099 // The offset from the active year to the "slot" for the starting year is the
1100 // *actual* first rendered year in the multi-year view.
1101 const activeYear = this._dateAdapter.getYear(this._activeDate);
1102 const minYearOfPage = activeYear - getActiveOffset(this._dateAdapter, this.activeDate, this.minDate, this.maxDate);
1103 this._years = [];
1104 for (let i = 0, row = []; i < yearsPerPage; i++) {
1105 row.push(minYearOfPage + i);
1106 if (row.length == yearsPerRow) {
1107 this._years.push(row.map(year => this._createCellForYear(year)));
1108 row = [];
1109 }
1110 }
1111 this._changeDetectorRef.markForCheck();
1112 }
1113 /** Handles when a new year is selected. */
1114 _yearSelected(event) {
1115 const year = event.value;
1116 const selectedYear = this._dateAdapter.createDate(year, 0, 1);
1117 const selectedDate = this._getDateFromYear(year);
1118 this.yearSelected.emit(selectedYear);
1119 this.selectedChange.emit(selectedDate);
1120 }
1121 /**
1122 * Takes the index of a calendar body cell wrapped in in an event as argument. For the date that
1123 * corresponds to the given cell, set `activeDate` to that date and fire `activeDateChange` with
1124 * that date.
1125 *
1126 * This fucntion is used to match each component's model of the active date with the calendar
1127 * body cell that was focused. It updates its value of `activeDate` synchronously and updates the
1128 * parent's value asynchonously via the `activeDateChange` event. The child component receives an
1129 * updated value asynchronously via the `activeCell` Input.
1130 */
1131 _updateActiveDate(event) {
1132 const year = event.value;
1133 const oldActiveDate = this._activeDate;
1134 this.activeDate = this._getDateFromYear(year);
1135 if (this._dateAdapter.compareDate(oldActiveDate, this.activeDate)) {
1136 this.activeDateChange.emit(this.activeDate);
1137 }
1138 }
1139 /** Handles keydown events on the calendar body when calendar is in multi-year view. */
1140 _handleCalendarBodyKeydown(event) {
1141 const oldActiveDate = this._activeDate;
1142 const isRtl = this._isRtl();
1143 switch (event.keyCode) {
1144 case LEFT_ARROW:
1145 this.activeDate = this._dateAdapter.addCalendarYears(this._activeDate, isRtl ? 1 : -1);
1146 break;
1147 case RIGHT_ARROW:
1148 this.activeDate = this._dateAdapter.addCalendarYears(this._activeDate, isRtl ? -1 : 1);
1149 break;
1150 case UP_ARROW:
1151 this.activeDate = this._dateAdapter.addCalendarYears(this._activeDate, -yearsPerRow);
1152 break;
1153 case DOWN_ARROW:
1154 this.activeDate = this._dateAdapter.addCalendarYears(this._activeDate, yearsPerRow);
1155 break;
1156 case HOME:
1157 this.activeDate = this._dateAdapter.addCalendarYears(this._activeDate, -getActiveOffset(this._dateAdapter, this.activeDate, this.minDate, this.maxDate));
1158 break;
1159 case END:
1160 this.activeDate = this._dateAdapter.addCalendarYears(this._activeDate, yearsPerPage -
1161 getActiveOffset(this._dateAdapter, this.activeDate, this.minDate, this.maxDate) -
1162 1);
1163 break;
1164 case PAGE_UP:
1165 this.activeDate = this._dateAdapter.addCalendarYears(this._activeDate, event.altKey ? -yearsPerPage * 10 : -yearsPerPage);
1166 break;
1167 case PAGE_DOWN:
1168 this.activeDate = this._dateAdapter.addCalendarYears(this._activeDate, event.altKey ? yearsPerPage * 10 : yearsPerPage);
1169 break;
1170 case ENTER:
1171 case SPACE:
1172 // Note that we only prevent the default action here while the selection happens in
1173 // `keyup` below. We can't do the selection here, because it can cause the calendar to
1174 // reopen if focus is restored immediately. We also can't call `preventDefault` on `keyup`
1175 // because it's too late (see #23305).
1176 this._selectionKeyPressed = true;
1177 break;
1178 default:
1179 // Don't prevent default or focus active cell on keys that we don't explicitly handle.
1180 return;
1181 }
1182 if (this._dateAdapter.compareDate(oldActiveDate, this.activeDate)) {
1183 this.activeDateChange.emit(this.activeDate);
1184 }
1185 this._focusActiveCellAfterViewChecked();
1186 // Prevent unexpected default actions such as form submission.
1187 event.preventDefault();
1188 }
1189 /** Handles keyup events on the calendar body when calendar is in multi-year view. */
1190 _handleCalendarBodyKeyup(event) {
1191 if (event.keyCode === SPACE || event.keyCode === ENTER) {
1192 if (this._selectionKeyPressed) {
1193 this._yearSelected({ value: this._dateAdapter.getYear(this._activeDate), event });
1194 }
1195 this._selectionKeyPressed = false;
1196 }
1197 }
1198 _getActiveCell() {
1199 return getActiveOffset(this._dateAdapter, this.activeDate, this.minDate, this.maxDate);
1200 }
1201 /** Focuses the active cell after the microtask queue is empty. */
1202 _focusActiveCell() {
1203 this._matCalendarBody._focusActiveCell();
1204 }
1205 /** Focuses the active cell after change detection has run and the microtask queue is empty. */
1206 _focusActiveCellAfterViewChecked() {
1207 this._matCalendarBody._scheduleFocusActiveCellAfterViewChecked();
1208 }
1209 /**
1210 * Takes a year and returns a new date on the same day and month as the currently active date
1211 * The returned date will have the same year as the argument date.
1212 */
1213 _getDateFromYear(year) {
1214 const activeMonth = this._dateAdapter.getMonth(this.activeDate);
1215 const daysInMonth = this._dateAdapter.getNumDaysInMonth(this._dateAdapter.createDate(year, activeMonth, 1));
1216 const normalizedDate = this._dateAdapter.createDate(year, activeMonth, Math.min(this._dateAdapter.getDate(this.activeDate), daysInMonth));
1217 return normalizedDate;
1218 }
1219 /** Creates an MatCalendarCell for the given year. */
1220 _createCellForYear(year) {
1221 const date = this._dateAdapter.createDate(year, 0, 1);
1222 const yearName = this._dateAdapter.getYearName(date);
1223 const cellClasses = this.dateClass ? this.dateClass(date, 'multi-year') : undefined;
1224 return new MatCalendarCell(year, yearName, yearName, this._shouldEnableYear(year), cellClasses);
1225 }
1226 /** Whether the given year is enabled. */
1227 _shouldEnableYear(year) {
1228 // disable if the year is greater than maxDate lower than minDate
1229 if (year === undefined ||
1230 year === null ||
1231 (this.maxDate && year > this._dateAdapter.getYear(this.maxDate)) ||
1232 (this.minDate && year < this._dateAdapter.getYear(this.minDate))) {
1233 return false;
1234 }
1235 // enable if it reaches here and there's no filter defined
1236 if (!this.dateFilter) {
1237 return true;
1238 }
1239 const firstOfYear = this._dateAdapter.createDate(year, 0, 1);
1240 // If any date in the year is enabled count the year as enabled.
1241 for (let date = firstOfYear; this._dateAdapter.getYear(date) == year; date = this._dateAdapter.addCalendarDays(date, 1)) {
1242 if (this.dateFilter(date)) {
1243 return true;
1244 }
1245 }
1246 return false;
1247 }
1248 /** Determines whether the user has the RTL layout direction. */
1249 _isRtl() {
1250 return this._dir && this._dir.value === 'rtl';
1251 }
1252 /** Sets the currently-highlighted year based on a model value. */
1253 _setSelectedYear(value) {
1254 this._selectedYear = null;
1255 if (value instanceof DateRange) {
1256 const displayValue = value.start || value.end;
1257 if (displayValue) {
1258 this._selectedYear = this._dateAdapter.getYear(displayValue);
1259 }
1260 }
1261 else if (value) {
1262 this._selectedYear = this._dateAdapter.getYear(value);
1263 }
1264 }
1265}
1266MatMultiYearView.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatMultiYearView, deps: [{ token: i0.ChangeDetectorRef }, { token: i1$1.DateAdapter, optional: true }, { token: i2.Directionality, optional: true }], target: i0.ɵɵFactoryTarget.Component });
1267MatMultiYearView.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.1", type: MatMultiYearView, selector: "mat-multi-year-view", inputs: { activeDate: "activeDate", selected: "selected", minDate: "minDate", maxDate: "maxDate", dateFilter: "dateFilter", dateClass: "dateClass" }, outputs: { selectedChange: "selectedChange", yearSelected: "yearSelected", activeDateChange: "activeDateChange" }, viewQueries: [{ propertyName: "_matCalendarBody", first: true, predicate: MatCalendarBody, descendants: true }], exportAs: ["matMultiYearView"], ngImport: i0, template: "<table class=\"mat-calendar-table\" role=\"grid\">\n <thead aria-hidden=\"true\" class=\"mat-calendar-table-header\">\n <tr><th class=\"mat-calendar-table-header-divider\" colspan=\"4\"></th></tr>\n </thead>\n <tbody mat-calendar-body\n [rows]=\"_years\"\n [todayValue]=\"_todayYear\"\n [startValue]=\"_selectedYear!\"\n [endValue]=\"_selectedYear!\"\n [numCols]=\"4\"\n [cellAspectRatio]=\"4 / 7\"\n [activeCell]=\"_getActiveCell()\"\n (selectedValueChange)=\"_yearSelected($event)\"\n (activeDateChange)=\"_updateActiveDate($event)\"\n (keyup)=\"_handleCalendarBodyKeyup($event)\"\n (keydown)=\"_handleCalendarBodyKeydown($event)\">\n </tbody>\n</table>\n", dependencies: [{ kind: "component", type: MatCalendarBody, selector: "[mat-calendar-body]", inputs: ["label", "rows", "todayValue", "startValue", "endValue", "labelMinRequiredCells", "numCols", "activeCell", "isRange", "cellAspectRatio", "comparisonStart", "comparisonEnd", "previewStart", "previewEnd"], outputs: ["selectedValueChange", "previewChange", "activeDateChange"], exportAs: ["matCalendarBody"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1268i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatMultiYearView, decorators: [{
1269 type: Component,
1270 args: [{ selector: 'mat-multi-year-view', exportAs: 'matMultiYearView', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: "<table class=\"mat-calendar-table\" role=\"grid\">\n <thead aria-hidden=\"true\" class=\"mat-calendar-table-header\">\n <tr><th class=\"mat-calendar-table-header-divider\" colspan=\"4\"></th></tr>\n </thead>\n <tbody mat-calendar-body\n [rows]=\"_years\"\n [todayValue]=\"_todayYear\"\n [startValue]=\"_selectedYear!\"\n [endValue]=\"_selectedYear!\"\n [numCols]=\"4\"\n [cellAspectRatio]=\"4 / 7\"\n [activeCell]=\"_getActiveCell()\"\n (selectedValueChange)=\"_yearSelected($event)\"\n (activeDateChange)=\"_updateActiveDate($event)\"\n (keyup)=\"_handleCalendarBodyKeyup($event)\"\n (keydown)=\"_handleCalendarBodyKeydown($event)\">\n </tbody>\n</table>\n" }]
1271 }], ctorParameters: function () {
1272 return [{ type: i0.ChangeDetectorRef }, { type: i1$1.DateAdapter, decorators: [{
1273 type: Optional
1274 }] }, { type: i2.Directionality, decorators: [{
1275 type: Optional
1276 }] }];
1277 }, propDecorators: { activeDate: [{
1278 type: Input
1279 }], selected: [{
1280 type: Input
1281 }], minDate: [{
1282 type: Input
1283 }], maxDate: [{
1284 type: Input
1285 }], dateFilter: [{
1286 type: Input
1287 }], dateClass: [{
1288 type: Input
1289 }], selectedChange: [{
1290 type: Output
1291 }], yearSelected: [{
1292 type: Output
1293 }], activeDateChange: [{
1294 type: Output
1295 }], _matCalendarBody: [{
1296 type: ViewChild,
1297 args: [MatCalendarBody]
1298 }] } });
1299function isSameMultiYearView(dateAdapter, date1, date2, minDate, maxDate) {
1300 const year1 = dateAdapter.getYear(date1);
1301 const year2 = dateAdapter.getYear(date2);
1302 const startingYear = getStartingYear(dateAdapter, minDate, maxDate);
1303 return (Math.floor((year1 - startingYear) / yearsPerPage) ===
1304 Math.floor((year2 - startingYear) / yearsPerPage));
1305}
1306/**
1307 * When the multi-year view is first opened, the active year will be in view.
1308 * So we compute how many years are between the active year and the *slot* where our
1309 * "startingYear" will render when paged into view.
1310 */
1311function getActiveOffset(dateAdapter, activeDate, minDate, maxDate) {
1312 const activeYear = dateAdapter.getYear(activeDate);
1313 return euclideanModulo(activeYear - getStartingYear(dateAdapter, minDate, maxDate), yearsPerPage);
1314}
1315/**
1316 * We pick a "starting" year such that either the maximum year would be at the end
1317 * or the minimum year would be at the beginning of a page.
1318 */
1319function getStartingYear(dateAdapter, minDate, maxDate) {
1320 let startingYear = 0;
1321 if (maxDate) {
1322 const maxYear = dateAdapter.getYear(maxDate);
1323 startingYear = maxYear - yearsPerPage + 1;
1324 }
1325 else if (minDate) {
1326 startingYear = dateAdapter.getYear(minDate);
1327 }
1328 return startingYear;
1329}
1330/** Gets remainder that is non-negative, even if first number is negative */
1331function euclideanModulo(a, b) {
1332 return ((a % b) + b) % b;
1333}
1334
1335/**
1336 * @license
1337 * Copyright Google LLC All Rights Reserved.
1338 *
1339 * Use of this source code is governed by an MIT-style license that can be
1340 * found in the LICENSE file at https://angular.io/license
1341 */
1342/**
1343 * An internal component used to display a single year in the datepicker.
1344 * @docs-private
1345 */
1346class MatYearView {
1347 constructor(_changeDetectorRef, _dateFormats, _dateAdapter, _dir) {
1348 this._changeDetectorRef = _changeDetectorRef;
1349 this._dateFormats = _dateFormats;
1350 this._dateAdapter = _dateAdapter;
1351 this._dir = _dir;
1352 this._rerenderSubscription = Subscription.EMPTY;
1353 /** Emits when a new month is selected. */
1354 this.selectedChange = new EventEmitter();
1355 /** Emits the selected month. This doesn't imply a change on the selected date */
1356 this.monthSelected = new EventEmitter();
1357 /** Emits when any date is activated. */
1358 this.activeDateChange = new EventEmitter();
1359 if (typeof ngDevMode === 'undefined' || ngDevMode) {
1360 if (!this._dateAdapter) {
1361 throw createMissingDateImplError('DateAdapter');
1362 }
1363 if (!this._dateFormats) {
1364 throw createMissingDateImplError('MAT_DATE_FORMATS');
1365 }
1366 }
1367 this._activeDate = this._dateAdapter.today();
1368 }
1369 /** The date to display in this year view (everything other than the year is ignored). */
1370 get activeDate() {
1371 return this._activeDate;
1372 }
1373 set activeDate(value) {
1374 let oldActiveDate = this._activeDate;
1375 const validDate = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value)) ||
1376 this._dateAdapter.today();
1377 this._activeDate = this._dateAdapter.clampDate(validDate, this.minDate, this.maxDate);
1378 if (this._dateAdapter.getYear(oldActiveDate) !== this._dateAdapter.getYear(this._activeDate)) {
1379 this._init();
1380 }
1381 }
1382 /** The currently selected date. */
1383 get selected() {
1384 return this._selected;
1385 }
1386 set selected(value) {
1387 if (value instanceof DateRange) {
1388 this._selected = value;
1389 }
1390 else {
1391 this._selected = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value));
1392 }
1393 this._setSelectedMonth(value);
1394 }
1395 /** The minimum selectable date. */
1396 get minDate() {
1397 return this._minDate;
1398 }
1399 set minDate(value) {
1400 this._minDate = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value));
1401 }
1402 /** The maximum selectable date. */
1403 get maxDate() {
1404 return this._maxDate;
1405 }
1406 set maxDate(value) {
1407 this._maxDate = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value));
1408 }
1409 ngAfterContentInit() {
1410 this._rerenderSubscription = this._dateAdapter.localeChanges
1411 .pipe(startWith(null))
1412 .subscribe(() => this._init());
1413 }
1414 ngOnDestroy() {
1415 this._rerenderSubscription.unsubscribe();
1416 }
1417 /** Handles when a new month is selected. */
1418 _monthSelected(event) {
1419 const month = event.value;
1420 const selectedMonth = this._dateAdapter.createDate(this._dateAdapter.getYear(this.activeDate), month, 1);
1421 this.monthSelected.emit(selectedMonth);
1422 const selectedDate = this._getDateFromMonth(month);
1423 this.selectedChange.emit(selectedDate);
1424 }
1425 /**
1426 * Takes the index of a calendar body cell wrapped in in an event as argument. For the date that
1427 * corresponds to the given cell, set `activeDate` to that date and fire `activeDateChange` with
1428 * that date.
1429 *
1430 * This fucntion is used to match each component's model of the active date with the calendar
1431 * body cell that was focused. It updates its value of `activeDate` synchronously and updates the
1432 * parent's value asynchonously via the `activeDateChange` event. The child component receives an
1433 * updated value asynchronously via the `activeCell` Input.
1434 */
1435 _updateActiveDate(event) {
1436 const month = event.value;
1437 const oldActiveDate = this._activeDate;
1438 this.activeDate = this._getDateFromMonth(month);
1439 if (this._dateAdapter.compareDate(oldActiveDate, this.activeDate)) {
1440 this.activeDateChange.emit(this.activeDate);
1441 }
1442 }
1443 /** Handles keydown events on the calendar body when calendar is in year view. */
1444 _handleCalendarBodyKeydown(event) {
1445 // TODO(mmalerba): We currently allow keyboard navigation to disabled dates, but just prevent
1446 // disabled ones from being selected. This may not be ideal, we should look into whether
1447 // navigation should skip over disabled dates, and if so, how to implement that efficiently.
1448 const oldActiveDate = this._activeDate;
1449 const isRtl = this._isRtl();
1450 switch (event.keyCode) {
1451 case LEFT_ARROW:
1452 this.activeDate = this._dateAdapter.addCalendarMonths(this._activeDate, isRtl ? 1 : -1);
1453 break;
1454 case RIGHT_ARROW:
1455 this.activeDate = this._dateAdapter.addCalendarMonths(this._activeDate, isRtl ? -1 : 1);
1456 break;
1457 case UP_ARROW:
1458 this.activeDate = this._dateAdapter.addCalendarMonths(this._activeDate, -4);
1459 break;
1460 case DOWN_ARROW:
1461 this.activeDate = this._dateAdapter.addCalendarMonths(this._activeDate, 4);
1462 break;
1463 case HOME:
1464 this.activeDate = this._dateAdapter.addCalendarMonths(this._activeDate, -this._dateAdapter.getMonth(this._activeDate));
1465 break;
1466 case END:
1467 this.activeDate = this._dateAdapter.addCalendarMonths(this._activeDate, 11 - this._dateAdapter.getMonth(this._activeDate));
1468 break;
1469 case PAGE_UP:
1470 this.activeDate = this._dateAdapter.addCalendarYears(this._activeDate, event.altKey ? -10 : -1);
1471 break;
1472 case PAGE_DOWN:
1473 this.activeDate = this._dateAdapter.addCalendarYears(this._activeDate, event.altKey ? 10 : 1);
1474 break;
1475 case ENTER:
1476 case SPACE:
1477 // Note that we only prevent the default action here while the selection happens in
1478 // `keyup` below. We can't do the selection here, because it can cause the calendar to
1479 // reopen if focus is restored immediately. We also can't call `preventDefault` on `keyup`
1480 // because it's too late (see #23305).
1481 this._selectionKeyPressed = true;
1482 break;
1483 default:
1484 // Don't prevent default or focus active cell on keys that we don't explicitly handle.
1485 return;
1486 }
1487 if (this._dateAdapter.compareDate(oldActiveDate, this.activeDate)) {
1488 this.activeDateChange.emit(this.activeDate);
1489 this._focusActiveCellAfterViewChecked();
1490 }
1491 // Prevent unexpected default actions such as form submission.
1492 event.preventDefault();
1493 }
1494 /** Handles keyup events on the calendar body when calendar is in year view. */
1495 _handleCalendarBodyKeyup(event) {
1496 if (event.keyCode === SPACE || event.keyCode === ENTER) {
1497 if (this._selectionKeyPressed) {
1498 this._monthSelected({ value: this._dateAdapter.getMonth(this._activeDate), event });
1499 }
1500 this._selectionKeyPressed = false;
1501 }
1502 }
1503 /** Initializes this year view. */
1504 _init() {
1505 this._setSelectedMonth(this.selected);
1506 this._todayMonth = this._getMonthInCurrentYear(this._dateAdapter.today());
1507 this._yearLabel = this._dateAdapter.getYearName(this.activeDate);
1508 let monthNames = this._dateAdapter.getMonthNames('short');
1509 // First row of months only contains 5 elements so we can fit the year label on the same row.
1510 this._months = [
1511 [0, 1, 2, 3],
1512 [4, 5, 6, 7],
1513 [8, 9, 10, 11],
1514 ].map(row => row.map(month => this._createCellForMonth(month, monthNames[month])));
1515 this._changeDetectorRef.markForCheck();
1516 }
1517 /** Focuses the active cell after the microtask queue is empty. */
1518 _focusActiveCell() {
1519 this._matCalendarBody._focusActiveCell();
1520 }
1521 /** Schedules the matCalendarBody to focus the active cell after change detection has run */
1522 _focusActiveCellAfterViewChecked() {
1523 this._matCalendarBody._scheduleFocusActiveCellAfterViewChecked();
1524 }
1525 /**
1526 * Gets the month in this year that the given Date falls on.
1527 * Returns null if the given Date is in another year.
1528 */
1529 _getMonthInCurrentYear(date) {
1530 return date && this._dateAdapter.getYear(date) == this._dateAdapter.getYear(this.activeDate)
1531 ? this._dateAdapter.getMonth(date)
1532 : null;
1533 }
1534 /**
1535 * Takes a month and returns a new date in the same day and year as the currently active date.
1536 * The returned date will have the same month as the argument date.
1537 */
1538 _getDateFromMonth(month) {
1539 const normalizedDate = this._dateAdapter.createDate(this._dateAdapter.getYear(this.activeDate), month, 1);
1540 const daysInMonth = this._dateAdapter.getNumDaysInMonth(normalizedDate);
1541 return this._dateAdapter.createDate(this._dateAdapter.getYear(this.activeDate), month, Math.min(this._dateAdapter.getDate(this.activeDate), daysInMonth));
1542 }
1543 /** Creates an MatCalendarCell for the given month. */
1544 _createCellForMonth(month, monthName) {
1545 const date = this._dateAdapter.createDate(this._dateAdapter.getYear(this.activeDate), month, 1);
1546 const ariaLabel = this._dateAdapter.format(date, this._dateFormats.display.monthYearA11yLabel);
1547 const cellClasses = this.dateClass ? this.dateClass(date, 'year') : undefined;
1548 return new MatCalendarCell(month, monthName.toLocaleUpperCase(), ariaLabel, this._shouldEnableMonth(month), cellClasses);
1549 }
1550 /** Whether the given month is enabled. */
1551 _shouldEnableMonth(month) {
1552 const activeYear = this._dateAdapter.getYear(this.activeDate);
1553 if (month === undefined ||
1554 month === null ||
1555 this._isYearAndMonthAfterMaxDate(activeYear, month) ||
1556 this._isYearAndMonthBeforeMinDate(activeYear, month)) {
1557 return false;
1558 }
1559 if (!this.dateFilter) {
1560 return true;
1561 }
1562 const firstOfMonth = this._dateAdapter.createDate(activeYear, month, 1);
1563 // If any date in the month is enabled count the month as enabled.
1564 for (let date = firstOfMonth; this._dateAdapter.getMonth(date) == month; date = this._dateAdapter.addCalendarDays(date, 1)) {
1565 if (this.dateFilter(date)) {
1566 return true;
1567 }
1568 }
1569 return false;
1570 }
1571 /**
1572 * Tests whether the combination month/year is after this.maxDate, considering
1573 * just the month and year of this.maxDate
1574 */
1575 _isYearAndMonthAfterMaxDate(year, month) {
1576 if (this.maxDate) {
1577 const maxYear = this._dateAdapter.getYear(this.maxDate);
1578 const maxMonth = this._dateAdapter.getMonth(this.maxDate);
1579 return year > maxYear || (year === maxYear && month > maxMonth);
1580 }
1581 return false;
1582 }
1583 /**
1584 * Tests whether the combination month/year is before this.minDate, considering
1585 * just the month and year of this.minDate
1586 */
1587 _isYearAndMonthBeforeMinDate(year, month) {
1588 if (this.minDate) {
1589 const minYear = this._dateAdapter.getYear(this.minDate);
1590 const minMonth = this._dateAdapter.getMonth(this.minDate);
1591 return year < minYear || (year === minYear && month < minMonth);
1592 }
1593 return false;
1594 }
1595 /** Determines whether the user has the RTL layout direction. */
1596 _isRtl() {
1597 return this._dir && this._dir.value === 'rtl';
1598 }
1599 /** Sets the currently-selected month based on a model value. */
1600 _setSelectedMonth(value) {
1601 if (value instanceof DateRange) {
1602 this._selectedMonth =
1603 this._getMonthInCurrentYear(value.start) || this._getMonthInCurrentYear(value.end);
1604 }
1605 else {
1606 this._selectedMonth = this._getMonthInCurrentYear(value);
1607 }
1608 }
1609}
1610MatYearView.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatYearView, deps: [{ token: i0.ChangeDetectorRef }, { token: MAT_DATE_FORMATS, optional: true }, { token: i1$1.DateAdapter, optional: true }, { token: i2.Directionality, optional: true }], target: i0.ɵɵFactoryTarget.Component });
1611MatYearView.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.1", type: MatYearView, selector: "mat-year-view", inputs: { activeDate: "activeDate", selected: "selected", minDate: "minDate", maxDate: "maxDate", dateFilter: "dateFilter", dateClass: "dateClass" }, outputs: { selectedChange: "selectedChange", monthSelected: "monthSelected", activeDateChange: "activeDateChange" }, viewQueries: [{ propertyName: "_matCalendarBody", first: true, predicate: MatCalendarBody, descendants: true }], exportAs: ["matYearView"], ngImport: i0, template: "<table class=\"mat-calendar-table\" role=\"grid\">\n <thead aria-hidden=\"true\" class=\"mat-calendar-table-header\">\n <tr><th class=\"mat-calendar-table-header-divider\" colspan=\"4\"></th></tr>\n </thead>\n <tbody mat-calendar-body\n [label]=\"_yearLabel\"\n [rows]=\"_months\"\n [todayValue]=\"_todayMonth!\"\n [startValue]=\"_selectedMonth!\"\n [endValue]=\"_selectedMonth!\"\n [labelMinRequiredCells]=\"2\"\n [numCols]=\"4\"\n [cellAspectRatio]=\"4 / 7\"\n [activeCell]=\"_dateAdapter.getMonth(activeDate)\"\n (selectedValueChange)=\"_monthSelected($event)\"\n (activeDateChange)=\"_updateActiveDate($event)\"\n (keyup)=\"_handleCalendarBodyKeyup($event)\"\n (keydown)=\"_handleCalendarBodyKeydown($event)\">\n </tbody>\n</table>\n", dependencies: [{ kind: "component", type: MatCalendarBody, selector: "[mat-calendar-body]", inputs: ["label", "rows", "todayValue", "startValue", "endValue", "labelMinRequiredCells", "numCols", "activeCell", "isRange", "cellAspectRatio", "comparisonStart", "comparisonEnd", "previewStart", "previewEnd"], outputs: ["selectedValueChange", "previewChange", "activeDateChange"], exportAs: ["matCalendarBody"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1612i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatYearView, decorators: [{
1613 type: Component,
1614 args: [{ selector: 'mat-year-view', exportAs: 'matYearView', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: "<table class=\"mat-calendar-table\" role=\"grid\">\n <thead aria-hidden=\"true\" class=\"mat-calendar-table-header\">\n <tr><th class=\"mat-calendar-table-header-divider\" colspan=\"4\"></th></tr>\n </thead>\n <tbody mat-calendar-body\n [label]=\"_yearLabel\"\n [rows]=\"_months\"\n [todayValue]=\"_todayMonth!\"\n [startValue]=\"_selectedMonth!\"\n [endValue]=\"_selectedMonth!\"\n [labelMinRequiredCells]=\"2\"\n [numCols]=\"4\"\n [cellAspectRatio]=\"4 / 7\"\n [activeCell]=\"_dateAdapter.getMonth(activeDate)\"\n (selectedValueChange)=\"_monthSelected($event)\"\n (activeDateChange)=\"_updateActiveDate($event)\"\n (keyup)=\"_handleCalendarBodyKeyup($event)\"\n (keydown)=\"_handleCalendarBodyKeydown($event)\">\n </tbody>\n</table>\n" }]
1615 }], ctorParameters: function () {
1616 return [{ type: i0.ChangeDetectorRef }, { type: undefined, decorators: [{
1617 type: Optional
1618 }, {
1619 type: Inject,
1620 args: [MAT_DATE_FORMATS]
1621 }] }, { type: i1$1.DateAdapter, decorators: [{
1622 type: Optional
1623 }] }, { type: i2.Directionality, decorators: [{
1624 type: Optional
1625 }] }];
1626 }, propDecorators: { activeDate: [{
1627 type: Input
1628 }], selected: [{
1629 type: Input
1630 }], minDate: [{
1631 type: Input
1632 }], maxDate: [{
1633 type: Input
1634 }], dateFilter: [{
1635 type: Input
1636 }], dateClass: [{
1637 type: Input
1638 }], selectedChange: [{
1639 type: Output
1640 }], monthSelected: [{
1641 type: Output
1642 }], activeDateChange: [{
1643 type: Output
1644 }], _matCalendarBody: [{
1645 type: ViewChild,
1646 args: [MatCalendarBody]
1647 }] } });
1648
1649/**
1650 * @license
1651 * Copyright Google LLC All Rights Reserved.
1652 *
1653 * Use of this source code is governed by an MIT-style license that can be
1654 * found in the LICENSE file at https://angular.io/license
1655 */
1656/** Datepicker data that requires internationalization. */
1657class MatDatepickerIntl {
1658 constructor() {
1659 /**
1660 * Stream that emits whenever the labels here are changed. Use this to notify
1661 * components if the labels have changed after initialization.
1662 */
1663 this.changes = new Subject();
1664 /** A label for the calendar popup (used by screen readers). */
1665 this.calendarLabel = 'Calendar';
1666 /** A label for the button used to open the calendar popup (used by screen readers). */
1667 this.openCalendarLabel = 'Open calendar';
1668 /** Label for the button used to close the calendar popup. */
1669 this.closeCalendarLabel = 'Close calendar';
1670 /** A label for the previous month button (used by screen readers). */
1671 this.prevMonthLabel = 'Previous month';
1672 /** A label for the next month button (used by screen readers). */
1673 this.nextMonthLabel = 'Next month';
1674 /** A label for the previous year button (used by screen readers). */
1675 this.prevYearLabel = 'Previous year';
1676 /** A label for the next year button (used by screen readers). */
1677 this.nextYearLabel = 'Next year';
1678 /** A label for the previous multi-year button (used by screen readers). */
1679 this.prevMultiYearLabel = 'Previous 24 years';
1680 /** A label for the next multi-year button (used by screen readers). */
1681 this.nextMultiYearLabel = 'Next 24 years';
1682 /** A label for the 'switch to month view' button (used by screen readers). */
1683 this.switchToMonthViewLabel = 'Choose date';
1684 /** A label for the 'switch to year view' button (used by screen readers). */
1685 this.switchToMultiYearViewLabel = 'Choose month and year';
1686 }
1687 /** Formats a range of years. */
1688 formatYearRange(start, end) {
1689 return `${start} \u2013 ${end}`;
1690 }
1691}
1692MatDatepickerIntl.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDatepickerIntl, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1693MatDatepickerIntl.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDatepickerIntl, providedIn: 'root' });
1694i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDatepickerIntl, decorators: [{
1695 type: Injectable,
1696 args: [{ providedIn: 'root' }]
1697 }] });
1698
1699/**
1700 * @license
1701 * Copyright Google LLC All Rights Reserved.
1702 *
1703 * Use of this source code is governed by an MIT-style license that can be
1704 * found in the LICENSE file at https://angular.io/license
1705 */
1706/** Counter used to generate unique IDs. */
1707let uniqueId = 0;
1708/** Default header for MatCalendar */
1709class MatCalendarHeader {
1710 constructor(_intl, calendar, _dateAdapter, _dateFormats, changeDetectorRef) {
1711 this._intl = _intl;
1712 this.calendar = calendar;
1713 this._dateAdapter = _dateAdapter;
1714 this._dateFormats = _dateFormats;
1715 this._buttonDescriptionId = `mat-calendar-button-${uniqueId++}`;
1716 this.calendar.stateChanges.subscribe(() => changeDetectorRef.markForCheck());
1717 }
1718 /** The label for the current calendar view. */
1719 get periodButtonText() {
1720 if (this.calendar.currentView == 'month') {
1721 return this._dateAdapter
1722 .format(this.calendar.activeDate, this._dateFormats.display.monthYearLabel)
1723 .toLocaleUpperCase();
1724 }
1725 if (this.calendar.currentView == 'year') {
1726 return this._dateAdapter.getYearName(this.calendar.activeDate);
1727 }
1728 // The offset from the active year to the "slot" for the starting year is the
1729 // *actual* first rendered year in the multi-year view, and the last year is
1730 // just yearsPerPage - 1 away.
1731 const activeYear = this._dateAdapter.getYear(this.calendar.activeDate);
1732 const minYearOfPage = activeYear -
1733 getActiveOffset(this._dateAdapter, this.calendar.activeDate, this.calendar.minDate, this.calendar.maxDate);
1734 const maxYearOfPage = minYearOfPage + yearsPerPage - 1;
1735 const minYearName = this._dateAdapter.getYearName(this._dateAdapter.createDate(minYearOfPage, 0, 1));
1736 const maxYearName = this._dateAdapter.getYearName(this._dateAdapter.createDate(maxYearOfPage, 0, 1));
1737 return this._intl.formatYearRange(minYearName, maxYearName);
1738 }
1739 get periodButtonLabel() {
1740 return this.calendar.currentView == 'month'
1741 ? this._intl.switchToMultiYearViewLabel
1742 : this._intl.switchToMonthViewLabel;
1743 }
1744 /** The label for the previous button. */
1745 get prevButtonLabel() {
1746 return {
1747 'month': this._intl.prevMonthLabel,
1748 'year': this._intl.prevYearLabel,
1749 'multi-year': this._intl.prevMultiYearLabel,
1750 }[this.calendar.currentView];
1751 }
1752 /** The label for the next button. */
1753 get nextButtonLabel() {
1754 return {
1755 'month': this._intl.nextMonthLabel,
1756 'year': this._intl.nextYearLabel,
1757 'multi-year': this._intl.nextMultiYearLabel,
1758 }[this.calendar.currentView];
1759 }
1760 /** Handles user clicks on the period label. */
1761 currentPeriodClicked() {
1762 this.calendar.currentView = this.calendar.currentView == 'month' ? 'multi-year' : 'month';
1763 }
1764 /** Handles user clicks on the previous button. */
1765 previousClicked() {
1766 this.calendar.activeDate =
1767 this.calendar.currentView == 'month'
1768 ? this._dateAdapter.addCalendarMonths(this.calendar.activeDate, -1)
1769 : this._dateAdapter.addCalendarYears(this.calendar.activeDate, this.calendar.currentView == 'year' ? -1 : -yearsPerPage);
1770 }
1771 /** Handles user clicks on the next button. */
1772 nextClicked() {
1773 this.calendar.activeDate =
1774 this.calendar.currentView == 'month'
1775 ? this._dateAdapter.addCalendarMonths(this.calendar.activeDate, 1)
1776 : this._dateAdapter.addCalendarYears(this.calendar.activeDate, this.calendar.currentView == 'year' ? 1 : yearsPerPage);
1777 }
1778 /** Whether the previous period button is enabled. */
1779 previousEnabled() {
1780 if (!this.calendar.minDate) {
1781 return true;
1782 }
1783 return (!this.calendar.minDate || !this._isSameView(this.calendar.activeDate, this.calendar.minDate));
1784 }
1785 /** Whether the next period button is enabled. */
1786 nextEnabled() {
1787 return (!this.calendar.maxDate || !this._isSameView(this.calendar.activeDate, this.calendar.maxDate));
1788 }
1789 /** Whether the two dates represent the same view in the current view mode (month or year). */
1790 _isSameView(date1, date2) {
1791 if (this.calendar.currentView == 'month') {
1792 return (this._dateAdapter.getYear(date1) == this._dateAdapter.getYear(date2) &&
1793 this._dateAdapter.getMonth(date1) == this._dateAdapter.getMonth(date2));
1794 }
1795 if (this.calendar.currentView == 'year') {
1796 return this._dateAdapter.getYear(date1) == this._dateAdapter.getYear(date2);
1797 }
1798 // Otherwise we are in 'multi-year' view.
1799 return isSameMultiYearView(this._dateAdapter, date1, date2, this.calendar.minDate, this.calendar.maxDate);
1800 }
1801}
1802MatCalendarHeader.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatCalendarHeader, deps: [{ token: MatDatepickerIntl }, { token: forwardRef(() => MatCalendar) }, { token: i1$1.DateAdapter, optional: true }, { token: MAT_DATE_FORMATS, optional: true }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
1803MatCalendarHeader.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.1", type: MatCalendarHeader, selector: "mat-calendar-header", exportAs: ["matCalendarHeader"], ngImport: i0, template: "<div class=\"mat-calendar-header\">\n <div class=\"mat-calendar-controls\">\n <button mat-button type=\"button\" class=\"mat-calendar-period-button\"\n (click)=\"currentPeriodClicked()\" [attr.aria-label]=\"periodButtonLabel\"\n [attr.aria-describedby]=\"_buttonDescriptionId\"\n aria-live=\"polite\">\n <span [attr.id]=\"_buttonDescriptionId\">{{periodButtonText}}</span>\n <svg class=\"mat-calendar-arrow\" [class.mat-calendar-invert]=\"calendar.currentView !== 'month'\"\n viewBox=\"0 0 10 5\" focusable=\"false\">\n <polygon points=\"0,0 5,5 10,0\"/>\n </svg>\n </button>\n\n <div class=\"mat-calendar-spacer\"></div>\n\n <ng-content></ng-content>\n\n <button mat-icon-button type=\"button\" class=\"mat-calendar-previous-button\"\n [disabled]=\"!previousEnabled()\" (click)=\"previousClicked()\"\n [attr.aria-label]=\"prevButtonLabel\">\n </button>\n\n <button mat-icon-button type=\"button\" class=\"mat-calendar-next-button\"\n [disabled]=\"!nextEnabled()\" (click)=\"nextClicked()\"\n [attr.aria-label]=\"nextButtonLabel\">\n </button>\n </div>\n</div>\n", dependencies: [{ kind: "component", type: i3.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1804i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatCalendarHeader, decorators: [{
1805 type: Component,
1806 args: [{ selector: 'mat-calendar-header', exportAs: 'matCalendarHeader', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"mat-calendar-header\">\n <div class=\"mat-calendar-controls\">\n <button mat-button type=\"button\" class=\"mat-calendar-period-button\"\n (click)=\"currentPeriodClicked()\" [attr.aria-label]=\"periodButtonLabel\"\n [attr.aria-describedby]=\"_buttonDescriptionId\"\n aria-live=\"polite\">\n <span [attr.id]=\"_buttonDescriptionId\">{{periodButtonText}}</span>\n <svg class=\"mat-calendar-arrow\" [class.mat-calendar-invert]=\"calendar.currentView !== 'month'\"\n viewBox=\"0 0 10 5\" focusable=\"false\">\n <polygon points=\"0,0 5,5 10,0\"/>\n </svg>\n </button>\n\n <div class=\"mat-calendar-spacer\"></div>\n\n <ng-content></ng-content>\n\n <button mat-icon-button type=\"button\" class=\"mat-calendar-previous-button\"\n [disabled]=\"!previousEnabled()\" (click)=\"previousClicked()\"\n [attr.aria-label]=\"prevButtonLabel\">\n </button>\n\n <button mat-icon-button type=\"button\" class=\"mat-calendar-next-button\"\n [disabled]=\"!nextEnabled()\" (click)=\"nextClicked()\"\n [attr.aria-label]=\"nextButtonLabel\">\n </button>\n </div>\n</div>\n" }]
1807 }], ctorParameters: function () {
1808 return [{ type: MatDatepickerIntl }, { type: MatCalendar, decorators: [{
1809 type: Inject,
1810 args: [forwardRef(() => MatCalendar)]
1811 }] }, { type: i1$1.DateAdapter, decorators: [{
1812 type: Optional
1813 }] }, { type: undefined, decorators: [{
1814 type: Optional
1815 }, {
1816 type: Inject,
1817 args: [MAT_DATE_FORMATS]
1818 }] }, { type: i0.ChangeDetectorRef }];
1819 } });
1820/** A calendar that is used as part of the datepicker. */
1821class MatCalendar {
1822 constructor(_intl, _dateAdapter, _dateFormats, _changeDetectorRef) {
1823 this._dateAdapter = _dateAdapter;
1824 this._dateFormats = _dateFormats;
1825 this._changeDetectorRef = _changeDetectorRef;
1826 /**
1827 * Used for scheduling that focus should be moved to the active cell on the next tick.
1828 * We need to schedule it, rather than do it immediately, because we have to wait
1829 * for Angular to re-evaluate the view children.
1830 */
1831 this._moveFocusOnNextTick = false;
1832 /** Whether the calendar should be started in month or year view. */
1833 this.startView = 'month';
1834 /** Emits when the currently selected date changes. */
1835 this.selectedChange = new EventEmitter();
1836 /**
1837 * Emits the year chosen in multiyear view.
1838 * This doesn't imply a change on the selected date.
1839 */
1840 this.yearSelected = new EventEmitter();
1841 /**
1842 * Emits the month chosen in year view.
1843 * This doesn't imply a change on the selected date.
1844 */
1845 this.monthSelected = new EventEmitter();
1846 /**
1847 * Emits when the current view changes.
1848 */
1849 this.viewChanged = new EventEmitter(true);
1850 /** Emits when any date is selected. */
1851 this._userSelection = new EventEmitter();
1852 /**
1853 * Emits whenever there is a state change that the header may need to respond to.
1854 */
1855 this.stateChanges = new Subject();
1856 if (typeof ngDevMode === 'undefined' || ngDevMode) {
1857 if (!this._dateAdapter) {
1858 throw createMissingDateImplError('DateAdapter');
1859 }
1860 if (!this._dateFormats) {
1861 throw createMissingDateImplError('MAT_DATE_FORMATS');
1862 }
1863 }
1864 this._intlChanges = _intl.changes.subscribe(() => {
1865 _changeDetectorRef.markForCheck();
1866 this.stateChanges.next();
1867 });
1868 }
1869 /** A date representing the period (month or year) to start the calendar in. */
1870 get startAt() {
1871 return this._startAt;
1872 }
1873 set startAt(value) {
1874 this._startAt = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value));
1875 }
1876 /** The currently selected date. */
1877 get selected() {
1878 return this._selected;
1879 }
1880 set selected(value) {
1881 if (value instanceof DateRange) {
1882 this._selected = value;
1883 }
1884 else {
1885 this._selected = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value));
1886 }
1887 }
1888 /** The minimum selectable date. */
1889 get minDate() {
1890 return this._minDate;
1891 }
1892 set minDate(value) {
1893 this._minDate = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value));
1894 }
1895 /** The maximum selectable date. */
1896 get maxDate() {
1897 return this._maxDate;
1898 }
1899 set maxDate(value) {
1900 this._maxDate = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value));
1901 }
1902 /**
1903 * The current active date. This determines which time period is shown and which date is
1904 * highlighted when using keyboard navigation.
1905 */
1906 get activeDate() {
1907 return this._clampedActiveDate;
1908 }
1909 set activeDate(value) {
1910 this._clampedActiveDate = this._dateAdapter.clampDate(value, this.minDate, this.maxDate);
1911 this.stateChanges.next();
1912 this._changeDetectorRef.markForCheck();
1913 }
1914 /** Whether the calendar is in month view. */
1915 get currentView() {
1916 return this._currentView;
1917 }
1918 set currentView(value) {
1919 const viewChangedResult = this._currentView !== value ? value : null;
1920 this._currentView = value;
1921 this._moveFocusOnNextTick = true;
1922 this._changeDetectorRef.markForCheck();
1923 if (viewChangedResult) {
1924 this.viewChanged.emit(viewChangedResult);
1925 }
1926 }
1927 ngAfterContentInit() {
1928 this._calendarHeaderPortal = new ComponentPortal(this.headerComponent || MatCalendarHeader);
1929 this.activeDate = this.startAt || this._dateAdapter.today();
1930 // Assign to the private property since we don't want to move focus on init.
1931 this._currentView = this.startView;
1932 }
1933 ngAfterViewChecked() {
1934 if (this._moveFocusOnNextTick) {
1935 this._moveFocusOnNextTick = false;
1936 this.focusActiveCell();
1937 }
1938 }
1939 ngOnDestroy() {
1940 this._intlChanges.unsubscribe();
1941 this.stateChanges.complete();
1942 }
1943 ngOnChanges(changes) {
1944 // Ignore date changes that are at a different time on the same day. This fixes issues where
1945 // the calendar re-renders when there is no meaningful change to [minDate] or [maxDate]
1946 // (#24435).
1947 const minDateChange = changes['minDate'] &&
1948 !this._dateAdapter.sameDate(changes['minDate'].previousValue, changes['minDate'].currentValue)
1949 ? changes['minDate']
1950 : undefined;
1951 const maxDateChange = changes['maxDate'] &&
1952 !this._dateAdapter.sameDate(changes['maxDate'].previousValue, changes['maxDate'].currentValue)
1953 ? changes['maxDate']
1954 : undefined;
1955 const change = minDateChange || maxDateChange || changes['dateFilter'];
1956 if (change && !change.firstChange) {
1957 const view = this._getCurrentViewComponent();
1958 if (view) {
1959 // We need to `detectChanges` manually here, because the `minDate`, `maxDate` etc. are
1960 // passed down to the view via data bindings which won't be up-to-date when we call `_init`.
1961 this._changeDetectorRef.detectChanges();
1962 view._init();
1963 }
1964 }
1965 this.stateChanges.next();
1966 }
1967 /** Focuses the active date. */
1968 focusActiveCell() {
1969 this._getCurrentViewComponent()._focusActiveCell(false);
1970 }
1971 /** Updates today's date after an update of the active date */
1972 updateTodaysDate() {
1973 this._getCurrentViewComponent()._init();
1974 }
1975 /** Handles date selection in the month view. */
1976 _dateSelected(event) {
1977 const date = event.value;
1978 if (this.selected instanceof DateRange ||
1979 (date && !this._dateAdapter.sameDate(date, this.selected))) {
1980 this.selectedChange.emit(date);
1981 }
1982 this._userSelection.emit(event);
1983 }
1984 /** Handles year selection in the multiyear view. */
1985 _yearSelectedInMultiYearView(normalizedYear) {
1986 this.yearSelected.emit(normalizedYear);
1987 }
1988 /** Handles month selection in the year view. */
1989 _monthSelectedInYearView(normalizedMonth) {
1990 this.monthSelected.emit(normalizedMonth);
1991 }
1992 /** Handles year/month selection in the multi-year/year views. */
1993 _goToDateInView(date, view) {
1994 this.activeDate = date;
1995 this.currentView = view;
1996 }
1997 /** Returns the component instance that corresponds to the current calendar view. */
1998 _getCurrentViewComponent() {
1999 // The return type is explicitly written as a union to ensure that the Closure compiler does
2000 // not optimize calls to _init(). Without the explict return type, TypeScript narrows it to
2001 // only the first component type. See https://github.com/angular/components/issues/22996.
2002 return this.monthView || this.yearView || this.multiYearView;
2003 }
2004}
2005MatCalendar.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatCalendar, deps: [{ token: MatDatepickerIntl }, { token: i1$1.DateAdapter, optional: true }, { token: MAT_DATE_FORMATS, optional: true }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
2006MatCalendar.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.1", type: MatCalendar, selector: "mat-calendar", inputs: { headerComponent: "headerComponent", startAt: "startAt", startView: "startView", selected: "selected", minDate: "minDate", maxDate: "maxDate", dateFilter: "dateFilter", dateClass: "dateClass", comparisonStart: "comparisonStart", comparisonEnd: "comparisonEnd" }, outputs: { selectedChange: "selectedChange", yearSelected: "yearSelected", monthSelected: "monthSelected", viewChanged: "viewChanged", _userSelection: "_userSelection" }, host: { classAttribute: "mat-calendar" }, providers: [MAT_SINGLE_DATE_SELECTION_MODEL_PROVIDER], viewQueries: [{ propertyName: "monthView", first: true, predicate: MatMonthView, descendants: true }, { propertyName: "yearView", first: true, predicate: MatYearView, descendants: true }, { propertyName: "multiYearView", first: true, predicate: MatMultiYearView, descendants: true }], exportAs: ["matCalendar"], usesOnChanges: true, ngImport: i0, template: "<ng-template [cdkPortalOutlet]=\"_calendarHeaderPortal\"></ng-template>\n\n<div class=\"mat-calendar-content\" [ngSwitch]=\"currentView\" cdkMonitorSubtreeFocus tabindex=\"-1\">\n <mat-month-view\n *ngSwitchCase=\"'month'\"\n [(activeDate)]=\"activeDate\"\n [selected]=\"selected\"\n [dateFilter]=\"dateFilter\"\n [maxDate]=\"maxDate\"\n [minDate]=\"minDate\"\n [dateClass]=\"dateClass\"\n [comparisonStart]=\"comparisonStart\"\n [comparisonEnd]=\"comparisonEnd\"\n (_userSelection)=\"_dateSelected($event)\">\n </mat-month-view>\n\n <mat-year-view\n *ngSwitchCase=\"'year'\"\n [(activeDate)]=\"activeDate\"\n [selected]=\"selected\"\n [dateFilter]=\"dateFilter\"\n [maxDate]=\"maxDate\"\n [minDate]=\"minDate\"\n [dateClass]=\"dateClass\"\n (monthSelected)=\"_monthSelectedInYearView($event)\"\n (selectedChange)=\"_goToDateInView($event, 'month')\">\n </mat-year-view>\n\n <mat-multi-year-view\n *ngSwitchCase=\"'multi-year'\"\n [(activeDate)]=\"activeDate\"\n [selected]=\"selected\"\n [dateFilter]=\"dateFilter\"\n [maxDate]=\"maxDate\"\n [minDate]=\"minDate\"\n [dateClass]=\"dateClass\"\n (yearSelected)=\"_yearSelectedInMultiYearView($event)\"\n (selectedChange)=\"_goToDateInView($event, 'year')\">\n </mat-multi-year-view>\n</div>\n", styles: [".mat-calendar{display:block}.mat-calendar-header{padding:8px 8px 0 8px}.mat-calendar-content{padding:0 8px 8px 8px;outline:none}.mat-calendar-controls{display:flex;margin:5% calc(4.7142857143% - 16px)}.mat-calendar-controls .mat-icon-button:hover .mat-button-focus-overlay{opacity:.04}.mat-calendar-spacer{flex:1 1 auto}.mat-calendar-period-button{min-width:0}.mat-calendar-arrow{display:inline-block;width:10px;height:5px;margin:0 0 0 5px;vertical-align:middle}.mat-calendar-arrow.mat-calendar-invert{transform:rotate(180deg)}[dir=rtl] .mat-calendar-arrow{margin:0 5px 0 0}.cdk-high-contrast-active .mat-calendar-arrow{fill:CanvasText}.mat-calendar-previous-button,.mat-calendar-next-button{position:relative}.mat-calendar-previous-button::after,.mat-calendar-next-button::after{top:0;left:0;right:0;bottom:0;position:absolute;content:\"\";margin:15.5px;border:0 solid currentColor;border-top-width:2px}[dir=rtl] .mat-calendar-previous-button,[dir=rtl] .mat-calendar-next-button{transform:rotate(180deg)}.mat-calendar-previous-button::after{border-left-width:2px;transform:translateX(2px) rotate(-45deg)}.mat-calendar-next-button::after{border-right-width:2px;transform:translateX(-2px) rotate(45deg)}.mat-calendar-table{border-spacing:0;border-collapse:collapse;width:100%}.mat-calendar-table-header th{text-align:center;padding:0 0 8px 0}.mat-calendar-table-header-divider{position:relative;height:1px}.mat-calendar-table-header-divider::after{content:\"\";position:absolute;top:0;left:-8px;right:-8px;height:1px}"], dependencies: [{ kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i5.CdkMonitorFocus, selector: "[cdkMonitorElementFocus], [cdkMonitorSubtreeFocus]", outputs: ["cdkFocusChange"] }, { kind: "directive", type: i6.CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }, { kind: "component", type: MatMonthView, selector: "mat-month-view", inputs: ["activeDate", "selected", "minDate", "maxDate", "dateFilter", "dateClass", "comparisonStart", "comparisonEnd"], outputs: ["selectedChange", "_userSelection", "activeDateChange"], exportAs: ["matMonthView"] }, { kind: "component", type: MatYearView, selector: "mat-year-view", inputs: ["activeDate", "selected", "minDate", "maxDate", "dateFilter", "dateClass"], outputs: ["selectedChange", "monthSelected", "activeDateChange"], exportAs: ["matYearView"] }, { kind: "component", type: MatMultiYearView, selector: "mat-multi-year-view", inputs: ["activeDate", "selected", "minDate", "maxDate", "dateFilter", "dateClass"], outputs: ["selectedChange", "yearSelected", "activeDateChange"], exportAs: ["matMultiYearView"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
2007i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatCalendar, decorators: [{
2008 type: Component,
2009 args: [{ selector: 'mat-calendar', host: {
2010 'class': 'mat-calendar',
2011 }, exportAs: 'matCalendar', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, providers: [MAT_SINGLE_DATE_SELECTION_MODEL_PROVIDER], template: "<ng-template [cdkPortalOutlet]=\"_calendarHeaderPortal\"></ng-template>\n\n<div class=\"mat-calendar-content\" [ngSwitch]=\"currentView\" cdkMonitorSubtreeFocus tabindex=\"-1\">\n <mat-month-view\n *ngSwitchCase=\"'month'\"\n [(activeDate)]=\"activeDate\"\n [selected]=\"selected\"\n [dateFilter]=\"dateFilter\"\n [maxDate]=\"maxDate\"\n [minDate]=\"minDate\"\n [dateClass]=\"dateClass\"\n [comparisonStart]=\"comparisonStart\"\n [comparisonEnd]=\"comparisonEnd\"\n (_userSelection)=\"_dateSelected($event)\">\n </mat-month-view>\n\n <mat-year-view\n *ngSwitchCase=\"'year'\"\n [(activeDate)]=\"activeDate\"\n [selected]=\"selected\"\n [dateFilter]=\"dateFilter\"\n [maxDate]=\"maxDate\"\n [minDate]=\"minDate\"\n [dateClass]=\"dateClass\"\n (monthSelected)=\"_monthSelectedInYearView($event)\"\n (selectedChange)=\"_goToDateInView($event, 'month')\">\n </mat-year-view>\n\n <mat-multi-year-view\n *ngSwitchCase=\"'multi-year'\"\n [(activeDate)]=\"activeDate\"\n [selected]=\"selected\"\n [dateFilter]=\"dateFilter\"\n [maxDate]=\"maxDate\"\n [minDate]=\"minDate\"\n [dateClass]=\"dateClass\"\n (yearSelected)=\"_yearSelectedInMultiYearView($event)\"\n (selectedChange)=\"_goToDateInView($event, 'year')\">\n </mat-multi-year-view>\n</div>\n", styles: [".mat-calendar{display:block}.mat-calendar-header{padding:8px 8px 0 8px}.mat-calendar-content{padding:0 8px 8px 8px;outline:none}.mat-calendar-controls{display:flex;margin:5% calc(4.7142857143% - 16px)}.mat-calendar-controls .mat-icon-button:hover .mat-button-focus-overlay{opacity:.04}.mat-calendar-spacer{flex:1 1 auto}.mat-calendar-period-button{min-width:0}.mat-calendar-arrow{display:inline-block;width:10px;height:5px;margin:0 0 0 5px;vertical-align:middle}.mat-calendar-arrow.mat-calendar-invert{transform:rotate(180deg)}[dir=rtl] .mat-calendar-arrow{margin:0 5px 0 0}.cdk-high-contrast-active .mat-calendar-arrow{fill:CanvasText}.mat-calendar-previous-button,.mat-calendar-next-button{position:relative}.mat-calendar-previous-button::after,.mat-calendar-next-button::after{top:0;left:0;right:0;bottom:0;position:absolute;content:\"\";margin:15.5px;border:0 solid currentColor;border-top-width:2px}[dir=rtl] .mat-calendar-previous-button,[dir=rtl] .mat-calendar-next-button{transform:rotate(180deg)}.mat-calendar-previous-button::after{border-left-width:2px;transform:translateX(2px) rotate(-45deg)}.mat-calendar-next-button::after{border-right-width:2px;transform:translateX(-2px) rotate(45deg)}.mat-calendar-table{border-spacing:0;border-collapse:collapse;width:100%}.mat-calendar-table-header th{text-align:center;padding:0 0 8px 0}.mat-calendar-table-header-divider{position:relative;height:1px}.mat-calendar-table-header-divider::after{content:\"\";position:absolute;top:0;left:-8px;right:-8px;height:1px}"] }]
2012 }], ctorParameters: function () {
2013 return [{ type: MatDatepickerIntl }, { type: i1$1.DateAdapter, decorators: [{
2014 type: Optional
2015 }] }, { type: undefined, decorators: [{
2016 type: Optional
2017 }, {
2018 type: Inject,
2019 args: [MAT_DATE_FORMATS]
2020 }] }, { type: i0.ChangeDetectorRef }];
2021 }, propDecorators: { headerComponent: [{
2022 type: Input
2023 }], startAt: [{
2024 type: Input
2025 }], startView: [{
2026 type: Input
2027 }], selected: [{
2028 type: Input
2029 }], minDate: [{
2030 type: Input
2031 }], maxDate: [{
2032 type: Input
2033 }], dateFilter: [{
2034 type: Input
2035 }], dateClass: [{
2036 type: Input
2037 }], comparisonStart: [{
2038 type: Input
2039 }], comparisonEnd: [{
2040 type: Input
2041 }], selectedChange: [{
2042 type: Output
2043 }], yearSelected: [{
2044 type: Output
2045 }], monthSelected: [{
2046 type: Output
2047 }], viewChanged: [{
2048 type: Output
2049 }], _userSelection: [{
2050 type: Output
2051 }], monthView: [{
2052 type: ViewChild,
2053 args: [MatMonthView]
2054 }], yearView: [{
2055 type: ViewChild,
2056 args: [MatYearView]
2057 }], multiYearView: [{
2058 type: ViewChild,
2059 args: [MatMultiYearView]
2060 }] } });
2061
2062/**
2063 * @license
2064 * Copyright Google LLC All Rights Reserved.
2065 *
2066 * Use of this source code is governed by an MIT-style license that can be
2067 * found in the LICENSE file at https://angular.io/license
2068 */
2069/**
2070 * Animations used by the Material datepicker.
2071 * @docs-private
2072 */
2073const matDatepickerAnimations = {
2074 /** Transforms the height of the datepicker's calendar. */
2075 transformPanel: trigger('transformPanel', [
2076 transition('void => enter-dropdown', animate('120ms cubic-bezier(0, 0, 0.2, 1)', keyframes([
2077 style({ opacity: 0, transform: 'scale(1, 0.8)' }),
2078 style({ opacity: 1, transform: 'scale(1, 1)' }),
2079 ]))),
2080 transition('void => enter-dialog', animate('150ms cubic-bezier(0, 0, 0.2, 1)', keyframes([
2081 style({ opacity: 0, transform: 'scale(0.7)' }),
2082 style({ transform: 'none', opacity: 1 }),
2083 ]))),
2084 transition('* => void', animate('100ms linear', style({ opacity: 0 }))),
2085 ]),
2086 /** Fades in the content of the calendar. */
2087 fadeInCalendar: trigger('fadeInCalendar', [
2088 state('void', style({ opacity: 0 })),
2089 state('enter', style({ opacity: 1 })),
2090 // TODO(crisbeto): this animation should be removed since it isn't quite on spec, but we
2091 // need to keep it until #12440 gets in, otherwise the exit animation will look glitchy.
2092 transition('void => *', animate('120ms 100ms cubic-bezier(0.55, 0, 0.55, 0.2)')),
2093 ]),
2094};
2095
2096/** Used to generate a unique ID for each datepicker instance. */
2097let datepickerUid = 0;
2098/** Injection token that determines the scroll handling while the calendar is open. */
2099const MAT_DATEPICKER_SCROLL_STRATEGY = new InjectionToken('mat-datepicker-scroll-strategy');
2100/** @docs-private */
2101function MAT_DATEPICKER_SCROLL_STRATEGY_FACTORY(overlay) {
2102 return () => overlay.scrollStrategies.reposition();
2103}
2104/** @docs-private */
2105const MAT_DATEPICKER_SCROLL_STRATEGY_FACTORY_PROVIDER = {
2106 provide: MAT_DATEPICKER_SCROLL_STRATEGY,
2107 deps: [Overlay],
2108 useFactory: MAT_DATEPICKER_SCROLL_STRATEGY_FACTORY,
2109};
2110// Boilerplate for applying mixins to MatDatepickerContent.
2111/** @docs-private */
2112const _MatDatepickerContentBase = mixinColor(class {
2113 constructor(_elementRef) {
2114 this._elementRef = _elementRef;
2115 }
2116});
2117/**
2118 * Component used as the content for the datepicker overlay. We use this instead of using
2119 * MatCalendar directly as the content so we can control the initial focus. This also gives us a
2120 * place to put additional features of the overlay that are not part of the calendar itself in the
2121 * future. (e.g. confirmation buttons).
2122 * @docs-private
2123 */
2124class MatDatepickerContent extends _MatDatepickerContentBase {
2125 constructor(elementRef, _changeDetectorRef, _globalModel, _dateAdapter, _rangeSelectionStrategy, intl) {
2126 super(elementRef);
2127 this._changeDetectorRef = _changeDetectorRef;
2128 this._globalModel = _globalModel;
2129 this._dateAdapter = _dateAdapter;
2130 this._rangeSelectionStrategy = _rangeSelectionStrategy;
2131 this._subscriptions = new Subscription();
2132 /** Emits when an animation has finished. */
2133 this._animationDone = new Subject();
2134 /** Portal with projected action buttons. */
2135 this._actionsPortal = null;
2136 this._closeButtonText = intl.closeCalendarLabel;
2137 }
2138 ngOnInit() {
2139 this._animationState = this.datepicker.touchUi ? 'enter-dialog' : 'enter-dropdown';
2140 }
2141 ngAfterViewInit() {
2142 this._subscriptions.add(this.datepicker.stateChanges.subscribe(() => {
2143 this._changeDetectorRef.markForCheck();
2144 }));
2145 this._calendar.focusActiveCell();
2146 }
2147 ngOnDestroy() {
2148 this._subscriptions.unsubscribe();
2149 this._animationDone.complete();
2150 }
2151 _handleUserSelection(event) {
2152 const selection = this._model.selection;
2153 const value = event.value;
2154 const isRange = selection instanceof DateRange;
2155 // If we're selecting a range and we have a selection strategy, always pass the value through
2156 // there. Otherwise don't assign null values to the model, unless we're selecting a range.
2157 // A null value when picking a range means that the user cancelled the selection (e.g. by
2158 // pressing escape), whereas when selecting a single value it means that the value didn't
2159 // change. This isn't very intuitive, but it's here for backwards-compatibility.
2160 if (isRange && this._rangeSelectionStrategy) {
2161 const newSelection = this._rangeSelectionStrategy.selectionFinished(value, selection, event.event);
2162 this._model.updateSelection(newSelection, this);
2163 }
2164 else if (value &&
2165 (isRange || !this._dateAdapter.sameDate(value, selection))) {
2166 this._model.add(value);
2167 }
2168 // Delegate closing the overlay to the actions.
2169 if ((!this._model || this._model.isComplete()) && !this._actionsPortal) {
2170 this.datepicker.close();
2171 }
2172 }
2173 _startExitAnimation() {
2174 this._animationState = 'void';
2175 this._changeDetectorRef.markForCheck();
2176 }
2177 _getSelected() {
2178 return this._model.selection;
2179 }
2180 /** Applies the current pending selection to the global model. */
2181 _applyPendingSelection() {
2182 if (this._model !== this._globalModel) {
2183 this._globalModel.updateSelection(this._model.selection, this);
2184 }
2185 }
2186 /**
2187 * Assigns a new portal containing the datepicker actions.
2188 * @param portal Portal with the actions to be assigned.
2189 * @param forceRerender Whether a re-render of the portal should be triggered. This isn't
2190 * necessary if the portal is assigned during initialization, but it may be required if it's
2191 * added at a later point.
2192 */
2193 _assignActions(portal, forceRerender) {
2194 // If we have actions, clone the model so that we have the ability to cancel the selection,
2195 // otherwise update the global model directly. Note that we want to assign this as soon as
2196 // possible, but `_actionsPortal` isn't available in the constructor so we do it in `ngOnInit`.
2197 this._model = portal ? this._globalModel.clone() : this._globalModel;
2198 this._actionsPortal = portal;
2199 if (forceRerender) {
2200 this._changeDetectorRef.detectChanges();
2201 }
2202 }
2203}
2204MatDatepickerContent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDatepickerContent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }, { token: MatDateSelectionModel }, { token: i1$1.DateAdapter }, { token: MAT_DATE_RANGE_SELECTION_STRATEGY, optional: true }, { token: MatDatepickerIntl }], target: i0.ɵɵFactoryTarget.Component });
2205MatDatepickerContent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.1", type: MatDatepickerContent, selector: "mat-datepicker-content", inputs: { color: "color" }, host: { listeners: { "@transformPanel.done": "_animationDone.next()" }, properties: { "@transformPanel": "_animationState", "class.mat-datepicker-content-touch": "datepicker.touchUi" }, classAttribute: "mat-datepicker-content" }, viewQueries: [{ propertyName: "_calendar", first: true, predicate: MatCalendar, descendants: true }], exportAs: ["matDatepickerContent"], usesInheritance: true, ngImport: i0, template: "<div\n cdkTrapFocus\n role=\"dialog\"\n [attr.aria-modal]=\"true\"\n [attr.aria-labelledby]=\"_dialogLabelId ?? undefined\"\n class=\"mat-datepicker-content-container\"\n [class.mat-datepicker-content-container-with-custom-header]=\"datepicker.calendarHeaderComponent\"\n [class.mat-datepicker-content-container-with-actions]=\"_actionsPortal\">\n <mat-calendar\n [id]=\"datepicker.id\"\n [ngClass]=\"datepicker.panelClass\"\n [startAt]=\"datepicker.startAt\"\n [startView]=\"datepicker.startView\"\n [minDate]=\"datepicker._getMinDate()\"\n [maxDate]=\"datepicker._getMaxDate()\"\n [dateFilter]=\"datepicker._getDateFilter()\"\n [headerComponent]=\"datepicker.calendarHeaderComponent\"\n [selected]=\"_getSelected()\"\n [dateClass]=\"datepicker.dateClass\"\n [comparisonStart]=\"comparisonStart\"\n [comparisonEnd]=\"comparisonEnd\"\n [@fadeInCalendar]=\"'enter'\"\n (yearSelected)=\"datepicker._selectYear($event)\"\n (monthSelected)=\"datepicker._selectMonth($event)\"\n (viewChanged)=\"datepicker._viewChanged($event)\"\n (_userSelection)=\"_handleUserSelection($event)\"></mat-calendar>\n\n <ng-template [cdkPortalOutlet]=\"_actionsPortal\"></ng-template>\n\n <!-- Invisible close button for screen reader users. -->\n <button\n type=\"button\"\n mat-raised-button\n [color]=\"color || 'primary'\"\n class=\"mat-datepicker-close-button\"\n [class.cdk-visually-hidden]=\"!_closeButtonFocused\"\n (focus)=\"_closeButtonFocused = true\"\n (blur)=\"_closeButtonFocused = false\"\n (click)=\"datepicker.close()\">{{ _closeButtonText }}</button>\n</div>\n", styles: [".mat-datepicker-content{display:block;border-radius:4px}.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}.mat-datepicker-content-touch{display:block;max-height:80vh;position:relative;overflow:visible}.mat-datepicker-content-touch .mat-datepicker-content-container{min-height:312px;max-height:788px;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:80vh}}@media all and (orientation: portrait){.mat-datepicker-content-touch .mat-datepicker-content-container{width:80vw;height:100vw}.mat-datepicker-content-touch .mat-datepicker-content-container-with-actions{height:115vw}}"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: i3.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "directive", type: i5.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "directive", type: i6.CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }, { kind: "component", type: MatCalendar, selector: "mat-calendar", inputs: ["headerComponent", "startAt", "startView", "selected", "minDate", "maxDate", "dateFilter", "dateClass", "comparisonStart", "comparisonEnd"], outputs: ["selectedChange", "yearSelected", "monthSelected", "viewChanged", "_userSelection"], exportAs: ["matCalendar"] }], animations: [matDatepickerAnimations.transformPanel, matDatepickerAnimations.fadeInCalendar], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
2206i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDatepickerContent, decorators: [{
2207 type: Component,
2208 args: [{ selector: 'mat-datepicker-content', host: {
2209 'class': 'mat-datepicker-content',
2210 '[@transformPanel]': '_animationState',
2211 '(@transformPanel.done)': '_animationDone.next()',
2212 '[class.mat-datepicker-content-touch]': 'datepicker.touchUi',
2213 }, animations: [matDatepickerAnimations.transformPanel, matDatepickerAnimations.fadeInCalendar], exportAs: 'matDatepickerContent', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, inputs: ['color'], template: "<div\n cdkTrapFocus\n role=\"dialog\"\n [attr.aria-modal]=\"true\"\n [attr.aria-labelledby]=\"_dialogLabelId ?? undefined\"\n class=\"mat-datepicker-content-container\"\n [class.mat-datepicker-content-container-with-custom-header]=\"datepicker.calendarHeaderComponent\"\n [class.mat-datepicker-content-container-with-actions]=\"_actionsPortal\">\n <mat-calendar\n [id]=\"datepicker.id\"\n [ngClass]=\"datepicker.panelClass\"\n [startAt]=\"datepicker.startAt\"\n [startView]=\"datepicker.startView\"\n [minDate]=\"datepicker._getMinDate()\"\n [maxDate]=\"datepicker._getMaxDate()\"\n [dateFilter]=\"datepicker._getDateFilter()\"\n [headerComponent]=\"datepicker.calendarHeaderComponent\"\n [selected]=\"_getSelected()\"\n [dateClass]=\"datepicker.dateClass\"\n [comparisonStart]=\"comparisonStart\"\n [comparisonEnd]=\"comparisonEnd\"\n [@fadeInCalendar]=\"'enter'\"\n (yearSelected)=\"datepicker._selectYear($event)\"\n (monthSelected)=\"datepicker._selectMonth($event)\"\n (viewChanged)=\"datepicker._viewChanged($event)\"\n (_userSelection)=\"_handleUserSelection($event)\"></mat-calendar>\n\n <ng-template [cdkPortalOutlet]=\"_actionsPortal\"></ng-template>\n\n <!-- Invisible close button for screen reader users. -->\n <button\n type=\"button\"\n mat-raised-button\n [color]=\"color || 'primary'\"\n class=\"mat-datepicker-close-button\"\n [class.cdk-visually-hidden]=\"!_closeButtonFocused\"\n (focus)=\"_closeButtonFocused = true\"\n (blur)=\"_closeButtonFocused = false\"\n (click)=\"datepicker.close()\">{{ _closeButtonText }}</button>\n</div>\n", styles: [".mat-datepicker-content{display:block;border-radius:4px}.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}.mat-datepicker-content-touch{display:block;max-height:80vh;position:relative;overflow:visible}.mat-datepicker-content-touch .mat-datepicker-content-container{min-height:312px;max-height:788px;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:80vh}}@media all and (orientation: portrait){.mat-datepicker-content-touch .mat-datepicker-content-container{width:80vw;height:100vw}.mat-datepicker-content-touch .mat-datepicker-content-container-with-actions{height:115vw}}"] }]
2214 }], ctorParameters: function () {
2215 return [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }, { type: MatDateSelectionModel }, { type: i1$1.DateAdapter }, { type: undefined, decorators: [{
2216 type: Optional
2217 }, {
2218 type: Inject,
2219 args: [MAT_DATE_RANGE_SELECTION_STRATEGY]
2220 }] }, { type: MatDatepickerIntl }];
2221 }, propDecorators: { _calendar: [{
2222 type: ViewChild,
2223 args: [MatCalendar]
2224 }] } });
2225/** Base class for a datepicker. */
2226class MatDatepickerBase {
2227 constructor(_overlay, _ngZone, _viewContainerRef, scrollStrategy, _dateAdapter, _dir, _model) {
2228 this._overlay = _overlay;
2229 this._ngZone = _ngZone;
2230 this._viewContainerRef = _viewContainerRef;
2231 this._dateAdapter = _dateAdapter;
2232 this._dir = _dir;
2233 this._model = _model;
2234 this._inputStateChanges = Subscription.EMPTY;
2235 /** The view that the calendar should start in. */
2236 this.startView = 'month';
2237 this._touchUi = false;
2238 /** Preferred position of the datepicker in the X axis. */
2239 this.xPosition = 'start';
2240 /** Preferred position of the datepicker in the Y axis. */
2241 this.yPosition = 'below';
2242 this._restoreFocus = true;
2243 /**
2244 * Emits selected year in multiyear view.
2245 * This doesn't imply a change on the selected date.
2246 */
2247 this.yearSelected = new EventEmitter();
2248 /**
2249 * Emits selected month in year view.
2250 * This doesn't imply a change on the selected date.
2251 */
2252 this.monthSelected = new EventEmitter();
2253 /**
2254 * Emits when the current view changes.
2255 */
2256 this.viewChanged = new EventEmitter(true);
2257 /** Emits when the datepicker has been opened. */
2258 this.openedStream = new EventEmitter();
2259 /** Emits when the datepicker has been closed. */
2260 this.closedStream = new EventEmitter();
2261 this._opened = false;
2262 /** The id for the datepicker calendar. */
2263 this.id = `mat-datepicker-${datepickerUid++}`;
2264 /** The element that was focused before the datepicker was opened. */
2265 this._focusedElementBeforeOpen = null;
2266 /** Unique class that will be added to the backdrop so that the test harnesses can look it up. */
2267 this._backdropHarnessClass = `${this.id}-backdrop`;
2268 /** Emits when the datepicker's state changes. */
2269 this.stateChanges = new Subject();
2270 if (!this._dateAdapter && (typeof ngDevMode === 'undefined' || ngDevMode)) {
2271 throw createMissingDateImplError('DateAdapter');
2272 }
2273 this._scrollStrategy = scrollStrategy;
2274 }
2275 /** The date to open the calendar to initially. */
2276 get startAt() {
2277 // If an explicit startAt is set we start there, otherwise we start at whatever the currently
2278 // selected value is.
2279 return this._startAt || (this.datepickerInput ? this.datepickerInput.getStartValue() : null);
2280 }
2281 set startAt(value) {
2282 this._startAt = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value));
2283 }
2284 /** Color palette to use on the datepicker's calendar. */
2285 get color() {
2286 return (this._color || (this.datepickerInput ? this.datepickerInput.getThemePalette() : undefined));
2287 }
2288 set color(value) {
2289 this._color = value;
2290 }
2291 /**
2292 * Whether the calendar UI is in touch mode. In touch mode the calendar opens in a dialog rather
2293 * than a dropdown and elements have more padding to allow for bigger touch targets.
2294 */
2295 get touchUi() {
2296 return this._touchUi;
2297 }
2298 set touchUi(value) {
2299 this._touchUi = coerceBooleanProperty(value);
2300 }
2301 /** Whether the datepicker pop-up should be disabled. */
2302 get disabled() {
2303 return this._disabled === undefined && this.datepickerInput
2304 ? this.datepickerInput.disabled
2305 : !!this._disabled;
2306 }
2307 set disabled(value) {
2308 const newValue = coerceBooleanProperty(value);
2309 if (newValue !== this._disabled) {
2310 this._disabled = newValue;
2311 this.stateChanges.next(undefined);
2312 }
2313 }
2314 /**
2315 * Whether to restore focus to the previously-focused element when the calendar is closed.
2316 * Note that automatic focus restoration is an accessibility feature and it is recommended that
2317 * you provide your own equivalent, if you decide to turn it off.
2318 */
2319 get restoreFocus() {
2320 return this._restoreFocus;
2321 }
2322 set restoreFocus(value) {
2323 this._restoreFocus = coerceBooleanProperty(value);
2324 }
2325 /**
2326 * Classes to be passed to the date picker panel.
2327 * Supports string and string array values, similar to `ngClass`.
2328 */
2329 get panelClass() {
2330 return this._panelClass;
2331 }
2332 set panelClass(value) {
2333 this._panelClass = coerceStringArray(value);
2334 }
2335 /** Whether the calendar is open. */
2336 get opened() {
2337 return this._opened;
2338 }
2339 set opened(value) {
2340 coerceBooleanProperty(value) ? this.open() : this.close();
2341 }
2342 /** The minimum selectable date. */
2343 _getMinDate() {
2344 return this.datepickerInput && this.datepickerInput.min;
2345 }
2346 /** The maximum selectable date. */
2347 _getMaxDate() {
2348 return this.datepickerInput && this.datepickerInput.max;
2349 }
2350 _getDateFilter() {
2351 return this.datepickerInput && this.datepickerInput.dateFilter;
2352 }
2353 ngOnChanges(changes) {
2354 const positionChange = changes['xPosition'] || changes['yPosition'];
2355 if (positionChange && !positionChange.firstChange && this._overlayRef) {
2356 const positionStrategy = this._overlayRef.getConfig().positionStrategy;
2357 if (positionStrategy instanceof FlexibleConnectedPositionStrategy) {
2358 this._setConnectedPositions(positionStrategy);
2359 if (this.opened) {
2360 this._overlayRef.updatePosition();
2361 }
2362 }
2363 }
2364 this.stateChanges.next(undefined);
2365 }
2366 ngOnDestroy() {
2367 this._destroyOverlay();
2368 this.close();
2369 this._inputStateChanges.unsubscribe();
2370 this.stateChanges.complete();
2371 }
2372 /** Selects the given date */
2373 select(date) {
2374 this._model.add(date);
2375 }
2376 /** Emits the selected year in multiyear view */
2377 _selectYear(normalizedYear) {
2378 this.yearSelected.emit(normalizedYear);
2379 }
2380 /** Emits selected month in year view */
2381 _selectMonth(normalizedMonth) {
2382 this.monthSelected.emit(normalizedMonth);
2383 }
2384 /** Emits changed view */
2385 _viewChanged(view) {
2386 this.viewChanged.emit(view);
2387 }
2388 /**
2389 * Register an input with this datepicker.
2390 * @param input The datepicker input to register with this datepicker.
2391 * @returns Selection model that the input should hook itself up to.
2392 */
2393 registerInput(input) {
2394 if (this.datepickerInput && (typeof ngDevMode === 'undefined' || ngDevMode)) {
2395 throw Error('A MatDatepicker can only be associated with a single input.');
2396 }
2397 this._inputStateChanges.unsubscribe();
2398 this.datepickerInput = input;
2399 this._inputStateChanges = input.stateChanges.subscribe(() => this.stateChanges.next(undefined));
2400 return this._model;
2401 }
2402 /**
2403 * Registers a portal containing action buttons with the datepicker.
2404 * @param portal Portal to be registered.
2405 */
2406 registerActions(portal) {
2407 var _a;
2408 if (this._actionsPortal && (typeof ngDevMode === 'undefined' || ngDevMode)) {
2409 throw Error('A MatDatepicker can only be associated with a single actions row.');
2410 }
2411 this._actionsPortal = portal;
2412 (_a = this._componentRef) === null || _a === void 0 ? void 0 : _a.instance._assignActions(portal, true);
2413 }
2414 /**
2415 * Removes a portal containing action buttons from the datepicker.
2416 * @param portal Portal to be removed.
2417 */
2418 removeActions(portal) {
2419 var _a;
2420 if (portal === this._actionsPortal) {
2421 this._actionsPortal = null;
2422 (_a = this._componentRef) === null || _a === void 0 ? void 0 : _a.instance._assignActions(null, true);
2423 }
2424 }
2425 /** Open the calendar. */
2426 open() {
2427 if (this._opened || this.disabled) {
2428 return;
2429 }
2430 if (!this.datepickerInput && (typeof ngDevMode === 'undefined' || ngDevMode)) {
2431 throw Error('Attempted to open an MatDatepicker with no associated input.');
2432 }
2433 this._focusedElementBeforeOpen = _getFocusedElementPierceShadowDom();
2434 this._openOverlay();
2435 this._opened = true;
2436 this.openedStream.emit();
2437 }
2438 /** Close the calendar. */
2439 close() {
2440 if (!this._opened) {
2441 return;
2442 }
2443 if (this._componentRef) {
2444 const instance = this._componentRef.instance;
2445 instance._startExitAnimation();
2446 instance._animationDone.pipe(take(1)).subscribe(() => this._destroyOverlay());
2447 }
2448 const completeClose = () => {
2449 // The `_opened` could've been reset already if
2450 // we got two events in quick succession.
2451 if (this._opened) {
2452 this._opened = false;
2453 this.closedStream.emit();
2454 this._focusedElementBeforeOpen = null;
2455 }
2456 };
2457 if (this._restoreFocus &&
2458 this._focusedElementBeforeOpen &&
2459 typeof this._focusedElementBeforeOpen.focus === 'function') {
2460 // Because IE moves focus asynchronously, we can't count on it being restored before we've
2461 // marked the datepicker as closed. If the event fires out of sequence and the element that
2462 // we're refocusing opens the datepicker on focus, the user could be stuck with not being
2463 // able to close the calendar at all. We work around it by making the logic, that marks
2464 // the datepicker as closed, async as well.
2465 this._focusedElementBeforeOpen.focus();
2466 setTimeout(completeClose);
2467 }
2468 else {
2469 completeClose();
2470 }
2471 }
2472 /** Applies the current pending selection on the overlay to the model. */
2473 _applyPendingSelection() {
2474 var _a, _b;
2475 (_b = (_a = this._componentRef) === null || _a === void 0 ? void 0 : _a.instance) === null || _b === void 0 ? void 0 : _b._applyPendingSelection();
2476 }
2477 /** Forwards relevant values from the datepicker to the datepicker content inside the overlay. */
2478 _forwardContentValues(instance) {
2479 instance.datepicker = this;
2480 instance.color = this.color;
2481 instance._dialogLabelId = this.datepickerInput.getOverlayLabelId();
2482 instance._assignActions(this._actionsPortal, false);
2483 }
2484 /** Opens the overlay with the calendar. */
2485 _openOverlay() {
2486 this._destroyOverlay();
2487 const isDialog = this.touchUi;
2488 const portal = new ComponentPortal(MatDatepickerContent, this._viewContainerRef);
2489 const overlayRef = (this._overlayRef = this._overlay.create(new OverlayConfig({
2490 positionStrategy: isDialog ? this._getDialogStrategy() : this._getDropdownStrategy(),
2491 hasBackdrop: true,
2492 backdropClass: [
2493 isDialog ? 'cdk-overlay-dark-backdrop' : 'mat-overlay-transparent-backdrop',
2494 this._backdropHarnessClass,
2495 ],
2496 direction: this._dir,
2497 scrollStrategy: isDialog ? this._overlay.scrollStrategies.block() : this._scrollStrategy(),
2498 panelClass: `mat-datepicker-${isDialog ? 'dialog' : 'popup'}`,
2499 })));
2500 this._getCloseStream(overlayRef).subscribe(event => {
2501 if (event) {
2502 event.preventDefault();
2503 }
2504 this.close();
2505 });
2506 // The `preventDefault` call happens inside the calendar as well, however focus moves into
2507 // it inside a timeout which can give browsers a chance to fire off a keyboard event in-between
2508 // that can scroll the page (see #24969). Always block default actions of arrow keys for the
2509 // entire overlay so the page doesn't get scrolled by accident.
2510 overlayRef.keydownEvents().subscribe(event => {
2511 const keyCode = event.keyCode;
2512 if (keyCode === UP_ARROW ||
2513 keyCode === DOWN_ARROW ||
2514 keyCode === LEFT_ARROW ||
2515 keyCode === RIGHT_ARROW ||
2516 keyCode === PAGE_UP ||
2517 keyCode === PAGE_DOWN) {
2518 event.preventDefault();
2519 }
2520 });
2521 this._componentRef = overlayRef.attach(portal);
2522 this._forwardContentValues(this._componentRef.instance);
2523 // Update the position once the calendar has rendered. Only relevant in dropdown mode.
2524 if (!isDialog) {
2525 this._ngZone.onStable.pipe(take(1)).subscribe(() => overlayRef.updatePosition());
2526 }
2527 }
2528 /** Destroys the current overlay. */
2529 _destroyOverlay() {
2530 if (this._overlayRef) {
2531 this._overlayRef.dispose();
2532 this._overlayRef = this._componentRef = null;
2533 }
2534 }
2535 /** Gets a position strategy that will open the calendar as a dropdown. */
2536 _getDialogStrategy() {
2537 return this._overlay.position().global().centerHorizontally().centerVertically();
2538 }
2539 /** Gets a position strategy that will open the calendar as a dropdown. */
2540 _getDropdownStrategy() {
2541 const strategy = this._overlay
2542 .position()
2543 .flexibleConnectedTo(this.datepickerInput.getConnectedOverlayOrigin())
2544 .withTransformOriginOn('.mat-datepicker-content')
2545 .withFlexibleDimensions(false)
2546 .withViewportMargin(8)
2547 .withLockedPosition();
2548 return this._setConnectedPositions(strategy);
2549 }
2550 /** Sets the positions of the datepicker in dropdown mode based on the current configuration. */
2551 _setConnectedPositions(strategy) {
2552 const primaryX = this.xPosition === 'end' ? 'end' : 'start';
2553 const secondaryX = primaryX === 'start' ? 'end' : 'start';
2554 const primaryY = this.yPosition === 'above' ? 'bottom' : 'top';
2555 const secondaryY = primaryY === 'top' ? 'bottom' : 'top';
2556 return strategy.withPositions([
2557 {
2558 originX: primaryX,
2559 originY: secondaryY,
2560 overlayX: primaryX,
2561 overlayY: primaryY,
2562 },
2563 {
2564 originX: primaryX,
2565 originY: primaryY,
2566 overlayX: primaryX,
2567 overlayY: secondaryY,
2568 },
2569 {
2570 originX: secondaryX,
2571 originY: secondaryY,
2572 overlayX: secondaryX,
2573 overlayY: primaryY,
2574 },
2575 {
2576 originX: secondaryX,
2577 originY: primaryY,
2578 overlayX: secondaryX,
2579 overlayY: secondaryY,
2580 },
2581 ]);
2582 }
2583 /** Gets an observable that will emit when the overlay is supposed to be closed. */
2584 _getCloseStream(overlayRef) {
2585 return merge(overlayRef.backdropClick(), overlayRef.detachments(), overlayRef.keydownEvents().pipe(filter(event => {
2586 // Closing on alt + up is only valid when there's an input associated with the datepicker.
2587 return ((event.keyCode === ESCAPE && !hasModifierKey(event)) ||
2588 (this.datepickerInput && hasModifierKey(event, 'altKey') && event.keyCode === UP_ARROW));
2589 })));
2590 }
2591}
2592MatDatepickerBase.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDatepickerBase, deps: [{ token: i9.Overlay }, { token: i0.NgZone }, { token: i0.ViewContainerRef }, { token: MAT_DATEPICKER_SCROLL_STRATEGY }, { token: i1$1.DateAdapter, optional: true }, { token: i2.Directionality, optional: true }, { token: MatDateSelectionModel }], target: i0.ɵɵFactoryTarget.Directive });
2593MatDatepickerBase.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.1", type: MatDatepickerBase, inputs: { calendarHeaderComponent: "calendarHeaderComponent", startAt: "startAt", startView: "startView", color: "color", touchUi: "touchUi", disabled: "disabled", xPosition: "xPosition", yPosition: "yPosition", restoreFocus: "restoreFocus", dateClass: "dateClass", panelClass: "panelClass", opened: "opened" }, outputs: { yearSelected: "yearSelected", monthSelected: "monthSelected", viewChanged: "viewChanged", openedStream: "opened", closedStream: "closed" }, usesOnChanges: true, ngImport: i0 });
2594i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDatepickerBase, decorators: [{
2595 type: Directive
2596 }], ctorParameters: function () {
2597 return [{ type: i9.Overlay }, { type: i0.NgZone }, { type: i0.ViewContainerRef }, { type: undefined, decorators: [{
2598 type: Inject,
2599 args: [MAT_DATEPICKER_SCROLL_STRATEGY]
2600 }] }, { type: i1$1.DateAdapter, decorators: [{
2601 type: Optional
2602 }] }, { type: i2.Directionality, decorators: [{
2603 type: Optional
2604 }] }, { type: MatDateSelectionModel }];
2605 }, propDecorators: { calendarHeaderComponent: [{
2606 type: Input
2607 }], startAt: [{
2608 type: Input
2609 }], startView: [{
2610 type: Input
2611 }], color: [{
2612 type: Input
2613 }], touchUi: [{
2614 type: Input
2615 }], disabled: [{
2616 type: Input
2617 }], xPosition: [{
2618 type: Input
2619 }], yPosition: [{
2620 type: Input
2621 }], restoreFocus: [{
2622 type: Input
2623 }], yearSelected: [{
2624 type: Output
2625 }], monthSelected: [{
2626 type: Output
2627 }], viewChanged: [{
2628 type: Output
2629 }], dateClass: [{
2630 type: Input
2631 }], openedStream: [{
2632 type: Output,
2633 args: ['opened']
2634 }], closedStream: [{
2635 type: Output,
2636 args: ['closed']
2637 }], panelClass: [{
2638 type: Input
2639 }], opened: [{
2640 type: Input
2641 }] } });
2642
2643/**
2644 * @license
2645 * Copyright Google LLC All Rights Reserved.
2646 *
2647 * Use of this source code is governed by an MIT-style license that can be
2648 * found in the LICENSE file at https://angular.io/license
2649 */
2650// TODO(mmalerba): We use a component instead of a directive here so the user can use implicit
2651// template reference variables (e.g. #d vs #d="matDatepicker"). We can change this to a directive
2652// if angular adds support for `exportAs: '$implicit'` on directives.
2653/** Component responsible for managing the datepicker popup/dialog. */
2654class MatDatepicker extends MatDatepickerBase {
2655}
2656MatDatepicker.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDatepicker, deps: null, target: i0.ɵɵFactoryTarget.Component });
2657MatDatepicker.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.1", type: MatDatepicker, selector: "mat-datepicker", providers: [
2658 MAT_SINGLE_DATE_SELECTION_MODEL_PROVIDER,
2659 { provide: MatDatepickerBase, useExisting: MatDatepicker },
2660 ], exportAs: ["matDatepicker"], usesInheritance: true, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
2661i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDatepicker, decorators: [{
2662 type: Component,
2663 args: [{
2664 selector: 'mat-datepicker',
2665 template: '',
2666 exportAs: 'matDatepicker',
2667 changeDetection: ChangeDetectionStrategy.OnPush,
2668 encapsulation: ViewEncapsulation.None,
2669 providers: [
2670 MAT_SINGLE_DATE_SELECTION_MODEL_PROVIDER,
2671 { provide: MatDatepickerBase, useExisting: MatDatepicker },
2672 ],
2673 }]
2674 }] });
2675
2676/**
2677 * @license
2678 * Copyright Google LLC All Rights Reserved.
2679 *
2680 * Use of this source code is governed by an MIT-style license that can be
2681 * found in the LICENSE file at https://angular.io/license
2682 */
2683/**
2684 * An event used for datepicker input and change events. We don't always have access to a native
2685 * input or change event because the event may have been triggered by the user clicking on the
2686 * calendar popup. For consistency, we always use MatDatepickerInputEvent instead.
2687 */
2688class MatDatepickerInputEvent {
2689 constructor(
2690 /** Reference to the datepicker input component that emitted the event. */
2691 target,
2692 /** Reference to the native input element associated with the datepicker input. */
2693 targetElement) {
2694 this.target = target;
2695 this.targetElement = targetElement;
2696 this.value = this.target.value;
2697 }
2698}
2699/** Base class for datepicker inputs. */
2700class MatDatepickerInputBase {
2701 constructor(_elementRef, _dateAdapter, _dateFormats) {
2702 this._elementRef = _elementRef;
2703 this._dateAdapter = _dateAdapter;
2704 this._dateFormats = _dateFormats;
2705 /** Emits when a `change` event is fired on this `<input>`. */
2706 this.dateChange = new EventEmitter();
2707 /** Emits when an `input` event is fired on this `<input>`. */
2708 this.dateInput = new EventEmitter();
2709 /** Emits when the internal state has changed */
2710 this.stateChanges = new Subject();
2711 this._onTouched = () => { };
2712 this._validatorOnChange = () => { };
2713 this._cvaOnChange = () => { };
2714 this._valueChangesSubscription = Subscription.EMPTY;
2715 this._localeSubscription = Subscription.EMPTY;
2716 /** The form control validator for whether the input parses. */
2717 this._parseValidator = () => {
2718 return this._lastValueValid
2719 ? null
2720 : { 'matDatepickerParse': { 'text': this._elementRef.nativeElement.value } };
2721 };
2722 /** The form control validator for the date filter. */
2723 this._filterValidator = (control) => {
2724 const controlValue = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(control.value));
2725 return !controlValue || this._matchesFilter(controlValue)
2726 ? null
2727 : { 'matDatepickerFilter': true };
2728 };
2729 /** The form control validator for the min date. */
2730 this._minValidator = (control) => {
2731 const controlValue = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(control.value));
2732 const min = this._getMinDate();
2733 return !min || !controlValue || this._dateAdapter.compareDate(min, controlValue) <= 0
2734 ? null
2735 : { 'matDatepickerMin': { 'min': min, 'actual': controlValue } };
2736 };
2737 /** The form control validator for the max date. */
2738 this._maxValidator = (control) => {
2739 const controlValue = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(control.value));
2740 const max = this._getMaxDate();
2741 return !max || !controlValue || this._dateAdapter.compareDate(max, controlValue) >= 0
2742 ? null
2743 : { 'matDatepickerMax': { 'max': max, 'actual': controlValue } };
2744 };
2745 /** Whether the last value set on the input was valid. */
2746 this._lastValueValid = false;
2747 if (typeof ngDevMode === 'undefined' || ngDevMode) {
2748 if (!this._dateAdapter) {
2749 throw createMissingDateImplError('DateAdapter');
2750 }
2751 if (!this._dateFormats) {
2752 throw createMissingDateImplError('MAT_DATE_FORMATS');
2753 }
2754 }
2755 // Update the displayed date when the locale changes.
2756 this._localeSubscription = _dateAdapter.localeChanges.subscribe(() => {
2757 this._assignValueProgrammatically(this.value);
2758 });
2759 }
2760 /** The value of the input. */
2761 get value() {
2762 return this._model ? this._getValueFromModel(this._model.selection) : this._pendingValue;
2763 }
2764 set value(value) {
2765 this._assignValueProgrammatically(value);
2766 }
2767 /** Whether the datepicker-input is disabled. */
2768 get disabled() {
2769 return !!this._disabled || this._parentDisabled();
2770 }
2771 set disabled(value) {
2772 const newValue = coerceBooleanProperty(value);
2773 const element = this._elementRef.nativeElement;
2774 if (this._disabled !== newValue) {
2775 this._disabled = newValue;
2776 this.stateChanges.next(undefined);
2777 }
2778 // We need to null check the `blur` method, because it's undefined during SSR.
2779 // In Ivy static bindings are invoked earlier, before the element is attached to the DOM.
2780 // This can cause an error to be thrown in some browsers (IE/Edge) which assert that the
2781 // element has been inserted.
2782 if (newValue && this._isInitialized && element.blur) {
2783 // Normally, native input elements automatically blur if they turn disabled. This behavior
2784 // is problematic, because it would mean that it triggers another change detection cycle,
2785 // which then causes a changed after checked error if the input element was focused before.
2786 element.blur();
2787 }
2788 }
2789 /** Gets the base validator functions. */
2790 _getValidators() {
2791 return [this._parseValidator, this._minValidator, this._maxValidator, this._filterValidator];
2792 }
2793 /** Registers a date selection model with the input. */
2794 _registerModel(model) {
2795 this._model = model;
2796 this._valueChangesSubscription.unsubscribe();
2797 if (this._pendingValue) {
2798 this._assignValue(this._pendingValue);
2799 }
2800 this._valueChangesSubscription = this._model.selectionChanged.subscribe(event => {
2801 if (this._shouldHandleChangeEvent(event)) {
2802 const value = this._getValueFromModel(event.selection);
2803 this._lastValueValid = this._isValidValue(value);
2804 this._cvaOnChange(value);
2805 this._onTouched();
2806 this._formatValue(value);
2807 this.dateInput.emit(new MatDatepickerInputEvent(this, this._elementRef.nativeElement));
2808 this.dateChange.emit(new MatDatepickerInputEvent(this, this._elementRef.nativeElement));
2809 }
2810 });
2811 }
2812 ngAfterViewInit() {
2813 this._isInitialized = true;
2814 }
2815 ngOnChanges(changes) {
2816 if (dateInputsHaveChanged(changes, this._dateAdapter)) {
2817 this.stateChanges.next(undefined);
2818 }
2819 }
2820 ngOnDestroy() {
2821 this._valueChangesSubscription.unsubscribe();
2822 this._localeSubscription.unsubscribe();
2823 this.stateChanges.complete();
2824 }
2825 /** @docs-private */
2826 registerOnValidatorChange(fn) {
2827 this._validatorOnChange = fn;
2828 }
2829 /** @docs-private */
2830 validate(c) {
2831 return this._validator ? this._validator(c) : null;
2832 }
2833 // Implemented as part of ControlValueAccessor.
2834 writeValue(value) {
2835 this._assignValueProgrammatically(value);
2836 }
2837 // Implemented as part of ControlValueAccessor.
2838 registerOnChange(fn) {
2839 this._cvaOnChange = fn;
2840 }
2841 // Implemented as part of ControlValueAccessor.
2842 registerOnTouched(fn) {
2843 this._onTouched = fn;
2844 }
2845 // Implemented as part of ControlValueAccessor.
2846 setDisabledState(isDisabled) {
2847 this.disabled = isDisabled;
2848 }
2849 _onKeydown(event) {
2850 const isAltDownArrow = event.altKey && event.keyCode === DOWN_ARROW;
2851 if (isAltDownArrow && !this._elementRef.nativeElement.readOnly) {
2852 this._openPopup();
2853 event.preventDefault();
2854 }
2855 }
2856 _onInput(value) {
2857 const lastValueWasValid = this._lastValueValid;
2858 let date = this._dateAdapter.parse(value, this._dateFormats.parse.dateInput);
2859 this._lastValueValid = this._isValidValue(date);
2860 date = this._dateAdapter.getValidDateOrNull(date);
2861 const hasChanged = !this._dateAdapter.sameDate(date, this.value);
2862 // We need to fire the CVA change event for all
2863 // nulls, otherwise the validators won't run.
2864 if (!date || hasChanged) {
2865 this._cvaOnChange(date);
2866 }
2867 else {
2868 // Call the CVA change handler for invalid values
2869 // since this is what marks the control as dirty.
2870 if (value && !this.value) {
2871 this._cvaOnChange(date);
2872 }
2873 if (lastValueWasValid !== this._lastValueValid) {
2874 this._validatorOnChange();
2875 }
2876 }
2877 if (hasChanged) {
2878 this._assignValue(date);
2879 this.dateInput.emit(new MatDatepickerInputEvent(this, this._elementRef.nativeElement));
2880 }
2881 }
2882 _onChange() {
2883 this.dateChange.emit(new MatDatepickerInputEvent(this, this._elementRef.nativeElement));
2884 }
2885 /** Handles blur events on the input. */
2886 _onBlur() {
2887 // Reformat the input only if we have a valid value.
2888 if (this.value) {
2889 this._formatValue(this.value);
2890 }
2891 this._onTouched();
2892 }
2893 /** Formats a value and sets it on the input element. */
2894 _formatValue(value) {
2895 this._elementRef.nativeElement.value =
2896 value != null ? this._dateAdapter.format(value, this._dateFormats.display.dateInput) : '';
2897 }
2898 /** Assigns a value to the model. */
2899 _assignValue(value) {
2900 // We may get some incoming values before the model was
2901 // assigned. Save the value so that we can assign it later.
2902 if (this._model) {
2903 this._assignValueToModel(value);
2904 this._pendingValue = null;
2905 }
2906 else {
2907 this._pendingValue = value;
2908 }
2909 }
2910 /** Whether a value is considered valid. */
2911 _isValidValue(value) {
2912 return !value || this._dateAdapter.isValid(value);
2913 }
2914 /**
2915 * Checks whether a parent control is disabled. This is in place so that it can be overridden
2916 * by inputs extending this one which can be placed inside of a group that can be disabled.
2917 */
2918 _parentDisabled() {
2919 return false;
2920 }
2921 /** Programmatically assigns a value to the input. */
2922 _assignValueProgrammatically(value) {
2923 value = this._dateAdapter.deserialize(value);
2924 this._lastValueValid = this._isValidValue(value);
2925 value = this._dateAdapter.getValidDateOrNull(value);
2926 this._assignValue(value);
2927 this._formatValue(value);
2928 }
2929 /** Gets whether a value matches the current date filter. */
2930 _matchesFilter(value) {
2931 const filter = this._getDateFilter();
2932 return !filter || filter(value);
2933 }
2934}
2935MatDatepickerInputBase.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDatepickerInputBase, deps: [{ token: i0.ElementRef }, { token: i1$1.DateAdapter, optional: true }, { token: MAT_DATE_FORMATS, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
2936MatDatepickerInputBase.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.1", type: MatDatepickerInputBase, inputs: { value: "value", disabled: "disabled" }, outputs: { dateChange: "dateChange", dateInput: "dateInput" }, usesOnChanges: true, ngImport: i0 });
2937i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDatepickerInputBase, decorators: [{
2938 type: Directive
2939 }], ctorParameters: function () {
2940 return [{ type: i0.ElementRef }, { type: i1$1.DateAdapter, decorators: [{
2941 type: Optional
2942 }] }, { type: undefined, decorators: [{
2943 type: Optional
2944 }, {
2945 type: Inject,
2946 args: [MAT_DATE_FORMATS]
2947 }] }];
2948 }, propDecorators: { value: [{
2949 type: Input
2950 }], disabled: [{
2951 type: Input
2952 }], dateChange: [{
2953 type: Output
2954 }], dateInput: [{
2955 type: Output
2956 }] } });
2957/**
2958 * Checks whether the `SimpleChanges` object from an `ngOnChanges`
2959 * callback has any changes, accounting for date objects.
2960 */
2961function dateInputsHaveChanged(changes, adapter) {
2962 const keys = Object.keys(changes);
2963 for (let key of keys) {
2964 const { previousValue, currentValue } = changes[key];
2965 if (adapter.isDateInstance(previousValue) && adapter.isDateInstance(currentValue)) {
2966 if (!adapter.sameDate(previousValue, currentValue)) {
2967 return true;
2968 }
2969 }
2970 else {
2971 return true;
2972 }
2973 }
2974 return false;
2975}
2976
2977/**
2978 * @license
2979 * Copyright Google LLC All Rights Reserved.
2980 *
2981 * Use of this source code is governed by an MIT-style license that can be
2982 * found in the LICENSE file at https://angular.io/license
2983 */
2984/** @docs-private */
2985const MAT_DATEPICKER_VALUE_ACCESSOR = {
2986 provide: NG_VALUE_ACCESSOR,
2987 useExisting: forwardRef(() => MatDatepickerInput),
2988 multi: true,
2989};
2990/** @docs-private */
2991const MAT_DATEPICKER_VALIDATORS = {
2992 provide: NG_VALIDATORS,
2993 useExisting: forwardRef(() => MatDatepickerInput),
2994 multi: true,
2995};
2996/** Directive used to connect an input to a MatDatepicker. */
2997class MatDatepickerInput extends MatDatepickerInputBase {
2998 constructor(elementRef, dateAdapter, dateFormats, _formField) {
2999 super(elementRef, dateAdapter, dateFormats);
3000 this._formField = _formField;
3001 this._closedSubscription = Subscription.EMPTY;
3002 this._validator = Validators.compose(super._getValidators());
3003 }
3004 /** The datepicker that this input is associated with. */
3005 set matDatepicker(datepicker) {
3006 if (datepicker) {
3007 this._datepicker = datepicker;
3008 this._closedSubscription = datepicker.closedStream.subscribe(() => this._onTouched());
3009 this._registerModel(datepicker.registerInput(this));
3010 }
3011 }
3012 /** The minimum valid date. */
3013 get min() {
3014 return this._min;
3015 }
3016 set min(value) {
3017 const validValue = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value));
3018 if (!this._dateAdapter.sameDate(validValue, this._min)) {
3019 this._min = validValue;
3020 this._validatorOnChange();
3021 }
3022 }
3023 /** The maximum valid date. */
3024 get max() {
3025 return this._max;
3026 }
3027 set max(value) {
3028 const validValue = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value));
3029 if (!this._dateAdapter.sameDate(validValue, this._max)) {
3030 this._max = validValue;
3031 this._validatorOnChange();
3032 }
3033 }
3034 /** Function that can be used to filter out dates within the datepicker. */
3035 get dateFilter() {
3036 return this._dateFilter;
3037 }
3038 set dateFilter(value) {
3039 const wasMatchingValue = this._matchesFilter(this.value);
3040 this._dateFilter = value;
3041 if (this._matchesFilter(this.value) !== wasMatchingValue) {
3042 this._validatorOnChange();
3043 }
3044 }
3045 /**
3046 * Gets the element that the datepicker popup should be connected to.
3047 * @return The element to connect the popup to.
3048 */
3049 getConnectedOverlayOrigin() {
3050 return this._formField ? this._formField.getConnectedOverlayOrigin() : this._elementRef;
3051 }
3052 /** Gets the ID of an element that should be used a description for the calendar overlay. */
3053 getOverlayLabelId() {
3054 if (this._formField) {
3055 return this._formField.getLabelId();
3056 }
3057 return this._elementRef.nativeElement.getAttribute('aria-labelledby');
3058 }
3059 /** Returns the palette used by the input's form field, if any. */
3060 getThemePalette() {
3061 return this._formField ? this._formField.color : undefined;
3062 }
3063 /** Gets the value at which the calendar should start. */
3064 getStartValue() {
3065 return this.value;
3066 }
3067 ngOnDestroy() {
3068 super.ngOnDestroy();
3069 this._closedSubscription.unsubscribe();
3070 }
3071 /** Opens the associated datepicker. */
3072 _openPopup() {
3073 if (this._datepicker) {
3074 this._datepicker.open();
3075 }
3076 }
3077 _getValueFromModel(modelValue) {
3078 return modelValue;
3079 }
3080 _assignValueToModel(value) {
3081 if (this._model) {
3082 this._model.updateSelection(value, this);
3083 }
3084 }
3085 /** Gets the input's minimum date. */
3086 _getMinDate() {
3087 return this._min;
3088 }
3089 /** Gets the input's maximum date. */
3090 _getMaxDate() {
3091 return this._max;
3092 }
3093 /** Gets the input's date filtering function. */
3094 _getDateFilter() {
3095 return this._dateFilter;
3096 }
3097 _shouldHandleChangeEvent(event) {
3098 return event.source !== this;
3099 }
3100}
3101MatDatepickerInput.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDatepickerInput, deps: [{ token: i0.ElementRef }, { token: i1$1.DateAdapter, optional: true }, { token: MAT_DATE_FORMATS, optional: true }, { token: MAT_FORM_FIELD, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
3102MatDatepickerInput.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.1", type: MatDatepickerInput, selector: "input[matDatepicker]", inputs: { matDatepicker: "matDatepicker", 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: [
3103 MAT_DATEPICKER_VALUE_ACCESSOR,
3104 MAT_DATEPICKER_VALIDATORS,
3105 { provide: MAT_INPUT_VALUE_ACCESSOR, useExisting: MatDatepickerInput },
3106 ], exportAs: ["matDatepickerInput"], usesInheritance: true, ngImport: i0 });
3107i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDatepickerInput, decorators: [{
3108 type: Directive,
3109 args: [{
3110 selector: 'input[matDatepicker]',
3111 providers: [
3112 MAT_DATEPICKER_VALUE_ACCESSOR,
3113 MAT_DATEPICKER_VALIDATORS,
3114 { provide: MAT_INPUT_VALUE_ACCESSOR, useExisting: MatDatepickerInput },
3115 ],
3116 host: {
3117 'class': 'mat-datepicker-input',
3118 '[attr.aria-haspopup]': '_datepicker ? "dialog" : null',
3119 '[attr.aria-owns]': '(_datepicker?.opened && _datepicker.id) || null',
3120 '[attr.min]': 'min ? _dateAdapter.toIso8601(min) : null',
3121 '[attr.max]': 'max ? _dateAdapter.toIso8601(max) : null',
3122 // Used by the test harness to tie this input to its calendar. We can't depend on
3123 // `aria-owns` for this, because it's only defined while the calendar is open.
3124 '[attr.data-mat-calendar]': '_datepicker ? _datepicker.id : null',
3125 '[disabled]': 'disabled',
3126 '(input)': '_onInput($event.target.value)',
3127 '(change)': '_onChange()',
3128 '(blur)': '_onBlur()',
3129 '(keydown)': '_onKeydown($event)',
3130 },
3131 exportAs: 'matDatepickerInput',
3132 }]
3133 }], ctorParameters: function () {
3134 return [{ type: i0.ElementRef }, { type: i1$1.DateAdapter, decorators: [{
3135 type: Optional
3136 }] }, { type: undefined, decorators: [{
3137 type: Optional
3138 }, {
3139 type: Inject,
3140 args: [MAT_DATE_FORMATS]
3141 }] }, { type: i2$1.MatFormField, decorators: [{
3142 type: Optional
3143 }, {
3144 type: Inject,
3145 args: [MAT_FORM_FIELD]
3146 }] }];
3147 }, propDecorators: { matDatepicker: [{
3148 type: Input
3149 }], min: [{
3150 type: Input
3151 }], max: [{
3152 type: Input
3153 }], dateFilter: [{
3154 type: Input,
3155 args: ['matDatepickerFilter']
3156 }] } });
3157
3158/**
3159 * @license
3160 * Copyright Google LLC All Rights Reserved.
3161 *
3162 * Use of this source code is governed by an MIT-style license that can be
3163 * found in the LICENSE file at https://angular.io/license
3164 */
3165/** Can be used to override the icon of a `matDatepickerToggle`. */
3166class MatDatepickerToggleIcon {
3167}
3168MatDatepickerToggleIcon.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDatepickerToggleIcon, deps: [], target: i0.ɵɵFactoryTarget.Directive });
3169MatDatepickerToggleIcon.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.1", type: MatDatepickerToggleIcon, selector: "[matDatepickerToggleIcon]", ngImport: i0 });
3170i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDatepickerToggleIcon, decorators: [{
3171 type: Directive,
3172 args: [{
3173 selector: '[matDatepickerToggleIcon]',
3174 }]
3175 }] });
3176class MatDatepickerToggle {
3177 constructor(_intl, _changeDetectorRef, defaultTabIndex) {
3178 this._intl = _intl;
3179 this._changeDetectorRef = _changeDetectorRef;
3180 this._stateChanges = Subscription.EMPTY;
3181 const parsedTabIndex = Number(defaultTabIndex);
3182 this.tabIndex = parsedTabIndex || parsedTabIndex === 0 ? parsedTabIndex : null;
3183 }
3184 /** Whether the toggle button is disabled. */
3185 get disabled() {
3186 if (this._disabled === undefined && this.datepicker) {
3187 return this.datepicker.disabled;
3188 }
3189 return !!this._disabled;
3190 }
3191 set disabled(value) {
3192 this._disabled = coerceBooleanProperty(value);
3193 }
3194 ngOnChanges(changes) {
3195 if (changes['datepicker']) {
3196 this._watchStateChanges();
3197 }
3198 }
3199 ngOnDestroy() {
3200 this._stateChanges.unsubscribe();
3201 }
3202 ngAfterContentInit() {
3203 this._watchStateChanges();
3204 }
3205 _open(event) {
3206 if (this.datepicker && !this.disabled) {
3207 this.datepicker.open();
3208 event.stopPropagation();
3209 }
3210 }
3211 _watchStateChanges() {
3212 const datepickerStateChanged = this.datepicker ? this.datepicker.stateChanges : of();
3213 const inputStateChanged = this.datepicker && this.datepicker.datepickerInput
3214 ? this.datepicker.datepickerInput.stateChanges
3215 : of();
3216 const datepickerToggled = this.datepicker
3217 ? merge(this.datepicker.openedStream, this.datepicker.closedStream)
3218 : of();
3219 this._stateChanges.unsubscribe();
3220 this._stateChanges = merge(this._intl.changes, datepickerStateChanged, inputStateChanged, datepickerToggled).subscribe(() => this._changeDetectorRef.markForCheck());
3221 }
3222}
3223MatDatepickerToggle.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDatepickerToggle, deps: [{ token: MatDatepickerIntl }, { token: i0.ChangeDetectorRef }, { token: 'tabindex', attribute: true }], target: i0.ɵɵFactoryTarget.Component });
3224MatDatepickerToggle.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.1", type: MatDatepickerToggle, selector: "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: MatDatepickerToggleIcon, descendants: true }], viewQueries: [{ propertyName: "_button", first: true, predicate: ["button"], descendants: true }], exportAs: ["matDatepickerToggle"], usesOnChanges: true, ngImport: i0, template: "<button\n #button\n mat-icon-button\n type=\"button\"\n [attr.aria-haspopup]=\"datepicker ? 'dialog' : null\"\n [attr.aria-label]=\"ariaLabel || _intl.openCalendarLabel\"\n [attr.tabindex]=\"disabled ? -1 : tabIndex\"\n [disabled]=\"disabled\"\n [disableRipple]=\"disableRipple\">\n\n <svg\n *ngIf=\"!_customIcon\"\n class=\"mat-datepicker-toggle-default-icon\"\n viewBox=\"0 0 24 24\"\n width=\"24px\"\n height=\"24px\"\n fill=\"currentColor\"\n focusable=\"false\">\n <path 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\"/>\n </svg>\n\n <ng-content select=\"[matDatepickerToggleIcon]\"></ng-content>\n</button>\n", styles: [".mat-form-field-appearance-legacy .mat-form-field-prefix .mat-datepicker-toggle-default-icon,.mat-form-field-appearance-legacy .mat-form-field-suffix .mat-datepicker-toggle-default-icon{width:1em}.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-prefix .mat-datepicker-toggle-default-icon,.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-suffix .mat-datepicker-toggle-default-icon{display:block;width:1.5em;height:1.5em}.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-prefix .mat-icon-button .mat-datepicker-toggle-default-icon,.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-suffix .mat-icon-button .mat-datepicker-toggle-default-icon{margin:auto}.cdk-high-contrast-active .mat-datepicker-toggle-default-icon{color:CanvasText}"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i3.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
3225i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDatepickerToggle, decorators: [{
3226 type: Component,
3227 args: [{ selector: 'mat-datepicker-toggle', host: {
3228 'class': 'mat-datepicker-toggle',
3229 '[attr.tabindex]': 'null',
3230 '[class.mat-datepicker-toggle-active]': 'datepicker && datepicker.opened',
3231 '[class.mat-accent]': 'datepicker && datepicker.color === "accent"',
3232 '[class.mat-warn]': 'datepicker && datepicker.color === "warn"',
3233 // Used by the test harness to tie this toggle to its datepicker.
3234 '[attr.data-mat-calendar]': 'datepicker ? datepicker.id : null',
3235 // Bind the `click` on the host, rather than the inner `button`, so that we can call
3236 // `stopPropagation` on it without affecting the user's `click` handlers. We need to stop
3237 // it so that the input doesn't get focused automatically by the form field (See #21836).
3238 '(click)': '_open($event)',
3239 }, exportAs: 'matDatepickerToggle', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: "<button\n #button\n mat-icon-button\n type=\"button\"\n [attr.aria-haspopup]=\"datepicker ? 'dialog' : null\"\n [attr.aria-label]=\"ariaLabel || _intl.openCalendarLabel\"\n [attr.tabindex]=\"disabled ? -1 : tabIndex\"\n [disabled]=\"disabled\"\n [disableRipple]=\"disableRipple\">\n\n <svg\n *ngIf=\"!_customIcon\"\n class=\"mat-datepicker-toggle-default-icon\"\n viewBox=\"0 0 24 24\"\n width=\"24px\"\n height=\"24px\"\n fill=\"currentColor\"\n focusable=\"false\">\n <path 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\"/>\n </svg>\n\n <ng-content select=\"[matDatepickerToggleIcon]\"></ng-content>\n</button>\n", styles: [".mat-form-field-appearance-legacy .mat-form-field-prefix .mat-datepicker-toggle-default-icon,.mat-form-field-appearance-legacy .mat-form-field-suffix .mat-datepicker-toggle-default-icon{width:1em}.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-prefix .mat-datepicker-toggle-default-icon,.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-suffix .mat-datepicker-toggle-default-icon{display:block;width:1.5em;height:1.5em}.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-prefix .mat-icon-button .mat-datepicker-toggle-default-icon,.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-suffix .mat-icon-button .mat-datepicker-toggle-default-icon{margin:auto}.cdk-high-contrast-active .mat-datepicker-toggle-default-icon{color:CanvasText}"] }]
3240 }], ctorParameters: function () {
3241 return [{ type: MatDatepickerIntl }, { type: i0.ChangeDetectorRef }, { type: undefined, decorators: [{
3242 type: Attribute,
3243 args: ['tabindex']
3244 }] }];
3245 }, propDecorators: { datepicker: [{
3246 type: Input,
3247 args: ['for']
3248 }], tabIndex: [{
3249 type: Input
3250 }], ariaLabel: [{
3251 type: Input,
3252 args: ['aria-label']
3253 }], disabled: [{
3254 type: Input
3255 }], disableRipple: [{
3256 type: Input
3257 }], _customIcon: [{
3258 type: ContentChild,
3259 args: [MatDatepickerToggleIcon]
3260 }], _button: [{
3261 type: ViewChild,
3262 args: ['button']
3263 }] } });
3264
3265/**
3266 * @license
3267 * Copyright Google LLC All Rights Reserved.
3268 *
3269 * Use of this source code is governed by an MIT-style license that can be
3270 * found in the LICENSE file at https://angular.io/license
3271 */
3272/**
3273 * Used to provide the date range input wrapper component
3274 * to the parts without circular dependencies.
3275 */
3276const MAT_DATE_RANGE_INPUT_PARENT = new InjectionToken('MAT_DATE_RANGE_INPUT_PARENT');
3277/**
3278 * Base class for the individual inputs that can be projected inside a `mat-date-range-input`.
3279 */
3280class MatDateRangeInputPartBase extends MatDatepickerInputBase {
3281 constructor(_rangeInput, elementRef, _defaultErrorStateMatcher, _injector, _parentForm, _parentFormGroup, dateAdapter, dateFormats) {
3282 super(elementRef, dateAdapter, dateFormats);
3283 this._rangeInput = _rangeInput;
3284 this._defaultErrorStateMatcher = _defaultErrorStateMatcher;
3285 this._injector = _injector;
3286 this._parentForm = _parentForm;
3287 this._parentFormGroup = _parentFormGroup;
3288 }
3289 ngOnInit() {
3290 // We need the date input to provide itself as a `ControlValueAccessor` and a `Validator`, while
3291 // injecting its `NgControl` so that the error state is handled correctly. This introduces a
3292 // circular dependency, because both `ControlValueAccessor` and `Validator` depend on the input
3293 // itself. Usually we can work around it for the CVA, but there's no API to do it for the
3294 // validator. We work around it here by injecting the `NgControl` in `ngOnInit`, after
3295 // everything has been resolved.
3296 // tslint:disable-next-line:no-bitwise
3297 const ngControl = this._injector.get(NgControl, null, InjectFlags.Self | InjectFlags.Optional);
3298 if (ngControl) {
3299 this.ngControl = ngControl;
3300 }
3301 }
3302 ngDoCheck() {
3303 if (this.ngControl) {
3304 // We need to re-evaluate this on every change detection cycle, because there are some
3305 // error triggers that we can't subscribe to (e.g. parent form submissions). This means
3306 // that whatever logic is in here has to be super lean or we risk destroying the performance.
3307 this.updateErrorState();
3308 }
3309 }
3310 /** Gets whether the input is empty. */
3311 isEmpty() {
3312 return this._elementRef.nativeElement.value.length === 0;
3313 }
3314 /** Gets the placeholder of the input. */
3315 _getPlaceholder() {
3316 return this._elementRef.nativeElement.placeholder;
3317 }
3318 /** Focuses the input. */
3319 focus() {
3320 this._elementRef.nativeElement.focus();
3321 }
3322 /** Handles `input` events on the input element. */
3323 _onInput(value) {
3324 super._onInput(value);
3325 this._rangeInput._handleChildValueChange();
3326 }
3327 /** Opens the datepicker associated with the input. */
3328 _openPopup() {
3329 this._rangeInput._openDatepicker();
3330 }
3331 /** Gets the minimum date from the range input. */
3332 _getMinDate() {
3333 return this._rangeInput.min;
3334 }
3335 /** Gets the maximum date from the range input. */
3336 _getMaxDate() {
3337 return this._rangeInput.max;
3338 }
3339 /** Gets the date filter function from the range input. */
3340 _getDateFilter() {
3341 return this._rangeInput.dateFilter;
3342 }
3343 _parentDisabled() {
3344 return this._rangeInput._groupDisabled;
3345 }
3346 _shouldHandleChangeEvent({ source }) {
3347 return source !== this._rangeInput._startInput && source !== this._rangeInput._endInput;
3348 }
3349 _assignValueProgrammatically(value) {
3350 super._assignValueProgrammatically(value);
3351 const opposite = (this === this._rangeInput._startInput
3352 ? this._rangeInput._endInput
3353 : this._rangeInput._startInput);
3354 opposite === null || opposite === void 0 ? void 0 : opposite._validatorOnChange();
3355 }
3356}
3357MatDateRangeInputPartBase.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDateRangeInputPartBase, deps: [{ token: MAT_DATE_RANGE_INPUT_PARENT }, { token: i0.ElementRef }, { token: i1$1.ErrorStateMatcher }, { token: i0.Injector }, { token: i2$2.NgForm, optional: true }, { token: i2$2.FormGroupDirective, optional: true }, { token: i1$1.DateAdapter, optional: true }, { token: MAT_DATE_FORMATS, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
3358MatDateRangeInputPartBase.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.1", type: MatDateRangeInputPartBase, usesInheritance: true, ngImport: i0 });
3359i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDateRangeInputPartBase, decorators: [{
3360 type: Directive
3361 }], ctorParameters: function () {
3362 return [{ type: undefined, decorators: [{
3363 type: Inject,
3364 args: [MAT_DATE_RANGE_INPUT_PARENT]
3365 }] }, { type: i0.ElementRef }, { type: i1$1.ErrorStateMatcher }, { type: i0.Injector }, { type: i2$2.NgForm, decorators: [{
3366 type: Optional
3367 }] }, { type: i2$2.FormGroupDirective, decorators: [{
3368 type: Optional
3369 }] }, { type: i1$1.DateAdapter, decorators: [{
3370 type: Optional
3371 }] }, { type: undefined, decorators: [{
3372 type: Optional
3373 }, {
3374 type: Inject,
3375 args: [MAT_DATE_FORMATS]
3376 }] }];
3377 } });
3378const _MatDateRangeInputBase = mixinErrorState(MatDateRangeInputPartBase);
3379/** Input for entering the start date in a `mat-date-range-input`. */
3380class MatStartDate extends _MatDateRangeInputBase {
3381 constructor(rangeInput, elementRef, defaultErrorStateMatcher, injector, parentForm, parentFormGroup, dateAdapter, dateFormats) {
3382 super(rangeInput, elementRef, defaultErrorStateMatcher, injector, parentForm, parentFormGroup, dateAdapter, dateFormats);
3383 /** Validator that checks that the start date isn't after the end date. */
3384 this._startValidator = (control) => {
3385 const start = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(control.value));
3386 const end = this._model ? this._model.selection.end : null;
3387 return !start || !end || this._dateAdapter.compareDate(start, end) <= 0
3388 ? null
3389 : { 'matStartDateInvalid': { 'end': end, 'actual': start } };
3390 };
3391 this._validator = Validators.compose([...super._getValidators(), this._startValidator]);
3392 }
3393 _getValueFromModel(modelValue) {
3394 return modelValue.start;
3395 }
3396 _shouldHandleChangeEvent(change) {
3397 var _a;
3398 if (!super._shouldHandleChangeEvent(change)) {
3399 return false;
3400 }
3401 else {
3402 return !((_a = change.oldValue) === null || _a === void 0 ? void 0 : _a.start)
3403 ? !!change.selection.start
3404 : !change.selection.start ||
3405 !!this._dateAdapter.compareDate(change.oldValue.start, change.selection.start);
3406 }
3407 }
3408 _assignValueToModel(value) {
3409 if (this._model) {
3410 const range = new DateRange(value, this._model.selection.end);
3411 this._model.updateSelection(range, this);
3412 }
3413 }
3414 _formatValue(value) {
3415 super._formatValue(value);
3416 // Any time the input value is reformatted we need to tell the parent.
3417 this._rangeInput._handleChildValueChange();
3418 }
3419 /** Gets the value that should be used when mirroring the input's size. */
3420 getMirrorValue() {
3421 const element = this._elementRef.nativeElement;
3422 const value = element.value;
3423 return value.length > 0 ? value : element.placeholder;
3424 }
3425}
3426MatStartDate.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatStartDate, deps: [{ token: MAT_DATE_RANGE_INPUT_PARENT }, { token: i0.ElementRef }, { token: i1$1.ErrorStateMatcher }, { token: i0.Injector }, { token: i2$2.NgForm, optional: true }, { token: i2$2.FormGroupDirective, optional: true }, { token: i1$1.DateAdapter, optional: true }, { token: MAT_DATE_FORMATS, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
3427MatStartDate.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.1", type: MatStartDate, selector: "input[matStartDate]", 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.id": "_rangeInput.id", "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: [
3428 { provide: NG_VALUE_ACCESSOR, useExisting: MatStartDate, multi: true },
3429 { provide: NG_VALIDATORS, useExisting: MatStartDate, multi: true },
3430 ], usesInheritance: true, ngImport: i0 });
3431i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatStartDate, decorators: [{
3432 type: Directive,
3433 args: [{
3434 selector: 'input[matStartDate]',
3435 host: {
3436 'class': 'mat-start-date mat-date-range-input-inner',
3437 '[disabled]': 'disabled',
3438 '(input)': '_onInput($event.target.value)',
3439 '(change)': '_onChange()',
3440 '(keydown)': '_onKeydown($event)',
3441 '[attr.id]': '_rangeInput.id',
3442 '[attr.aria-haspopup]': '_rangeInput.rangePicker ? "dialog" : null',
3443 '[attr.aria-owns]': '(_rangeInput.rangePicker?.opened && _rangeInput.rangePicker.id) || null',
3444 '[attr.min]': '_getMinDate() ? _dateAdapter.toIso8601(_getMinDate()) : null',
3445 '[attr.max]': '_getMaxDate() ? _dateAdapter.toIso8601(_getMaxDate()) : null',
3446 '(blur)': '_onBlur()',
3447 'type': 'text',
3448 },
3449 providers: [
3450 { provide: NG_VALUE_ACCESSOR, useExisting: MatStartDate, multi: true },
3451 { provide: NG_VALIDATORS, useExisting: MatStartDate, multi: true },
3452 ],
3453 // These need to be specified explicitly, because some tooling doesn't
3454 // seem to pick them up from the base class. See #20932.
3455 outputs: ['dateChange', 'dateInput'],
3456 inputs: ['errorStateMatcher'],
3457 }]
3458 }], ctorParameters: function () {
3459 return [{ type: undefined, decorators: [{
3460 type: Inject,
3461 args: [MAT_DATE_RANGE_INPUT_PARENT]
3462 }] }, { type: i0.ElementRef }, { type: i1$1.ErrorStateMatcher }, { type: i0.Injector }, { type: i2$2.NgForm, decorators: [{
3463 type: Optional
3464 }] }, { type: i2$2.FormGroupDirective, decorators: [{
3465 type: Optional
3466 }] }, { type: i1$1.DateAdapter, decorators: [{
3467 type: Optional
3468 }] }, { type: undefined, decorators: [{
3469 type: Optional
3470 }, {
3471 type: Inject,
3472 args: [MAT_DATE_FORMATS]
3473 }] }];
3474 } });
3475/** Input for entering the end date in a `mat-date-range-input`. */
3476class MatEndDate extends _MatDateRangeInputBase {
3477 constructor(rangeInput, elementRef, defaultErrorStateMatcher, injector, parentForm, parentFormGroup, dateAdapter, dateFormats) {
3478 super(rangeInput, elementRef, defaultErrorStateMatcher, injector, parentForm, parentFormGroup, dateAdapter, dateFormats);
3479 /** Validator that checks that the end date isn't before the start date. */
3480 this._endValidator = (control) => {
3481 const end = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(control.value));
3482 const start = this._model ? this._model.selection.start : null;
3483 return !end || !start || this._dateAdapter.compareDate(end, start) >= 0
3484 ? null
3485 : { 'matEndDateInvalid': { 'start': start, 'actual': end } };
3486 };
3487 this._validator = Validators.compose([...super._getValidators(), this._endValidator]);
3488 }
3489 _getValueFromModel(modelValue) {
3490 return modelValue.end;
3491 }
3492 _shouldHandleChangeEvent(change) {
3493 var _a;
3494 if (!super._shouldHandleChangeEvent(change)) {
3495 return false;
3496 }
3497 else {
3498 return !((_a = change.oldValue) === null || _a === void 0 ? void 0 : _a.end)
3499 ? !!change.selection.end
3500 : !change.selection.end ||
3501 !!this._dateAdapter.compareDate(change.oldValue.end, change.selection.end);
3502 }
3503 }
3504 _assignValueToModel(value) {
3505 if (this._model) {
3506 const range = new DateRange(this._model.selection.start, value);
3507 this._model.updateSelection(range, this);
3508 }
3509 }
3510 _onKeydown(event) {
3511 // If the user is pressing backspace on an empty end input, move focus back to the start.
3512 if (event.keyCode === BACKSPACE && !this._elementRef.nativeElement.value) {
3513 this._rangeInput._startInput.focus();
3514 }
3515 super._onKeydown(event);
3516 }
3517}
3518MatEndDate.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatEndDate, deps: [{ token: MAT_DATE_RANGE_INPUT_PARENT }, { token: i0.ElementRef }, { token: i1$1.ErrorStateMatcher }, { token: i0.Injector }, { token: i2$2.NgForm, optional: true }, { token: i2$2.FormGroupDirective, optional: true }, { token: i1$1.DateAdapter, optional: true }, { token: MAT_DATE_FORMATS, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
3519MatEndDate.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.1", type: MatEndDate, selector: "input[matEndDate]", 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: [
3520 { provide: NG_VALUE_ACCESSOR, useExisting: MatEndDate, multi: true },
3521 { provide: NG_VALIDATORS, useExisting: MatEndDate, multi: true },
3522 ], usesInheritance: true, ngImport: i0 });
3523i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatEndDate, decorators: [{
3524 type: Directive,
3525 args: [{
3526 selector: 'input[matEndDate]',
3527 host: {
3528 'class': 'mat-end-date mat-date-range-input-inner',
3529 '[disabled]': 'disabled',
3530 '(input)': '_onInput($event.target.value)',
3531 '(change)': '_onChange()',
3532 '(keydown)': '_onKeydown($event)',
3533 '[attr.aria-haspopup]': '_rangeInput.rangePicker ? "dialog" : null',
3534 '[attr.aria-owns]': '(_rangeInput.rangePicker?.opened && _rangeInput.rangePicker.id) || null',
3535 '[attr.min]': '_getMinDate() ? _dateAdapter.toIso8601(_getMinDate()) : null',
3536 '[attr.max]': '_getMaxDate() ? _dateAdapter.toIso8601(_getMaxDate()) : null',
3537 '(blur)': '_onBlur()',
3538 'type': 'text',
3539 },
3540 providers: [
3541 { provide: NG_VALUE_ACCESSOR, useExisting: MatEndDate, multi: true },
3542 { provide: NG_VALIDATORS, useExisting: MatEndDate, multi: true },
3543 ],
3544 // These need to be specified explicitly, because some tooling doesn't
3545 // seem to pick them up from the base class. See #20932.
3546 outputs: ['dateChange', 'dateInput'],
3547 inputs: ['errorStateMatcher'],
3548 }]
3549 }], ctorParameters: function () {
3550 return [{ type: undefined, decorators: [{
3551 type: Inject,
3552 args: [MAT_DATE_RANGE_INPUT_PARENT]
3553 }] }, { type: i0.ElementRef }, { type: i1$1.ErrorStateMatcher }, { type: i0.Injector }, { type: i2$2.NgForm, decorators: [{
3554 type: Optional
3555 }] }, { type: i2$2.FormGroupDirective, decorators: [{
3556 type: Optional
3557 }] }, { type: i1$1.DateAdapter, decorators: [{
3558 type: Optional
3559 }] }, { type: undefined, decorators: [{
3560 type: Optional
3561 }, {
3562 type: Inject,
3563 args: [MAT_DATE_FORMATS]
3564 }] }];
3565 } });
3566
3567/**
3568 * @license
3569 * Copyright Google LLC All Rights Reserved.
3570 *
3571 * Use of this source code is governed by an MIT-style license that can be
3572 * found in the LICENSE file at https://angular.io/license
3573 */
3574let nextUniqueId = 0;
3575class MatDateRangeInput {
3576 constructor(_changeDetectorRef, _elementRef, control, _dateAdapter, _formField) {
3577 this._changeDetectorRef = _changeDetectorRef;
3578 this._elementRef = _elementRef;
3579 this._dateAdapter = _dateAdapter;
3580 this._formField = _formField;
3581 this._closedSubscription = Subscription.EMPTY;
3582 /** Unique ID for the input. */
3583 this.id = `mat-date-range-input-${nextUniqueId++}`;
3584 /** Whether the control is focused. */
3585 this.focused = false;
3586 /** Name of the form control. */
3587 this.controlType = 'mat-date-range-input';
3588 this._groupDisabled = false;
3589 /** Value for the `aria-describedby` attribute of the inputs. */
3590 this._ariaDescribedBy = null;
3591 /** Separator text to be shown between the inputs. */
3592 this.separator = '–';
3593 /** Start of the comparison range that should be shown in the calendar. */
3594 this.comparisonStart = null;
3595 /** End of the comparison range that should be shown in the calendar. */
3596 this.comparisonEnd = null;
3597 /** Emits when the input's state has changed. */
3598 this.stateChanges = new Subject();
3599 if (!_dateAdapter && (typeof ngDevMode === 'undefined' || ngDevMode)) {
3600 throw createMissingDateImplError('DateAdapter');
3601 }
3602 // The datepicker module can be used both with MDC and non-MDC form fields. We have
3603 // to conditionally add the MDC input class so that the range picker looks correctly.
3604 if (_formField === null || _formField === void 0 ? void 0 : _formField._elementRef.nativeElement.classList.contains('mat-mdc-form-field')) {
3605 const classList = _elementRef.nativeElement.classList;
3606 classList.add('mat-mdc-input-element');
3607 classList.add('mat-mdc-form-field-input-control');
3608 }
3609 // TODO(crisbeto): remove `as any` after #18206 lands.
3610 this.ngControl = control;
3611 }
3612 /** Current value of the range input. */
3613 get value() {
3614 return this._model ? this._model.selection : null;
3615 }
3616 /** Whether the control's label should float. */
3617 get shouldLabelFloat() {
3618 return this.focused || !this.empty;
3619 }
3620 /**
3621 * Implemented as a part of `MatFormFieldControl`.
3622 * Set the placeholder attribute on `matStartDate` and `matEndDate`.
3623 * @docs-private
3624 */
3625 get placeholder() {
3626 var _a, _b;
3627 const start = ((_a = this._startInput) === null || _a === void 0 ? void 0 : _a._getPlaceholder()) || '';
3628 const end = ((_b = this._endInput) === null || _b === void 0 ? void 0 : _b._getPlaceholder()) || '';
3629 return start || end ? `${start} ${this.separator} ${end}` : '';
3630 }
3631 /** The range picker that this input is associated with. */
3632 get rangePicker() {
3633 return this._rangePicker;
3634 }
3635 set rangePicker(rangePicker) {
3636 if (rangePicker) {
3637 this._model = rangePicker.registerInput(this);
3638 this._rangePicker = rangePicker;
3639 this._closedSubscription.unsubscribe();
3640 this._closedSubscription = rangePicker.closedStream.subscribe(() => {
3641 var _a, _b;
3642 (_a = this._startInput) === null || _a === void 0 ? void 0 : _a._onTouched();
3643 (_b = this._endInput) === null || _b === void 0 ? void 0 : _b._onTouched();
3644 });
3645 this._registerModel(this._model);
3646 }
3647 }
3648 /** Whether the input is required. */
3649 get required() {
3650 return !!this._required;
3651 }
3652 set required(value) {
3653 this._required = coerceBooleanProperty(value);
3654 }
3655 /** Function that can be used to filter out dates within the date range picker. */
3656 get dateFilter() {
3657 return this._dateFilter;
3658 }
3659 set dateFilter(value) {
3660 const start = this._startInput;
3661 const end = this._endInput;
3662 const wasMatchingStart = start && start._matchesFilter(start.value);
3663 const wasMatchingEnd = end && end._matchesFilter(start.value);
3664 this._dateFilter = value;
3665 if (start && start._matchesFilter(start.value) !== wasMatchingStart) {
3666 start._validatorOnChange();
3667 }
3668 if (end && end._matchesFilter(end.value) !== wasMatchingEnd) {
3669 end._validatorOnChange();
3670 }
3671 }
3672 /** The minimum valid date. */
3673 get min() {
3674 return this._min;
3675 }
3676 set min(value) {
3677 const validValue = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value));
3678 if (!this._dateAdapter.sameDate(validValue, this._min)) {
3679 this._min = validValue;
3680 this._revalidate();
3681 }
3682 }
3683 /** The maximum valid date. */
3684 get max() {
3685 return this._max;
3686 }
3687 set max(value) {
3688 const validValue = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value));
3689 if (!this._dateAdapter.sameDate(validValue, this._max)) {
3690 this._max = validValue;
3691 this._revalidate();
3692 }
3693 }
3694 /** Whether the input is disabled. */
3695 get disabled() {
3696 return this._startInput && this._endInput
3697 ? this._startInput.disabled && this._endInput.disabled
3698 : this._groupDisabled;
3699 }
3700 set disabled(value) {
3701 const newValue = coerceBooleanProperty(value);
3702 if (newValue !== this._groupDisabled) {
3703 this._groupDisabled = newValue;
3704 this.stateChanges.next(undefined);
3705 }
3706 }
3707 /** Whether the input is in an error state. */
3708 get errorState() {
3709 if (this._startInput && this._endInput) {
3710 return this._startInput.errorState || this._endInput.errorState;
3711 }
3712 return false;
3713 }
3714 /** Whether the datepicker input is empty. */
3715 get empty() {
3716 const startEmpty = this._startInput ? this._startInput.isEmpty() : false;
3717 const endEmpty = this._endInput ? this._endInput.isEmpty() : false;
3718 return startEmpty && endEmpty;
3719 }
3720 /**
3721 * Implemented as a part of `MatFormFieldControl`.
3722 * @docs-private
3723 */
3724 setDescribedByIds(ids) {
3725 this._ariaDescribedBy = ids.length ? ids.join(' ') : null;
3726 }
3727 /**
3728 * Implemented as a part of `MatFormFieldControl`.
3729 * @docs-private
3730 */
3731 onContainerClick() {
3732 if (!this.focused && !this.disabled) {
3733 if (!this._model || !this._model.selection.start) {
3734 this._startInput.focus();
3735 }
3736 else {
3737 this._endInput.focus();
3738 }
3739 }
3740 }
3741 ngAfterContentInit() {
3742 if (typeof ngDevMode === 'undefined' || ngDevMode) {
3743 if (!this._startInput) {
3744 throw Error('mat-date-range-input must contain a matStartDate input');
3745 }
3746 if (!this._endInput) {
3747 throw Error('mat-date-range-input must contain a matEndDate input');
3748 }
3749 }
3750 if (this._model) {
3751 this._registerModel(this._model);
3752 }
3753 // We don't need to unsubscribe from this, because we
3754 // know that the input streams will be completed on destroy.
3755 merge(this._startInput.stateChanges, this._endInput.stateChanges).subscribe(() => {
3756 this.stateChanges.next(undefined);
3757 });
3758 }
3759 ngOnChanges(changes) {
3760 if (dateInputsHaveChanged(changes, this._dateAdapter)) {
3761 this.stateChanges.next(undefined);
3762 }
3763 }
3764 ngOnDestroy() {
3765 this._closedSubscription.unsubscribe();
3766 this.stateChanges.complete();
3767 }
3768 /** Gets the date at which the calendar should start. */
3769 getStartValue() {
3770 return this.value ? this.value.start : null;
3771 }
3772 /** Gets the input's theme palette. */
3773 getThemePalette() {
3774 return this._formField ? this._formField.color : undefined;
3775 }
3776 /** Gets the element to which the calendar overlay should be attached. */
3777 getConnectedOverlayOrigin() {
3778 return this._formField ? this._formField.getConnectedOverlayOrigin() : this._elementRef;
3779 }
3780 /** Gets the ID of an element that should be used a description for the calendar overlay. */
3781 getOverlayLabelId() {
3782 return this._formField ? this._formField.getLabelId() : null;
3783 }
3784 /** Gets the value that is used to mirror the state input. */
3785 _getInputMirrorValue() {
3786 return this._startInput ? this._startInput.getMirrorValue() : '';
3787 }
3788 /** Whether the input placeholders should be hidden. */
3789 _shouldHidePlaceholders() {
3790 return this._startInput ? !this._startInput.isEmpty() : false;
3791 }
3792 /** Handles the value in one of the child inputs changing. */
3793 _handleChildValueChange() {
3794 this.stateChanges.next(undefined);
3795 this._changeDetectorRef.markForCheck();
3796 }
3797 /** Opens the date range picker associated with the input. */
3798 _openDatepicker() {
3799 if (this._rangePicker) {
3800 this._rangePicker.open();
3801 }
3802 }
3803 /** Whether the separate text should be hidden. */
3804 _shouldHideSeparator() {
3805 return ((!this._formField ||
3806 (this._formField.getLabelId() && !this._formField._shouldLabelFloat())) &&
3807 this.empty);
3808 }
3809 /** Gets the value for the `aria-labelledby` attribute of the inputs. */
3810 _getAriaLabelledby() {
3811 const formField = this._formField;
3812 return formField && formField._hasFloatingLabel() ? formField._labelId : null;
3813 }
3814 /** Updates the focused state of the range input. */
3815 _updateFocus(origin) {
3816 this.focused = origin !== null;
3817 this.stateChanges.next();
3818 }
3819 /** Re-runs the validators on the start/end inputs. */
3820 _revalidate() {
3821 if (this._startInput) {
3822 this._startInput._validatorOnChange();
3823 }
3824 if (this._endInput) {
3825 this._endInput._validatorOnChange();
3826 }
3827 }
3828 /** Registers the current date selection model with the start/end inputs. */
3829 _registerModel(model) {
3830 if (this._startInput) {
3831 this._startInput._registerModel(model);
3832 }
3833 if (this._endInput) {
3834 this._endInput._registerModel(model);
3835 }
3836 }
3837}
3838MatDateRangeInput.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDateRangeInput, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: i2$2.ControlContainer, optional: true, self: true }, { token: i1$1.DateAdapter, optional: true }, { token: MAT_FORM_FIELD, optional: true }], target: i0.ɵɵFactoryTarget.Component });
3839MatDateRangeInput.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.1", type: MatDateRangeInput, selector: "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": "null", "attr.aria-labelledby": "_getAriaLabelledby()", "attr.aria-describedby": "_ariaDescribedBy", "attr.data-mat-calendar": "rangePicker ? rangePicker.id : null" }, classAttribute: "mat-date-range-input" }, providers: [
3840 { provide: MatFormFieldControl, useExisting: MatDateRangeInput },
3841 { provide: MAT_DATE_RANGE_INPUT_PARENT, useExisting: MatDateRangeInput },
3842 ], queries: [{ propertyName: "_startInput", first: true, predicate: MatStartDate, descendants: true }, { propertyName: "_endInput", first: true, predicate: MatEndDate, descendants: true }], exportAs: ["matDateRangeInput"], usesOnChanges: true, ngImport: i0, template: "<div\n class=\"mat-date-range-input-container\"\n cdkMonitorSubtreeFocus\n (cdkFocusChange)=\"_updateFocus($event)\">\n <div class=\"mat-date-range-input-start-wrapper\">\n <ng-content select=\"input[matStartDate]\"></ng-content>\n <span\n class=\"mat-date-range-input-mirror\"\n aria-hidden=\"true\">{{_getInputMirrorValue()}}</span>\n </div>\n\n <span\n class=\"mat-date-range-input-separator\"\n [class.mat-date-range-input-separator-hidden]=\"_shouldHideSeparator()\">{{separator}}</span>\n\n <div class=\"mat-date-range-input-end-wrapper\">\n <ng-content select=\"input[matEndDate]\"></ng-content>\n </div>\n</div>\n\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 400ms 133.3333333333ms cubic-bezier(0.25, 0.8, 0.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-inner{font:inherit;background:rgba(0,0,0,0);color:currentColor;border:none;outline:none;padding:0;margin:0;vertical-align:bottom;text-align:inherit;-webkit-appearance:none;width:100%}.mat-date-range-input-inner:-moz-ui-invalid{box-shadow:none}.mat-date-range-input-inner::placeholder{transition:color 400ms 133.3333333333ms cubic-bezier(0.25, 0.8, 0.25, 1)}.mat-date-range-input-inner::-moz-placeholder{transition:color 400ms 133.3333333333ms cubic-bezier(0.25, 0.8, 0.25, 1)}.mat-date-range-input-inner::-webkit-input-placeholder{transition:color 400ms 133.3333333333ms cubic-bezier(0.25, 0.8, 0.25, 1)}.mat-date-range-input-inner:-ms-input-placeholder{transition:color 400ms 133.3333333333ms cubic-bezier(0.25, 0.8, 0.25, 1)}.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:rgba(0,0,0,0) !important;-webkit-text-fill-color:rgba(0,0,0,0);transition:none}.cdk-high-contrast-active .mat-form-field-hide-placeholder .mat-date-range-input-inner::placeholder,.cdk-high-contrast-active .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:rgba(0,0,0,0) !important;-webkit-text-fill-color:rgba(0,0,0,0);transition:none}.cdk-high-contrast-active .mat-form-field-hide-placeholder .mat-date-range-input-inner::-moz-placeholder,.cdk-high-contrast-active .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:rgba(0,0,0,0) !important;-webkit-text-fill-color:rgba(0,0,0,0);transition:none}.cdk-high-contrast-active .mat-form-field-hide-placeholder .mat-date-range-input-inner::-webkit-input-placeholder,.cdk-high-contrast-active .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:rgba(0,0,0,0) !important;-webkit-text-fill-color:rgba(0,0,0,0);transition:none}.cdk-high-contrast-active .mat-form-field-hide-placeholder .mat-date-range-input-inner:-ms-input-placeholder,.cdk-high-contrast-active .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-date-range-input-start-wrapper{position:relative;overflow:hidden;max-width:calc(50% - 4px)}.mat-date-range-input-start-wrapper .mat-date-range-input-inner{position:absolute;top:0;left:0}.mat-date-range-input-end-wrapper{flex-grow:1;max-width:calc(50% - 4px)}.mat-form-field-type-mat-date-range-input .mat-form-field-infix{width:200px}"], dependencies: [{ kind: "directive", type: i5.CdkMonitorFocus, selector: "[cdkMonitorElementFocus], [cdkMonitorSubtreeFocus]", outputs: ["cdkFocusChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
3843i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDateRangeInput, decorators: [{
3844 type: Component,
3845 args: [{ selector: 'mat-date-range-input', exportAs: 'matDateRangeInput', host: {
3846 'class': 'mat-date-range-input',
3847 '[class.mat-date-range-input-hide-placeholders]': '_shouldHidePlaceholders()',
3848 '[class.mat-date-range-input-required]': 'required',
3849 '[attr.id]': 'null',
3850 'role': 'group',
3851 '[attr.aria-labelledby]': '_getAriaLabelledby()',
3852 '[attr.aria-describedby]': '_ariaDescribedBy',
3853 // Used by the test harness to tie this input to its calendar. We can't depend on
3854 // `aria-owns` for this, because it's only defined while the calendar is open.
3855 '[attr.data-mat-calendar]': 'rangePicker ? rangePicker.id : null',
3856 }, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, providers: [
3857 { provide: MatFormFieldControl, useExisting: MatDateRangeInput },
3858 { provide: MAT_DATE_RANGE_INPUT_PARENT, useExisting: MatDateRangeInput },
3859 ], template: "<div\n class=\"mat-date-range-input-container\"\n cdkMonitorSubtreeFocus\n (cdkFocusChange)=\"_updateFocus($event)\">\n <div class=\"mat-date-range-input-start-wrapper\">\n <ng-content select=\"input[matStartDate]\"></ng-content>\n <span\n class=\"mat-date-range-input-mirror\"\n aria-hidden=\"true\">{{_getInputMirrorValue()}}</span>\n </div>\n\n <span\n class=\"mat-date-range-input-separator\"\n [class.mat-date-range-input-separator-hidden]=\"_shouldHideSeparator()\">{{separator}}</span>\n\n <div class=\"mat-date-range-input-end-wrapper\">\n <ng-content select=\"input[matEndDate]\"></ng-content>\n </div>\n</div>\n\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 400ms 133.3333333333ms cubic-bezier(0.25, 0.8, 0.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-inner{font:inherit;background:rgba(0,0,0,0);color:currentColor;border:none;outline:none;padding:0;margin:0;vertical-align:bottom;text-align:inherit;-webkit-appearance:none;width:100%}.mat-date-range-input-inner:-moz-ui-invalid{box-shadow:none}.mat-date-range-input-inner::placeholder{transition:color 400ms 133.3333333333ms cubic-bezier(0.25, 0.8, 0.25, 1)}.mat-date-range-input-inner::-moz-placeholder{transition:color 400ms 133.3333333333ms cubic-bezier(0.25, 0.8, 0.25, 1)}.mat-date-range-input-inner::-webkit-input-placeholder{transition:color 400ms 133.3333333333ms cubic-bezier(0.25, 0.8, 0.25, 1)}.mat-date-range-input-inner:-ms-input-placeholder{transition:color 400ms 133.3333333333ms cubic-bezier(0.25, 0.8, 0.25, 1)}.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:rgba(0,0,0,0) !important;-webkit-text-fill-color:rgba(0,0,0,0);transition:none}.cdk-high-contrast-active .mat-form-field-hide-placeholder .mat-date-range-input-inner::placeholder,.cdk-high-contrast-active .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:rgba(0,0,0,0) !important;-webkit-text-fill-color:rgba(0,0,0,0);transition:none}.cdk-high-contrast-active .mat-form-field-hide-placeholder .mat-date-range-input-inner::-moz-placeholder,.cdk-high-contrast-active .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:rgba(0,0,0,0) !important;-webkit-text-fill-color:rgba(0,0,0,0);transition:none}.cdk-high-contrast-active .mat-form-field-hide-placeholder .mat-date-range-input-inner::-webkit-input-placeholder,.cdk-high-contrast-active .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:rgba(0,0,0,0) !important;-webkit-text-fill-color:rgba(0,0,0,0);transition:none}.cdk-high-contrast-active .mat-form-field-hide-placeholder .mat-date-range-input-inner:-ms-input-placeholder,.cdk-high-contrast-active .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-date-range-input-start-wrapper{position:relative;overflow:hidden;max-width:calc(50% - 4px)}.mat-date-range-input-start-wrapper .mat-date-range-input-inner{position:absolute;top:0;left:0}.mat-date-range-input-end-wrapper{flex-grow:1;max-width:calc(50% - 4px)}.mat-form-field-type-mat-date-range-input .mat-form-field-infix{width:200px}"] }]
3860 }], ctorParameters: function () {
3861 return [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i2$2.ControlContainer, decorators: [{
3862 type: Optional
3863 }, {
3864 type: Self
3865 }] }, { type: i1$1.DateAdapter, decorators: [{
3866 type: Optional
3867 }] }, { type: i2$1.MatFormField, decorators: [{
3868 type: Optional
3869 }, {
3870 type: Inject,
3871 args: [MAT_FORM_FIELD]
3872 }] }];
3873 }, propDecorators: { rangePicker: [{
3874 type: Input
3875 }], required: [{
3876 type: Input
3877 }], dateFilter: [{
3878 type: Input
3879 }], min: [{
3880 type: Input
3881 }], max: [{
3882 type: Input
3883 }], disabled: [{
3884 type: Input
3885 }], separator: [{
3886 type: Input
3887 }], comparisonStart: [{
3888 type: Input
3889 }], comparisonEnd: [{
3890 type: Input
3891 }], _startInput: [{
3892 type: ContentChild,
3893 args: [MatStartDate]
3894 }], _endInput: [{
3895 type: ContentChild,
3896 args: [MatEndDate]
3897 }] } });
3898
3899/**
3900 * @license
3901 * Copyright Google LLC All Rights Reserved.
3902 *
3903 * Use of this source code is governed by an MIT-style license that can be
3904 * found in the LICENSE file at https://angular.io/license
3905 */
3906// TODO(mmalerba): We use a component instead of a directive here so the user can use implicit
3907// template reference variables (e.g. #d vs #d="matDateRangePicker"). We can change this to a
3908// directive if angular adds support for `exportAs: '$implicit'` on directives.
3909/** Component responsible for managing the date range picker popup/dialog. */
3910class MatDateRangePicker extends MatDatepickerBase {
3911 _forwardContentValues(instance) {
3912 super._forwardContentValues(instance);
3913 const input = this.datepickerInput;
3914 if (input) {
3915 instance.comparisonStart = input.comparisonStart;
3916 instance.comparisonEnd = input.comparisonEnd;
3917 }
3918 }
3919}
3920MatDateRangePicker.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDateRangePicker, deps: null, target: i0.ɵɵFactoryTarget.Component });
3921MatDateRangePicker.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.1", type: MatDateRangePicker, selector: "mat-date-range-picker", providers: [
3922 MAT_RANGE_DATE_SELECTION_MODEL_PROVIDER,
3923 MAT_CALENDAR_RANGE_STRATEGY_PROVIDER,
3924 { provide: MatDatepickerBase, useExisting: MatDateRangePicker },
3925 ], exportAs: ["matDateRangePicker"], usesInheritance: true, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
3926i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDateRangePicker, decorators: [{
3927 type: Component,
3928 args: [{
3929 selector: 'mat-date-range-picker',
3930 template: '',
3931 exportAs: 'matDateRangePicker',
3932 changeDetection: ChangeDetectionStrategy.OnPush,
3933 encapsulation: ViewEncapsulation.None,
3934 providers: [
3935 MAT_RANGE_DATE_SELECTION_MODEL_PROVIDER,
3936 MAT_CALENDAR_RANGE_STRATEGY_PROVIDER,
3937 { provide: MatDatepickerBase, useExisting: MatDateRangePicker },
3938 ],
3939 }]
3940 }] });
3941
3942/**
3943 * @license
3944 * Copyright Google LLC All Rights Reserved.
3945 *
3946 * Use of this source code is governed by an MIT-style license that can be
3947 * found in the LICENSE file at https://angular.io/license
3948 */
3949/** Button that will close the datepicker and assign the current selection to the data model. */
3950class MatDatepickerApply {
3951 constructor(_datepicker) {
3952 this._datepicker = _datepicker;
3953 }
3954 _applySelection() {
3955 this._datepicker._applyPendingSelection();
3956 this._datepicker.close();
3957 }
3958}
3959MatDatepickerApply.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDatepickerApply, deps: [{ token: MatDatepickerBase }], target: i0.ɵɵFactoryTarget.Directive });
3960MatDatepickerApply.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.1", type: MatDatepickerApply, selector: "[matDatepickerApply], [matDateRangePickerApply]", host: { listeners: { "click": "_applySelection()" } }, ngImport: i0 });
3961i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDatepickerApply, decorators: [{
3962 type: Directive,
3963 args: [{
3964 selector: '[matDatepickerApply], [matDateRangePickerApply]',
3965 host: { '(click)': '_applySelection()' },
3966 }]
3967 }], ctorParameters: function () { return [{ type: MatDatepickerBase }]; } });
3968/** Button that will close the datepicker and discard the current selection. */
3969class MatDatepickerCancel {
3970 constructor(_datepicker) {
3971 this._datepicker = _datepicker;
3972 }
3973}
3974MatDatepickerCancel.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDatepickerCancel, deps: [{ token: MatDatepickerBase }], target: i0.ɵɵFactoryTarget.Directive });
3975MatDatepickerCancel.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.1", type: MatDatepickerCancel, selector: "[matDatepickerCancel], [matDateRangePickerCancel]", host: { listeners: { "click": "_datepicker.close()" } }, ngImport: i0 });
3976i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDatepickerCancel, decorators: [{
3977 type: Directive,
3978 args: [{
3979 selector: '[matDatepickerCancel], [matDateRangePickerCancel]',
3980 host: { '(click)': '_datepicker.close()' },
3981 }]
3982 }], ctorParameters: function () { return [{ type: MatDatepickerBase }]; } });
3983/**
3984 * Container that can be used to project a row of action buttons
3985 * to the bottom of a datepicker or date range picker.
3986 */
3987class MatDatepickerActions {
3988 constructor(_datepicker, _viewContainerRef) {
3989 this._datepicker = _datepicker;
3990 this._viewContainerRef = _viewContainerRef;
3991 }
3992 ngAfterViewInit() {
3993 this._portal = new TemplatePortal(this._template, this._viewContainerRef);
3994 this._datepicker.registerActions(this._portal);
3995 }
3996 ngOnDestroy() {
3997 var _a;
3998 this._datepicker.removeActions(this._portal);
3999 // Needs to be null checked since we initialize it in `ngAfterViewInit`.
4000 if (this._portal && this._portal.isAttached) {
4001 (_a = this._portal) === null || _a === void 0 ? void 0 : _a.detach();
4002 }
4003 }
4004}
4005MatDatepickerActions.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDatepickerActions, deps: [{ token: MatDatepickerBase }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Component });
4006MatDatepickerActions.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.1", type: MatDatepickerActions, selector: "mat-datepicker-actions, mat-date-range-picker-actions", viewQueries: [{ propertyName: "_template", first: true, predicate: TemplateRef, descendants: true }], ngImport: i0, template: `
4007 <ng-template>
4008 <div class="mat-datepicker-actions">
4009 <ng-content></ng-content>
4010 </div>
4011 </ng-template>
4012 `, isInline: true, styles: [".mat-datepicker-actions{display:flex;justify-content:flex-end;align-items:center;padding:0 8px 8px 8px}.mat-datepicker-actions .mat-button-base+.mat-button-base{margin-left:8px}[dir=rtl] .mat-datepicker-actions .mat-button-base+.mat-button-base{margin-left:0;margin-right:8px}"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
4013i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDatepickerActions, decorators: [{
4014 type: Component,
4015 args: [{ selector: 'mat-datepicker-actions, mat-date-range-picker-actions', template: `
4016 <ng-template>
4017 <div class="mat-datepicker-actions">
4018 <ng-content></ng-content>
4019 </div>
4020 </ng-template>
4021 `, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, styles: [".mat-datepicker-actions{display:flex;justify-content:flex-end;align-items:center;padding:0 8px 8px 8px}.mat-datepicker-actions .mat-button-base+.mat-button-base{margin-left:8px}[dir=rtl] .mat-datepicker-actions .mat-button-base+.mat-button-base{margin-left:0;margin-right:8px}"] }]
4022 }], ctorParameters: function () { return [{ type: MatDatepickerBase }, { type: i0.ViewContainerRef }]; }, propDecorators: { _template: [{
4023 type: ViewChild,
4024 args: [TemplateRef]
4025 }] } });
4026
4027/**
4028 * @license
4029 * Copyright Google LLC All Rights Reserved.
4030 *
4031 * Use of this source code is governed by an MIT-style license that can be
4032 * found in the LICENSE file at https://angular.io/license
4033 */
4034class MatDatepickerModule {
4035}
4036MatDatepickerModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDatepickerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
4037MatDatepickerModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.0.1", ngImport: i0, type: MatDatepickerModule, declarations: [MatCalendar,
4038 MatCalendarBody,
4039 MatDatepicker,
4040 MatDatepickerContent,
4041 MatDatepickerInput,
4042 MatDatepickerToggle,
4043 MatDatepickerToggleIcon,
4044 MatMonthView,
4045 MatYearView,
4046 MatMultiYearView,
4047 MatCalendarHeader,
4048 MatDateRangeInput,
4049 MatStartDate,
4050 MatEndDate,
4051 MatDateRangePicker,
4052 MatDatepickerActions,
4053 MatDatepickerCancel,
4054 MatDatepickerApply], imports: [CommonModule,
4055 MatButtonModule,
4056 OverlayModule,
4057 A11yModule,
4058 PortalModule,
4059 MatCommonModule], exports: [CdkScrollableModule,
4060 MatCalendar,
4061 MatCalendarBody,
4062 MatDatepicker,
4063 MatDatepickerContent,
4064 MatDatepickerInput,
4065 MatDatepickerToggle,
4066 MatDatepickerToggleIcon,
4067 MatMonthView,
4068 MatYearView,
4069 MatMultiYearView,
4070 MatCalendarHeader,
4071 MatDateRangeInput,
4072 MatStartDate,
4073 MatEndDate,
4074 MatDateRangePicker,
4075 MatDatepickerActions,
4076 MatDatepickerCancel,
4077 MatDatepickerApply] });
4078MatDatepickerModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDatepickerModule, providers: [MatDatepickerIntl, MAT_DATEPICKER_SCROLL_STRATEGY_FACTORY_PROVIDER], imports: [CommonModule,
4079 MatButtonModule,
4080 OverlayModule,
4081 A11yModule,
4082 PortalModule,
4083 MatCommonModule, CdkScrollableModule] });
4084i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatDatepickerModule, decorators: [{
4085 type: NgModule,
4086 args: [{
4087 imports: [
4088 CommonModule,
4089 MatButtonModule,
4090 OverlayModule,
4091 A11yModule,
4092 PortalModule,
4093 MatCommonModule,
4094 ],
4095 exports: [
4096 CdkScrollableModule,
4097 MatCalendar,
4098 MatCalendarBody,
4099 MatDatepicker,
4100 MatDatepickerContent,
4101 MatDatepickerInput,
4102 MatDatepickerToggle,
4103 MatDatepickerToggleIcon,
4104 MatMonthView,
4105 MatYearView,
4106 MatMultiYearView,
4107 MatCalendarHeader,
4108 MatDateRangeInput,
4109 MatStartDate,
4110 MatEndDate,
4111 MatDateRangePicker,
4112 MatDatepickerActions,
4113 MatDatepickerCancel,
4114 MatDatepickerApply,
4115 ],
4116 declarations: [
4117 MatCalendar,
4118 MatCalendarBody,
4119 MatDatepicker,
4120 MatDatepickerContent,
4121 MatDatepickerInput,
4122 MatDatepickerToggle,
4123 MatDatepickerToggleIcon,
4124 MatMonthView,
4125 MatYearView,
4126 MatMultiYearView,
4127 MatCalendarHeader,
4128 MatDateRangeInput,
4129 MatStartDate,
4130 MatEndDate,
4131 MatDateRangePicker,
4132 MatDatepickerActions,
4133 MatDatepickerCancel,
4134 MatDatepickerApply,
4135 ],
4136 providers: [MatDatepickerIntl, MAT_DATEPICKER_SCROLL_STRATEGY_FACTORY_PROVIDER],
4137 }]
4138 }] });
4139
4140/**
4141 * @license
4142 * Copyright Google LLC All Rights Reserved.
4143 *
4144 * Use of this source code is governed by an MIT-style license that can be
4145 * found in the LICENSE file at https://angular.io/license
4146 */
4147
4148/**
4149 * @license
4150 * Copyright Google LLC All Rights Reserved.
4151 *
4152 * Use of this source code is governed by an MIT-style license that can be
4153 * found in the LICENSE file at https://angular.io/license
4154 */
4155
4156/**
4157 * Generated bundle index. Do not edit.
4158 */
4159
4160export { DateRange, DefaultMatCalendarRangeStrategy, MAT_DATEPICKER_SCROLL_STRATEGY, MAT_DATEPICKER_SCROLL_STRATEGY_FACTORY, MAT_DATEPICKER_SCROLL_STRATEGY_FACTORY_PROVIDER, MAT_DATEPICKER_VALIDATORS, MAT_DATEPICKER_VALUE_ACCESSOR, MAT_DATE_RANGE_SELECTION_STRATEGY, MAT_RANGE_DATE_SELECTION_MODEL_FACTORY, MAT_RANGE_DATE_SELECTION_MODEL_PROVIDER, MAT_SINGLE_DATE_SELECTION_MODEL_FACTORY, MAT_SINGLE_DATE_SELECTION_MODEL_PROVIDER, MatCalendar, MatCalendarBody, MatCalendarCell, MatCalendarHeader, MatDateRangeInput, MatDateRangePicker, MatDateSelectionModel, MatDatepicker, MatDatepickerActions, MatDatepickerApply, MatDatepickerCancel, MatDatepickerContent, MatDatepickerInput, MatDatepickerInputEvent, MatDatepickerIntl, MatDatepickerModule, MatDatepickerToggle, MatDatepickerToggleIcon, MatEndDate, MatMonthView, MatMultiYearView, MatRangeDateSelectionModel, MatSingleDateSelectionModel, MatStartDate, MatYearView, matDatepickerAnimations, yearsPerPage, yearsPerRow };
4161//# sourceMappingURL=datepicker.mjs.map