import { Component, Host, Prop, Element, h, Event, State, Listen, Method, Watch, } from '@stencil/core';
import { addDays, startOfWeek, endOfWeek, setMonth, setYear, clamp, inRange, endOfMonth, startOfMonth, printISODate, parseISODate, DaysOfWeek, createDate, } from './date-utils';
import { DatePickerInput } from './date-picker-input';
import { DatePickerMonth } from './date-picker-month';
import defaultLocalization from './date-localization';
import isoAdapter from './date-adapter';
import range from '../../utils/range';
import uniqueId from '../../utils/uniqueId';
import stringCombiner from '../../utils/stringCombiner';
import { chevronDown, chevronLeft, chevronRight, close } from '@teliads/icons';
import breakpoints from '../../../../foundations-old/breakpoints/variables';
const keyCode = {
  TAB: 9,
  ESC: 27,
  SPACE: 32,
  PAGE_UP: 33,
  PAGE_DOWN: 34,
  END: 35,
  HOME: 36,
  LEFT: 37,
  UP: 38,
  RIGHT: 39,
  DOWN: 40,
};
function cleanValue(input, regex) {
  const value = input.value;
  const cursor = input.selectionStart;
  const beforeCursor = value.slice(0, cursor);
  const afterCursor = value.slice(cursor, value.length);
  const filteredBeforeCursor = beforeCursor.replace(regex, '');
  const filterAfterCursor = afterCursor.replace(regex, '');
  const newValue = filteredBeforeCursor + filterAfterCursor;
  const newCursor = filteredBeforeCursor.length;
  input.value = newValue;
  input.selectionStart = input.selectionEnd = newCursor;
  return newValue;
}
const DISALLOWED_CHARACTERS = /[^0-9\.\/\-]+/g;
const TRANSITION_MS = 300;
export class TeliaDatePicker {
  constructor() {
    /**
     * Own Properties
     */
    this.monthSelectId = uniqueId('dateMonth');
    this.yearSelectId = uniqueId('dateYear');
    this.dialogLabelId = uniqueId('dateLabel');
    this.body = document.body;
    this.initialTouchX = null;
    this.initialTouchY = null;
    /** Tracking id is used to identify and count Component usage */
    this.dataTrackingId = 'telia-date-picker';
    /** Name of the date picker input. */
    this.name = 'date';
    /** Additional description id */
    this.additionalId = uniqueId('additional');
    /** Input element id */
    this.inputId = uniqueId('input');
    /** Makes the date picker input component disabled. This prevents users from being able to interact with the input, and conveys its inactive state to assistive technologies. */
    this.disabled = false;
    /**
     * Forces the opening direction of the calendar modal to be always left or right.
     * This setting can be useful when the input is smaller than the opening date picker
     * would be as by default the picker always opens towards right.
     */
    this.direction = 'right';
    /** Enable readonly state */
    this.readonly = false;
    /** Should the input be marked as required? */
    this.required = false;
    /** Date value. Must be in IS0-8601 format: YYYY-MM-DD. */
    this.value = '';
    /** Minimum date allowed to be picked. Must be in IS0-8601 format: YYYY-MM-DD. This setting can be used alone or together with the max property. */
    this.min = '';
    /** Maximum date allowed to be picked. Must be in IS0-8601 format: YYYY-MM-DD. This setting can be used alone or together with the min property. */
    this.max = '';
    /** Year range specifies the range of the years to be displayed in past and future, default value is 10 years */
    this.yearRange = { past: 10, future: 10 };
    /** Which day is considered first day of the week? `0` for Sunday, `1` for Monday, etc. Default is Monday. */
    this.firstDayOfWeek = DaysOfWeek.Monday;
    /** Button labels, day names, month names, etc, used for localization. Default is English. */
    this.localization = defaultLocalization;
    /**
     * Date adapter, for custom parsing/formatting.
     * Must be object with a `parse` function which accepts a `string` and returns a `Date`,
     * and a `format` function which accepts a `Date` and returns a `string`.
     * Default is IS0-8601 parsing and formatting.
     */
    this.dateAdapter = isoAdapter;
    /** Indicates if the modal is open */
    this.modalOpen = false;
    /** Controls which days are disabled and therefore disallowed. For example, this can be used to disallow selection of weekends. */
    this.isDateDisabled = () => false;
    /** Error description id */
    this.errorId = uniqueId('error');
    this.activeFocus = false;
    this.focusedDay = new Date();
    this.open = this.modalOpen;
    /** Error message */
    this.errorMessageState = '';
    /** Input has been blurred at least once */
    this.touched = false;
    /**
     * Local methods.
     */
    // TODO: remove this & style body in css once Firefox supports :has() selector
    this.toggleSmallScreenScroll = () => {
      if (this.body.style.overflowY === 'hidden') {
        this.body.style.overflowY = '';
        return;
      }
      const { matches: isSmallScreen } = window.matchMedia(`(max-width: ${breakpoints.breakpointMd})`);
      if (isSmallScreen) {
        this.body.style.overflowY = 'hidden';
      }
    };
    this.enableActiveFocus = () => {
      this.activeFocus = true;
    };
    this.disableActiveFocus = () => {
      this.activeFocus = false;
    };
    this.toggleOpen = (e) => {
      e.preventDefault();
      this.open ? this.hide(false) : this.show();
    };
    this.handleEscKey = (event) => {
      if (event.keyCode === keyCode.ESC) {
        this.hide();
      }
    };
    this.handleBlur = (event) => {
      event.stopPropagation();
      this.updateErrorState();
      this.vocaBlur.emit({
        component: 'telia-date-picker',
      });
    };
    this.handleFocus = (event) => {
      event.stopPropagation();
      this.vocaFocus.emit({
        component: 'telia-date-picker',
      });
    };
    this.handleTouchStart = (event) => {
      const touch = event.changedTouches[0];
      this.initialTouchX = touch.pageX;
      this.initialTouchY = touch.pageY;
    };
    this.handleTouchEnd = (event) => {
      const touch = event.changedTouches[0];
      const distX = touch.pageX - this.initialTouchX; // get horizontal dist traveled
      const distY = touch.pageY - this.initialTouchY; // get vertical dist traveled
      const threshold = 70;
      const isHorizontalSwipe = Math.abs(distX) >= threshold && Math.abs(distY) <= threshold;
      const isDownwardsSwipe = Math.abs(distY) >= threshold && Math.abs(distX) <= threshold && distY > 0;
      if (isHorizontalSwipe) {
        this.addMonths(distX < 0 ? 1 : -1);
      }
      else if (isDownwardsSwipe) {
        this.hide(false);
        event.preventDefault();
      }
      this.initialTouchY = null;
      this.initialTouchX = null;
    };
    this.handleNextMonthClick = (event) => {
      event.preventDefault();
      this.addMonths(1);
    };
    this.handlePreviousMonthClick = (event) => {
      event.preventDefault();
      this.addMonths(-1);
    };
    this.handleFirstFocusableKeydown = (event) => {
      // this ensures focus is trapped inside the dialog
      if (event.keyCode === keyCode.TAB && event.shiftKey) {
        this.focusedDayNode.focus();
        event.preventDefault();
      }
    };
    this.handleCloseButtonClick = () => {
      this.hide();
    };
    this.handleKeyboardNavigation = (event) => {
      // handle tab separately, since it needs to be treated
      // differently to other keyboard interactions
      if (event.keyCode === keyCode.TAB && !event.shiftKey) {
        event.preventDefault();
        // TODO: querySelector as a workaround to focus native button inside telia-button, until telia-button doesn't handle that itself
        this.firstFocusableElement.querySelector('button').focus();
        return;
      }
      var handled = true;
      switch (event.keyCode) {
        case keyCode.RIGHT:
          this.addDays(1);
          break;
        case keyCode.LEFT:
          this.addDays(-1);
          break;
        case keyCode.DOWN:
          this.addDays(7);
          break;
        case keyCode.UP:
          this.addDays(-7);
          break;
        case keyCode.PAGE_UP:
          if (event.shiftKey) {
            this.addYears(-1);
          }
          else {
            this.addMonths(-1);
          }
          break;
        case keyCode.PAGE_DOWN:
          if (event.shiftKey) {
            this.addYears(1);
          }
          else {
            this.addMonths(1);
          }
          break;
        case keyCode.HOME:
          this.startOfWeek();
          break;
        case keyCode.END:
          this.endOfWeek();
          break;
        default:
          handled = false;
      }
      if (handled) {
        event.preventDefault();
        this.enableActiveFocus();
      }
    };
    this.handleDaySelect = (_event, day) => {
      const isInRange = inRange(day, parseISODate(this.min), parseISODate(this.max));
      const isAllowed = !this.isDateDisabled(day);
      if (isInRange && isAllowed) {
        this.setValue(day);
        this.updateErrorMessage('');
        this.hide();
      }
      else {
        // for consistency we should set the focused day in cases where
        // user has selected a day that has been specifically disallowed
        this.setFocusedDay(day);
      }
    };
    this.handleMonthSelect = (e) => {
      e.stopPropagation();
      this.setMonth(parseInt(e.target.value, 10));
    };
    this.handleYearSelect = (e) => {
      e.stopPropagation();
      this.setYear(parseInt(e.target.value, 10));
    };
    this.handleInputChange = () => {
      const target = this.datePickerInput;
      // clean up any invalid characters
      cleanValue(target, DISALLOWED_CHARACTERS);
      const parsed = this.dateAdapter.parse(target.value, createDate);
      if (parsed || target.value === '') {
        this.setValue(parsed);
      }
    };
    this.processFocusedDayNode = (element) => {
      this.focusedDayNode = element;
      if (this.activeFocus && this.open) {
        setTimeout(() => element.focus(), 0);
      }
    };
    /**
     * Helper for updating touched state, so we can update touched
     * state from functional component.
     */
    this.makeTouched = () => {
      this.touched = true;
    };
    /**
     * Return true if input value is following date input format.
     */
    this.isValueValid = () => {
      const inputValue = this.datePickerInput.value;
      /*
       * We expect dateAdapter.parse to return undefined, if input value
       * is not valid. This way there is no need to separate regexp.
       */
      const parsedDate = this.dateAdapter.parse(inputValue, createDate);
      if (parsedDate === undefined)
        return false;
      const isInRange = inRange(parsedDate, parseISODate(this.min), parseISODate(this.max));
      if (!isInRange)
        return false;
      const isDisabled = this.isDateDisabled(parsedDate);
      return !isDisabled;
    };
    /**
     * Update error message and keep native input error message in sync.
     */
    this.updateErrorMessage = (message) => {
      var _a, _b;
      (_b = (_a = this.datePickerInput) === null || _a === void 0 ? void 0 : _a.setCustomValidity) === null || _b === void 0 ? void 0 : _b.call(_a, message);
      this.errorMessageState = message;
    };
    /**
     * Check if input value is empty, so required should be triggered.
     */
    this.isValueMissing = () => {
      var _a;
      return ((_a = this.datePickerInput) === null || _a === void 0 ? void 0 : _a.value.length) === 0;
    };
    this.updateErrorState = () => {
      var _a, _b, _c;
      const errorMessageIsSet = !!((_a = this.errorMessageState) === null || _a === void 0 ? void 0 : _a.length);
      const requiredInUse = this.required;
      const generalErrorInUse = !!((_b = this.errorMessage) === null || _b === void 0 ? void 0 : _b.length);
      const invalidErrorInUse = !!((_c = this.invalidErrorMessage) === null || _c === void 0 ? void 0 : _c.length);
      // eslint-disable-next-line @stencil/strict-boolean-conditions
      const isInputRefSet = !!this.datePickerInput;
      if (generalErrorInUse) {
        this.updateErrorMessage(this.errorMessage);
        this.makeTouched();
        // General error message overrides other errors, so exit here.
        return;
      }
      if (invalidErrorInUse) {
        if (isInputRefSet && !this.isValueValid()) {
          this.updateErrorMessage(this.invalidErrorMessage);
        }
      }
      if (requiredInUse) {
        if (this.touched &&
          !!this.requiredErrorMessage &&
          this.isValueMissing()) {
          this.updateErrorMessage(this.requiredErrorMessage);
        }
      }
      // Clean error message if needed
      if (errorMessageIsSet) {
        if (generalErrorInUse)
          return;
        if (invalidErrorInUse && !this.isValueValid())
          return;
        this.updateErrorMessage('');
      }
    };
    this.setToggleRef = (element) => {
      this.datePickerButton = element;
    };
    this.setTextInputRef = (element) => {
      this.datePickerInput = element;
    };
    this.setDialogWrapperRef = (element) => {
      this.dialogWrapperNode = element;
    };
    this.setCloseButtonRef = (element) => {
      this.firstFocusableElement = element;
    };
    this.setMonthSelectRef = (element) => {
      this.monthSelectNode = element;
    };
  }
  connectedCallback() {
    this.createDateFormatters();
  }
  componentWillLoad() {
    this.updateErrorState();
    this.yearRangeChanged(this.yearRange);
  }
  componentDidRender() {
    var _a, _b;
    (_b = (_a = this.datePickerInput) === null || _a === void 0 ? void 0 : _a.setCustomValidity) === null || _b === void 0 ? void 0 : _b.call(_a, this.errorMessageState);
  }
  yearRangeChanged(newValue) {
    let value = typeof newValue === 'string' ? JSON.parse(newValue) : newValue;
    // Convert fractional numbers and minus values
    Object.keys(value).map(key => {
      value[key] = parseInt(value[key]);
      value[key] = value[key] < 0 ? (value[key] = 0) : value[key];
    });
    this.range = value;
  }
  createDateFormatters() {
    this.dateFormatShort = new Intl.DateTimeFormat(this.localization.locale, {
      day: 'numeric',
      month: 'long',
    });
    this.dateFormatLong = new Intl.DateTimeFormat(this.localization.locale, {
      day: 'numeric',
      month: 'long',
      year: 'numeric',
    });
  }
  /**
   * Component event handling.
   */
  handleDocumentClick(e) {
    if (!this.open) {
      return;
    }
    // the dialog and the button aren't considered clicks outside.
    // dialog for obvious reasons, but the button needs to be skipped
    // so that two things are possible:
    //
    // a) clicking again on the button when dialog is open should close the modal.
    //    without skipping the button here, we would see a click outside
    //    _and_ a click on the button, so the `open` state goes
    //    open -> close (click outside) -> open (click button)
    //
    // b) clicking another date picker's button should close the current calendar
    //    and open the new one. this means we can't stopPropagation() on the button itself
    //
    // this was the only satisfactory combination of things to get the above to work
    const isClickOutside = e
      .composedPath()
      .every(node => node !== this.dialogWrapperNode && node !== this.datePickerButton);
    if (isClickOutside) {
      this.hide(false);
    }
  }
  /**
   * Public methods API
   */
  /**
   * Sets focus on the date picker's input. Use this method instead of the global `focus()`.
   */
  async setFocus() {
    return this.datePickerInput.focus();
  }
  /**
   * Show the calendar modal, moving focus to the calendar inside.
   */
  async show() {
    this.open = true;
    this.modalOpen = true;
    this.setFocusedDay(parseISODate(this.value) || new Date());
    this.toggleSmallScreenScroll();
    clearTimeout(this.focusTimeoutId);
    this.focusTimeoutId = setTimeout(() => this.monthSelectNode.focus(), TRANSITION_MS);
  }
  /**
   * Hide the calendar modal. Set `moveFocusToButton` to false to prevent focus
   * returning to the date picker's button. Default is true.
   */
  async hide(moveFocusToButton = true) {
    this.open = false;
    this.modalOpen = false;
    this.toggleSmallScreenScroll();
    // in cases where calendar is quickly shown and hidden
    // we should avoid moving focus to the button
    clearTimeout(this.focusTimeoutId);
    if (moveFocusToButton) {
      // iOS VoiceOver needs to wait for all transitions to finish.
      setTimeout(
      // TODO: querySelector as a workaround to focus native button inside telia-button, until telia-button doesn't handle that itself
      () => this.datePickerButton.querySelector('button').focus(), TRANSITION_MS + 200);
    }
  }
  addDays(days) {
    this.setFocusedDay(addDays(this.focusedDay, days));
  }
  addMonths(months) {
    this.setMonth(this.focusedDay.getMonth() + months);
  }
  addYears(years) {
    this.setYear(this.focusedDay.getFullYear() + years);
  }
  startOfWeek() {
    this.setFocusedDay(startOfWeek(this.focusedDay, this.firstDayOfWeek));
  }
  endOfWeek() {
    this.setFocusedDay(endOfWeek(this.focusedDay, this.firstDayOfWeek));
  }
  setMonth(month) {
    const min = setMonth(startOfMonth(this.focusedDay), month);
    const max = endOfMonth(min);
    const date = setMonth(this.focusedDay, month);
    this.setFocusedDay(clamp(date, min, max));
  }
  setYear(year) {
    const min = setYear(startOfMonth(this.focusedDay), year);
    const max = endOfMonth(min);
    const date = setYear(this.focusedDay, year);
    this.setFocusedDay(clamp(date, min, max));
  }
  setFocusedDay(day) {
    this.focusedDay = clamp(day, parseISODate(this.min), parseISODate(this.max));
  }
  setValue(date) {
    this.value = printISODate(date);
    this.vocaChange.emit({
      component: 'telia-date-picker',
      value: this.value,
      valueAsDate: date,
    });
  }
  /**
   * render() function
   * Always the last one in the class.
   */
  render() {
    var _a;
    const showAdditional = !!this.additional;
    const showError = !!((_a = this.errorMessageState) === null || _a === void 0 ? void 0 : _a.length);
    const describedBy = stringCombiner({
      [this.additionalId]: showAdditional,
      [this.errorId]: showError,
    });
    const valueAsDate = parseISODate(this.value);
    const formattedDate = valueAsDate && this.dateAdapter.format(valueAsDate);
    const selectedYear = (valueAsDate || this.focusedDay).getFullYear();
    const focusedMonth = this.focusedDay.getMonth();
    const focusedYear = this.focusedDay.getFullYear();
    const minDate = parseISODate(this.min);
    const maxDate = parseISODate(this.max);
    const prevMonthDisabled = minDate !== undefined &&
      minDate.getMonth() === focusedMonth &&
      minDate.getFullYear() === focusedYear;
    const nextMonthDisabled = maxDate !== undefined &&
      maxDate.getMonth() === focusedMonth &&
      maxDate.getFullYear() === focusedYear;
    const minYear = minDate !== undefined
      ? minDate.getFullYear()
      : selectedYear - this.range.past;
    const maxYear = maxDate !== undefined
      ? maxDate.getFullYear()
      : selectedYear + this.range.future;
    return (h(Host, null,
      h("telia-vst", { dataTrackingId: this.dataTrackingId }),
      h("div", { class: "telia-date-picker" },
        h(DatePickerInput, { dateFormatter: this.dateFormatLong, describedBy: describedBy, value: this.value, valueAsDate: valueAsDate, formattedValue: formattedDate, onInput: this.handleInputChange, onBlur: this.handleBlur, onFocus: this.handleFocus, onClick: this.toggleOpen, name: this.name, disabled: this.disabled, readonly: this.readonly, role: this.role, required: this.required, identifier: this.inputId, localization: this.localization, buttonLabel: this.buttonLabel, buttonRef: this.setToggleRef, inputRef: this.setTextInputRef, touched: this.touched, makeTouched: this.makeTouched, htmlForm: this.htmlForm }),
        h("telia-label", { class: "telia-date-picker__label", htmlFor: this.inputId },
          this.required && h("span", { "aria-hidden": "true" }, '* '),
          this.label),
        showAdditional && (h("telia-field-assistive-text", { class: "telia-date-picker__additional", id: this.additionalId }, this.additional)),
        showError && (h("telia-field-error", { class: "telia-date-picker__error", id: this.errorId }, this.errorMessageState)),
        h("div", { class: "telia-date-picker__dialog-container" },
          h("div", { class: {
              'telia-date-picker__dialog': true,
              'is-left': this.direction === 'left',
              'is-active': this.open,
            }, role: "dialog", "aria-modal": "true", "aria-hidden": this.open ? 'false' : 'true', "aria-labelledby": this.dialogLabelId, onTouchStart: this.handleTouchStart, onTouchEnd: this.handleTouchEnd },
            h("div", { class: "telia-date-picker__dialog-content", onKeyDown: this.handleEscKey, ref: this.setDialogWrapperRef },
              h("div", { class: "telia-date-picker__mobile", onFocusin: this.disableActiveFocus },
                h("telia-heading", { tag: "h2", class: "telia-date-picker__mobile-heading", variant: "subsection-100" }, this.localization.calendarHeading),
                h("telia-button", { class: "telia-date-picker__close", ref: this.setCloseButtonRef, onKeyDown: this.handleFirstFocusableKeydown, onClick: this.handleCloseButtonClick, size: "sm", variant: "text", type: "button", allyLabel: this.localization.closeLabel },
                  h("telia-icon", { class: "telia-date-picker__close-icon", svg: close.svg, size: "sm" }))),
              h("div", { class: "telia-date-picker__header", onFocusin: this.disableActiveFocus },
                h("div", null,
                  h("h2", { id: this.dialogLabelId, class: "telia-date-picker__vhidden", "aria-live": "polite", "aria-atomic": "true" },
                    this.localization.monthNames[focusedMonth],
                    ' ',
                    this.focusedDay.getFullYear()),
                  h("label", { htmlFor: this.monthSelectId, class: "telia-date-picker__vhidden" }, this.localization.monthSelectLabel),
                  h("div", { class: "telia-date-picker__select" },
                    h("select", { id: this.monthSelectId, class: "telia-date-picker__select--month", ref: this.setMonthSelectRef, onChange: this.handleMonthSelect, onInput: e => {
                        e.stopPropagation();
                      } }, this.localization.monthNames.map((month, i) => (h("option", { key: month, value: i, selected: i === focusedMonth, disabled: !inRange(new Date(focusedYear, i, 1), minDate !== undefined
                        ? startOfMonth(minDate)
                        : null, maxDate !== undefined
                        ? endOfMonth(maxDate)
                        : null) }, month)))),
                    h("div", { class: "telia-date-picker__select-label", "aria-hidden": "true" },
                      h("span", null, this.localization.monthNamesShort[focusedMonth]),
                      h("telia-icon", { class: "telia-date-picker__select-icon", svg: chevronDown.svg, size: "sm" }))),
                  h("label", { htmlFor: this.yearSelectId, class: "telia-date-picker__vhidden" }, this.localization.yearSelectLabel),
                  h("div", { class: "telia-date-picker__select" },
                    h("select", { id: this.yearSelectId, class: "telia-date-picker__select--year", onChange: this.handleYearSelect, onInput: e => {
                        e.stopPropagation();
                      } }, range(minYear, maxYear).map(year => (h("option", { key: year, selected: year === focusedYear }, year)))),
                    h("div", { class: "telia-date-picker__select-label", "aria-hidden": "true" },
                      h("span", null, this.focusedDay.getFullYear()),
                      h("telia-icon", { class: "telia-date-picker__select-icon", svg: chevronDown.svg, size: "sm" })))),
                h("div", { class: "telia-date-picker__nav" },
                  h("button", { class: "telia-date-picker__prev", onClick: this.handlePreviousMonthClick, disabled: prevMonthDisabled, type: "button", "aria-label": this.localization.prevMonthLabel },
                    h("telia-icon", { class: "telia-date-picker__prev-icon", svg: chevronLeft.svg, size: "sm" })),
                  h("button", { class: "telia-date-picker__next", onClick: this.handleNextMonthClick, disabled: nextMonthDisabled, type: "button", "aria-label": this.localization.nextMonthLabel },
                    h("telia-icon", { class: "telia-date-picker__next-icon", svg: chevronRight.svg, size: "sm" })))),
              h(DatePickerMonth, { dateFormatter: this.dateFormatShort, selectedDate: valueAsDate, focusedDate: this.focusedDay, onDateSelect: this.handleDaySelect, onKeyboardNavigation: this.handleKeyboardNavigation, labelledById: this.dialogLabelId, localization: this.localization, firstDayOfWeek: this.firstDayOfWeek, focusedDayRef: this.processFocusedDayNode, min: minDate, max: maxDate, isDateDisabled: this.isDateDisabled })))))));
  }
  static get is() { return "telia-date-picker"; }
  static get originalStyleUrls() { return {
    "$": ["telia-date-picker.scss"]
  }; }
  static get styleUrls() { return {
    "$": ["telia-date-picker.css"]
  }; }
  static get properties() { return {
    "dataTestid": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Test id set for web component host"
      },
      "attribute": "data-testid",
      "reflect": false
    },
    "htmlForm": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "ID of the form this component belongs to. Should only be set If the component is not wrapped inside its form element."
      },
      "attribute": "html-form",
      "reflect": false
    },
    "name": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Name of the date picker input."
      },
      "attribute": "name",
      "reflect": false,
      "defaultValue": "'date'"
    },
    "label": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Label of input"
      },
      "attribute": "label",
      "reflect": false
    },
    "additional": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": true,
      "docs": {
        "tags": [],
        "text": "Additional description. Describe here input format."
      },
      "attribute": "additional",
      "reflect": false
    },
    "additionalId": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Additional description id"
      },
      "attribute": "additional-id",
      "reflect": false,
      "defaultValue": "uniqueId('additional')"
    },
    "inputId": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Input element id"
      },
      "attribute": "input-id",
      "reflect": false,
      "defaultValue": "uniqueId('input')"
    },
    "disabled": {
      "type": "boolean",
      "mutable": false,
      "complexType": {
        "original": "boolean",
        "resolved": "boolean",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Makes the date picker input component disabled. This prevents users from being able to interact with the input, and conveys its inactive state to assistive technologies."
      },
      "attribute": "disabled",
      "reflect": true,
      "defaultValue": "false"
    },
    "role": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Defines a specific role attribute for the date picker input."
      },
      "attribute": "role",
      "reflect": false
    },
    "buttonLabel": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Button aria-label for assistive technologies"
      },
      "attribute": "button-label",
      "reflect": false
    },
    "direction": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "DatePickerDirectionsType",
        "resolved": "\"left\" | \"right\"",
        "references": {
          "DatePickerDirectionsType": {
            "location": "import",
            "path": "../../types/DatePickerDirection"
          }
        }
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Forces the opening direction of the calendar modal to be always left or right.\nThis setting can be useful when the input is smaller than the opening date picker\nwould be as by default the picker always opens towards right."
      },
      "attribute": "direction",
      "reflect": false,
      "defaultValue": "'right'"
    },
    "readonly": {
      "type": "boolean",
      "mutable": false,
      "complexType": {
        "original": "boolean",
        "resolved": "boolean",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Enable readonly state"
      },
      "attribute": "readonly",
      "reflect": false,
      "defaultValue": "false"
    },
    "required": {
      "type": "boolean",
      "mutable": false,
      "complexType": {
        "original": "boolean",
        "resolved": "boolean",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Should the input be marked as required?"
      },
      "attribute": "required",
      "reflect": false,
      "defaultValue": "false"
    },
    "value": {
      "type": "string",
      "mutable": true,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Date value. Must be in IS0-8601 format: YYYY-MM-DD."
      },
      "attribute": "value",
      "reflect": true,
      "defaultValue": "''"
    },
    "min": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Minimum date allowed to be picked. Must be in IS0-8601 format: YYYY-MM-DD. This setting can be used alone or together with the max property."
      },
      "attribute": "min",
      "reflect": false,
      "defaultValue": "''"
    },
    "max": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Maximum date allowed to be picked. Must be in IS0-8601 format: YYYY-MM-DD. This setting can be used alone or together with the min property."
      },
      "attribute": "max",
      "reflect": false,
      "defaultValue": "''"
    },
    "yearRange": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "TeliaYearRange | string",
        "resolved": "string | { past: number; future: number; }",
        "references": {
          "TeliaYearRange": {
            "location": "local"
          }
        }
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Year range specifies the range of the years to be displayed in past and future, default value is 10 years"
      },
      "attribute": "year-range",
      "reflect": false,
      "defaultValue": "{ past: 10, future: 10 }"
    },
    "firstDayOfWeek": {
      "type": "number",
      "mutable": false,
      "complexType": {
        "original": "DaysOfWeek",
        "resolved": "DaysOfWeek.Friday | DaysOfWeek.Monday | DaysOfWeek.Saturday | DaysOfWeek.Sunday | DaysOfWeek.Thursday | DaysOfWeek.Tuesday | DaysOfWeek.Wednesday",
        "references": {
          "DaysOfWeek": {
            "location": "import",
            "path": "./date-utils"
          }
        }
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Which day is considered first day of the week? `0` for Sunday, `1` for Monday, etc. Default is Monday."
      },
      "attribute": "first-day-of-week",
      "reflect": false,
      "defaultValue": "DaysOfWeek.Monday"
    },
    "localization": {
      "type": "unknown",
      "mutable": false,
      "complexType": {
        "original": "TeliaLocalizedText",
        "resolved": "{ buttonLabel: string; placeholder: string; selectedDateMessage: string; prevMonthLabel: string; nextMonthLabel: string; monthSelectLabel: string; yearSelectLabel: string; closeLabel: string; calendarHeading: string; dayNames: DayNames; monthNames: MonthsNames; monthNamesShort: MonthsNames; locale: string | string[]; }",
        "references": {
          "TeliaLocalizedText": {
            "location": "import",
            "path": "./date-localization"
          }
        }
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Button labels, day names, month names, etc, used for localization. Default is English."
      },
      "defaultValue": "defaultLocalization"
    },
    "dateAdapter": {
      "type": "unknown",
      "mutable": false,
      "complexType": {
        "original": "TeliaDateAdapter",
        "resolved": "TeliaDateAdapter",
        "references": {
          "TeliaDateAdapter": {
            "location": "import",
            "path": "./date-adapter"
          }
        }
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Date adapter, for custom parsing/formatting.\nMust be object with a `parse` function which accepts a `string` and returns a `Date`,\nand a `format` function which accepts a `Date` and returns a `string`.\nDefault is IS0-8601 parsing and formatting."
      },
      "defaultValue": "isoAdapter"
    },
    "modalOpen": {
      "type": "boolean",
      "mutable": true,
      "complexType": {
        "original": "boolean",
        "resolved": "boolean",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Indicates if the modal is open"
      },
      "attribute": "modal-open",
      "reflect": true,
      "defaultValue": "false"
    },
    "isDateDisabled": {
      "type": "unknown",
      "mutable": false,
      "complexType": {
        "original": "DateDisabledPredicate",
        "resolved": "(date: Date) => boolean",
        "references": {
          "DateDisabledPredicate": {
            "location": "local"
          }
        }
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Controls which days are disabled and therefore disallowed. For example, this can be used to disallow selection of weekends."
      },
      "defaultValue": "() => false"
    },
    "errorId": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Error description id"
      },
      "attribute": "error-id",
      "reflect": false,
      "defaultValue": "uniqueId('error')"
    },
    "errorMessage": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": true,
      "docs": {
        "tags": [],
        "text": "General error message, which overrides other error messages and is shown at initial render"
      },
      "attribute": "error-message",
      "reflect": false
    },
    "invalidErrorMessage": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": true,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Error message to be shown if user writes invalid date"
      },
      "attribute": "invalid-error-message",
      "reflect": false
    },
    "requiredErrorMessage": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": true,
      "docs": {
        "tags": [],
        "text": "Error message for required"
      },
      "attribute": "required-error-message",
      "reflect": false
    }
  }; }
  static get states() { return {
    "activeFocus": {},
    "focusedDay": {},
    "open": {},
    "errorMessageState": {},
    "touched": {}
  }; }
  static get events() { return [{
      "method": "vocaChange",
      "name": "vocaChange",
      "bubbles": true,
      "cancelable": true,
      "composed": true,
      "docs": {
        "tags": [],
        "text": "Event emitted when a valid date is selected or written."
      },
      "complexType": {
        "original": "VocaDatePickerChangeEvent",
        "resolved": "{ component: \"telia-date-picker\"; valueAsDate: Date; value: string; }",
        "references": {
          "VocaDatePickerChangeEvent": {
            "location": "local"
          }
        }
      }
    }, {
      "method": "vocaBlur",
      "name": "vocaBlur",
      "bubbles": true,
      "cancelable": true,
      "composed": true,
      "docs": {
        "tags": [],
        "text": "Event emitted the date picker input is blurred."
      },
      "complexType": {
        "original": "VocaDatePickerBlurEvent",
        "resolved": "{ component: \"telia-date-picker\"; }",
        "references": {
          "VocaDatePickerBlurEvent": {
            "location": "local"
          }
        }
      }
    }, {
      "method": "vocaFocus",
      "name": "vocaFocus",
      "bubbles": true,
      "cancelable": true,
      "composed": true,
      "docs": {
        "tags": [],
        "text": "Event emitted the date picker input is focused."
      },
      "complexType": {
        "original": "VocaDatePickerFocusEvent",
        "resolved": "{ component: \"telia-date-picker\"; }",
        "references": {
          "VocaDatePickerFocusEvent": {
            "location": "local"
          }
        }
      }
    }]; }
  static get methods() { return {
    "setFocus": {
      "complexType": {
        "signature": "() => Promise<void>",
        "parameters": [],
        "references": {
          "Promise": {
            "location": "global"
          }
        },
        "return": "Promise<void>"
      },
      "docs": {
        "text": "Sets focus on the date picker's input. Use this method instead of the global `focus()`.",
        "tags": []
      }
    },
    "show": {
      "complexType": {
        "signature": "() => Promise<void>",
        "parameters": [],
        "references": {
          "Promise": {
            "location": "global"
          }
        },
        "return": "Promise<void>"
      },
      "docs": {
        "text": "Show the calendar modal, moving focus to the calendar inside.",
        "tags": []
      }
    },
    "hide": {
      "complexType": {
        "signature": "(moveFocusToButton?: boolean) => Promise<void>",
        "parameters": [{
            "tags": [],
            "text": ""
          }],
        "references": {
          "Promise": {
            "location": "global"
          }
        },
        "return": "Promise<void>"
      },
      "docs": {
        "text": "Hide the calendar modal. Set `moveFocusToButton` to false to prevent focus\nreturning to the date picker's button. Default is true.",
        "tags": []
      }
    }
  }; }
  static get elementRef() { return "element"; }
  static get watchers() { return [{
      "propName": "yearRange",
      "methodName": "yearRangeChanged"
    }, {
      "propName": "localization",
      "methodName": "createDateFormatters"
    }]; }
  static get listeners() { return [{
      "name": "click",
      "method": "handleDocumentClick",
      "target": "document",
      "capture": true,
      "passive": false
    }]; }
}
