UNPKG

@esri/calcite-components

Version:

Web Components for Esri's Calcite Design System.

397 lines (396 loc) • 16.4 kB
/*! All material copyright ESRI, All Rights Reserved, unless otherwise specified. See https://github.com/Esri/calcite-design-system/blob/dev/LICENSE.md for details. v3.2.1 */ import { c as customElement } from "../../chunks/runtime.js"; import { isServer, html } from "lit"; import { LitElement, createEvent } from "@arcgis/lumina"; import { a as dateFromISO, n as nextMonth, p as prevMonth, o as getDaysDiff, c as dateToISO, b as dateFromRange, m as getFirstValidDateInMonth, s as sameDate, i as inRange } from "../../chunks/date.js"; import { c as componentFocusable } from "../../chunks/component.js"; import { n as numberStringFormatter, g as getDateTimeFormat } from "../../chunks/locale.js"; import { h as focusFirstTabbable } from "../../chunks/dom.js"; import { u as useT9n } from "../../chunks/useT9n.js"; import { g as getValueAsDateRange, a as getLocaleData } from "../../chunks/utils2.js"; import { css } from "@lit/reactive-element/css-tag.js"; const HEADING_LEVEL = 2; const DATE_PICKER_FORMAT_OPTIONS = { dateStyle: "full" }; const styles = css`:host{box-sizing:border-box;background-color:var(--calcite-color-foreground-1);color:var(--calcite-color-text-2);font-size:var(--calcite-font-size--1)}:host *{box-sizing:border-box}:host{display:inline-block;inline-size:100%;overflow:visible;border-width:1px;border-style:solid;vertical-align:top;border-color:var(--calcite-date-picker-border-color, var(--calcite-color-border-1));border-radius:var(--calcite-date-picker-corner-radius, 0)}:host([scale=s]){inline-size:236px;min-inline-size:216px;max-inline-size:380px}:host([scale=s][range][layout=horizontal]){inline-size:480px;min-inline-size:432px;max-inline-size:772px}:host([scale=m]){inline-size:298px;min-inline-size:272px;max-inline-size:480px}:host([scale=m][range][layout=horizontal]){inline-size:608px;min-inline-size:544px;max-inline-size:972px}:host([scale=l]){inline-size:334px;min-inline-size:320px;max-inline-size:600px}:host([scale=l][range][layout=horizontal]){inline-size:684px;min-inline-size:640px;max-inline-size:1212px}:host([hidden]){display:none}[hidden]{display:none}`; class DatePicker extends LitElement { constructor() { super(); this.rangeValueChangedByUser = false; this.messages = useT9n({ blocking: true }); this.layout = "horizontal"; this.monthStyle = "wide"; this.proximitySelectionDisabled = false; this.range = false; this.scale = "m"; this.calciteDatePickerChange = createEvent({ cancelable: false }); this.calciteDatePickerRangeChange = createEvent({ cancelable: false }); this.listen("keydown", this.keyDownHandler); } static { this.properties = { activeEndDate: [16, {}, { state: true }], activeStartDate: [16, {}, { state: true }], dateTimeFormat: [16, {}, { state: true }], endAsDate: [16, {}, { state: true }], hoverRange: [16, {}, { state: true }], localeData: [16, {}, { state: true }], startAsDate: [16, {}, { state: true }], activeDate: [0, {}, { attribute: false }], activeRange: [3, {}, { reflect: true }], headingLevel: [11, {}, { type: Number, reflect: true }], layout: [3, {}, { reflect: true }], max: [3, {}, { reflect: true }], maxAsDate: [0, {}, { attribute: false }], messageOverrides: [0, {}, { attribute: false }], min: [3, {}, { reflect: true }], minAsDate: [0, {}, { attribute: false }], monthStyle: 1, numberingSystem: [3, {}, { reflect: true }], proximitySelectionDisabled: [7, {}, { reflect: true, type: Boolean }], range: [7, {}, { reflect: true, type: Boolean }], scale: [3, {}, { reflect: true }], value: 1, valueAsDate: [0, {}, { attribute: false }] }; } static { this.shadowRootOptions = { mode: "open", delegatesFocus: true }; } static { this.styles = styles; } async reset() { this.resetActiveDates(); this.rangeValueChangedByUser = false; } async setFocus() { await componentFocusable(this); focusFirstTabbable(this.el); } connectedCallback() { super.connectedCallback(); if (Array.isArray(this.value)) { this.valueAsDate = getValueAsDateRange(this.value); } else if (this.value) { this.valueAsDate = dateFromISO(this.value); } if (this.min) { this.minAsDate = dateFromISO(this.min); } if (this.max) { this.maxAsDate = dateFromISO(this.max); } this.setActiveStartAndEndDates(); } async load() { await this.loadLocaleData(); this.onMinChanged(this.min); this.onMaxChanged(this.max); } willUpdate(changes) { if (changes.has("activeDate")) { this.activeDateWatcher(this.activeDate); } if (changes.has("value")) { this.valueHandler(this.value); } if (changes.has("valueAsDate")) { this.valueAsDateWatcher(this.valueAsDate); } if (changes.has("min")) { this.onMinChanged(this.min); } if (changes.has("max")) { this.onMaxChanged(this.max); } if (changes.has("messages") && this.hasUpdated) { this.loadLocaleData().catch(console.error); } } activeDateWatcher(newValue) { if (!this.range) { return; } if (!this.rangeValueChangedByUser) { if (newValue) { this.activeStartDate = newValue; this.activeEndDate = nextMonth(this.activeStartDate); } else { this.resetActiveDates(); } } } valueHandler(value) { if (Array.isArray(value)) { this.valueAsDate = getValueAsDateRange(value); if (!this.rangeValueChangedByUser) { this.resetActiveDates(); } } else if (value) { this.valueAsDate = dateFromISO(value); } } valueAsDateWatcher(newValueAsDate) { if (this.range && Array.isArray(newValueAsDate) && !this.rangeValueChangedByUser) { this.setActiveStartAndEndDates(); } else if (newValueAsDate && newValueAsDate !== this.activeDate) { this.activeDate = newValueAsDate; } } onMinChanged(min) { this.minAsDate = dateFromISO(min); if (this.range) { this.setActiveStartAndEndDates(); } } onMaxChanged(max) { this.maxAsDate = dateFromISO(max); if (this.range) { this.setActiveStartAndEndDates(); } } keyDownHandler(event) { if (event.key === "Escape") { this.resetActiveDates(); } } async loadLocaleData() { if (isServer) { return; } numberStringFormatter.numberFormatOptions = { numberingSystem: this.numberingSystem, locale: this.messages._lang, useGrouping: false }; this.localeData = await getLocaleData(this.messages._lang); this.dateTimeFormat = getDateTimeFormat(this.messages._lang, DATE_PICKER_FORMAT_OPTIONS); } monthHeaderSelectChange(event) { const date = new Date(event.detail.date); const position = event.detail.position; if (!this.range) { this.activeDate = date; } else { if (position === "end") { this.activeEndDate = date; this.activeStartDate = prevMonth(date); } else { this.activeStartDate = date; this.activeEndDate = nextMonth(date); } } event.stopPropagation(); } monthActiveDateChange(event) { const date = new Date(event.detail); if (!this.range) { this.activeDate = date; } else { const month = date.getMonth(); const isDateOutOfCurrentRange = month !== this.activeStartDate.getMonth() && month !== nextMonth(this.activeStartDate).getMonth(); if (this.activeRange === "end") { if (!this.activeEndDate || this.activeStartDate && isDateOutOfCurrentRange) { this.activeEndDate = date; this.activeStartDate = prevMonth(date); } } else { if (this.activeStartDate && isDateOutOfCurrentRange || !this.activeStartDate) { this.activeStartDate = date; this.activeEndDate = nextMonth(date); } } } event.stopPropagation(); } monthHoverChange(event) { if (!this.range) { this.hoverRange = void 0; return; } const { valueAsDate } = this; const start = Array.isArray(valueAsDate) && valueAsDate[0]; const end = Array.isArray(valueAsDate) && valueAsDate[1]; const date = new Date(event.detail); this.hoverRange = { focused: this.activeRange || "start", start, end }; if (this.proximitySelectionDisabled) { if (end && start || !end && date >= start) { this.hoverRange.focused = "end"; this.hoverRange.end = date; } else if (!end && date < start) { this.hoverRange = { focused: "start", start: date, end: start }; } else { this.hoverRange = void 0; } } else { if (this.activeRange) { if (this.activeRange === "end") { this.hoverRange.end = date; this.hoverRange.focused = "end"; } else { this.hoverRange.start = date; this.hoverRange.focused = "start"; } } else if (start && end) { const startDiff = Math.abs(getDaysDiff(date, start)); const endDiff = Math.abs(getDaysDiff(date, end)); if (date > end) { this.hoverRange.end = date; this.hoverRange.focused = "end"; } else if (date < start) { this.hoverRange.start = date; this.hoverRange.focused = "start"; } else if (date > start && date < end) { if (startDiff < endDiff) { this.hoverRange.start = date; this.hoverRange.focused = "start"; } else { this.hoverRange.end = date; this.hoverRange.focused = "end"; } } } else { if (start) { if (date < start) { this.hoverRange = { focused: "start", start: date, end: start }; } else { this.hoverRange.end = date; this.hoverRange.focused = "end"; } } } } event.stopPropagation(); } monthMouseOutChange(event) { if (this.hoverRange) { this.hoverRange = void 0; } event.stopPropagation(); } resetActiveDates() { const { valueAsDate } = this; if (!Array.isArray(valueAsDate) && valueAsDate && valueAsDate !== this.activeDate) { this.activeDate = new Date(valueAsDate); } if (Array.isArray(valueAsDate)) { if (valueAsDate[0] && valueAsDate[0] !== this.activeStartDate) { this.activeStartDate = new Date(valueAsDate[0]); } if (valueAsDate[1] && valueAsDate[1] !== this.activeEndDate) { this.activeEndDate = new Date(valueAsDate[1]); } } this.hoverRange = void 0; } getEndDate() { return Array.isArray(this.valueAsDate) && this.valueAsDate[1] || void 0; } setEndDate(date) { const startDate = this.getStartDate(); this.rangeValueChangedByUser = true; this.value = [dateToISO(startDate), dateToISO(date)]; this.valueAsDate = [startDate, date]; if (date) { this.calciteDatePickerRangeChange.emit(); } } getStartDate() { return Array.isArray(this.valueAsDate) && this.valueAsDate[0]; } setStartDate(date) { const endDate = this.getEndDate(); this.rangeValueChangedByUser = true; this.value = [dateToISO(date), dateToISO(endDate)]; this.valueAsDate = [date, endDate]; this.calciteDatePickerRangeChange.emit(); } monthDateChange(event) { const date = new Date(event.detail); const isoDate = dateToISO(date); if (!this.range && isoDate === dateToISO(this.valueAsDate)) { return; } if (!this.range) { this.value = isoDate || ""; this.valueAsDate = date || null; this.activeDate = date || null; this.calciteDatePickerChange.emit(); return; } const start = this.getStartDate(); const end = this.getEndDate(); if (!start || !end && date < start) { if (start) { this.setEndDate(new Date(start)); } if (this.activeRange == "end") { this.setEndDate(date); } else { this.setStartDate(date); } } else if (!end) { this.setEndDate(date); } else { if (this.proximitySelectionDisabled) { this.setStartDate(date); this.setEndDate(null); } else { if (this.activeRange) { if (this.activeRange == "end") { this.setEndDate(date); } else { if (date > end) { this.setEndDate(null); this.activeEndDate = null; } this.setStartDate(date); } } else { const startDiff = getDaysDiff(date, start); const endDiff = getDaysDiff(date, end); if (endDiff === 0 || startDiff < 0) { this.setStartDate(date); } else if (startDiff === 0 || endDiff < 0) { this.setEndDate(date); } else if (startDiff < endDiff) { this.setStartDate(date); } else { this.setEndDate(date); } } } } event.stopPropagation(); this.calciteDatePickerChange.emit(); } getActiveDate(value, min, max) { const activeDate = dateFromRange(/* @__PURE__ */ new Date(), min, max); return dateFromRange(this.activeDate, min, max) || value || (sameDate(max, activeDate) && !this.range ? getFirstValidDateInMonth(activeDate, min, max) : activeDate); } getActiveEndDate(value, min, max) { return dateFromRange(this.activeEndDate, min, max) || value || dateFromRange(nextMonth(/* @__PURE__ */ new Date()), min, max); } setActiveStartAndEndDates() { if (this.range) { const startDate = dateFromRange(Array.isArray(this.valueAsDate) ? this.valueAsDate[0] : this.valueAsDate, this.minAsDate, this.maxAsDate); const endDate = dateFromRange(Array.isArray(this.valueAsDate) ? this.valueAsDate[1] : null, this.minAsDate, this.maxAsDate); this.activeStartDate = this.getActiveDate(startDate, this.minAsDate, this.maxAsDate); this.activeEndDate = this.getActiveEndDate(endDate, this.minAsDate, this.maxAsDate); if (sameDate(this.activeStartDate, this.activeEndDate)) { const previousMonthActiveDate = getFirstValidDateInMonth(prevMonth(this.activeEndDate), this.minAsDate, this.maxAsDate); const nextMonthActiveDate = nextMonth(this.activeEndDate); if (inRange(previousMonthActiveDate, this.minAsDate, this.maxAsDate)) { this.activeStartDate = previousMonthActiveDate; } else if (inRange(nextMonthActiveDate, this.minAsDate, this.maxAsDate)) { this.activeEndDate = nextMonthActiveDate; } } } } render() { const date = dateFromRange(this.range && Array.isArray(this.valueAsDate) ? this.valueAsDate[0] : this.valueAsDate, this.minAsDate, this.maxAsDate); const activeDate = this.getActiveDate(date, this.minAsDate, this.maxAsDate); const endDate = this.range && Array.isArray(this.valueAsDate) ? dateFromRange(this.valueAsDate[1], this.minAsDate, this.maxAsDate) : null; const minDate = this.range && this.activeRange ? this.activeRange === "start" ? this.minAsDate : date : this.minAsDate; const startCalendarActiveDate = this.range ? this.activeStartDate : activeDate; return this.renderMonth(startCalendarActiveDate, this.maxAsDate, minDate, date, endDate); } renderMonth(activeDate, maxDate, minDate, date, endDate) { return this.localeData && html`<calcite-date-picker-month .activeDate=${activeDate} .dateTimeFormat=${this.dateTimeFormat} .endDate=${this.range ? endDate : void 0} .headingLevel=${this.headingLevel || HEADING_LEVEL} .hoverRange=${this.hoverRange} .layout=${this.layout} .localeData=${this.localeData} .max=${maxDate} .messages=${this.messages} .min=${minDate} .monthStyle=${this.monthStyle} @calciteInternalDatePickerDayHover=${this.monthHoverChange} @calciteInternalDatePickerDaySelect=${this.monthDateChange} @calciteInternalDatePickerMonthActiveDateChange=${this.monthActiveDateChange} @calciteInternalDatePickerMonthChange=${this.monthHeaderSelectChange} @calciteInternalDatePickerMonthMouseOut=${this.monthMouseOutChange} .range=${this.range} .scale=${this.scale} .selectedDate=${this.activeRange === "end" ? endDate : date} .startDate=${this.range ? date : void 0}></calcite-date-picker-month>` || ""; } } customElement("calcite-date-picker", DatePicker); export { DatePicker };