@esri/calcite-components
Version:
Web Components for Esri's Calcite Design System.
397 lines (396 loc) • 16.4 kB
JavaScript
/*! 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} =${this.monthHoverChange} =${this.monthDateChange} =${this.monthActiveDateChange} =${this.monthHeaderSelectChange} =${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
};