UNPKG

@esri/calcite-components

Version:

Web Components for Esri's Calcite Design System.

676 lines (675 loc) • 41.8 kB
/* COPYRIGHT Esri - https://js.arcgis.com/5.0/LICENSE.txt */ import { c as customElement } from "../../chunks/runtime.js"; import { css, isServer, nothing, html } from "lit"; import { createRef, ref } from "lit/directives/ref.js"; import { LitElement, createEvent, stringOrBoolean, safeClassMap } from "@arcgis/lumina"; import { u as useFocusTrap } from "../../chunks/useFocusTrap.js"; import { l as datePartsFromISO, d as dateFromISO, b as dateFromRange, a as dateToISO, m as datePartsFromLocalizedString, o as dateFromLocalizedString, i as inRange } from "../../chunks/date.js"; import { d as defaultMenuPlacement, r as reposition, c as connectFloatingUI, a as disconnectFloatingUI, f as filterValidFlipPlacements, h as hideFloatingUI, F as FloatingCSS } from "../../chunks/floating-ui.js"; import { c as connectForm, d as disconnectForm, s as submitForm, H as HiddenFormInputSlot } from "../../chunks/form.js"; import { n as numberKeys } from "../../chunks/key.js"; import { c as connectLabel, d as disconnectLabel, g as getLabelText } from "../../chunks/label.js"; import { g as getIconScale } from "../../chunks/component.js"; import { b as getSupportedNumberingSystem, c as getDateFormatSupportedLocale, n as numberStringFormatter } from "../../chunks/locale.js"; import { t as toggleOpenClose } from "../../chunks/openCloseComponent.js"; import { g as getValueAsDateRange, a as applyLocaleOverride, b as getLocaleData } from "../../chunks/utils3.js"; import { g as guid } from "../../chunks/guid.js"; import { I as InternalLabel } from "../../chunks/InternalLabel.js"; import { V as Validation } from "../../chunks/Validation.js"; import { s as syncHiddenFormInput } from "../../chunks/input.js"; import { u as useT9n } from "../../chunks/useT9n.js"; import { u as useSetFocus } from "../../chunks/useSetFocus.js"; import { u as useInteractive } from "../../chunks/useInteractive.js"; import { u as useTopLayer } from "../../chunks/useTopLayer.js"; const styles = css`:host([disabled]){cursor:default;-webkit-user-select:none;user-select:none;opacity:var(--calcite-opacity-disabled)}:host([disabled]) *,:host([disabled]) ::slotted(*){pointer-events:none}:host .menu-container[popover]{padding:0;margin:0;border:none;background-color:transparent;overflow:visible;display:none}:host .menu-container:popover-open{display:block}:host .menu-container .calcite-floating-ui-anim{position:relative;transition-duration:var(--calcite-floating-ui-transition);transition-property:inset-block-start,left,opacity,display;transition-behavior:allow-discrete;opacity:0;box-shadow:0 0 16px #00000029;z-index:var(--calcite-z-index);border-radius:.25rem}:host .menu-container[data-placement^=bottom] .calcite-floating-ui-anim{inset-block-start:-5px}:host .menu-container[data-placement^=top] .calcite-floating-ui-anim{inset-block-start:5px}:host .menu-container[data-placement^=left] .calcite-floating-ui-anim{left:5px}:host .menu-container[data-placement^=right] .calcite-floating-ui-anim{left:-5px}:host .menu-container[data-placement] .calcite-floating-ui-anim--active{opacity:1;inset-block-start:0;left:0}@starting-style{:host .menu-container[data-placement] .calcite-floating-ui-anim--active{opacity:0}}:host{position:relative;display:inline-block;width:100%;overflow:visible;vertical-align:top;box-shadow:var(--calcite-input-date-picker-shadow, var(--calcite-shadow-none))}:host .menu-container .calcite-floating-ui-anim{box-shadow:var(--calcite-input-date-picker-calendar-shadow, var(--calcite-shadow-sm))}:host([scale=s]){--calcite-internal-date-picker-toggle-spacing: var(--calcite-spacing-sm);--calcite-internal-input-text-input-padding-inline-end: calc(var(--calcite-internal-date-picker-toggle-spacing) + var(--calcite-spacing-lg))}:host([scale=m]){--calcite-internal-date-picker-toggle-spacing: var(--calcite-spacing-md);--calcite-internal-input-text-input-padding-inline-end: calc(var(--calcite-internal-date-picker-toggle-spacing) + var(--calcite-spacing-xxl))}:host([scale=l]){--calcite-internal-date-picker-toggle-spacing: var(--calcite-spacing-lg);--calcite-internal-input-text-input-padding-inline-end: calc(var(--calcite-internal-date-picker-toggle-spacing) + var(--calcite-spacing-xxxl))}:host([disabled]) ::slotted([calcite-hydrated][disabled]),:host([disabled]) [calcite-hydrated][disabled]{opacity:1}.interaction-container{display:contents}.calendar-wrapper{box-shadow:var(--calcite-input-date-picker-calendar-shadow, var(--calcite-shadow-none));transform:translateZ(0)}.input-wrapper{position:relative}.input-wrapper .chevron-icon{color:var(--calcite-input-date-picker-actions-icon-color, var(--calcite-color-text-3))}.input-wrapper:focus-within .chevron-icon,.input-wrapper:active .chevron-icon,.input-wrapper:hover .chevron-icon{color:var(--calcite-input-date-picker-actions-icon-color-hover, var(--calcite-color-text-1))}.input-wrapper:focus-within~.input-wrapper .chevron-icon,.input-wrapper:active~.input-wrapper .chevron-icon,.input-wrapper:hover~.input-wrapper .chevron-icon{color:var(--calcite-input-date-picker-actions-icon-color-hover, var(--calcite-color-text-1))}.toggle-icon{position:absolute;display:flex;cursor:pointer;align-items:center;inset-inline-end:0;inset-block:0;padding-inline:var(--calcite-internal-date-picker-toggle-spacing)}:host([range]) .container{display:flex}:host([range]) .input-container{display:flex;flex:1 1 auto}:host([range]) .input-wrapper{flex:1 1 auto}.divider-container{display:flex;align-items:stretch;border-width:1px;border-left-width:0px;border-right-width:0px;border-style:solid;background-color:var(--calcite-input-date-picker-background-color, var(--calcite-color-foreground-1));border-color:var(--calcite-input-date-picker-border-color, var(--calcite-color-border-input))}:host([layout=horizontal]) .divider-container{inline-size:var(--calcite-spacing-px)}.divider{display:inline-block;margin-block:var(--calcite-spacing-xxs);background-color:var(--calcite-input-date-picker-divider-color, var(--calcite-color-border-2));inline-size:var(--calcite-spacing-px)}:host([layout=vertical]) .divider-container{height:1px;width:100%;border-top-width:0px;border-bottom-width:0px;border-inline-start-width:var(--calcite-border-width-sm);border-inline-end-width:var(--calcite-border-width-none);padding-inline:var(--calcite-spacing-md)}:host([layout=vertical]) .divider-container .divider{margin-top:0;margin-bottom:0;height:1px;width:100%}:host([range][layout=vertical]) .input-wrapper{width:100%}:host([range][layout=vertical]) .input-container{flex-direction:column;align-items:flex-start}.menu-container{--calcite-floating-ui-z-index: var(--calcite-z-index-dropdown);inline-size:max-content;display:none;max-inline-size:100vw;max-block-size:100vh;inset-block-start:0;left:0;z-index:var(--calcite-floating-ui-z-index)}@starting-style{.menu-container{opacity:0;inset-block-start:0;left:0}}.menu-container[popover]{padding:0;margin:0;border:none;background-color:transparent;overflow:visible;display:none}.menu-container:popover-open{display:block}.menu-container .calcite-floating-ui-anim{position:relative;transition-duration:var(--calcite-floating-ui-transition);transition-property:inset-block-start,left,opacity,display;transition-behavior:allow-discrete;opacity:0;box-shadow:0 0 16px #00000029;z-index:var(--calcite-z-index);border-radius:.25rem}.menu-container[data-placement^=bottom] .calcite-floating-ui-anim{inset-block-start:-5px}.menu-container[data-placement^=top] .calcite-floating-ui-anim{inset-block-start:5px}.menu-container[data-placement^=left] .calcite-floating-ui-anim{left:5px}.menu-container[data-placement^=right] .calcite-floating-ui-anim{left:-5px}.menu-container[data-placement] .calcite-floating-ui-anim--active{opacity:1;inset-block-start:0;left:0}@starting-style{.menu-container[data-placement] .calcite-floating-ui-anim--active{opacity:0}}.input .calcite-input__wrapper{margin-top:0}.vertical-chevron-container{display:flex;align-items:center;border-width:1px;border-style:solid;padding-inline:var(--calcite-spacing-md);background-color:var(--calcite-input-date-picker-background-color, var(--calcite-color-foreground-1));border-color:var(--calcite-input-date-picker-border-color, var(--calcite-color-border-input));border-inline-start-width:0}.vertical-chevron-container calcite-icon{color:var(--calcite-input-date-picker-actions-icon-color, var(--calcite-color-text-3))}.vertical-chevron-container calcite-icon:hover{color:var(--calcite-input-date-picker-actions-icon-color-hover, var(--calcite-color-text-1))}:host([range][layout=vertical][scale=s]) .vertical-chevron-container,:host([range][layout=vertical][scale=s]) .divider-container{padding-inline:var(--calcite-spacing-sm)}:host([range][layout=vertical][scale=l]) .vertical-chevron-container,:host([range][layout=vertical][scale=l]) .divider-container{padding-inline:var(--calcite-spacing-lg)}.container:focus-within .vertical-chevron-container calcite-icon,.container:active .vertical-chevron-container calcite-icon,.container:hover .vertical-chevron-container calcite-icon{color:var(--calcite-input-date-picker-actions-icon-color-hover, var(--calcite-color-text-1))}.input{--calcite-input-text-background-color: var(--calcite-input-date-picker-background-color);--calcite-input-text-border-color: var(--calcite-input-date-picker-border-color);--calcite-input-text-corner-radius: var(--calcite-input-date-picker-corner-radius);--calcite-input-text-shadow: var(--calcite-input-date-picker-shadow);--calcite-input-text-icon-color: var(--calcite-input-date-picker-icon-color);--calcite-input-text-text-color: var(--calcite-input-date-picker-text-color);--calcite-input-text-placeholder-text-color: var(--calcite-input-date-picker-placeholder-text-color)}calcite-date-picker{--calcite-date-picker-border-color: var(--calcite-input-date-picker-calendar-border-color);--calcite-date-picker-corner-radius: var(--calcite-input-date-picker-calendar-corner-radius);--calcite-date-picker-range-calendar-divider-color: var(--calcite-input-date-picker-calendar-range-divider-color);--calcite-date-picker-week-header-text-color: var(--calcite-input-date-picker-calendar-text-color);--calcite-date-picker-header-action-background-color: var( --calcite-input-date-picker-calendar-actions-background-color );--calcite-date-picker-header-action-background-color-hover: var( --calcite-input-date-picker-calendar-actions-background-color-hover );--calcite-date-picker-header-action-background-color-press: var( --calcite-input-date-picker-calendar-actions-background-color-press );--calcite-date-picker-header-action-text-color: var(--calcite-input-date-picker-calendar-actions-text-color);--calcite-date-picker-header-action-text-color-press: var( --calcite-input-date-picker-calendar-actions-text-color-press );--calcite-date-picker-year-text-color: var(--calcite-input-date-picker-calendar-text-color);--calcite-date-picker-month-select-text-color: var(--calcite-input-date-picker-calendar-month-select-text-color);--calcite-date-picker-month-select-icon-color: var(--calcite-input-date-picker-calendar-icon-color);--calcite-date-picker-month-select-icon-color-hover: var(--calcite-input-date-picker-calendar-icon-color-hover);--calcite-date-picker-day-background-color: var(--calcite-input-date-picker-calendar-day-background-color);--calcite-date-picker-day-background-color-hover: var( --calcite-input-date-picker-calendar-day-background-color-hover );--calcite-date-picker-day-background-color-selected: var( --calcite-input-date-picker-calendar-selected-background-color );--calcite-date-picker-day-text-color: var(--calcite-input-date-picker-calendar-day-text-color);--calcite-date-picker-day-text-color-hover: var(--calcite-input-date-picker-calendar-day-text-color-hover);--calcite-date-picker-day-text-color-selected: var(--calcite-input-date-picker-calendar-day-text-color-selected);--calcite-date-picker-current-day-text-color: var( --calcite-input-date-picker-calendar-current-day-text-color, var(--calcite-input-date-picker-calendar-day-current-text-color) );--calcite-date-picker-day-range-text-color: var(--calcite-input-date-picker-calendar-day-range-text-color);--calcite-date-picker-day-range-background-color: var( --calcite-input-date-picker-calendar-day-range-background-color );--calcite-date-picker-day-outside-range-background-color-hover: var( --calcite-input-date-picker-calendar-day-outside-range-background-color-hover );--calcite-date-picker-day-outside-range-text-color-hover: var( --calcite-input-date-picker-calendar-day-outside-range-text-color-hover )}.assistive-text{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.validation-container{display:flex;flex-direction:column;align-items:flex-start;align-self:stretch}:host([scale=m]) .validation-container,:host([scale=l]) .validation-container{padding-block-start:.5rem}:host([scale=s]) .validation-container{padding-block-start:.25rem}::slotted(input[slot=hidden-form-input]){margin:0!important;opacity:0!important;outline:none!important;padding:0!important;position:absolute!important;inset:0!important;transform:none!important;-webkit-appearance:none!important;z-index:-1!important}.internal-label-alignment--center{align-items:center}.internal-label-alignment--end{align-items:end}.internal-label--container{display:flex;justify-content:space-between;color:var(--calcite-color-text-1)}.internal-label-required--indicator{font-weight:var(--calcite-font-weight-medium);color:var(--calcite-color-status-danger);padding-inline:var(--calcite-spacing-base)}.internal-label-required--indicator:hover{cursor:help}.internal-label--text{line-height:1}:host([scale=s]) .internal-label-spacing--bottom{margin-block-end:var(--calcite-spacing-xxs)}:host([scale=s]) .internal-label-spacing-inline--end{margin-inline-end:var(--calcite-spacing-sm)}:host([scale=s]) .internal-label-spacing-inline--start{margin-inline-start:var(--calcite-spacing-sm)}:host([scale=s]) .internal-label--text{font-size:var(--calcite-font-size--2)}:host([scale=m]) .internal-label-spacing--bottom{margin-block-end:var(--calcite-spacing-sm)}:host([scale=m]) .internal-label-spacing-inline--end{margin-inline-end:var(--calcite-spacing-sm)}:host([scale=m]) .internal-label-spacing-inline--start{margin-inline-start:var(--calcite-spacing-sm)}:host([scale=m]) .internal-label--text{font-size:var(--calcite-font-size--1)}:host([scale=l]) .internal-label-spacing--bottom{margin-block-end:var(--calcite-spacing-sm)}:host([scale=l]) .internal-label-spacing-inline--end{margin-inline-end:var(--calcite-spacing-md)}:host([scale=l]) .internal-label-spacing-inline--start{margin-inline-start:var(--calcite-spacing-md)}:host([scale=l]) .internal-label--text{font-size:var(--calcite-font-size-0)}:host([hidden]){display:none}[hidden]{display:none}`; const CSS = { assistiveText: "assistive-text", calendarWrapper: "calendar-wrapper", container: "container", dividerContainer: "divider-container", divider: "divider", inputContainer: "input-container", inputNoBottomBorder: "input--no-bottom-border", inputNoRightBorder: "input--no-right-border", inputNoTopBorder: "input--no-top-border", inputNoLeftBorder: "input--no-left-border", inputWrapper: "input-wrapper", input: "input", menu: "menu-container", toggleIcon: "toggle-icon", verticalChevronContainer: "vertical-chevron-container", chevronIcon: "chevron-icon" }; const idPrefix = "calcite-input-date-picker"; const IDS = { validationMessage: "inputDatePickerValidationMessage", dialog: (id) => `date-picker-dialog--${id}`, placeholder: (id) => `${idPrefix}-placeholder-${id}` }; const POSITION = { start: "start", end: "end" }; const ICONS = { calendar: "calendar", chevronDown: "chevron-down", chevronUp: "chevron-up" }; function isTwoDigitYear(value) { if (!value) { return false; } const { year } = datePartsFromISO(value); return Number(year) < 100; } function normalizeToCurrentCentury(twoDigitYear) { const currentYear = (/* @__PURE__ */ new Date()).getFullYear(); const normalizedYear = Math.floor(currentYear / 100) * 100 + twoDigitYear; return normalizedYear; } class InputDatePicker extends LitElement { constructor() { super(); this.commonDateSeparators = [".", "-", "/"]; this.dialogId = IDS.dialog(guid()); this.endInputRef = createRef(); this.focusOnOpen = false; this.focusTrap = useFocusTrap({ triggerProp: "open", focusTrapOptions: { onActivate: () => { if (this.focusOnOpen) { this.datePickerEl?.setFocus(); this.focusOnOpen = false; } }, allowOutsideClick: true, // Allow outside click and let the popover manager take care of closing the popover. clickOutsideDeactivates: false, initialFocus: false, setReturnFocus: false, onDeactivate: () => { this.open = false; } } })(this); this.transitionProp = "opacity"; this.placeholderTextId = IDS.placeholder(guid()); this.rangeStartValueChangedByUser = false; this.startInputRef = createRef(); this.transitionRef = createRef(); this.userChangedValue = false; this._value = ""; this.valueAsDateChangedExternally = false; this.messages = useT9n({ blocking: true }); this.focusSetter = useSetFocus()(this); this.interactiveContainer = useInteractive(this); this.topLayer = useTopLayer({ target: () => this.floatingEl })(this); this.focusedInput = "start"; this.calendars = 2; this.disabled = false; this.focusTrapDisabled = false; this.layout = "horizontal"; this.monthStyle = "wide"; this.open = false; this.overlayPositioning = "absolute"; this.placement = defaultMenuPlacement; this.proximitySelectionDisabled = false; this.range = false; this.readOnly = false; this.required = false; this.scale = "m"; this.status = "idle"; this.topLayerDisabled = false; this.validity = { valid: false, badInput: false, customError: false, patternMismatch: false, rangeOverflow: false, rangeUnderflow: false, stepMismatch: false, tooLong: false, tooShort: false, typeMismatch: false, valueMissing: false }; this.calciteInputDatePickerBeforeClose = createEvent({ cancelable: false }); this.calciteInputDatePickerBeforeOpen = createEvent({ cancelable: false }); this.calciteInputDatePickerChange = createEvent({ cancelable: false }); this.calciteInputDatePickerClose = createEvent({ cancelable: false }); this.calciteInputDatePickerOpen = createEvent({ cancelable: false }); this.listen("blur", this.blurHandler); this.listen("keydown", this.keyDownHandler); this.handleDateTimeFormatChange(); } static { this.properties = { datePickerActiveDate: [16, {}, { state: true }], focusedInput: [16, {}, { state: true }], localeData: [16, {}, { state: true }], calendars: [11, {}, { type: Number, reflect: true }], disabled: [7, {}, { reflect: true, type: Boolean }], flipPlacements: [0, {}, { attribute: false }], focusTrapDisabled: [7, {}, { reflect: true, type: Boolean }], form: [3, {}, { reflect: true }], headingLevel: [11, {}, { type: Number, reflect: true }], label: 1, labelText: 1, 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, name: [3, {}, { reflect: true }], numberingSystem: [3, {}, { reflect: true }], open: [7, {}, { reflect: true, type: Boolean }], overlayPositioning: [3, {}, { reflect: true }], placement: [3, {}, { reflect: true }], proximitySelectionDisabled: [5, {}, { type: Boolean }], range: [7, {}, { reflect: true, type: Boolean }], readOnly: [7, {}, { reflect: true, type: Boolean }], required: [7, {}, { reflect: true, type: Boolean }], scale: [3, {}, { reflect: true }], status: [3, {}, { reflect: true }], topLayerDisabled: [7, {}, { reflect: true, type: Boolean }], validationIcon: [3, { converter: stringOrBoolean, type: String }, { reflect: true }], validationMessage: 1, validity: [0, {}, { attribute: false }], value: 1, valueAsDate: [0, {}, { attribute: false }] }; } static { this.shadowRootOptions = { mode: "open", delegatesFocus: true }; } static { this.styles = styles; } get value() { return this._value; } set value(value) { const valueChanged = value !== this._value; const invalidValueCleared = value === "" && (this.startInputRef.value?.value !== "" || this.endInputRef.value?.value !== ""); if (valueChanged || invalidValueCleared) { this._value = value; this.valueWatcher(value); } } async reposition(delayed = false) { const { floatingEl, referenceEl, placement, overlayPositioning, filteredFlipPlacements } = this; return reposition(this, { floatingEl, referenceEl, overlayPositioning, placement, flipPlacements: filteredFlipPlacements, type: "menu" }, delayed); } async setFocus(options) { return this.focusSetter(() => this.el, options); } connectedCallback() { super.connectedCallback(); const { open } = this; if (open) { this.openHandler(); } if (this.min) { this.minAsDate = dateFromISO(this.min); } if (this.max) { this.maxAsDate = dateFromISO(this.max); } if (Array.isArray(this.value)) { this.valueAsDate = getValueAsDateRange(this.value); } else if (this.value) { try { const date = dateFromISO(this.value); const dateInRange = dateFromRange(date, this.minAsDate, this.maxAsDate); this.valueAsDate = dateInRange; } catch { this.warnAboutInvalidValue(this.value); this.value = ""; } } else if (this.valueAsDate) { if (this.range && Array.isArray(this.valueAsDate)) { this.value = [dateToISO(this.valueAsDate[0]), dateToISO(this.valueAsDate[1])]; } else if (!this.range && !Array.isArray(this.valueAsDate)) { this.value = dateToISO(this.valueAsDate); } } connectLabel(this); connectForm(this); this.setFilteredPlacements(); connectFloatingUI(this); } async load() { this.handleDateTimeFormatChange(); await this.loadLocaleData(); this.onMinChanged(this.min); this.onMaxChanged(this.max); } willUpdate(changes) { if (changes.has("disabled") && (this.hasUpdated || this.disabled !== false)) { this.handleDisabledAndReadOnlyChange(this.disabled); } if (changes.has("readOnly") && (this.hasUpdated || this.readOnly !== false)) { this.handleDisabledAndReadOnlyChange(this.readOnly); } if (changes.has("valueAsDate")) { this.valueAsDateWatcher(this.valueAsDate); } if (changes.has("flipPlacements")) { this.flipPlacementsHandler(); } if (changes.has("min")) { this.onMinChanged(this.min); } if (changes.has("max")) { this.onMaxChanged(this.max); } if (changes.has("open") && (this.hasUpdated || this.open !== false)) { this.openHandler(); } if (changes.has("overlayPositioning") && (this.hasUpdated || this.overlayPositioning !== "absolute")) { this.reposition(true); } if (changes.has("numberingSystem") || changes.has("messages")) { this.handleDateTimeFormatChange(); } if (changes.has("layout") && (this.hasUpdated || this.layout !== "horizontal")) { this.setReferenceEl(); } if (changes.has("messages")) { this.loadLocaleData(); } } loaded() { this.localizeInputValues(); connectFloatingUI(this); } disconnectedCallback() { super.disconnectedCallback(); disconnectLabel(this); disconnectForm(this); disconnectFloatingUI(this); } handleDisabledAndReadOnlyChange(value) { if (!value) { this.open = false; } } valueWatcher(newValue) { if (!this.userChangedValue) { let newValueAsDate; if (Array.isArray(newValue)) { newValueAsDate = getValueAsDateRange(newValue); } else if (newValue) { newValueAsDate = dateFromISO(newValue); } else { newValueAsDate = void 0; } if (!this.valueAsDateChangedExternally && newValueAsDate !== this.valueAsDate) { this.valueAsDate = newValueAsDate; } this.localizeInputValues(); } this.userChangedValue = false; } valueAsDateWatcher(valueAsDate) { const newValue = Array.isArray(valueAsDate) ? [dateToISO(valueAsDate[0]), dateToISO(valueAsDate[1])] : dateToISO(valueAsDate); this.datePickerActiveDate = Array.isArray(valueAsDate) ? valueAsDate[0] : valueAsDate; if (this.value !== newValue) { this.valueAsDateChangedExternally = true; this.value = newValue; this.valueAsDateChangedExternally = false; } } flipPlacementsHandler() { this.setFilteredPlacements(); this.reposition(true); } onMinChanged(min) { this.minAsDate = dateFromISO(min); } onMaxChanged(max) { this.maxAsDate = dateFromISO(max); } openHandler() { if (this.disabled || this.readOnly) { return; } toggleOpenClose(this); this.reposition(true); } calciteInternalInputInputHandler(event) { const target = event.target; const value = target.value; const parsedValue = this.parseNumerals(value); const formattedValue = this.formatNumerals(parsedValue); target.value = formattedValue; const { year } = datePartsFromLocalizedString(value, this.localeData); if (year && year.length < 4) { return; } const date = dateFromLocalizedString(value, this.localeData); if (inRange(date, this.min, this.max)) { this.datePickerActiveDate = date; } } calciteInternalInputBlurHandler() { this.commitValue(); } handleDateTimeFormatChange() { const formattingOptions = { // we explicitly set numberingSystem to prevent the browser-inferred value // @see [Arabic numbering system support context](https://github.com/Esri/calcite-design-system/issues/3079#issuecomment-1168964195) for more info. numberingSystem: getSupportedNumberingSystem(this.numberingSystem) }; this.dateTimeFormat = new Intl.DateTimeFormat(getDateFormatSupportedLocale(applyLocaleOverride(this.messages._lang)), formattingOptions); } setReferenceEl() { const { focusedInput, layout, endWrapper, startWrapper } = this; this.referenceEl = focusedInput === "end" || layout === "vertical" ? endWrapper || startWrapper : startWrapper || endWrapper; requestAnimationFrame(() => connectFloatingUI(this)); } onInputWrapperPointerDown() { this.currentOpenInput = this.focusedInput; } onInputWrapperClick(event) { const { range, endInputRef, startInputRef, currentOpenInput } = this; const currentTarget = event.currentTarget; const position = currentTarget.getAttribute("data-position"); const path = event.composedPath(); const wasToggleClicked = path.find((el) => el.classList?.contains(CSS.toggleIcon)); if (wasToggleClicked) { const targetInput = position === "start" ? startInputRef : endInputRef; targetInput.value.setFocus(); } if (!range || !this.open || currentOpenInput === position) { this.open = !this.open; } } setFilteredPlacements() { const { el, flipPlacements } = this; this.filteredFlipPlacements = flipPlacements ? filterValidFlipPlacements(flipPlacements, el) : null; } onLabelClick() { this.setFocus(); } onBeforeOpen() { this.calciteInputDatePickerBeforeOpen.emit(); this.topLayer.show(); } onOpen() { this.focusTrap.activate(); this.calciteInputDatePickerOpen.emit(); } onBeforeClose() { this.calciteInputDatePickerBeforeClose.emit(); } onClose() { this.calciteInputDatePickerClose.emit(); hideFloatingUI(this); this.focusTrap.deactivate(); this.focusOnOpen = false; this.datePickerEl?.reset(); this.topLayer.hide(); } syncHiddenFormInput(input) { syncHiddenFormInput("date", this, input); } blurHandler() { this.open = false; } commitValue() { const { focusedInput, value } = this; const focusedInputRef = this.getInputRef(focusedInput); const date = dateFromLocalizedString(focusedInputRef.value.value, this.localeData); const dateAsISO = dateToISO(date); const valueIsArray = Array.isArray(value); if (this.range) { const focusedInputValueIndex = focusedInput === "start" ? 0 : 1; if (valueIsArray) { if (dateAsISO === value[focusedInputValueIndex]) { return; } if (date) { this.setRangeValue([ focusedInput === "start" ? date : dateFromISO(value[0]), focusedInput === "end" ? date : dateFromISO(value[1]) ]); this.localizeInputValues(); } else { this.setRangeValue([ focusedInput === "end" && dateFromISO(value[0]), focusedInput === "start" && dateFromISO(value[1]) ]); } } else { if (date) { this.setRangeValue([ focusedInput === "start" ? date : dateFromISO(value[0]), focusedInput === "end" ? date : dateFromISO(value[1]) ]); this.localizeInputValues(); } } } else { if (dateAsISO === value) { return; } this.setValue(date); this.localizeInputValues(); } } keyDownHandler(event) { const { defaultPrevented, key } = event; if (defaultPrevented) { return; } const targetHasSelect = event.composedPath().some((el) => el.tagName === "CALCITE-SELECT"); if (key === "Enter") { event.preventDefault(); this.commitValue(); if (this.shouldFocusRangeEnd()) { this.endInputRef.value?.setFocus(); } else if (this.shouldFocusRangeStart()) { this.startInputRef.value?.setFocus(); } if (submitForm(this)) { this.restoreInputFocus(true); } } else if ((key === "ArrowDown" || key === "ArrowUp") && !targetHasSelect) { this.open = true; this.focusOnOpen = true; event.preventDefault(); } else if (this.open && key === "Escape") { this.open = false; event.preventDefault(); this.restoreInputFocus(true); } } startInputFocus() { this.focusedInput = "start"; } endInputFocus() { this.focusedInput = "end"; } setFloatingEl(el) { this.floatingEl = el; connectFloatingUI(this); } setStartWrapper(el) { this.startWrapper = el; this.setReferenceEl(); } setEndWrapper(el) { this.endWrapper = el; this.setReferenceEl(); } setDatePickerRef(el) { this.datePickerEl = el; if (el) { this.focusTrap.overrideFocusTrapEl(el); } } async loadLocaleData() { if (isServer) { return; } const locale = applyLocaleOverride(this.messages._lang); numberStringFormatter.numberFormatOptions = { numberingSystem: this.numberingSystem, locale, useGrouping: false }; this.localeData = await getLocaleData(locale); this.localizeInputValues(); } handleDateChange(event) { if (this.range) { return; } event.stopPropagation(); this.setValue(event.target.valueAsDate); this.localizeInputValues(); this.restoreInputFocus(); } shouldFocusRangeStart() { const startValue = this.value[0]; const endValue = this.value[1]; return !!(endValue && !startValue && this.focusedInput === "end" && this.startInputRef); } shouldFocusRangeEnd() { const startValue = this.value[0]; const endValue = this.value[1]; return !!(startValue && !endValue && this.focusedInput === "start" && this.endInputRef); } handleDateRangeChange(event) { if (!this.range) { return; } event.stopPropagation(); const value = event.target.valueAsDate; this.setRangeValue(value); this.localizeInputValues(); this.restoreInputFocus(); } restoreInputFocus(isDatePickerClosed = false) { if (!this.range) { this.startInputRef.value.setFocus(); this.open = false; return; } if (isDatePickerClosed) { this.focusInput(); return; } this.rangeStartValueChangedByUser = this.focusedInput === "start"; this.focusedInput = "end"; if (this.shouldFocusRangeStart() || this.rangeStartValueChangedByUser) { return; } if (this.proximitySelectionDisabled && this.valueAsDate[1] === null) { return; } this.open = false; this.focusInput(); } localizeInputValues() { const date = dateFromRange(this.range ? Array.isArray(this.valueAsDate) && this.valueAsDate[0] || void 0 : this.valueAsDate, this.minAsDate, this.maxAsDate); const endDate = this.range ? dateFromRange(Array.isArray(this.valueAsDate) && this.valueAsDate[1] || void 0, this.minAsDate, this.maxAsDate) : null; this.setInputValue((date && this.dateTimeFormat.format(date)) ?? "", "start"); this.setInputValue((this.range && endDate && this.dateTimeFormat.format(endDate)) ?? "", "end"); } getInputRef(input = "start") { return input === "start" ? this.startInputRef : this.endInputRef; } setInputValue(newValue, input = "start") { const inputRef = this.getInputRef(input); if (!inputRef.value) { return; } inputRef.value.value = newValue; } setRangeValue(valueAsDate) { if (!this.range) { return; } const { value: oldValue } = this; const oldValueIsArray = Array.isArray(oldValue); const valueIsArray = Array.isArray(valueAsDate); const newStartDate = valueIsArray ? valueAsDate[0] : null; let newStartDateISO = valueIsArray ? dateToISO(newStartDate) : ""; if (newStartDateISO) { newStartDateISO = this.getNormalizedDate(newStartDateISO); } const newEndDate = valueIsArray ? valueAsDate[1] : null; let newEndDateISO = valueIsArray ? dateToISO(newEndDate) : ""; if (newEndDateISO) { newEndDateISO = this.getNormalizedDate(newEndDateISO); } const newValue = newStartDateISO || newEndDateISO ? [newStartDateISO, newEndDateISO] : ""; if (newValue === oldValue) { return; } this.userChangedValue = true; this.value = newValue; this.valueAsDate = newValue ? getValueAsDateRange(newValue) : void 0; const changeEvent = this.calciteInputDatePickerChange.emit(); if (changeEvent && changeEvent.defaultPrevented) { this.value = oldValue; if (oldValueIsArray) { this.setInputValue(oldValue[0], "start"); this.setInputValue(oldValue[1], "end"); } else { this.value = oldValue; this.setInputValue(oldValue); } } } setValue(value) { if (this.range) { return; } const oldValue = this.value; let newValue = dateToISO(value); newValue = this.getNormalizedDate(newValue); if (newValue === oldValue) { return; } this.userChangedValue = true; this.valueAsDate = newValue ? dateFromISO(newValue) : void 0; this.value = newValue || ""; const changeEvent = this.calciteInputDatePickerChange.emit(); if (changeEvent.defaultPrevented) { this.value = oldValue; this.setInputValue(oldValue); } } warnAboutInvalidValue(value) { console.warn(`The specified value "${value}" does not conform to the required format, "YYYY-MM-DD".`); } formatNumerals(value) { return value ? value.split("").map((char) => this.commonDateSeparators?.includes(char) ? this.localeData?.separator : numberKeys?.includes(char) ? numberStringFormatter?.numberFormatter?.format(Number(char)) : char).join("") : ""; } parseNumerals(value) { return value ? value.split("").map((char) => numberKeys.includes(char) ? numberStringFormatter.delocalize(char) : char).join("") : ""; } getNormalizedDate(value) { if (!value) { return ""; } if (!isTwoDigitYear(value)) { return value; } const { day, month, year } = datePartsFromISO(value); const normalizedYear = normalizeToCurrentCentury(Number(year)); return `${normalizedYear}-${month}-${day}`; } focusInput() { const focusedInput = this.focusedInput === "start" ? this.startInputRef : this.endInputRef; focusedInput.value.setFocus(); } render() { const { disabled, messages: { _lang: effectiveLocale }, messages, numberingSystem, readOnly } = this; numberStringFormatter.numberFormatOptions = { numberingSystem, locale: effectiveLocale, useGrouping: false }; return this.interactiveContainer({ disabled: this.disabled, children: html`${this.labelText && InternalLabel({ labelText: this.labelText, onClick: this.onLabelClick, required: this.required, tooltipText: this.messages.required }) || ""}<div class=${safeClassMap(CSS.container)}><div aria-label=${getLabelText(this) ?? nothing} .ariaRequired=${this.required} class=${safeClassMap(CSS.inputContainer)} role=group><div class=${safeClassMap(CSS.inputWrapper)} data-position=${POSITION.start} @click=${this.onInputWrapperClick} @pointerdown=${this.onInputWrapperPointerDown} ${ref(this.setStartWrapper)}><calcite-input-text aria-controls=${this.dialogId ?? nothing} aria-describedby=${this.placeholderTextId ?? nothing} aria-errormessage=${IDS.validationMessage} aria-autocomplete=none .ariaExpanded=${this.open} aria-haspopup=dialog .ariaInvalid=${this.status === "invalid"} class=${safeClassMap({ [CSS.input]: true, [CSS.inputNoBottomBorder]: this.layout === "vertical" && this.range, [CSS.inputNoRightBorder]: this.range })} .disabled=${disabled} .icon=${ICONS.calendar} .label=${this.range ? this.messages.startDate : this.messages.date} @calciteInputTextInput=${this.calciteInternalInputInputHandler} @calciteInternalInputTextBlur=${this.calciteInternalInputBlurHandler} @calciteInternalInputTextFocus=${this.startInputFocus} .placeholder=${this.localeData?.placeholder} .readOnly=${readOnly} role=combobox .scale=${this.scale} .status=${this.status} ${ref(this.startInputRef)}></calcite-input-text>${!this.readOnly && !this.range && this.renderToggleIcon(this.open && this.focusedInput === "start") || ""}<span aria-hidden=true class=${safeClassMap(CSS.assistiveText)} id=${this.placeholderTextId ?? nothing}>${messages.dateFormat.replace("{format}", this.localeData?.placeholder)}</span></div><div .ariaHidden=${!this.open} .ariaLabel=${messages.chooseDate} aria-live=polite class=${safeClassMap(CSS.menu)} id=${this.dialogId ?? nothing} popover=manual role=dialog ${ref(this.setFloatingEl)}><div class=${safeClassMap({ [CSS.calendarWrapper]: true, [FloatingCSS.animation]: true, [FloatingCSS.animationActive]: this.open })} ${ref(this.transitionRef)}><calcite-date-picker .activeDate=${this.datePickerActiveDate} .activeRange=${this.focusedInput} .calendars=${this.calendars} .headingLevel=${this.headingLevel} .layout=${this.layout} .max=${this.max} .maxAsDate=${this.maxAsDate} .messageOverrides=${this.messageOverrides} .min=${this.min} .minAsDate=${this.minAsDate} .monthStyle=${this.monthStyle} .numberingSystem=${numberingSystem} @calciteDatePickerChange=${this.handleDateChange} @calciteDatePickerRangeChange=${this.handleDateRangeChange} .proximitySelectionDisabled=${this.proximitySelectionDisabled} .range=${this.range} .scale=${this.scale} tabindex=${(this.open ? void 0 : -1) ?? nothing} .valueAsDate=${this.valueAsDate} ${ref(this.setDatePickerRef)}></calcite-date-picker></div></div>${this.range && html`<div class=${safeClassMap(CSS.dividerContainer)}><div class=${safeClassMap(CSS.divider)}></div></div>` || ""}${this.range && html`<div class=${safeClassMap(CSS.inputWrapper)} data-position=${POSITION.end} @click=${this.onInputWrapperClick} @pointerdown=${this.onInputWrapperPointerDown} ${ref(this.setEndWrapper)}><calcite-input-text aria-controls=${this.dialogId ?? nothing} aria-autocomplete=none .ariaExpanded=${this.open} aria-haspopup=dialog class=${safeClassMap({ [CSS.input]: true, [CSS.inputNoTopBorder]: this.layout === "vertical" && this.range, [CSS.inputNoLeftBorder]: this.layout === "horizontal" && this.range, [CSS.inputNoRightBorder]: this.layout === "vertical" && this.range })} .disabled=${disabled} .icon=${ICONS.calendar} .label=${this.messages.endDate} @calciteInputTextInput=${this.calciteInternalInputInputHandler} @calciteInternalInputTextBlur=${this.calciteInternalInputBlurHandler} @calciteInternalInputTextFocus=${this.endInputFocus} .placeholder=${this.localeData?.placeholder} .readOnly=${readOnly} role=combobox .scale=${this.scale} .status=${this.status} ${ref(this.endInputRef)}></calcite-input-text>${!this.readOnly && this.layout === "horizontal" && this.renderToggleIcon(this.open) || ""}</div>` || ""}</div>${this.range && this.layout === "vertical" && html`<div class=${safeClassMap(CSS.verticalChevronContainer)}><calcite-icon .icon=${this.open ? ICONS.chevronUp : ICONS.chevronDown} .scale=${getIconScale(this.scale)}></calcite-icon></div>` || ""}</div>${HiddenFormInputSlot({ component: this })}${this.validationMessage && this.status === "invalid" ? Validation({ icon: this.validationIcon, id: IDS.validationMessage, message: this.validationMessage, scale: this.scale, status: this.status }) : null}` }); } renderToggleIcon(open) { return html`<span class=${safeClassMap(CSS.toggleIcon)} tabindex=-1><calcite-icon class=${safeClassMap(CSS.chevronIcon)} .icon=${open ? ICONS.chevronUp : ICONS.chevronDown} .scale=${getIconScale(this.scale)}></calcite-icon></span>`; } } customElement("calcite-input-date-picker", InputDatePicker); export { InputDatePicker };