igniteui-webcomponents
Version:
Ignite UI for Web Components is a complete library of UI components, giving you the ability to build modern web applications using encapsulation and the concept of reusable components in a dependency-free approach.
399 lines • 14.9 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { getDateFormatter } from 'igniteui-i18n-core';
import { html } from 'lit';
import { eventOptions, property } from 'lit/decorators.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { live } from 'lit/directives/live.js';
import { addThemingController } from '../../theming/theming-controller.js';
import { convertToDate, isValidDate } from '../calendar/helpers.js';
import { addKeybindings, arrowDown, arrowLeft, arrowRight, arrowUp, ctrlKey, } from '../common/controllers/key-bindings.js';
import { addSlotController, setSlots } from '../common/controllers/slot.js';
import { registerComponent } from '../common/definitions/register.js';
import { addI18nController, formatDisplayDate, getDefaultDateTimeFormat, } from '../common/i18n/i18n-controller.js';
import { EventEmitterMixin } from '../common/mixins/event-emitter.js';
import { FormValueDateTimeTransformers } from '../common/mixins/forms/form-transformers.js';
import { createFormValueState } from '../common/mixins/forms/form-value.js';
import { partMap } from '../common/part-map.js';
import { styles } from '../input/themes/input.base.css.js';
import { styles as shared } from '../input/themes/shared/input.common.css.js';
import { all } from '../input/themes/themes.js';
import { IgcMaskInputBaseComponent, } from '../mask-input/mask-input-base.js';
import IgcValidationContainerComponent from '../validation-container/validation-container.js';
import { DatePart, DEFAULT_DATE_PARTS_SPIN_DELTAS, } from './date-part.js';
import { createDatePart, DateParts, DateTimeMaskParser, } from './datetime-mask-parser.js';
import { dateTimeInputValidators } from './validators.js';
const Slots = setSlots('prefix', 'suffix', 'helper-text', 'value-missing', 'range-overflow', 'range-underflow', 'custom-error', 'invalid');
export default class IgcDateTimeInputComponent extends EventEmitterMixin(IgcMaskInputBaseComponent) {
static { this.tagName = 'igc-date-time-input'; }
static { this.styles = [styles, shared]; }
static register() {
registerComponent(IgcDateTimeInputComponent, IgcValidationContainerComponent);
}
get __validators() {
return dateTimeInputValidators;
}
get _targetDatePart() {
return this._focused
? this._getDatePartAtCursor()
: this._getDefaultDatePart();
}
get _datePartDeltas() {
return { ...DEFAULT_DATE_PARTS_SPIN_DELTAS, ...this.spinDelta };
}
set inputFormat(val) {
if (val) {
this._applyMask(val);
this._inputFormat = val;
this._updateMaskDisplay();
}
}
get inputFormat() {
return this._inputFormat || this._parser.mask;
}
set value(value) {
this._formValue.setValueAndFormState(value);
this._updateMaskDisplay();
}
get value() {
return this._formValue.value;
}
set min(value) {
this._min = convertToDate(value);
this._validate();
}
get min() {
return this._min;
}
set max(value) {
this._max = convertToDate(value);
this._validate();
}
get max() {
return this._max;
}
set displayFormat(value) {
this._displayFormat = value;
}
get displayFormat() {
return (this._displayFormat ?? this._inputFormat ?? this._defaultDisplayFormat);
}
set locale(value) {
this._i18nController.locale = value;
}
get locale() {
return this._i18nController.locale;
}
constructor() {
super();
this._parser = new DateTimeMaskParser();
this._defaultDisplayFormat = '';
this._oldValue = null;
this._min = null;
this._max = null;
this._i18nController = addI18nController(this, {
defaultEN: {},
onResourceChange: this._handleResourceChange,
});
this._themes = addThemingController(this, all);
this._slots = addSlotController(this, {
slots: Slots,
});
this._formValue = createFormValueState(this, {
initialValue: null,
transformers: FormValueDateTimeTransformers,
});
this.spinLoop = true;
addKeybindings(this, {
skip: () => this.readOnly,
bindingDefaults: { triggers: ['keydownRepeat'] },
})
.set([ctrlKey, ';'], this._setCurrentDateTime)
.set(arrowUp, this._keyboardSpin.bind(this, 'up'))
.set(arrowDown, this._keyboardSpin.bind(this, 'down'))
.set([ctrlKey, arrowLeft], this._navigateParts.bind(this, 0))
.set([ctrlKey, arrowRight], this._navigateParts.bind(this, 1));
}
update(props) {
if (props.has('displayFormat')) {
this._updateDefaultDisplayFormat();
}
if (props.has('locale')) {
this._initializeDefaultMask();
}
if (props.has('displayFormat') || props.has('locale')) {
this._updateMaskDisplay();
}
super.update(props);
}
_resolvePartNames(base) {
const result = super._resolvePartNames(base);
result.filled = result.filled || !this._isEmptyMask;
return result;
}
_updateSetRangeTextValue() {
this._updateValueFromMask();
}
_emitInputEvent() {
this._setTouchedState();
this.emitEvent('igcInput', { detail: this.value?.toString() });
}
_handleResourceChange() {
this._initializeDefaultMask();
this._updateMaskDisplay();
}
_handleDragLeave() {
if (!this._focused) {
this._updateMaskDisplay();
}
}
_handleDragEnter() {
if (!this._focused) {
this._maskedValue = this._buildMaskedValue();
}
}
async _handleWheel(event) {
if (!this._focused || this.readOnly) {
return;
}
event.preventDefault();
event.stopPropagation();
const { start, end } = this._inputSelection;
event.deltaY > 0 ? this.stepDown() : this.stepUp();
this._emitInputEvent();
await this.updateComplete;
this.setSelectionRange(start, end);
}
async _handleFocus() {
this._focused = true;
if (this.readOnly) {
return;
}
this._oldValue = this.value;
if (!this.value) {
this._maskedValue = this._parser.emptyMask;
await this.updateComplete;
this.select();
}
else if (this.displayFormat !== this.inputFormat) {
this._updateMaskDisplay();
}
}
_handleBlur() {
this._focused = false;
if (!(this._isMaskComplete() || this._isEmptyMask)) {
const parsedDate = this._parser.parseDate(this._maskedValue);
if (parsedDate) {
this.value = parsedDate;
}
else {
this.clear();
}
}
else {
this._updateMaskDisplay();
}
if (!this.readOnly && this._oldValue !== this.value) {
this.emitEvent('igcChange', { detail: this.value });
}
super._handleBlur();
}
_setCurrentDateTime() {
this.value = new Date();
this._emitInputEvent();
}
_navigateParts(direction) {
const position = this._calculatePartNavigationPosition(this._input?.value ?? '', direction);
this.setSelectionRange(position, position);
}
_calculatePartNavigationPosition(inputValue, direction) {
const cursorPos = this._maskSelection.start;
const dateParts = this._parser.dateParts;
if (direction === 0) {
const part = dateParts.findLast((part) => part.type === DateParts.Literal && part.end < cursorPos);
return part?.end ?? 0;
}
const part = dateParts.find((part) => part.type === DateParts.Literal && part.start > cursorPos);
return part?.start ?? inputValue.length;
}
async _keyboardSpin(direction) {
direction === 'up' ? this.stepUp() : this.stepDown();
this._emitInputEvent();
await this.updateComplete;
this.setSelectionRange(this._maskSelection.start, this._maskSelection.end);
}
_updateMaskDisplay() {
if (this._focused) {
this._maskedValue = this._buildMaskedValue();
return;
}
if (!isValidDate(this.value)) {
this._maskedValue = '';
return;
}
this._maskedValue = formatDisplayDate(this.value, this.locale, this.displayFormat);
}
async _updateInput(text, { start, end }) {
const result = this._parser.replace(this._maskedValue, text, start, end);
this._maskedValue = result.value;
this._updateValueFromMask();
this.requestUpdate();
if (start !== this.inputFormat.length) {
this._emitInputEvent();
}
await this.updateComplete;
this._input?.setSelectionRange(result.end, result.end);
}
_performStep(datePart, delta, isDecrement) {
const part = datePart || this._targetDatePart;
const { start, end } = this._inputSelection;
this.value = this._calculateSpunValue(part, delta, isDecrement);
this.updateComplete.then(() => this._input?.setSelectionRange(start, end));
}
_calculateSpunValue(datePart, delta, isDecrement) {
const effectiveDelta = delta || this._datePartDeltas[datePart] || 1;
const spinAmount = isDecrement
? -Math.abs(effectiveDelta)
: Math.abs(effectiveDelta);
return this._spinDatePart(datePart, spinAmount);
}
_spinDatePart(datePart, delta) {
if (!isValidDate(this.value)) {
return new Date();
}
const newDate = new Date(this.value.getTime());
const partType = datePart;
let part = this._parser.getPartByType(partType);
if (!part) {
part = createDatePart(partType, { start: 0, end: 0, format: '' });
}
let amPmValue;
if (datePart === DatePart.AmPm) {
const formatPart = this._parser.getPartByType(DateParts.AmPm);
if (formatPart) {
amPmValue = this._maskedValue.substring(formatPart.start, formatPart.end);
}
}
part.spin(delta, {
date: newDate,
spinLoop: this.spinLoop,
amPmValue,
originalDate: this.value,
});
return newDate;
}
_updateDefaultDisplayFormat() {
this._defaultDisplayFormat = getDateFormatter().getLocaleDateTimeFormat(this.locale);
}
_applyMask(formatString) {
const previous = this._parser.mask;
this._parser.mask = formatString;
if (!this.placeholder || previous === this.placeholder) {
this.placeholder = this._parser.mask;
}
}
_buildMaskedValue() {
return isValidDate(this.value)
? this._parser.formatDate(this.value)
: this._maskedValue || this._parser.emptyMask;
}
_initializeDefaultMask() {
this._updateDefaultDisplayFormat();
if (!this._inputFormat) {
this._applyMask(getDefaultDateTimeFormat(this.locale));
}
}
_getDatePartAtCursor() {
return this._parser.getDatePartForCursor(this._inputSelection.start)
?.type;
}
_getDefaultDatePart() {
return (this._parser.getPartByType(DateParts.Date)?.type ??
this._parser.getPartByType(DateParts.Hours)?.type ??
this._parser.getFirstDatePart()?.type);
}
_isMaskComplete() {
return !this._maskedValue.includes(this.prompt);
}
_updateValueFromMask() {
if (!this._isMaskComplete()) {
this.value = null;
return;
}
const parsedDate = this._parser.parseDate(this._maskedValue);
this.value = isValidDate(parsedDate) ? parsedDate : null;
}
stepUp(datePart, delta) {
this._performStep(datePart, delta, false);
}
stepDown(datePart, delta) {
this._performStep(datePart, delta, true);
}
clear() {
this._maskedValue = '';
this.value = null;
}
hasDateParts() {
return this._parser.hasDateParts();
}
hasTimeParts() {
return this._parser.hasTimeParts();
}
_renderInput() {
return html `
<input
type="text"
part=${partMap(this._resolvePartNames('input'))}
name=${ifDefined(this.name)}
.value=${live(this._maskedValue)}
.placeholder=${this.placeholder || this._parser.emptyMask}
?readonly=${this.readOnly}
?disabled=${this.disabled}
=${this._handleBlur}
=${this._handleFocus}
=${this._handleInput}
=${this._handleWheel}
=${this._setMaskSelection}
=${this._handleClick}
=${this._setMaskSelection}
=${this._handleCompositionStart}
=${this._handleCompositionEnd}
=${this._handleDragEnter}
=${this._handleDragLeave}
=${this._setMaskSelection}
/>
`;
}
}
__decorate([
property({ attribute: 'input-format' })
], IgcDateTimeInputComponent.prototype, "inputFormat", null);
__decorate([
property({ converter: convertToDate })
], IgcDateTimeInputComponent.prototype, "value", null);
__decorate([
property({ converter: convertToDate })
], IgcDateTimeInputComponent.prototype, "min", null);
__decorate([
property({ converter: convertToDate })
], IgcDateTimeInputComponent.prototype, "max", null);
__decorate([
property({ attribute: 'display-format' })
], IgcDateTimeInputComponent.prototype, "displayFormat", null);
__decorate([
property({ attribute: false })
], IgcDateTimeInputComponent.prototype, "spinDelta", void 0);
__decorate([
property({ type: Boolean, attribute: 'spin-loop' })
], IgcDateTimeInputComponent.prototype, "spinLoop", void 0);
__decorate([
property()
], IgcDateTimeInputComponent.prototype, "locale", null);
__decorate([
eventOptions({ passive: false })
], IgcDateTimeInputComponent.prototype, "_handleWheel", null);
//# sourceMappingURL=date-time-input.js.map