@wizco/fenixds-ngx
Version:
Componentes fenix design system para Angular.
673 lines • 132 kB
JavaScript
import { Component, EventEmitter, HostListener, Input, Output, ViewEncapsulation, forwardRef, } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, NG_VALIDATORS, NG_VALUE_ACCESSOR, ReactiveFormsModule, } from '@angular/forms';
import { buildDisabledPredicate, clampToMinute, coerceDate, formatDate, isValidDate, parseDate, toDateOnly, toIsoDateKey, } from './datepicker.utils';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
export class DatepickerComponent {
el;
openedChange = new EventEmitter();
mode = 'single';
valueFormat = 'api';
inline = false;
label = ' ';
placeholder;
placeholderStart = 'Data inicial';
placeholderEnd = 'Data final';
labelStart = ' ';
labelEnd = ' ';
inputId = 'datepicker_' + Math.random().toString(36).substring(2);
inputName;
required = false;
readonly = false;
showError = false;
allowTyping = true;
autoClose = true;
showClear = true;
highlightToday = true;
disableFuture = false;
disablePast = false;
minDate;
maxDate;
disableWeekends = false;
disableHolidays = false;
holidays = [];
dateFilter;
locale = 'pt-BR';
weekStartsOn = 0;
displayFormat;
apiFormat;
isMobile = window.innerWidth <= 768;
isOpen = false;
view = 'day';
control = null;
disabled = false;
selected = null;
rangeStart = null;
rangeEnd = null;
activeMonth = toDateOnly(new Date());
activeYearPageStart = new Date().getFullYear() - 6;
inputValue = '';
timeValue = '00:00';
manualInputError = null;
onTouched = () => { };
propagateChange = () => { };
constructor(el) {
this.el = el;
}
ngOnInit() {
if (this.inline) {
this.view = this.mode === 'month' ? 'month' : 'day';
}
}
writeValue(obj) {
this.manualInputError = null;
if (this.mode === 'range') {
const range = this.coerceRange(obj);
this.rangeStart = range?.start ? toDateOnly(range.start) : null;
this.rangeEnd = range?.end ? toDateOnly(range.end) : null;
this.activeMonth = toDateOnly(this.rangeStart || this.rangeEnd || new Date());
this.syncInputText();
return;
}
const date = this.coerceSingle(obj);
if (!date) {
this.selected = null;
this.inputValue = '';
if (this.mode === 'datetime')
this.timeValue = '00:00';
this.activeMonth = toDateOnly(new Date());
return;
}
if (this.mode === 'month') {
this.selected = new Date(date.getFullYear(), date.getMonth(), 1);
}
else if (this.mode === 'datetime') {
this.selected = clampToMinute(date);
this.timeValue = `${String(this.selected.getHours()).padStart(2, '0')}:${String(this.selected.getMinutes()).padStart(2, '0')}`;
}
else {
this.selected = toDateOnly(date);
}
this.activeMonth = toDateOnly(this.selected);
this.syncInputText();
}
registerOnChange(fn) {
this.propagateChange = fn;
}
registerOnTouched(fn) {
this.onTouched = fn;
}
setDisabledState(isDisabled) {
this.disabled = isDisabled;
if (isDisabled)
this.close();
}
validate(control) {
this.control = control;
if (this.manualInputError) {
return { wcoDateInvalid: { reason: this.manualInputError } };
}
const isDisabled = this.buildIsDisabled();
if (this.mode === 'range') {
if (this.required && (!this.rangeStart || !this.rangeEnd)) {
return { required: true };
}
if (this.rangeStart && this.rangeEnd) {
if (this.rangeStart.getTime() > this.rangeEnd.getTime()) {
return { wcoDateRange: { reason: 'startAfterEnd' } };
}
}
if (this.rangeStart) {
const result = isDisabled(this.rangeStart);
if (result.disabled) {
return {
wcoDateDisabled: { part: 'start', reason: result.reason },
};
}
}
if (this.rangeEnd) {
const result = isDisabled(this.rangeEnd);
if (result.disabled) {
return { wcoDateDisabled: { part: 'end', reason: result.reason } };
}
}
return null;
}
if (this.required && !this.selected) {
return { required: true };
}
if (this.selected) {
const result = isDisabled(this.selected);
if (result.disabled)
return { wcoDateDisabled: { reason: result.reason } };
}
return null;
}
get hasError() {
if (this.showError)
return true;
return !!this.control && this.control.invalid && this.control.touched;
}
get canInteract() {
return !this.disabled && !this.readonly;
}
get resolvedPlaceholder() {
if (this.mode === 'range') {
return (this.placeholder ||
`${this.placeholderStart || 'Data inicial'} - ${this.placeholderEnd || 'Data final'}`);
}
return this.placeholder || this.resolvedDisplayFormat();
}
open() {
if (!this.canInteract)
return;
this.isOpen = true;
this.view = this.mode === 'month' ? 'month' : 'day';
this.activeYearPageStart = this.activeMonth.getFullYear() - 6;
this.openedChange.emit(true);
}
close() {
if (this.inline)
return;
this.isOpen = false;
this.openedChange.emit(false);
}
toggleOpen() {
if (this.isOpen)
this.close();
else
this.open();
}
onInputChange(value) {
this.inputValue = value;
if (!this.allowTyping)
return;
this.manualInputError = null;
}
onInputBlur() {
this.onTouched();
if (!this.allowTyping)
return;
if (this.mode === 'range') {
const parsed = this.parseRangeText(this.inputValue);
if (!parsed && this.inputValue.trim()) {
this.manualInputError = 'format';
this.emitValue();
return;
}
this.manualInputError = null;
this.rangeStart = parsed?.start ? toDateOnly(parsed.start) : null;
this.rangeEnd = parsed?.end ? toDateOnly(parsed.end) : null;
if (this.rangeStart && this.rangeEnd) {
if (this.rangeStart.getTime() > this.rangeEnd.getTime()) {
const tmp = this.rangeStart;
this.rangeStart = this.rangeEnd;
this.rangeEnd = tmp;
}
}
const isDisabled = this.buildIsDisabled();
if (this.rangeStart && isDisabled(this.rangeStart).disabled) {
this.manualInputError = 'disabled';
}
if (this.rangeEnd && isDisabled(this.rangeEnd).disabled) {
this.manualInputError = 'disabled';
}
this.activeMonth = toDateOnly(this.rangeStart || this.rangeEnd || new Date());
this.syncInputText();
this.emitValue();
return;
}
const parsed = this.parseUserText(this.inputValue);
if (!parsed && this.inputValue.trim()) {
this.manualInputError = 'format';
this.emitValue();
return;
}
this.manualInputError = null;
this.applySingleSelection(parsed);
}
onTimeChange(value) {
this.timeValue = value;
if (this.mode !== 'datetime')
return;
if (!this.selected)
return;
const match = /^(\d{2}):(\d{2})$/.exec(value);
if (!match)
return;
const hour = Number.parseInt(match[1], 10);
const minute = Number.parseInt(match[2], 10);
if (hour > 23 || minute > 59)
return;
this.selected = new Date(this.selected.getFullYear(), this.selected.getMonth(), this.selected.getDate(), hour, minute, 0, 0);
this.syncInputText();
this.emitValue();
}
selectDay(day) {
if (!this.canInteract)
return;
if (day.disabled)
return;
if (this.mode === 'range') {
if (!this.rangeStart || (this.rangeStart && this.rangeEnd)) {
this.rangeStart = toDateOnly(day.date);
this.rangeEnd = null;
}
else {
const end = toDateOnly(day.date);
if (end.getTime() < this.rangeStart.getTime()) {
this.rangeEnd = this.rangeStart;
this.rangeStart = end;
}
else {
this.rangeEnd = end;
}
if (this.autoClose)
this.close();
}
this.activeMonth = toDateOnly(this.rangeStart || day.date);
this.syncInputText();
this.emitValue();
return;
}
if (this.mode === 'datetime') {
const match = /^(\d{2}):(\d{2})$/.exec(this.timeValue);
const hour = match ? Number.parseInt(match[1], 10) : 0;
const minute = match ? Number.parseInt(match[2], 10) : 0;
this.selected = new Date(day.date.getFullYear(), day.date.getMonth(), day.date.getDate(), hour, minute, 0, 0);
this.syncInputText();
this.emitValue();
if (this.autoClose)
this.close();
return;
}
this.selected = toDateOnly(day.date);
this.activeMonth = toDateOnly(this.selected);
this.syncInputText();
this.emitValue();
if (this.autoClose)
this.close();
}
selectMonth(monthIndex) {
if (!this.canInteract)
return;
const candidate = new Date(this.activeMonth.getFullYear(), monthIndex, 1);
const isDisabled = this.buildIsDisabled();
if (isDisabled(candidate).disabled)
return;
if (this.mode === 'month') {
this.selected = candidate;
this.activeMonth = toDateOnly(candidate);
this.syncInputText();
this.emitValue();
if (this.autoClose)
this.close();
return;
}
this.activeMonth = toDateOnly(candidate);
this.view = 'day';
}
selectYear(year) {
if (!this.canInteract)
return;
this.activeMonth = new Date(year, this.activeMonth.getMonth(), 1);
this.view = this.mode === 'month' ? 'month' : 'day';
}
prev() {
if (this.view === 'day') {
this.activeMonth = new Date(this.activeMonth.getFullYear(), this.activeMonth.getMonth() - 1, 1);
return;
}
if (this.view === 'month') {
this.activeMonth = new Date(this.activeMonth.getFullYear() - 1, this.activeMonth.getMonth(), 1);
return;
}
this.activeYearPageStart -= 12;
}
next() {
if (this.view === 'day') {
this.activeMonth = new Date(this.activeMonth.getFullYear(), this.activeMonth.getMonth() + 1, 1);
return;
}
if (this.view === 'month') {
this.activeMonth = new Date(this.activeMonth.getFullYear() + 1, this.activeMonth.getMonth(), 1);
return;
}
this.activeYearPageStart += 12;
}
switchView() {
if (this.view === 'day') {
this.view = 'month';
return;
}
if (this.view === 'month') {
this.view = 'year';
this.activeYearPageStart = this.activeMonth.getFullYear() - 6;
return;
}
this.view = this.mode === 'month' ? 'month' : 'day';
}
get headerLabel() {
if (this.view === 'month' || this.view === 'year') {
return String(this.activeMonth.getFullYear());
}
const monthFormatter = new Intl.DateTimeFormat(this.locale, {
month: 'long',
year: 'numeric',
});
const label = monthFormatter.format(new Date(this.activeMonth.getFullYear(), this.activeMonth.getMonth(), 1));
return label.charAt(0).toUpperCase() + label.slice(1);
}
get weekdayLabels() {
const formatter = new Intl.DateTimeFormat(this.locale, { weekday: 'short' });
const base = new Date(2023, 0, 1); // Sunday
const labels = [];
for (let i = 0; i < 7; i++) {
const day = new Date(base.getFullYear(), base.getMonth(), base.getDate() + i);
labels.push(formatter.format(day));
}
if (this.weekStartsOn === 1) {
const sunday = labels.shift();
if (sunday)
labels.push(sunday);
}
return labels.map((label) => {
const clean = label.replace('.', '').trim();
const first = Array.from(clean)[0] ?? '';
return first ? first.toLocaleUpperCase(this.locale) : '';
});
}
get days() {
const year = this.activeMonth.getFullYear();
const month = this.activeMonth.getMonth();
const first = new Date(year, month, 1);
const firstDow = first.getDay();
const offset = this.weekStartsOn === 1 ? (firstDow === 0 ? 6 : firstDow - 1) : firstDow;
const start = new Date(year, month, 1 - offset);
const isDisabled = this.buildIsDisabled();
const todayKey = toIsoDateKey(new Date());
const cells = [];
for (let i = 0; i < 42; i++) {
const date = new Date(start.getFullYear(), start.getMonth(), start.getDate() + i);
const inMonth = date.getMonth() === month;
const key = toIsoDateKey(date);
const disabled = isDisabled(date).disabled;
const isToday = this.highlightToday && key === todayKey;
const selectedKey = this.selected ? toIsoDateKey(this.selected) : null;
const startKey = this.rangeStart ? toIsoDateKey(this.rangeStart) : null;
const endKey = this.rangeEnd ? toIsoDateKey(this.rangeEnd) : null;
const isSelected = selectedKey ? key === selectedKey : false;
const isRangeStart = startKey ? key === startKey : false;
const isRangeEnd = endKey ? key === endKey : false;
const isInRange = this.mode === 'range' && this.rangeStart && this.rangeEnd
? !disabled &&
key >= toIsoDateKey(this.rangeStart) &&
key <= toIsoDateKey(this.rangeEnd)
: false;
cells.push({
date,
label: date.getDate(),
inMonth,
disabled,
isToday,
isSelected,
isRangeStart,
isRangeEnd,
isInRange,
});
}
return cells;
}
isCurrentYear(year) {
return year === new Date().getFullYear();
}
isSelectedYear(year) {
if (this.mode === 'range')
return false;
return !!this.selected && this.selected.getFullYear() === year;
}
isCurrentMonth(monthIndex) {
const now = new Date();
return (monthIndex === now.getMonth() && this.activeMonth.getFullYear() === now.getFullYear());
}
isSelectedMonth(monthIndex) {
if (this.mode === 'range')
return false;
return (!!this.selected &&
this.selected.getFullYear() === this.activeMonth.getFullYear() &&
this.selected.getMonth() === monthIndex);
}
get monthLabels() {
const formatter = new Intl.DateTimeFormat(this.locale, { month: 'short' });
const isDisabled = this.buildIsDisabled();
const year = this.activeMonth.getFullYear();
const items = [];
for (let i = 0; i < 12; i++) {
const date = new Date(year, i, 1);
const label = formatter.format(date).replace('.', '').trim();
items.push({
index: i,
label: label.toLocaleUpperCase(this.locale),
disabled: isDisabled(date).disabled,
});
}
return items;
}
get years() {
return Array.from({ length: 12 }, (_, i) => this.activeYearPageStart + i);
}
onDocumentClick(event) {
if (!this.isOpen)
return;
const target = event.target;
if (!target)
return;
if (!this.el.nativeElement.contains(target))
this.close();
}
onResize() {
this.isMobile = window.innerWidth <= 768;
}
getFixedContainingBlock(el) {
// In some environments (e.g. Storybook), an ancestor may have `transform`,
// which changes the containing block for `position: fixed`.
// When that happens, we must position relative to that ancestor.
let node = el.parentElement;
while (node && node !== document.documentElement) {
const style = window.getComputedStyle(node);
const hasTransform = style.transform && style.transform !== 'none';
const hasPerspective = style.perspective && style.perspective !== 'none';
const hasFilter = style.filter && style.filter !== 'none';
const hasContainPaint = style.contain?.includes('paint') ?? false;
if (hasTransform || hasPerspective || hasFilter || hasContainPaint) {
return node;
}
node = node.parentElement;
}
return null;
}
emitValue() {
this.propagateChange(this.buildOutgoingValue());
}
buildOutgoingValue() {
const resolvedApiFormat = this.resolvedApiFormat();
const resolvedDisplayFormat = this.resolvedDisplayFormat();
const format = this.valueFormat === 'api' ? resolvedApiFormat : resolvedDisplayFormat;
if (this.mode === 'range') {
const start = this.rangeStart
? formatDate(this.rangeStart, format)
: null;
const end = this.rangeEnd ? formatDate(this.rangeEnd, format) : null;
return { start, end };
}
if (!this.selected)
return null;
return formatDate(this.selected, format);
}
resolvedApiFormat() {
if (this.apiFormat)
return this.apiFormat;
if (this.mode === 'datetime')
return "yyyy-MM-dd'T'HH:mm";
if (this.mode === 'month')
return 'yyyy-MM';
return 'yyyy-MM-dd';
}
resolvedDisplayFormat() {
if (this.displayFormat)
return this.displayFormat;
if (this.mode === 'datetime')
return 'dd/MM/yyyy HH:mm';
if (this.mode === 'month')
return 'MM/yyyy';
return 'dd/MM/yyyy';
}
syncInputText() {
const display = this.resolvedDisplayFormat();
if (this.mode === 'range') {
const start = this.rangeStart ? formatDate(this.rangeStart, display) : '';
const end = this.rangeEnd ? formatDate(this.rangeEnd, display) : '';
this.inputValue = end ? `${start} - ${end}` : start;
return;
}
this.inputValue = this.selected ? formatDate(this.selected, display) : '';
}
parseUserText(value) {
const display = this.resolvedDisplayFormat();
const api = this.resolvedApiFormat();
const trimmed = value.trim();
if (!trimmed)
return null;
const parsedDisplay = parseDate(trimmed, display);
const parsedApi = parsedDisplay ? null : parseDate(trimmed, api);
const parsed = parsedDisplay || parsedApi;
if (!parsed)
return null;
if (this.mode === 'month')
return new Date(parsed.getFullYear(), parsed.getMonth(), 1);
if (this.mode === 'datetime')
return clampToMinute(parsed);
return toDateOnly(parsed);
}
parseRangeText(value) {
const trimmed = value.trim();
if (!trimmed)
return null;
const separators = [' - ', ' até ', ' to '];
let sepFound = null;
for (const sep of separators) {
if (trimmed.includes(sep)) {
sepFound = sep;
break;
}
}
if (!sepFound) {
const only = this.parseUserText(trimmed);
return { start: only, end: null };
}
const parts = trimmed.split(sepFound).map((p) => p.trim());
const startText = parts[0] || '';
const endText = parts.slice(1).join(sepFound).trim();
const start = startText ? this.parseUserText(startText) : null;
const end = endText ? this.parseUserText(endText) : null;
if (!start && !end)
return null;
return { start, end };
}
applySingleSelection(date) {
if (this.mode === 'range')
return;
if (!date) {
this.selected = null;
this.syncInputText();
this.emitValue();
return;
}
const isDisabled = this.buildIsDisabled();
if (isDisabled(date).disabled) {
this.manualInputError = 'disabled';
this.emitValue();
return;
}
this.manualInputError = null;
if (this.mode === 'month')
this.selected = new Date(date.getFullYear(), date.getMonth(), 1);
else if (this.mode === 'datetime')
this.selected = clampToMinute(date);
else
this.selected = toDateOnly(date);
this.activeMonth = toDateOnly(this.selected);
this.syncInputText();
this.emitValue();
}
coerceSingle(obj) {
if (obj === null || obj === undefined)
return null;
if (obj instanceof Date)
return isValidDate(obj) ? obj : null;
if (typeof obj === 'string')
return coerceDate(obj);
if (typeof obj === 'object' && 'start' in obj && 'end' in obj)
return null;
return null;
}
coerceRange(obj) {
if (!obj)
return null;
if (typeof obj !== 'object')
return null;
if (!('start' in obj) || !('end' in obj))
return null;
const start = coerceDate(obj.start);
const end = coerceDate(obj.end);
return { start, end };
}
buildIsDisabled() {
const min = coerceDate(this.minDate ?? null);
const max = coerceDate(this.maxDate ?? null);
const holidaySet = new Set();
for (const h of this.holidays || []) {
const d = coerceDate(h);
if (d)
holidaySet.add(toIsoDateKey(d));
}
return buildDisabledPredicate({
disableFuture: this.disableFuture,
disablePast: this.disablePast,
minDate: min,
maxDate: max,
disableWeekends: this.disableWeekends,
disableHolidays: this.disableHolidays,
holidaySet,
dateFilter: this.dateFilter || null,
});
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DatepickerComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: DatepickerComponent, isStandalone: true, selector: "wco-datepicker", inputs: { mode: "mode", valueFormat: "valueFormat", inline: "inline", label: "label", placeholder: "placeholder", placeholderStart: "placeholderStart", placeholderEnd: "placeholderEnd", labelStart: "labelStart", labelEnd: "labelEnd", inputId: "inputId", inputName: "inputName", required: "required", readonly: "readonly", showError: "showError", allowTyping: "allowTyping", autoClose: "autoClose", showClear: "showClear", highlightToday: "highlightToday", disableFuture: "disableFuture", disablePast: "disablePast", minDate: "minDate", maxDate: "maxDate", disableWeekends: "disableWeekends", disableHolidays: "disableHolidays", holidays: "holidays", dateFilter: "dateFilter", locale: "locale", weekStartsOn: "weekStartsOn", displayFormat: "displayFormat", apiFormat: "apiFormat" }, outputs: { openedChange: "openedChange" }, host: { listeners: { "document:click": "onDocumentClick($event)", "window:resize": "onResize()" } }, providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DatepickerComponent),
multi: true,
},
{
provide: NG_VALIDATORS,
useExisting: DatepickerComponent,
multi: true,
},
], ngImport: i0, template: "<div\n class=\"wco-datepicker\"\n [class.wco-datepicker--open]=\"isOpen\"\n [class.wco-datepicker--isMobile]=\"isMobile\"\n>\n <ng-container *ngIf=\"mode !== 'range' && !inline\">\n <div\n class=\"form-field wco-datepicker__field\"\n [class.form-field--error]=\"hasError\"\n [class.form-field--readonly]=\"readonly\"\n >\n <input\n [id]=\"inputId\"\n [name]=\"inputName\"\n [attr.required]=\"required ? '' : null\"\n [placeholder]=\"resolvedPlaceholder\"\n [readOnly]=\"readonly || !allowTyping\"\n [disabled]=\"disabled\"\n [value]=\"inputValue\"\n (click)=\"open()\"\n (input)=\"onInputChange($any($event.target).value)\"\n (blur)=\"onInputBlur()\"\n (keydown.enter)=\"$event.preventDefault(); onInputBlur()\"\n />\n <label [for]=\"inputId\">{{ label }}</label>\n\n <span\n class=\"material-icons-round wco-datepicker__suffix wco-datepicker__toggle\"\n (click)=\"toggleOpen()\"\n >calendar_today</span\n >\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"mode === 'range' && !inline\">\n <div\n class=\"form-field wco-datepicker__field\"\n [class.form-field--error]=\"hasError\"\n [class.form-field--readonly]=\"readonly\"\n >\n <input\n [id]=\"inputId\"\n [name]=\"inputName\"\n [attr.required]=\"required ? '' : null\"\n [placeholder]=\"resolvedPlaceholder\"\n [readOnly]=\"readonly || !allowTyping\"\n [disabled]=\"disabled\"\n [value]=\"inputValue\"\n (click)=\"open()\"\n (input)=\"onInputChange($any($event.target).value)\"\n (blur)=\"onInputBlur()\"\n (keydown.enter)=\"$event.preventDefault(); onInputBlur()\"\n />\n <label [for]=\"inputId\">{{ label }}</label>\n <span\n class=\"material-icons-round wco-datepicker__suffix wco-datepicker__toggle\"\n (click)=\"toggleOpen()\"\n >calendar_today</span\n >\n </div>\n </ng-container>\n\n <div\n class=\"wco-datepicker__box\"\n [class.wco-datepicker__box--open]=\"isOpen || inline\"\n [class.wco-datepicker__box--inline]=\"inline\"\n >\n <div class=\"wco-datepicker__panel\" (click)=\"$event.stopPropagation()\">\n <div class=\"wco-datepicker__header\">\n <button\n type=\"button\"\n class=\"wco-datepicker__title\"\n (click)=\"switchView()\"\n [disabled]=\"!canInteract\"\n >\n {{ headerLabel }}\n <span class=\"material-icons text-primary-600\">{{\n view === \"year\" ? \"arrow_drop_up\" : \"arrow_drop_down\"\n }}</span>\n </button>\n\n <button\n type=\"button\"\n class=\"wco-datepicker__nav\"\n (click)=\"prev()\"\n [disabled]=\"!canInteract\"\n >\n <span class=\"material-icons text-primary-600\">chevron_left</span>\n </button>\n\n <button\n type=\"button\"\n class=\"wco-datepicker__nav\"\n (click)=\"next()\"\n [disabled]=\"!canInteract\"\n >\n <span class=\"material-icons text-primary-600\">chevron_right</span>\n </button>\n </div>\n\n <div class=\"wco-datepicker__content\" *ngIf=\"view === 'day'\">\n <div class=\"wco-datepicker__weekdays\">\n <span *ngFor=\"let w of weekdayLabels\">{{ w }}</span>\n </div>\n <div class=\"wco-datepicker__grid\">\n <button\n type=\"button\"\n class=\"wco-datepicker__day\"\n *ngFor=\"let d of days\"\n [class.wco-datepicker__day--muted]=\"!d.inMonth\"\n [class.wco-datepicker__day--today]=\"d.isToday\"\n [class.wco-datepicker__day--selected]=\"d.isSelected\"\n [class.wco-datepicker__day--range]=\"d.isInRange\"\n [class.wco-datepicker__day--rangeStart]=\"d.isRangeStart\"\n [class.wco-datepicker__day--rangeEnd]=\"d.isRangeEnd\"\n [disabled]=\"d.disabled || !canInteract\"\n (click)=\"selectDay(d)\"\n >\n {{ d.label }}\n </button>\n </div>\n </div>\n\n <div class=\"wco-datepicker__content\" *ngIf=\"view === 'month'\">\n <div class=\"wco-datepicker__months\">\n <button\n type=\"button\"\n class=\"wco-datepicker__month\"\n *ngFor=\"let m of monthLabels\"\n [disabled]=\"m.disabled || !canInteract\"\n [class.wco-datepicker__month--active]=\"\n m.index === activeMonth.getMonth()\n \"\n [class.wco-datepicker__month--current]=\"isCurrentMonth(m.index)\"\n [class.wco-datepicker__month--selected]=\"isSelectedMonth(m.index)\"\n (click)=\"selectMonth(m.index)\"\n >\n {{ m.label }}\n </button>\n </div>\n </div>\n\n <div class=\"wco-datepicker__content\" *ngIf=\"view === 'year'\">\n <div class=\"wco-datepicker__years\">\n <button\n type=\"button\"\n class=\"wco-datepicker__year\"\n *ngFor=\"let y of years\"\n [class.wco-datepicker__year--active]=\"\n y === activeMonth.getFullYear()\n \"\n [class.wco-datepicker__year--current]=\"isCurrentYear(y)\"\n [class.wco-datepicker__year--selected]=\"isSelectedYear(y)\"\n [disabled]=\"!canInteract\"\n (click)=\"selectYear(y)\"\n >\n {{ y }}\n </button>\n </div>\n </div>\n\n <div class=\"wco-datepicker__time\" *ngIf=\"mode === 'datetime'\">\n <label class=\"wco-datepicker__timeLabel\">Hora</label>\n <input\n type=\"time\"\n class=\"wco-datepicker__timeInput\"\n [disabled]=\"disabled || readonly\"\n [value]=\"timeValue\"\n (input)=\"onTimeChange($any($event.target).value)\"\n />\n </div>\n </div>\n </div>\n</div>\n", styles: [":host{display:block;width:100%}.wco-datepicker{width:100%;position:relative;display:inline-block;--wco-datepicker-radius: var(--wco-radius-md, 8px);--wco-datepicker-shadow: var( --wco-shadow-level-1, 0px 2px 16px rgba(0, 0, 0, .2) );--wco-datepicker-bg: var(--wco-color-neutral-50, #fff);--wco-datepicker-border: 1px solid var(--wco-color-neutral-100, #e9ebec);--wco-datepicker-muted: var(--wco-color-neutral-500, #8d9399);--wco-datepicker-text: var(--wco-color-neutral-900, #080809);--wco-datepicker-primary: var(--wco-color-primary-600, #bf5600);--wco-datepicker-primary-weak: var(--wco-color-primary-50, #ffb578);--wco-datepicker-hover: var(--wco-color-neutral-100, #e9ebec)}.wco-datepicker .wco-datepicker__suffix{cursor:pointer;-webkit-user-select:none;user-select:none}.wco-datepicker .wco-datepicker__toggle{transition:transform .15s ease-in-out;color:var(--wco-color-primary-600)}.wco-datepicker--open .wco-datepicker__toggle{transform:rotate(180deg)}.wco-datepicker .wco-datepicker__box{position:absolute;max-width:270px;width:var(--wco-datepicker-overlay-width, 320px);z-index:2147483647;opacity:0;visibility:hidden;pointer-events:none;transition:opacity .12s ease-in-out,transform .12s ease-in-out;transform:translateY(-6px)}.wco-datepicker .wco-datepicker__box--open{opacity:1;visibility:visible;pointer-events:all;transform:translateY(0)}.wco-datepicker--isMobile .wco-datepicker__box{position:absolute;width:100%;padding:var(--wco-spacing-nano, 8px)}.wco-datepicker .wco-datepicker__box--inline{position:static;padding:0;transform:none;transition:none}.wco-datepicker .wco-datepicker__panel{background:var(--wco-datepicker-bg);border:var(--wco-datepicker-border);border-radius:var(--wco-datepicker-radius);box-shadow:var(--wco-datepicker-shadow);padding:var(--wco-spacing-nano, 8px)}.wco-datepicker .wco-datepicker__header{display:grid;grid-template-columns:1fr 40px 40px;gap:var(--wco-spacing-quark, 4px);align-items:center;margin-bottom:var(--wco-spacing-nano, 8px)}.wco-datepicker .wco-datepicker__nav{width:40px;height:40px;border:none;background:transparent;cursor:pointer;color:var(--wco-datepicker-text);display:flex;justify-content:center;align-items:center}.wco-datepicker .wco-datepicker__nav:hover:not(:disabled){background:var(--wco-datepicker-hover)}.wco-datepicker .wco-datepicker__nav:disabled{cursor:not-allowed;opacity:.6}.wco-datepicker .wco-datepicker__title{border:none;background:transparent;cursor:pointer;display:inline-flex;justify-content:flex-start;align-items:center;gap:var(--wco-spacing-quark, 4px);font-family:var(--wco-font-family);font-size:var(--wco-font-size-xs, 16px);color:var(--wco-datepicker-text);padding:var(--wco-spacing-quark, 4px) var(--wco-spacing-nano, 8px)}.wco-datepicker .wco-datepicker__title:hover:not(:disabled){background:var(--wco-datepicker-hover)}.wco-datepicker .wco-datepicker__title:disabled{cursor:not-allowed;opacity:.6}.wco-datepicker .wco-datepicker__weekdays{display:grid;grid-template-columns:repeat(7,1fr);gap:0;padding:0 var(--wco-spacing-quark, 4px);margin-bottom:var(--wco-spacing-quark, 4px);color:var(--wco-datepicker-muted);font-size:var(--wco-font-size-xxxs, 12px);text-align:center;-webkit-user-select:none;user-select:none}.wco-datepicker .wco-datepicker__weekdays>span{width:36px;justify-self:center}.wco-datepicker .wco-datepicker__grid{display:grid;grid-template-columns:repeat(7,1fr);gap:0}.wco-datepicker .wco-datepicker__day{width:36px;height:36px;justify-self:center;position:relative;isolation:isolate;border-radius:999px;border:1px solid transparent;background:transparent;cursor:pointer;font-family:var(--wco-font-family);font-size:var(--wco-font-size-xxxs, 12px);color:var(--wco-datepicker-text)}.wco-datepicker .wco-datepicker__day:hover:not(:disabled){background:var(--wco-datepicker-primary-weak);color:var(--wco-datepicker-primary)}.wco-datepicker .wco-datepicker__day:disabled{cursor:not-allowed;opacity:.35;background:transparent}.wco-datepicker .wco-datepicker__day--muted{color:var(--wco-datepicker-muted)}.wco-datepicker .wco-datepicker__day--today{border-color:var(--wco-datepicker-text)}.wco-datepicker .wco-datepicker__day--selected{background:var(--wco-datepicker-primary);border-color:var(--wco-datepicker-primary);color:var(--wco-color-primary-text, #fff)}.wco-datepicker .wco-datepicker__day--range{background:var(--wco-datepicker-primary-weak);color:var(--wco-datepicker-primary)}.wco-datepicker .wco-datepicker__day--range:not(.wco-datepicker .wco-datepicker__day--rangeStart):not(.wco-datepicker .wco-datepicker__day--rangeEnd){border-radius:0}.wco-datepicker .wco-datepicker__day--rangeStart,.wco-datepicker .wco-datepicker__day--rangeEnd{z-index:5;border-radius:999px;background:var(--wco-datepicker-primary);border-color:var(--wco-datepicker-primary);color:var(--wco-color-primary-text, #fff)}.wco-datepicker .wco-datepicker__months,.wco-datepicker .wco-datepicker__years{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--wco-spacing-quark, 4px)}.wco-datepicker .wco-datepicker__month,.wco-datepicker .wco-datepicker__year{height:26px;border-radius:999px;border:1px solid transparent;background:transparent;cursor:pointer;display:inline-flex;align-items:center;justify-content:flex-start;padding:0 var(--wco-spacing-nano, 8px);width:max-content;justify-self:flex-start;font-family:var(--wco-font-family);font-size:var(--wco-font-size-xxxs, 12px);color:var(--wco-datepicker-text);text-align:left}.wco-datepicker .wco-datepicker__month:hover:not(:disabled),.wco-datepicker .wco-datepicker__year:hover:not(:disabled){background:var(--wco-datepicker-primary-weak);color:var(--wco-datepicker-primary)}.wco-datepicker .wco-datepicker__month:disabled,.wco-datepicker .wco-datepicker__year:disabled{cursor:not-allowed;opacity:.35;background:transparent}.wco-datepicker .wco-datepicker__month--active,.wco-datepicker .wco-datepicker__year--active{background:transparent;border-color:var(--wco-datepicker-text);font-weight:600}.wco-datepicker .wco-datepicker__month--current,.wco-datepicker .wco-datepicker__year--current{border-color:var(--wco-datepicker-text)}.wco-datepicker .wco-datepicker__month--selected,.wco-datepicker .wco-datepicker__year--selected{background:var(--wco-datepicker-primary);border-color:var(--wco-datepicker-primary);color:var(--wco-color-primary-text, #fff);font-weight:600}.wco-datepicker .wco-datepicker__time{margin-top:var(--wco-spacing-nano, 8px);display:grid;grid-template-columns:1fr auto;gap:var(--wco-spacing-nano, 8px);align-items:center}.wco-datepicker .wco-datepicker__timeLabel{font-family:var(--wco-font-family);font-size:var(--wco-font-size-xxxs, 12px);color:var(--wco-datepicker-muted)}.wco-datepicker .wco-datepicker__timeInput{border:var(--wco-datepicker-border);border-radius:999px;padding:var(--wco-spacing-quark, 4px) var(--wco-spacing-nano, 8px);font-family:var(--wco-font-family);font-size:var(--wco-font-size-xxs, 14px)}.wco-datepicker .wco-datepicker__actions{margin-top:var(--wco-spacing-nano, 8px);display:flex;justify-content:space-between;gap:var(--wco-spacing-nano, 8px)}.wco-datepicker .wco-datepicker__action{border:none;background:transparent;cursor:pointer;font-family:var(--wco-font-family);font-size:var(--wco-font-size-xxs, 14px);color:var(--wco-datepicker-primary);padding:var(--wco-spacing-quark, 4px) var(--wco-spacing-nano, 8px);border-radius:999px}.wco-datepicker .wco-datepicker__action:hover:not(:disabled){background:var(--wco-datepicker-hover)}.wco-datepicker .wco-datepicker__action:disabled{cursor:not-allowed;opacity:.6}.wco-datepicker input[readonly]+label+.material-icons-round,.wco-datepicker input:disabled+label+.material-icons-round{cursor:pointer;color:var(--wco-color-neutral-300)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: FormsModule }], encapsulation: i0.ViewEncapsulation.None });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DatepickerComponent, decorators: [{
type: Component,
args: [{ selector: 'wco-datepicker', standalone: true, imports: [CommonModule, ReactiveFormsModule, FormsModule], encapsulation: ViewEncapsulation.None, providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DatepickerComponent),
multi: true,
},
{
provide: NG_VALIDATORS,
useExisting: DatepickerComponent,
multi: true,
},
], template: "<div\n class=\"wco-datepicker\"\n [class.wco-datepicker--open]=\"isOpen\"\n [class.wco-datepicker--isMobile]=\"isMobile\"\n>\n <ng-container *ngIf=\"mode !== 'range' && !inline\">\n <div\n class=\"form-field wco-datepicker__field\"\n [class.form-field--error]=\"hasError\"\n [class.form-field--readonly]=\"readonly\"\n >\n <input\n [id]=\"inputId\"\n [name]=\"inputName\"\n [attr.required]=\"required ? '' : null\"\n [placeholder]=\"resolvedPlaceholder\"\n [readOnly]=\"readonly || !allowTyping\"\n [disabled]=\"disabled\"\n [value]=\"inputValue\"\n (click)=\"open()\"\n (input)=\"onInputChange($any($event.target).value)\"\n (blur)=\"onInputBlur()\"\n (keydown.enter)=\"$event.preventDefault(); onInputBlur()\"\n />\n <label [for]=\"inputId\">{{ label }}</label>\n\n <span\n class=\"material-icons-round wco-datepicker__suffix wco-datepicker__toggle\"\n (click)=\"toggleOpen()\"\n >calendar_today</span\n >\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"mode === 'range' && !inline\">\n <div\n class=\"form-field wco-datepicker__field\"\n [class.form-field--error]=\"hasError\"\n [class.form-field--readonly]=\"readonly\"\n >\n <input\n [id]=\"inputId\"\n [name]=\"inputName\"\n [attr.required]=\"required ? '' : null\"\n [placeholder]=\"resolvedPlaceholder\"\n [readOnly]=\"readonly || !allowTyping\"\n [disabled]=\"disabled\"\n [value]=\"inputValue\"\n (click)=\"open()\"\n (input)=\"onInputChange($any($event.target).value)\"\n (blur)=\"onInputBlur()\"\n (keydown.enter)=\"$event.preventDefault(); onInputBlur()\"\n />\n <label [for]=\"inputId\">{{ label }}</label>\n <span\n class=\"material-icons-round wco-datepicker__suffix wco-datepicker__toggle\"\n (click)=\"toggleOpen()\"\n >calendar_today</span\n >\n </div>\n </ng-container>\n\n <div\n class=\"wco-datepicker__box\"\n [class.wco-datepicker__box--open]=\"isOpen || inline\"\n [class.wco-datepicker__box--inline]=\"inline\"\n >\n <div class=\"wco-datepicker__panel\" (click)=\"$event.stopPropagation()\">\n <div class=\"wco-datepicker__header\">\n <button\n type=\"button\"\n class=\"wco-datepicker__title\"\n (click)=\"switchView()\"\n [disabled]=\"!canInteract\"\n >\n {{ headerLabel }}\n <span class=\"material-icons text-primary-600\">{{\n view === \"year\" ? \"arrow_drop_up\" : \"arrow_drop_down\"\n }}</span>\n </button>\n\n <button\n type=\"button\"\n class=\"wco-datepicker__nav\"\n (click)=\"prev()\"\n [disabled]=\"!canInteract\"\n >\n <span class=\"material-icons text-primary-600\">chevron_left</span>\n </button>\n\n <button\n type=\"button\"\n class=\"wco-datepicker__nav\"\n (click)=\"next()\"\n [disabled]=\"!canInteract\"\n >\n <span class=\"material-icons text-primary-600\">chevron_right</span>\n </button>\n </div>\n\n <div class=\"wco-datepicker__content\" *ngIf=\"view === 'day'\">\n <div class=\"wco-datepicker__weekdays\">\n <span *ngFor=\"let w of weekdayLabels\">{{ w }}</span>\n </div>\n <div class=\"wco-datepicker__grid\">\n <button\n type=\"button\"\n class=\"wco-datepicker__day\"\n *ngFor=\"let d of days\"\n [class.wco-datepicker__day--muted]=\"!d.inMonth\"\n [class.wco-datepicker__day--today]=\"d.isToday\"\n [class.wco-datepicker__day--selected]=\"d.isSelected\"\n [class.wco-datepicker__day--range]=\"d.isInRange\"\n [class.wco-datepicker__day--rangeStart]=\"d.isRangeStart\"\n [class.wco-datepicker__day--rangeEnd]=\"d.isRangeEnd\"\n [disabled]=\"d.disabled || !canInteract\"\n (click)=\"selectDay(d)\"\n >\n {{ d.label }}\n </button>\n </div>\n </div>\n\n <div class=\"wco-datepicker__content\" *ngIf=\"view === 'month'\">\n <div class=\"wco-datepicker__months\">\n <button\n type=\"button\"\n class=\"wco-datepicker__month\"\n *ngFor=\"let m of monthLabels\"\n [disabled]=\"m.disabled || !canInteract\"\n [class.wco-datepicker__month--active]=\"\n m.index === activeMonth.getMonth()\n \"\n [class.wco-datepicker__month--current]=\"isCurrentMonth(m.index)\"\n [class.wco-datepicker__month--selected]=\"isSelectedMonth(m.index)\"\n (click)=\"selectMonth(m.index)\"\n >\n {{ m.label }}\n </button>\n </div>\n </div>\n\n <div class=\"wco-datepicker__content\" *ngIf=\"view === 'year'\">\n <div class=\"wco-datepicker__years\">\n <button\n type=\"button\"\n class=\"wco-datepicker__year\"\n *ngFor=\"let y of years\"\n [class.wco-datepicker__year--active]=\"\n y === activeMonth.getFullYear()\n \"\n [class.wco-datepicker__year--current]=\"isCurrentYear(y)\"\n [class.wco-datepicker__year--selected]=\"isSelectedYear(y)\"\n [disabled]=\"!canInteract\"\n (click)=\"selectYear(y)\"\n >\n {{ y }}\n </button>\n </div>\n </div>\n\n <div class=\"wco-datepicker__time\" *ngIf=\"mode === 'datetime'\">\n <label class=\"wco-datepicker__timeLabel\">Hora</label>\n <input\n type=\"time\"\n class=\"wco-datepicker__timeInput\"\n [disabled]=\"disabled || readonly\"\n [value]=\"timeValue\"\n (input)=\"onTimeChange($any($event.target).value)\"\n />\n </div>\n </div>\n </div>\n</div>\n", styles: [":host{display:block;width:100%}.wco-datepicker{width:100%;position:relative;display:inline-block;--wco-datepicker-radius: var(--wco-radius-md, 8px);--wco-datepicker-shadow: var( --wco-shadow-level-1, 0px 2px 16px rgba(0, 0, 0, .2) );--wco-datepicker-bg: var(--wco-color-neutral-50, #fff);--wco-datepicker-border: 1px solid var(--wco-color-neutral-100, #e9ebec);--wco-datepicker-muted: var(--wco-color-neutral-500, #8d9399);--wco-datepicker-text: var(--wco-color-neutral-900, #080809);--wco-datepicker-primary: var(--wco-color-primary-600, #bf5600);--wco-datepicker-primary-weak: var(--wco-color-primary-50, #ffb578);--wco-datepicker-hover: var(--wco-color-neutral-100, #e9ebec)}.wco-datepicker .wco-datepicker__suffix{cursor:pointer;-webkit-user-select:none;user-select:none}.wco-datepicker .wco-datepicker__toggle{transition:transform .15s ease-in-out;color:var(--wco-color-primary-600)}.wco-datepicker--open .wco-datepicker__toggle{transform:rotate(180deg)}.wco-datepicker .wco-datepicker__box{position:absolute;max-width:270px;width:var(--wco-datepicker-overlay-width, 320px);z-index:2147483647;opacity:0;visibility:hidden;pointer-events:none;transition:opacity .12s ease-in-out,transform .12s ease-in-out;transform:translateY(-6px)}.wco-datepicker .wco-datepicker__box--open{opacity:1;visibility:visible;pointer-events:all;transform:translateY(0)}.wco-datepicker--isMobile .wco-datepicker__box{position:absolute;width:100%;padding:var(--wco-spacing-nano, 8px)}.wco-datepicker .wco-datepicker__box--inline{position:static;padding:0;transform:none;transition:none}.wco-datepicker .wco-datepicker__panel{background:var(--wco-datepicker-bg);border:var(--wco-datepicker-border);border-radius:var(--wco-datepicker-radius);box-shadow:var(--wco-datepicker-shadow);padding:var(--wco-spacing-nano, 8px)}.wco-datepicker .wco-datepicker__header{display:grid;grid-template-columns:1fr 40px 40px;gap:var(--wco-spacing-quark, 4px);align-items:center;margin-bottom:var(--wco-spacing-nano, 8px)}.wco-datepicker .wco-datepicker__nav{width:40px;height:40px;border:none;background:transparent;cursor:pointer;color:var(--wco-datepicker-text);display:flex;justify-content:center;align-items:center}.wco-datepicker .wco-datepicker__nav:hover:not(:disabled){background:var(--wco-datepicker-hover)}.wco-datepicker .wco-datepicker__nav:disabled{cursor:not-allowed;opacity:.6}.wco-datepicker .wco-datepicker__title{border:none;background:transparent;cursor:pointer;display:inline-flex;justify-content:flex-start;align-items:center;gap:var(--wco-spacing-quark, 4px);font-family:var(--wco-font-family);font-size:var(--wco-font-size-xs, 16px);color:var(--wco-datepicker-text);padding:var(--wco-spacing-quark, 4px) var(--wco-spacing-nano, 8px)}.wco-datepicker .wco-datepicker__title:hover:not(:disabled){background:var(--wco-datepicker-hover)}.wco-datepicker .wco-datepicker__title:disabled{cursor:not-allowed;opacity:.6}.wco-datepicker .wco-datepicker__weekdays{display:grid;grid-template-columns:repeat(7,1fr);gap:0;padding:0 var(--wco-spacing-quark, 4px);margin-bottom:var(--wco-spacing-quark, 4px);color:var(--wco-datepicker-muted);font-size:var(--wco-font-size-xxxs, 12px);text-align:center;-webkit-user-select:none;user-select:none}.wco-datepicker .wco-datepicker__weekdays>span{width:36px;justify-self:center}.wco-datepicker .wco-datepicker__grid{display:grid;grid-template-columns:repeat(7,1fr);gap:0}.wco-datepicker .wco-datepicker__day{width:36px;height:36px;justify-self:center;position:relative;isolation:isolate;border-radius:999px;border:1px solid transparent;background:transparent;cursor:pointer;font-family:var(--wco-font-family);font-size:var(--wco-font-size-xxxs, 12px);color:var(--wco-datepicker-text)}.wco-datepicker .wco-datepicker__day:hover:not(:disa