UNPKG

@kelvininc/ui-components

Version:
530 lines (529 loc) 23.4 kB
import { Host, h } from "@stencil/core"; import { areDatesValid, formatDate, fromDateFields, getDateMonth, getDateYear, getMonthAndYearTitle, getNumberOfDaysInMonth, getWeekdaysNames, isDateAfter, isDateBefore, isDateInArray, isDateInRange, isDateSame, isDateValid, newDate } from "../../utils/date"; import { getArrayOfIndexes } from "../../utils/arrays.helper"; import { EIconName } from "../icon/icon.types"; import { getCalendarEndDisabledDays, getCalendarStartDisabledDays, getHooveredDate, getSelectedRange } from "./calendar.helper"; import { CALENDAR_DEFAULT_MIN_DATE, DATE_FORMAT } from "./calendar.config"; import dayjs from "dayjs"; import { EAbsoluteTimePickerMode } from "../../types"; import { isEmpty } from "lodash-es"; export class KvCalendar { constructor() { var _a, _b; /** @inheritdoc */ this.selectedDates = []; /** @inheritdoc */ this.disableHoveringStyling = false; /** @inheritdoc */ this.disabledDates = []; /** @inheritdoc */ this.displayPreviousMonthArrow = true; /** @inheritdoc */ this.displayNextMonthArrow = true; /** @inheritdoc */ this.mode = EAbsoluteTimePickerMode.Range; this.month = getDateMonth((_a = this.initialDate) !== null && _a !== void 0 ? _a : new Date()); this.year = getDateYear((_b = this.initialDate) !== null && _b !== void 0 ? _b : new Date()); this.onClickPreviousMonth = () => { if (!this.isBackNavigationDisabled()) { if (this.month === 1) { this.year = this.year - 1; this.month = 12; this.changeMonth.emit({ month: this.month }); this.changeYear.emit({ year: this.year }); return; } this.month = this.month - 1; this.changeMonth.emit({ month: this.month }); } }; this.onClickNextMonth = () => { if (!this.isNextNavigationDisabled()) { if (this.month === 12) { this.year = this.year + 1; this.month = 1; this.changeMonth.emit({ month: this.month }); this.changeYear.emit({ year: this.year }); return; } this.month = this.month + 1; this.changeMonth.emit({ month: this.month }); } }; this.isDayDisabled = (day) => { const dayMoment = fromDateFields(day, this.month, this.year); if (isDateInArray(dayMoment, this.disabledDates)) { return true; } if (this.minDate && isDateBefore(dayMoment, dayjs(this.minDate, DATE_FORMAT))) { return true; } if (this.maxDate && isDateAfter(dayMoment, dayjs(this.maxDate, DATE_FORMAT))) { return true; } return false; }; this.onClickDay = (day) => { const clickedDateMoment = fromDateFields(day, this.month, this.year); this.clickDate.emit({ date: formatDate(clickedDateMoment) }); }; this.isDayActive = (day) => { const date = fromDateFields(day, this.month, this.year); return isDateInArray(date, this.selectedDates.filter(date => date !== undefined)); }; this.onMouseEnter = (day) => { this.hoveredDay = day; const date = fromDateFields(day, this.month, this.year).format(DATE_FORMAT); this.hoveredDateChange.emit(date); }; this.onMouseLeave = (_day) => { this.hoveredDay = undefined; this.hoveredDateChange.emit(''); }; this.isDayInRange = (day) => { const [selectedStartDate, selectedEndDate] = this.getSelectedRange(); if (this.disableHoveringStyling || this.mode === EAbsoluteTimePickerMode.Single || this.isDayDisabled(day) || selectedStartDate === undefined || selectedEndDate !== undefined) { return false; } const date = fromDateFields(day, this.month, this.year).format(DATE_FORMAT); const hoveredDate = getHooveredDate(this.hoveredDay, this.month, this.year, this.hoveredDate); return isDateInRange(date, newDate(selectedStartDate).format(DATE_FORMAT), hoveredDate, false); }; this.isSelectedStartDay = (day) => { const [selectedStartDate] = this.getSelectedRange(); if (selectedStartDate === undefined) { return false; } const dateMoment = fromDateFields(day, this.month, this.year); return isDateSame(dateMoment, selectedStartDate); }; this.isSelectedEndDay = (day) => { const date = fromDateFields(day, this.month, this.year); const [selectedStartDate, selectedEndDate] = this.getSelectedRange(); if (selectedStartDate === undefined) { return false; } return isDateSame(date, selectedEndDate !== null && selectedEndDate !== void 0 ? selectedEndDate : selectedStartDate); }; this.isToday = (day) => { const nowDate = newDate().format(DATE_FORMAT); const dayDate = fromDateFields(day, this.month, this.year).format(DATE_FORMAT); return nowDate === dayDate; }; this.isInsideDataRange = (day) => { const dayDate = fromDateFields(day, this.month, this.year); const [selectedStartDate, selectedEndDate] = this.getSelectedRange(); if (selectedStartDate === undefined || selectedEndDate === undefined) return false; return isDateInRange(dayDate, selectedStartDate, selectedEndDate, false); }; this.isBackNavigationDisabled = () => { const calendarMinDate = this.minDate ? this.minDate : CALENDAR_DEFAULT_MIN_DATE; const dayDate = fromDateFields(1, this.month, this.year); const minDateFormatted = dayjs(calendarMinDate, DATE_FORMAT); return dayDate.isBefore(minDateFormatted) || dayDate.isSame(minDateFormatted); }; this.isNextNavigationDisabled = () => { if (isEmpty(this.maxDate)) return false; const dayDate = fromDateFields(1, this.month, this.year); const maxDateFormatted = dayjs(this.maxDate, DATE_FORMAT); return dayDate.isAfter(maxDateFormatted); }; } validateSelectedDates(newSelectedDates) { if (newSelectedDates !== undefined && !areDatesValid(newSelectedDates)) { throw new Error('Selected date should be an array with valid dates'); } } validateInitialDate(newInitialDate) { if (newInitialDate !== undefined && !isDateValid(newInitialDate)) { throw new Error('Initial date should be a valid date'); } else { this.month = getDateMonth(newInitialDate !== null && newInitialDate !== void 0 ? newInitialDate : new Date()); this.year = getDateYear(newInitialDate !== null && newInitialDate !== void 0 ? newInitialDate : new Date()); } } validateDisabledDates(newDisabledDates) { if (newDisabledDates !== undefined && !areDatesValid(newDisabledDates)) { throw new Error('Disabled dates should be an array with valid dates'); } } componentWillLoad() { this.validateSelectedDates(this.selectedDates); this.validateInitialDate(this.initialDate); this.validateDisabledDates(this.disabledDates); } getSelectedRange() { return getSelectedRange(this.selectedDates); } render() { const previousMonthLastDays = getCalendarStartDisabledDays(this.month, this.year); const currentMonthDays = getArrayOfIndexes(getNumberOfDaysInMonth(this.month, this.year)); const nextMonthStartDays = getCalendarEndDisabledDays(previousMonthLastDays.length + currentMonthDays.length); return (h(Host, { key: '8f5764e3f37cdd1d2dbb68900eeaca1e77fd1cd3' }, h("div", { key: 'c73976a343e46594dcdbe47d8438983f61fd3082', class: "calendar" }, h("div", { key: 'dbada5e01ae087e2cce5f2c60626592343768c62', class: "calendar__header" }, h("div", { key: 'da12ffadf2ed1f3a3fd5d22e89b2c3dace26438b', class: { 'navigator': true, 'navigator--disabled': this.isBackNavigationDisabled() }, onClick: this.onClickPreviousMonth }, this.displayPreviousMonthArrow && h("kv-icon", { key: '2058734c09beeab7e263cc50aa8e35077bb638a0', name: EIconName.NavClose })), h("div", { key: 'de22d24456eb450aac401c14651948732585e0fb', class: "month" }, getMonthAndYearTitle(this.month, this.year)), h("div", { key: '187ad16cca89403441617b91134070f486a9a7a4', class: { 'navigator': true, 'navigator--disabled': this.isNextNavigationDisabled() }, onClick: this.onClickNextMonth }, this.displayNextMonthArrow && h("kv-icon", { key: '6a166df8116d9c6235ae65122913ec4f5155279a', name: EIconName.NavOpen }))), h("div", { key: 'e7f86824e86c2f693ba703c5dfe009bb227541d3', class: "calendar__body" }, h("div", { key: 'bfe88d3c9553a40c04db2e731b2003bc04ee4441', class: "calendar-month" }, h("div", { key: '62c7b6798491be9241243204337c36d2abbf1c42', class: "calendar-month__weekdays" }, getWeekdaysNames().map(weekday => (h("div", { key: weekday, class: "weekday" }, weekday)))), h("div", { key: 'd5a0036cea1e6d77239b07ef2d5a8a2756cdd78b', class: "calendar-month__days" }, previousMonthLastDays.map(id => (h("kv-calendar-day", { key: `previous-${this.year}-${this.month}-${id + 1}`, day: id, disabled: true }))), currentMonthDays.map(index => (h("kv-calendar-day", { key: `${this.year}-${this.month}-${index + 1}`, day: index + 1, onClickDay: this.onClickDay.bind(this, index + 1), disabled: this.isDayDisabled(index + 1), active: this.isDayActive(index + 1), inRange: this.isDayInRange(index + 1), isRangeStartDate: this.isSelectedStartDay(index + 1), isRangeEndDate: this.isSelectedEndDay(index + 1), isToday: this.isToday(index + 1), isBetweenSelectedDates: this.isInsideDataRange(index + 1), onMouseEnterDay: this.onMouseEnter.bind(this, index + 1), onMouseLeaveDay: this.onMouseLeave.bind(this, index + 1) }))), nextMonthStartDays.map(id => (h("kv-calendar-day", { key: `after-${this.year}-${this.month}-${id + 1}`, day: id, disabled: true }))))))))); } static get is() { return "kv-calendar"; } static get encapsulation() { return "shadow"; } static get originalStyleUrls() { return { "$": ["calendar.scss"] }; } static get styleUrls() { return { "$": ["calendar.css"] }; } static get properties() { return { "selectedDates": { "type": "unknown", "attribute": "selected-dates", "mutable": false, "complexType": { "original": "string[]", "resolved": "string[]", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "inheritdoc", "text": undefined }], "text": "(optional) The currently selected dates" }, "getter": false, "setter": false, "defaultValue": "[]" }, "initialDate": { "type": "string", "attribute": "initial-date", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "inheritdoc", "text": undefined }], "text": "(optional) Initial date" }, "getter": false, "setter": false, "reflect": false }, "disableHoveringStyling": { "type": "boolean", "attribute": "disable-hovering-styling", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "inheritdoc", "text": undefined }], "text": "(optional) Disables the hovering styling when the dates are being selected, and when start or end date is not defined" }, "getter": false, "setter": false, "reflect": false, "defaultValue": "false" }, "hoveredDate": { "type": "string", "attribute": "hovered-date", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "inheritdoc", "text": undefined }], "text": "(optional) Defines if a date is hovered" }, "getter": false, "setter": false, "reflect": false }, "disabledDates": { "type": "unknown", "attribute": "disabled-dates", "mutable": false, "complexType": { "original": "string[]", "resolved": "string[]", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "inheritdoc", "text": undefined }], "text": "(options) The disabled dates array" }, "getter": false, "setter": false, "defaultValue": "[]" }, "minDate": { "type": "string", "attribute": "min-date", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "inheritdoc", "text": undefined }], "text": "(optional) Minimum accepted date. Format: YYYY-MM-DD" }, "getter": false, "setter": false, "reflect": false }, "maxDate": { "type": "string", "attribute": "max-date", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "inheritdoc", "text": undefined }], "text": "(optional) Maximum accepted date. Format: YYYY-MM-DD" }, "getter": false, "setter": false, "reflect": false }, "displayPreviousMonthArrow": { "type": "boolean", "attribute": "display-previous-month-arrow", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "inheritdoc", "text": undefined }], "text": "(optional) Enables the previous month click icon" }, "getter": false, "setter": false, "reflect": false, "defaultValue": "true" }, "displayNextMonthArrow": { "type": "boolean", "attribute": "display-next-month-arrow", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "inheritdoc", "text": undefined }], "text": "(optional) Enables the next month click icon" }, "getter": false, "setter": false, "reflect": false, "defaultValue": "true" }, "mode": { "type": "string", "attribute": "mode", "mutable": false, "complexType": { "original": "EAbsoluteTimePickerMode", "resolved": "EAbsoluteTimePickerMode.Range | EAbsoluteTimePickerMode.Single", "references": { "EAbsoluteTimePickerMode": { "location": "import", "path": "../../types", "id": "src/types.ts::EAbsoluteTimePickerMode" } } }, "required": false, "optional": true, "docs": { "tags": [{ "name": "inheritdoc", "text": undefined }], "text": "(optional) Defines if the calendar is in single date or range mode" }, "getter": false, "setter": false, "reflect": false, "defaultValue": "EAbsoluteTimePickerMode.Range" } }; } static get states() { return { "month": {}, "year": {}, "hoveredDay": {} }; } static get events() { return [{ "method": "changeMonth", "name": "changeMonth", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [{ "name": "inheritdoc", "text": undefined }], "text": "Emitted when a month changes" }, "complexType": { "original": "IChangeMonthEvent", "resolved": "IChangeMonthEvent", "references": { "IChangeMonthEvent": { "location": "import", "path": "./calendar.types", "id": "src/components/calendar/calendar.types.ts::IChangeMonthEvent" } } } }, { "method": "changeYear", "name": "changeYear", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [{ "name": "inheritdoc", "text": undefined }], "text": "Emitted when a year changes" }, "complexType": { "original": "IChangeYearEvent", "resolved": "IChangeYearEvent", "references": { "IChangeYearEvent": { "location": "import", "path": "./calendar.types", "id": "src/components/calendar/calendar.types.ts::IChangeYearEvent" } } } }, { "method": "clickDate", "name": "clickDate", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [{ "name": "inheritdoc", "text": undefined }], "text": "Emitted when a date is clicked" }, "complexType": { "original": "IClickDateEvent", "resolved": "IClickDateEvent", "references": { "IClickDateEvent": { "location": "import", "path": "./calendar.types", "id": "src/components/calendar/calendar.types.ts::IClickDateEvent" } } } }, { "method": "hoveredDateChange", "name": "hoveredDateChange", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [{ "name": "inheritdoc", "text": undefined }], "text": "Emitted when the hovered date changes" }, "complexType": { "original": "string", "resolved": "string", "references": {} } }]; } static get watchers() { return [{ "propName": "selectedDates", "methodName": "validateSelectedDates" }, { "propName": "initialDate", "methodName": "validateInitialDate" }, { "propName": "disabledDates", "methodName": "validateDisabledDates" }]; } }