@kelvininc/ui-components
Version:
Kelvin UI Components
530 lines (529 loc) • 23.4 kB
JavaScript
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"
}];
}
}