sass-references/angular-material/material/datepicker/datepicker-input.ts

211 lines
6.4 KiB
TypeScript
Raw Normal View History

2024-12-06 10:42:08 +08:00
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {Directive, ElementRef, forwardRef, Input, OnDestroy, signal, inject} from '@angular/core';
import {NG_VALIDATORS, NG_VALUE_ACCESSOR, ValidatorFn, Validators} from '@angular/forms';
import {ThemePalette} from '@angular/material/core';
import {MAT_FORM_FIELD} from '@angular/material/form-field';
import {MAT_INPUT_VALUE_ACCESSOR} from '@angular/material/input';
import {Subscription} from 'rxjs';
import {DateSelectionModelChange} from './date-selection-model';
import {MatDatepickerControl, MatDatepickerPanel} from './datepicker-base';
import {_MatFormFieldPartial, DateFilterFn, MatDatepickerInputBase} from './datepicker-input-base';
/** @docs-private */
export const MAT_DATEPICKER_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => MatDatepickerInput),
multi: true,
};
/** @docs-private */
export const MAT_DATEPICKER_VALIDATORS: any = {
provide: NG_VALIDATORS,
useExisting: forwardRef(() => MatDatepickerInput),
multi: true,
};
/** Directive used to connect an input to a MatDatepicker. */
@Directive({
selector: 'input[matDatepicker]',
providers: [
MAT_DATEPICKER_VALUE_ACCESSOR,
MAT_DATEPICKER_VALIDATORS,
{provide: MAT_INPUT_VALUE_ACCESSOR, useExisting: MatDatepickerInput},
],
host: {
'class': 'mat-datepicker-input',
'[attr.aria-haspopup]': '_datepicker ? "dialog" : null',
'[attr.aria-owns]': '_ariaOwns()',
'[attr.min]': 'min ? _dateAdapter.toIso8601(min) : null',
'[attr.max]': 'max ? _dateAdapter.toIso8601(max) : null',
// Used by the test harness to tie this input to its calendar. We can't depend on
// `aria-owns` for this, because it's only defined while the calendar is open.
'[attr.data-mat-calendar]': '_datepicker ? _datepicker.id : null',
'[disabled]': 'disabled',
'(input)': '_onInput($event.target.value)',
'(change)': '_onChange()',
'(blur)': '_onBlur()',
'(keydown)': '_onKeydown($event)',
},
exportAs: 'matDatepickerInput',
})
export class MatDatepickerInput<D>
extends MatDatepickerInputBase<D | null, D>
implements MatDatepickerControl<D | null>, OnDestroy
{
private _formField = inject<_MatFormFieldPartial>(MAT_FORM_FIELD, {optional: true});
private _closedSubscription = Subscription.EMPTY;
private _openedSubscription = Subscription.EMPTY;
/** The datepicker that this input is associated with. */
@Input()
set matDatepicker(datepicker: MatDatepickerPanel<MatDatepickerControl<D>, D | null, D>) {
if (datepicker) {
this._datepicker = datepicker;
this._ariaOwns.set(datepicker.opened ? datepicker.id : null);
this._closedSubscription = datepicker.closedStream.subscribe(() => {
this._onTouched();
this._ariaOwns.set(null);
});
this._openedSubscription = datepicker.openedStream.subscribe(() => {
this._ariaOwns.set(datepicker.id);
});
this._registerModel(datepicker.registerInput(this));
}
}
_datepicker: MatDatepickerPanel<MatDatepickerControl<D>, D | null, D>;
/** The id of the panel owned by this input. */
protected _ariaOwns = signal<string | null>(null);
/** The minimum valid date. */
@Input()
get min(): D | null {
return this._min;
}
set min(value: D | null) {
const validValue = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value));
if (!this._dateAdapter.sameDate(validValue, this._min)) {
this._min = validValue;
this._validatorOnChange();
}
}
private _min: D | null;
/** The maximum valid date. */
@Input()
get max(): D | null {
return this._max;
}
set max(value: D | null) {
const validValue = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(value));
if (!this._dateAdapter.sameDate(validValue, this._max)) {
this._max = validValue;
this._validatorOnChange();
}
}
private _max: D | null;
/** Function that can be used to filter out dates within the datepicker. */
@Input('matDatepickerFilter')
get dateFilter() {
return this._dateFilter;
}
set dateFilter(value: DateFilterFn<D | null>) {
const wasMatchingValue = this._matchesFilter(this.value);
this._dateFilter = value;
if (this._matchesFilter(this.value) !== wasMatchingValue) {
this._validatorOnChange();
}
}
private _dateFilter: DateFilterFn<D | null>;
/** The combined form control validator for this input. */
protected _validator: ValidatorFn | null;
constructor(...args: unknown[]);
constructor() {
super();
this._validator = Validators.compose(super._getValidators());
}
/**
* Gets the element that the datepicker popup should be connected to.
* @return The element to connect the popup to.
*/
getConnectedOverlayOrigin(): ElementRef {
return this._formField ? this._formField.getConnectedOverlayOrigin() : this._elementRef;
}
/** Gets the ID of an element that should be used a description for the calendar overlay. */
getOverlayLabelId(): string | null {
if (this._formField) {
return this._formField.getLabelId();
}
return this._elementRef.nativeElement.getAttribute('aria-labelledby');
}
/** Returns the palette used by the input's form field, if any. */
getThemePalette(): ThemePalette {
return this._formField ? this._formField.color : undefined;
}
/** Gets the value at which the calendar should start. */
getStartValue(): D | null {
return this.value;
}
override ngOnDestroy() {
super.ngOnDestroy();
this._closedSubscription.unsubscribe();
this._openedSubscription.unsubscribe();
}
/** Opens the associated datepicker. */
protected _openPopup(): void {
if (this._datepicker) {
this._datepicker.open();
}
}
protected _getValueFromModel(modelValue: D | null): D | null {
return modelValue;
}
protected _assignValueToModel(value: D | null): void {
if (this._model) {
this._model.updateSelection(value, this);
}
}
/** Gets the input's minimum date. */
_getMinDate() {
return this._min;
}
/** Gets the input's maximum date. */
_getMaxDate() {
return this._max;
}
/** Gets the input's date filtering function. */
protected _getDateFilter() {
return this._dateFilter;
}
protected _shouldHandleChangeEvent(event: DateSelectionModelChange<D>) {
return event.source !== this;
}
}