UNPKG

@freshworks/crayons

Version:
1,405 lines 55 kB
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 { Component, Element, Event, Listen, Prop, State, h, Method, Watch, } from '@stencil/core'; import { isValid, parse, parseISO, getYear, getMonth, getDate, startOfDay, getDaysInMonth, format, isMatch, formatISO, addDays, startOfWeek, } from 'date-fns'; import { handleKeyDown, renderHiddenField, getFocusableChildren, hasSlot, } from '../../utils'; import FieldControl from '../../function-components/field-control'; import { i18n, TranslationController } from '../../global/Translation'; const defaultweekDays = ['S', 'M', 'T', 'W', 'T', 'F', 'S']; const monthDetails = [ { value: 'Jan', text: 'January' }, { value: 'Feb', text: 'February' }, { value: 'Mar', text: 'March' }, { value: 'Apr', text: 'April' }, { value: 'May', text: 'May' }, { value: 'Jun', text: 'June' }, { value: 'Jul', text: 'July' }, { value: 'Aug', text: 'August' }, { value: 'Sep', text: 'September' }, { value: 'Oct', text: 'October' }, { value: 'Nov', text: 'November' }, { value: 'Dec', text: 'December' }, ]; const getMonthNames = (lang) => { if (!lang) { return { longMonthNames: monthDetails.map((m) => m.text), shortMonthNames: monthDetails.map((m) => m.value), }; } const shortMonthNames = []; const longMonthNames = []; for (let i = 0; i <= 11; i++) { shortMonthNames.push(lang.localize.month(i, { width: 'abbreviated' })); longMonthNames.push(lang.localize.month(i)); } return { longMonthNames, shortMonthNames, }; }; const getWeekDays = (lang) => { if (!lang) return defaultweekDays; return Array.from(Array(7)).map((_e, i) => format(addDays(startOfWeek(new Date()), i), 'EEEEE', { locale: lang })); }; export class Datepicker { constructor() { this.firstFocusElement = null; this.lastFocusElement = null; this.hasHintTextSlot = false; this.hasWarningTextSlot = false; this.hasErrorTextSlot = false; /** * Type of date selection enabled for the calendar. If the value is range, a user can select a date range in the calendar. */ this.mode = 'single date'; /** * Name of the component, saved as part of form data. */ this.name = ''; this.updateText = ''; this.cancelText = ''; /** * Specifies the input box as a mandatory field and displays an asterisk next to the label. If the attribute’s value is undefined, the value is set to false. */ this.required = false; /** * Theme based on which the input of the datepicker is styled. */ this.state = 'normal'; /** * Minimum year that needs to be displayed in the year dropdown. */ this.minYear = 1970; /** * Maximum year that needs to be displayed in the year dropdown. */ this.maxYear = new Date().getFullYear(); /** * Make the input box as readonly. Default `false` */ this.readonly = false; /** * Indicates if footer needs to be shown. Default `true`. */ this.showFooter = true; /** * Displays a clear icon in the text box. Clicking the icon clears the value. Default `false` */ this.clearInput = false; /** * Hint text displayed below the text box. */ this.hintText = ''; /** * Warning text displayed below the text box. */ this.warningText = ''; /** * Error text displayed below the text box. */ this.errorText = ''; /** * Label displayed on the interface, for the component. */ this.label = ''; this.escapeHandler = null; this.isDisplayFormatSet = false; this.isPlaceholderSet = false; this.getSupportedYears = () => { const yearsArr = []; if (+this.maxYear < +this.minYear) this.maxYear = +this.minYear; let year = +this.minYear; while (year <= +this.maxYear) { yearsArr.push(year.toString()); year++; } return yearsArr; }; this.getDayDetails = (args) => { const date = args.index - args.firstDay; const day = args.index % 7; let prevMonth = args.month - 1; let prevYear = Number(args.year); if (prevMonth < 0) { prevMonth = 11; prevYear--; } const prevMonthNumberOfDays = getDaysInMonth(new Date(prevYear, prevMonth)) || 0; const _date = (date < 0 ? prevMonthNumberOfDays + date : date % args.numberOfDays) + 1; const month = this._getValidDateInMonth(date, args); const timestamp = new Date(args.year, args.month, _date).valueOf(); return { date: _date, day, month, timestamp }; }; this.getMonthDetails = (year, month) => { const firstDay = new Date(year, month).getDay(); const numberOfDays = getDaysInMonth(new Date(year, month)) || 0; const monthArray = []; const rows = 6; let currentDay; let index = 0; const cols = 7; for (let row = 0; row < rows; row++) { for (let col = 0; col < cols; col++) { currentDay = this.getDayDetails({ index, numberOfDays, firstDay, year, month, }); monthArray.push(currentDay); index++; } } return monthArray; }; this.setMonth = (offset) => { let year = Number(this.year); let month = this.month + offset; if (month === -1) { month = 11; year--; } else if (month === 12) { month = 0; year++; } this.year = year.toString(); this.month = month; this.toMonth = this.month === 11 ? 0 : this.month + 1; this.toYear = this.toMonth === 0 ? this.yearCalculation(this.year, 1) : this.year; this.monthDetails = this.getMonthDetails(year, month); this.nextMonthDetails = this.month === 11 ? this.getMonthDetails(this.yearCalculation(this.year, 1), 0) : this.getMonthDetails(this.year, this.month + 1); }; this.isCurrentDay = (day) => { return day.timestamp === this.todayTimestamp; }; this.isSelectedDay = ({ date, timestamp }) => { if (this.mode !== 'range') { const parsedDate = parse(this.value, this.displayFormat, new Date(), { locale: this.langModule, }); const isValidDate = isValid(parsedDate); return isValidDate ? date === this.selectedDay && getMonth(parsedDate) === getMonth(timestamp) && getYear(parsedDate) === getYear(timestamp) : date === this.selectedDay; } return timestamp === this.startDate || timestamp === this.endDate; }; this.handleDateHover = (day) => { if (this.startDate && !this.endDate) { if (this.startDate > day.timestamp) { this.endDate = this.startDate; this.startDate = undefined; } this.dateHovered = day.timestamp; } else if (!this.startDate && this.endDate) { if (this.endDate < day.timestamp) { this.startDate = this.endDate; this.endDate = undefined; } this.dateHovered = day.timestamp; } }; this.isInRange = ({ timestamp }) => { const { endDate } = this; const { startDate } = this; if (startDate === endDate) return; return (startDate && endDate && timestamp >= startDate && timestamp <= endDate); }; this.onDateClick = (e, { date, timestamp }) => { if (this.showSingleDatePicker()) { this.selectedDay = date; if (!this.showFooter) { this.updateValueAndEmitEvent(e); this.showDatePicker = false; this.host.shadowRoot.querySelector('fw-popover').hide(); } } else if (this.showDateRangePicker()) { this.handleRangeSelection(timestamp); if (!this.showFooter) { if (this.startDate && this.endDate) { this.updateValueAndEmitEvent(e); this.showDatePicker = false; this.host.shadowRoot.querySelector('fw-popover').hide(); } } this.dateHovered = ''; } }; this.handleInputClear = (e) => { this.clearInputValue(); this.emitEvent(e, undefined); }; // handle cancel and popover close this.handlePopoverClose = (e) => { var _a, _b; if (((_a = e.target) === null || _a === void 0 ? void 0 : _a.tagName) === 'FW-SELECT') return; if (this.mode === 'range') { // handle resetting of startDate and endDate on clicking cancel if (this.value) { let [fromDateStr, toDateStr] = ((_b = this.value) === null || _b === void 0 ? void 0 : _b.split(TranslationController.t('datepicker.to'))) || []; fromDateStr = fromDateStr === null || fromDateStr === void 0 ? void 0 : fromDateStr.trim(); toDateStr = toDateStr === null || toDateStr === void 0 ? void 0 : toDateStr.trim(); const startDate = getDate(new Date(this.startDate)); const endDate = getDate(new Date(this.endDate)); const fromDate = getDate(parse(fromDateStr, this.displayFormat, new Date(), { locale: this.langModule, })); const toDate = getDate(parse(toDateStr, this.displayFormat, new Date(), { locale: this.langModule, })); if (startDate !== fromDate) { this.startDate = parse(fromDateStr, this.displayFormat, new Date(), { locale: this.langModule, }).valueOf(); } if (endDate !== toDate) { this.endDate = parse(toDateStr, this.displayFormat, new Date(), { locale: this.langModule, }).valueOf(); } } else if (!this.startDate && !this.endDate) { this.startDate = this.endDate = undefined; } } else { // handle resetting of selectedDay on clicking cancel if (this.value) { const date = getDate(parse(this.value, this.displayFormat, new Date(), { locale: this.langModule, })); if (this.selectedDay !== date) { this.selectedDay = date; } } else this.selectedDay = undefined; } }; this.onBlur = async (e) => { var _a, _b, _c, _d; e.stopImmediatePropagation(); if (((_d = (_c = (_b = (_a = e) === null || _a === void 0 ? void 0 : _a.detail) === null || _b === void 0 ? void 0 : _b.event) === null || _c === void 0 ? void 0 : _c.relatedTarget) === null || _d === void 0 ? void 0 : _d.tagName) !== 'SPAN') { this.fwBlur.emit({ event: e, name: this.name, }); } }; } makeDatePickerInert() { if (!this.madeInert) { /** * Focus trapping inside datepicker. */ const focusableElements = getFocusableChildren(this.host); if (focusableElements.length) { this.firstFocusElement = focusableElements[0]; this.lastFocusElement = focusableElements[focusableElements.length - 1]; this.lastFocusElement.addEventListener('keydown', (e) => { !e.shiftKey && e.keyCode === 9 && this.focusElement(this.firstFocusElement); }); this.firstFocusElement.addEventListener('keydown', (e) => { e.shiftKey && e.keyCode === 9 && this.focusElement(this.lastFocusElement); }); } if (this.firstFocusElement) { this.focusElement(this.firstFocusElement); } this.madeInert = true; } this.escapeHandler = ((e) => { if (e.keyCode === 27) { this.showDatePicker = false; this.host.shadowRoot.querySelector('fw-popover').hide(); } }).bind(this); document.addEventListener('keydown', this.escapeHandler); } emitEvent(event, eventDetails) { this.fwChange.emit({ event: event, name: this.name, value: eventDetails, }); } focusElement(element) { element.focus(); } disconnectedCallback() { document.removeEventListener('keydown', this.escapeHandler); } formatDate(value) { if (!value) return value; return this.displayFormat ? formatISO(parse(value, this.displayFormat, new Date(), { locale: this.langModule, })) : formatISO(new Date(value)); } /** * Returns the date value in ISO format. */ async getValue() { if (this.mode === 'range') { return { fromDate: (this.startDate && format(parse(this.startDate, this.displayFormat, new Date(), { locale: this.langModule, }), this.displayFormat, { locale: this.langModule, })) || undefined, toDate: (this.endDate && format(parse(this.endDate, this.displayFormat, new Date(), { locale: this.langModule, }), this.displayFormat, { locale: this.langModule, })) || undefined, }; } return this.displayFormat ? (this.value && format(parse(this.value, this.displayFormat, new Date(), { locale: this.langModule, }), this.displayFormat, { locale: this.langModule, })) || undefined : (this.value && formatISO(new Date(this.value))) || undefined; } /** * Sets focus on a specific `fw-datepicker`. Use this method instead of the global `input.focus()`. */ async setFocus() { var _a, _b; if (this.nativeInput) { (_b = (_a = this.nativeInput).setFocus) === null || _b === void 0 ? void 0 : _b.call(_a); } } /** * Clears the input value and unselects selected date. */ async clearValue() { this.clearInputValue(); } handleKeyDown(event) { switch (event.code) { case 'Enter': this.host.shadowRoot.querySelector('fw-popover').show(); break; case 'ArrowDown': event.preventDefault(); } this.makeDatePickerInert(); } displayDatePicker() { this.showDatePicker = true; } handleButtonClick(e) { const isUpdateRange = e .composedPath()[0] .classList.value.includes('update-range-value'); const isUpdateDate = e .composedPath()[0] .classList.value.includes('update-date-value'); if (isUpdateRange) { if (this.startDate && this.endDate) { this.updateValueAndEmitEvent(e); } } else if (isUpdateDate) { if (this.selectedDay) { this.updateValueAndEmitEvent(e); } } if (e.composedPath()[0].innerText === this.cancelText && !this.value) { if (this.mode === 'range') { this.startDate = this.endDate = undefined; } else { this.selectedDay = undefined; } } if (e.composedPath()[0].innerText === this.cancelText) { this.handlePopoverClose(e); } // Close datepicker only for fwClick event of Update and cancel buttons. Since this will // be triggered for month and year select dropdown as well the below check is added. if (e.composedPath()[0].innerText === this.updateText || e.composedPath()[0].innerText === this.cancelText) { this.showDatePicker = false; this.host.shadowRoot.querySelector('fw-popover').hide(); } } /** * Listener to handle input changes */ handleInputChanges(e) { e.stopImmediatePropagation(); if (e.composedPath()[0].classList.value.includes('range-date-input')) { // Range input const val = e.composedPath()[0].value; if (!val) { this.value = undefined; } let [fromDate, toDate] = (val === null || val === void 0 ? void 0 : val.split(TranslationController.t('datepicker.to'))) || []; fromDate = fromDate === null || fromDate === void 0 ? void 0 : fromDate.trim(); toDate = toDate === null || toDate === void 0 ? void 0 : toDate.trim(); if (!isMatch(fromDate, this.displayFormat, { locale: this.langModule, }) || !isMatch(toDate, this.displayFormat, { locale: this.langModule, })) return; const parsedFromDate = parse(fromDate, this.displayFormat, new Date(), { locale: this.langModule, }); const parsedToDate = parse(toDate, this.displayFormat, new Date(), { locale: this.langModule, }); const isValidFromDate = isValid(parsedFromDate); const isValidToDate = isValid(parsedToDate); if (!isValidFromDate || !isValidToDate) { // Invalid date format return; } const year = getYear(parse(fromDate, this.displayFormat, new Date(), { locale: this.langModule, })); if (year < this.minYear || year > this.maxYear) { return; } this.year = year; this.month = getMonth(parse(fromDate, this.displayFormat, new Date(), { locale: this.langModule, })); this.startDate = parse(fromDate, this.displayFormat, new Date(), { locale: this.langModule, }).valueOf(); this.endDate = parse(toDate, this.displayFormat, new Date(), { locale: this.langModule, }).valueOf(); this.toMonth = this.month === 11 ? 0 : this.month + 1; this.toYear = this.toMonth === 0 ? this.yearCalculation(this.year, 1) : this.year; } else { // Single Date input const val = e.composedPath()[0].value; if (!val) { this.value = undefined; } if (!isMatch(val, this.displayFormat, { locale: this.langModule, })) return; const parsedDate = parse(val, this.displayFormat, new Date(), { locale: this.langModule, }); const isValidDate = isValid(parsedDate); if (!isValidDate) { // Invalid date format return; } const year = getYear(parse(val, this.displayFormat, new Date(), { locale: this.langModule, })); if (year < this.minYear || year > this.maxYear) { return; } this.year = year; this.month = getMonth(parse(val, this.displayFormat, new Date(), { locale: this.langModule, })); this.selectedDay = getDate(parse(val, this.displayFormat, new Date(), { locale: this.langModule, })); this.value = format(new Date(this.year, this.month, this.selectedDay), this.displayFormat, { locale: this.langModule, }); } } /** * Listener to handle Month Year dropdown. */ handleMonthYearDropDownSelection(e) { if (e.composedPath()[0].tagName !== 'FW-DATEPICKER') { e.stopImmediatePropagation(); } const newValue = e.detail && e.detail.value; if (!newValue) { return; } if (this.mode === 'range') { this.handleDateRangeDropDownUpdate(e, newValue); this.nextMonthDetails = this.getMonthDetails(this.toYear, this.toMonth); } else { this.handleSingleDateDropDownUpdate(e, newValue); } this.monthDetails = this.getMonthDetails(this.year, this.month); } handleSingleDateDropDownUpdate(e, newValue) { const isMonthUpdate = e .composedPath()[0] .classList.value.includes('single-month-selector'); const isYearUpdate = e .composedPath()[0] .classList.value.includes('single-year-selector'); if (isMonthUpdate) { this.month = this.shortMonthNames.indexOf(newValue); } else if (isYearUpdate) { this.year = newValue; } } handleDateRangeDropDownUpdate(e, newValue) { const isFromMonthUpdate = e .composedPath()[0] .classList.value.includes('from-month-selector'); const isFromYearUpdate = e .composedPath()[0] .classList.value.includes('from-year-selector'); const isToMonthUpdate = e .composedPath()[0] .classList.value.includes('to-month-selector'); const isToYearUpdate = e .composedPath()[0] .classList.value.includes('to-year-selector'); if (isFromMonthUpdate) { this.month = this.shortMonthNames.indexOf(newValue); if (this.month === 11) { this.toMonth = 0; this.toYear = this.yearCalculation(this.year, 1); } else { this.toMonth = this.month + 1; } } else if (isFromYearUpdate) { this.year = newValue; this.toYear = this.month === 11 ? this.yearCalculation(this.year, 1) : this.year; } else if (isToMonthUpdate) { this.toMonth = this.shortMonthNames.indexOf(newValue); if (this.toMonth === 0) { this.month = 11; this.year = this.yearCalculation(this.toYear, -1); } else { this.month = this.toMonth - 1; } } else if (isToYearUpdate) { this.toYear = newValue; this.year = this.toMonth === 0 ? this.yearCalculation(this.toYear, -1) : this.toYear; } } yearCalculation(year, offset) { const resultYear = Number(year) + offset; return resultYear.toString(); } async handleLocaleChange(newLocale) { this.langModule = await TranslationController.getDateLangModule(newLocale); } async componentWillLoad() { var _a, _b; this.langModule = await TranslationController.getDateLangModule(this.locale); if (this.displayFormat) { this.isDisplayFormatSet = true; } if (this.placeholder) { this.isPlaceholderSet = true; } this.checkSlotContent(); this.displayFormat = this.displayFormat || ((_b = (_a = this.langModule) === null || _a === void 0 ? void 0 : _a.formatLong) === null || _b === void 0 ? void 0 : _b.date({ width: 'short' })); this.placeholder = this.placeholder || this.displayFormat; const onChange = TranslationController.onChange.bind(TranslationController); onChange('lang', async (locale) => { var _a, _b; this.langModule = await TranslationController.getDateLangModule(locale); this.displayFormat = this.isDisplayFormatSet ? this.displayFormat : (_b = (_a = this.langModule) === null || _a === void 0 ? void 0 : _a.formatLong) === null || _b === void 0 ? void 0 : _b.date({ width: 'short' }); this.placeholder = this.isPlaceholderSet ? this.placeholder : this.displayFormat; if (this.mode === 'range') this.placeholder = this.isPlaceholderSet ? this.placeholder : `${this.displayFormat} ${TranslationController.t('datepicker.to')} ${this.displayFormat}`; const monthNames = getMonthNames(this.langModule); this.shortMonthNames = monthNames.shortMonthNames; this.longMonthNames = monthNames.longMonthNames; this.weekDays = getWeekDays(this.langModule); }); if (this.mode === 'range') { const today = new Date(); if ((this.fromDate && !isValid(parseISO(this.fromDate))) || (this.toDate && !isValid(parseISO(this.toDate)))) { // Show current month and year if invalid date is provided this.year = getYear(today); this.month = getMonth(today); } else { const fromDate = new Date(this.fromDate); this.year = this.fromDate ? getYear(fromDate) : getYear(today); this.month = this.fromDate ? getMonth(fromDate) : getMonth(today); } } else { const today = new Date(); if (this.value && !isValid(parseISO(this.value))) { // Show current date if invalid date is provided this.year = getYear(today); this.month = getMonth(today); this.selectedDay = getDate(today); } else { const date = new Date(this.value); this.year = this.value ? getYear(date) : getYear(today); this.month = this.value ? getMonth(date) : getMonth(today); this.selectedDay = this.value && getDate(date); } } this.toMonth = this.month === 11 ? 0 : this.month + 1; this.toYear = this.toMonth === 0 ? this.yearCalculation(this.year, 1) : this.year; this.monthDetails = this.getMonthDetails(this.year, this.month); this.todayTimestamp = startOfDay(new Date()).valueOf(); const monthNames = getMonthNames(this.langModule); this.shortMonthNames = monthNames.shortMonthNames; this.longMonthNames = monthNames.longMonthNames; this.weekDays = getWeekDays(this.langModule); this.value = this.value ? format(new Date(this.value), this.displayFormat, { locale: this.langModule, }) : this.value; this.setInitialValues(); } setInitialValues() { this.nextMonthDetails = this.month === 11 ? this.getMonthDetails(this.yearCalculation(this.year, 1), 0) : this.getMonthDetails(this.year, this.month + 1); if (this.mode === 'range') this.placeholder = this.isPlaceholderSet ? this.placeholder : `${this.displayFormat} ${TranslationController.t('datepicker.to')} ${this.displayFormat}`; this.supportedYears = this.getSupportedYears(); this.startDate = this.fromDate !== undefined ? parse(this.fromDate, this.displayFormat, new Date(), { locale: this.langModule, }).valueOf() : undefined; this.endDate = this.toDate !== undefined ? parse(this.toDate, this.displayFormat, new Date(), { locale: this.langModule, }).valueOf() : undefined; if (this.mode === 'range' && this.startDate && this.endDate) { const formattedFromDate = format(new Date(this.startDate), this.displayFormat, { locale: this.langModule, }); const formattedToDate = format(new Date(this.endDate), this.displayFormat, { locale: this.langModule, }); this.value = `${formattedFromDate} to ${formattedToDate}`; } } watchValueChanged(value) { if (!value) { this.startDate = undefined; this.endDate = undefined; this.selectedDay = undefined; this.value = undefined; const date = new Date(); this.year = getYear(date); this.month = getMonth(date); this.monthDetails = this.getMonthDetails(this.year, this.month); } else { if (this.mode !== 'range') { const date = new Date(); date.setMonth(this.month, 1); date.setFullYear(this.year); date.setDate(this.selectedDay); this.value = format(date, this.displayFormat, { locale: this.langModule, }); } else { const formattedFromDate = format(new Date(this.startDate), this.displayFormat, { locale: this.langModule, }); const formattedToDate = format(new Date(this.endDate), this.displayFormat, { locale: this.langModule, }); this.value = `${formattedFromDate} to ${formattedToDate}`; } } } _getValidDateInMonth(date, args) { if (this.minDate !== undefined && this.maxDate !== undefined) { if (date < 0) { return -1; } const minDate = parseISO(this.minDate); const maxDate = parseISO(this.maxDate); if (!isValid(minDate) || !isValid(maxDate)) { // Invalid minDate or maxDate provided. return; } const argDate = new Date(args.year, args.month, date + 1); const isValidDate = minDate.valueOf() <= argDate.valueOf() && argDate.valueOf() <= maxDate.valueOf(); return !isValidDate ? -1 : date >= args.numberOfDays ? 1 : 0; } return date < 0 ? -1 : date >= args.numberOfDays ? 1 : 0; } handleKeyUp(e, day) { if (e.code === 'Enter') { if (e .composedPath() .find((e) => e.classList && e.classList.value === 'mdp-range-container')) { // Range Container this.onDateClick(e, day); this.startDateFormatted = format(new Date(this.startDate), this.displayFormat, { locale: this.langModule, }); this.endDateFormatted = format(new Date(this.endDate), this.displayFormat, { locale: this.langModule, }); if (this.startDate && this.endDate) { this.value = this.startDateFormatted + ' to ' + this.endDateFormatted; this.emitEvent(e, { fromDate: this.formatDate(this.startDateFormatted), toDate: this.formatDate(this.endDateFormatted), }); this.showDatePicker = false; this.host.shadowRoot.querySelector('fw-popover').hide(); } } else { // Single Date Container this.onDateClick(e, day); this.value = format(new Date(this.year, this.month, this.selectedDay), this.displayFormat, { locale: this.langModule, }); this.emitEvent(e, this.formatDate(this.value)); this.showDatePicker = false; this.host.shadowRoot.querySelector('fw-popover').hide(); } } } isHoverInRange({ timestamp }) { const { startDate, endDate, dateHovered } = this; const startDateCondtion = startDate && dateHovered && timestamp <= dateHovered && timestamp >= startDate; const endDateCondition = endDate && dateHovered && timestamp >= dateHovered && timestamp <= endDate; return startDateCondtion || endDateCondition; } updateValueAndEmitEvent(e) { if (this.showSingleDatePicker()) { this.value = format(new Date(this.year, this.month, this.selectedDay), this.displayFormat, { locale: this.langModule, }); this.emitEvent(e, this.formatDate(this.value)); } else if (this.showDateRangePicker()) { this.startDateFormatted = format(this.startDate, this.displayFormat, { locale: this.langModule, }); this.endDateFormatted = format(this.endDate, this.displayFormat, { locale: this.langModule, }); this.fromDate = this.startDateFormatted; this.toDate = this.endDateFormatted; this.value = this.startDateFormatted + ' to ' + this.endDateFormatted; this.emitEvent(e, { fromDate: this.formatDate(this.startDateFormatted), toDate: this.formatDate(this.endDateFormatted), }); } } clearInputValue() { if (this.mode !== 'range') { if (this.selectedDay) { this.selectedDay = undefined; } } else { if (this.startDate && this.endDate) { this.startDate = this.endDate = undefined; } } this.value = undefined; } handleRangeSelection(timestamp) { if (this.startDate && this.endDate) { this.endDate = undefined; this.startDate = timestamp; } else if (this.startDate && !this.endDate) { if (timestamp >= this.startDate) { this.endDate = timestamp; } else if (timestamp < this.startDate) { this.endDate = this.startDate; this.startDate = timestamp; } } else if (!this.startDate && this.endDate) { this.startDate = timestamp; } else if (!this.startDate && !this.endDate) { this.startDate = timestamp; } } getCellStyle(day) { let cellStyle = 'c-day-container'; if (day.month !== 0) { cellStyle += ' disabled'; } if (this.isCurrentDay(day)) { cellStyle += ' highlight'; } if (this.isSelectedDay(day) || day.timestamp === this.dateHovered) { cellStyle += ' highlight-blue'; } if (this.isInRange(day) || this.isHoverInRange(day)) { cellStyle += ' highlight-range'; } if (day.timestamp === this.startDate) { cellStyle += ' start-day'; } if (day.timestamp === this.endDate) { cellStyle += ' end-day'; } if (this.startDate && this.dateHovered < this.startDate && day.timestamp === this.dateHovered) { cellStyle += ' start-day'; } else if (this.endDate && this.dateHovered < this.endDate && day.timestamp === this.dateHovered) { cellStyle += ' start-day'; } else if (this.startDate && this.dateHovered > this.startDate && day.timestamp === this.dateHovered) { cellStyle += ' end-day'; } return cellStyle; } renderCalendar(monthDetails) { const days = monthDetails.map((day, index) => { return (h("div", { class: this.getCellStyle(day), key: index }, h("div", { class: 'cdc-day' }, h("span", { role: 'button', tabindex: day.month === -1 || day.month === 1 ? '-1' : '0', onClick: (e) => this.onDateClick(e, day), onMouseOver: () => this.handleDateHover(day), onFocus: () => this.handleDateHover(day), onKeyDown: handleKeyDown(() => this.handleDateHover(day)), onKeyUp: (e) => this.handleKeyUp(e, day) }, day.date)))); }); return (h("div", { class: 'c-container' }, h("div", { class: 'cc-head' }, this.weekDays.map((day, index) => (h("div", { key: index, class: 'cch-name' }, day)))), h("div", { class: 'cc-body' }, days))); } showSingleDatePicker() { return this.showDatePicker && this.mode !== 'range'; } showDateRangePicker() { return this.showDatePicker && this.mode === 'range'; } checkSlotContent() { this.hasHintTextSlot = hasSlot(this.host, 'hint-text'); this.hasWarningTextSlot = hasSlot(this.host, 'warning-text'); this.hasErrorTextSlot = hasSlot(this.host, 'error-text'); } renderNavButtons() { return (h("div", { class: 'btns' }, h("div", { class: 'mdpch-button' }, h("div", { role: 'button', tabindex: '0', class: 'mdpchb-inner', onClick: () => this.setMonth(-1), onKeyDown: handleKeyDown(() => this.setMonth(-1)) }, h("span", { class: 'mdpchbi-left-arrow' }))), h("div", { class: 'mdpch-button-right' }, h("div", { role: 'button', tabindex: '0', class: 'mdpchb-inner', onClick: () => this.setMonth(1), onKeyDown: handleKeyDown(() => this.setMonth(1)) }, h("span", { class: 'mdpchbi-right-arrow' }))))); } renderSupportedYears() { return this.supportedYears.map((year, i) => (h("fw-select-option", { value: year, key: i, selected: +year === +this.year }, year))); } renderFooter() { return (h("div", { class: 'mdpc-footer' }, h("fw-button", { color: 'secondary', class: 'close-date-picker' }, this.cancelText), h("fw-button", { color: 'primary', class: this.mode === 'range' ? 'update-range-value' : 'update-date-value' }, this.updateText))); } render() { const { host, name, value } = this; renderHiddenField(host, name, value); return (h(FieldControl, { inputId: this.name, label: this.label, labelId: `${this.label}-${this.name}`, state: this.state, hintTextId: `hint-${this.name}`, hintText: this.hintText, hasHintTextSlot: this.hasHintTextSlot, errorTextId: `error-${this.name}`, errorText: this.errorText, hasErrorTextSlot: this.hasErrorTextSlot, warningTextId: `warning-${this.name}`, warningText: this.warningText, hasWarningTextSlot: this.hasWarningTextSlot, required: this.required }, h("fw-popover", { "same-width": 'false', distance: '8', placement: 'bottom-start', fallbackPlacements: ['top-start'], "hide-on-tab": 'false', onFwHide: this.handlePopoverClose }, h("div", { role: 'combobox', "aria-controls": 'datepicker', "aria-expanded": this.showDatePicker, tabindex: '-1', onClick: () => (this.showDatePicker = true), onKeyUp: () => (this.showDatePicker = true), slot: 'popover-trigger', style: { display: 'inline-flex', alignItems: 'center', } }, h("fw-input", { value: this.value, name: this.name, class: (this.mode === 'range' ? 'range-' : '') + 'date-input', placeholder: this.placeholder, required: this.required, onFwBlur: this.onBlur, ref: (el) => (this.nativeInput = el), state: this.state, readonly: this.readonly, clearInput: this.clearInput, onFwInputClear: this.handleInputClear }, h("div", { class: 'icon-calendar', slot: 'input-suffix' }, h("div", { class: 'separator', style: { borderLeftColor: this.state === 'error' ? '#d72d30' : '#ebeff3', } }), h("span", { class: 'date-icon' }, h("fw-icon", { name: 'calendar', style: { '--fw-icon-color': this.state === 'error' && '#d72d30', } }))))), this.showSingleDatePicker() ? (h("div", { id: 'datepicker', class: 'datepicker', slot: 'popover-content' }, h("div", { class: 'mdp-container' }, h("div", { class: 'mdpc-head' }, h("div", { class: 'mdpch-container' }, h("span", { class: 'mdpchc-month' }, h("fw-select", { class: 'first single-month-selector', readonly: true, value: this.shortMonthNames[this.month], "same-width": 'false', variant: 'button', "options-placement": 'bottom-start', options: this.longMonthNames.map((month, i) => ({ value: this.shortMonthNames[i], key: i, selected: month === this.longMonthNames[this.month], text: month, })), allowDeselect: false })), h("span", { class: 'mdpchc-year' }, h("fw-select", { class: 'last single-year-selector', readonly: true, value: this.year, "same-width": 'false', "options-placement": 'bottom', variant: 'button', "allow-deselect": 'false' }, this.renderSupportedYears()))), this.renderNavButtons()), h("div", { class: 'mdpc-body' }, this.renderCalendar(this.monthDetails))), this.showFooter && this.renderFooter())) : (''), this.showDateRangePicker() ? (h("div", { id: 'datepicker', class: 'daterangepicker', slot: 'popover-content' }, h("div", { class: 'mdp-range-container' }, h("div", { class: 'mdpc-head' }, h("div", { class: 'mdpch-container' }, h("span", { class: 'mdpchc-month' }, h("fw-select", { class: 'first from-month-selector', readonly: true, value: this.shortMonthNames[this.month], "same-width": 'false', variant: 'button', "options-placement": 'bottom-start', options: this.longMonthNames.map((month, i) => ({ value: this.shortMonthNames[i], key: i, selected: month === this.longMonthNames[this.month], text: month, })), allowDeselect: false })), h("span", { class: 'mdpchc-year' }, h("fw-select", { class: 'last from-year-selector', readonly: true, value: this.year, "same-width": 'false', "options-placement": 'bottom', variant: 'button', "allow-deselect": 'false' }, this.renderSupportedYears()))), h("div", { class: 'mdpch-container-right' }, h("span", { class: 'mdpchc-month' }, h("fw-select", { class: 'first to-month-selector', readonly: true, "same-width": 'false', variant: 'button', value: this.shortMonthNames[this.toMonth], "options-placement": 'bottom-start', options: this.longMonthNames.map((month, i) => ({ value: this.shortMonthNames[i], key: i, selected: month === this.longMonthNames[this.toMonth], text: month, })), allowDeselect: false })), h("span", { class: 'mdpchc-year' }, h("fw-select", { class: 'last to-year-selector', readonly: true, value: this.toYear, "same-width": 'false', "options-placement": 'bottom', variant: 'button', "allow-deselect": 'false' }, this.renderSupportedYears()))), this.renderNavButtons()), h("div", { class: 'body-container' }, h("div", { class: 'mdpc-body' }, this.renderCalendar(this.monthDetails)), h("div", { class: 'mdpc-body mdpc-body-right' }, this.renderCalendar(this.nextMonthDetails)))), this.showFooter && this.renderFooter())) : ('')))); } static get is() { return "fw-datepicker"; } static get encapsulation() { return "shadow"; } static get originalStyleUrls() { return { "$": ["datepicker.scss"] }; } static get styleUrls() { return { "$": ["datepicker.css"] }; } static get properties() { return { "mode": { "type": "string", "mutable": false, "complexType": { "original": "'single date' | 'range'", "resolved": "\"range\" | \"single date\"", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Type of date selection enabled for the calendar. If the value is range, a user can select a date range in the calendar." }, "attribute": "mode", "reflect": false, "defaultValue": "'single date'" }, "minDate": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Earliest date a user can select in the calendar, if mode is range. Must be a valid ISO date format if set." }, "attribute": "min-date", "reflect": false }, "maxDate": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Latest date a user can select in the calendar, if mode is range. Must be a valid ISO date format if set." }, "attribute": "max-date", "reflect": false }, "fromDate": { "type": "string", "mutable": true, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Starting date of the date range that is preselected in the calendar, if mode is range. Must be a date later than the min-date value and valid ISO date format." }, "attribute": "from-date", "reflect": false }, "toDate": { "type": "string", "mutable": true, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Ending date of the date range that is preselected in the calendar, if mode is range. Must be a date earlier than the max-date value and valid ISO date format." }, "attribute": "to-date", "reflect": false }, "displayFormat": { "type": "string", "mutable": true, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Format in which the date values selected in the calendar are populated in the input box. Defaults to the locale specific display format." }, "attribute": "display-format", "reflect": false }, "value": { "type": "string", "mutable": true, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Date that is preselected in the calendar, if mode is single date or undefined. If set this must be valid ISO date format." }, "attribute": "value", "reflect": false }, "name": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Name of the component, saved as part of form data." }, "attribute": "name", "reflect": false, "defaultValue": "''" }, "placeholder": { "type": "string", "mutable": true, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Text displayed in the input box before a user selects a date or date range." }, "attribute": "placeholder", "reflect": false }, "updateText": { "type": "string", "mutable": true, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "" }, "attribute": "update-text", "reflect": false, "defaultValue": "''" }, "cancelText": { "type": "string", "mutable": true, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "" }, "attribute": "cancel-text", "reflect": false, "defaultValue": "''" }, "required": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Specifies the input box as a mandatory field and displays an asterisk next to the label. If the attribute\u2019s value is undefined, the value is set to false." }, "attribute": "required", "reflect": false, "defaultValue": "false" }, "state": { "type": "string", "mutable": false, "complexType": { "original": "'normal' | 'warning' | 'error'", "resolved": "\"error\" | \"normal\" | \"warning\"", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Theme based on which the input of the datepicker is styled." }, "attribute": "state", "reflect": false, "defaultValue": "'normal'" }, "minYear": { "type": "number", "mutable": false, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Minimum year that needs to be displayed in the year dropdown." }, "attribute": "min-year", "reflect": false, "defaultValue": "1970" }, "maxYear": { "type": "number", "mutable": false, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Maximum year that needs to be displayed in the year dropdown." }, "attribute": "max-year", "reflect": false, "defaultValue": "new Date().getFullYear()" }, "locale": { "type": "string", "mutable": true, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Locale for which datepicker needs to be shown. Defaults to browser's current locale." }, "attribute": "locale", "reflect": false }, "readonly": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Make the input box as readonly. Default `false`" }, "attribute": "readonly", "reflect": false, "defaultValue": "false" }, "showFooter": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Indicates if footer needs to be shown. Default `true`." }, "attribute": "show-footer", "reflect": false, "defaultValue": "true" }, "clearInput": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Displays a clear icon in the text box. Clicking the icon clears the value. Default `false`" }, "attribute": "clear-input", "reflect": false, "defaultValue": "false" }, "hintText": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Hint text displayed below the text box." }, "attribute": "hint-text", "reflect": false, "defaultValue": "''" }, "warningText": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "reference