UNPKG

buefy

Version:

Lightweight UI components for Vue.js (v3) based on Bulma

2,121 lines 77.4 kB
'use strict';

var vue = require('vue');
var CompatFallthroughMixin = require('./CompatFallthroughMixin-hhK0Gkhr.js');
var FormElementMixin = require('./FormElementMixin-DavX4iOv.js');
var helpers = require('./helpers.js');
var config = require('./config-DR826Ki2.js');
var Dropdown = require('./Dropdown-DtpKU9qf.js');
var DropdownItem = require('./DropdownItem-IMOKyRGV.js');
var Input = require('./Input-BcloGeZ3.js');
var Field = require('./Field-19ZCJFF8.js');
var Select = require('./Select-DayPKwCY.js');
var Icon = require('./Icon-lsDKE2wQ.js');
var _pluginVue_exportHelper = require('./_plugin-vue_export-helper-Die8u8yB.js');

var _sfc_main$3 = vue.defineComponent({
  name: "BDatepickerTableRow",
  inject: {
    $datepicker: { name: "$datepicker", default: false }
  },
  props: {
    selectedDate: {
      type: [Date, Array]
    },
    hoveredDateRange: Array,
    day: {
      type: Number
    },
    week: {
      type: Array,
      required: true
    },
    month: {
      type: Number,
      required: true
    },
    minDate: [Date, null],
    maxDate: [Date, null],
    disabled: Boolean,
    unselectableDates: [Array, Function, null],
    unselectableDaysOfWeek: [Array, null],
    selectableDates: [Array, Function, null],
    events: Array,
    indicators: String,
    dateCreator: Function,
    nearbyMonthDays: Boolean,
    nearbySelectableMonthDays: Boolean,
    showWeekNumber: Boolean,
    weekNumberClickable: Boolean,
    range: Boolean,
    multiple: Boolean,
    rulesForFirstWeek: Number,
    firstDayOfWeek: [Number, null]
  },
  emits: {
    /* eslint-disable @typescript-eslint/no-unused-vars */
    "change-focus": (_day) => true,
    rangeHoverEndDate: (_day) => true,
    select: (_day) => true
    /* eslint-enable @typescript-eslint/no-unused-vars */
  },
  watch: {
    day(day) {
      const refName = `day-${this.month}-${day}`;
      this.$nextTick(() => {
        let cell;
        if (Array.isArray(this.$refs[refName])) {
          cell = this.$refs[refName][0];
        } else {
          cell = this.$refs[refName];
        }
        if (cell) {
          cell.focus();
        }
      });
    }
  },
  methods: {
    firstWeekOffset(year, dow, doy) {
      const fwd = 7 + dow - doy;
      const firstJanuary = new Date(year, 0, fwd);
      const fwdlw = (7 + firstJanuary.getDay() - dow) % 7;
      return -fwdlw + fwd - 1;
    },
    daysInYear(year) {
      return this.isLeapYear(year) ? 366 : 365;
    },
    isLeapYear(year) {
      return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
    },
    getSetDayOfYear(input) {
      return Math.round((+input - +new Date(input.getFullYear(), 0, 1)) / 864e5) + 1;
    },
    weeksInYear(year, dow, doy) {
      const weekOffset = this.firstWeekOffset(year, dow, doy);
      const weekOffsetNext = this.firstWeekOffset(year + 1, dow, doy);
      return (this.daysInYear(year) - weekOffset + weekOffsetNext) / 7;
    },
    getWeekNumber(mom) {
      const dow = this.firstDayOfWeek;
      const doy = this.rulesForFirstWeek;
      const weekOffset = this.firstWeekOffset(mom.getFullYear(), dow, doy);
      const week = Math.floor((this.getSetDayOfYear(mom) - weekOffset - 1) / 7) + 1;
      let resWeek;
      let resYear;
      if (week < 1) {
        resYear = mom.getFullYear() - 1;
        resWeek = week + this.weeksInYear(resYear, dow, doy);
      } else if (week > this.weeksInYear(mom.getFullYear(), dow, doy)) {
        resWeek = week - this.weeksInYear(mom.getFullYear(), dow, doy);
        resYear = mom.getFullYear() + 1;
      } else {
        resYear = mom.getFullYear();
        resWeek = week;
      }
      return { week: resWeek, year: resYear };
    },
    clickWeekNumber(weekData) {
      if (this.weekNumberClickable) {
        this.$datepicker.$emit("week-number-click", weekData.week, weekData.year);
      }
    },
    /*
     * Check that selected day is within earliest/latest params and
     * is within this month
     */
    selectableDate(day) {
      const validity = [];
      if (this.minDate) {
        validity.push(day >= this.minDate);
      }
      if (this.maxDate) {
        validity.push(day <= this.maxDate);
      }
      if (this.nearbyMonthDays && !this.nearbySelectableMonthDays) {
        validity.push(day.getMonth() === this.month);
      }
      if (this.selectableDates) {
        if (typeof this.selectableDates === "function") {
          if (this.selectableDates(day)) {
            return true;
          } else {
            validity.push(false);
          }
        } else {
          for (let i = 0; i < this.selectableDates.length; i++) {
            const enabledDate = this.selectableDates[i];
            if (day.getDate() === enabledDate.getDate() && day.getFullYear() === enabledDate.getFullYear() && day.getMonth() === enabledDate.getMonth()) {
              return true;
            } else {
              validity.push(false);
            }
          }
        }
      }
      if (this.unselectableDates) {
        if (typeof this.unselectableDates === "function") {
          validity.push(!this.unselectableDates(day));
        } else {
          for (let i = 0; i < this.unselectableDates.length; i++) {
            const disabledDate = this.unselectableDates[i];
            validity.push(
              day.getDate() !== disabledDate.getDate() || day.getFullYear() !== disabledDate.getFullYear() || day.getMonth() !== disabledDate.getMonth()
            );
          }
        }
      }
      if (this.unselectableDaysOfWeek) {
        for (let i = 0; i < this.unselectableDaysOfWeek.length; i++) {
          const dayOfWeek = this.unselectableDaysOfWeek[i];
          validity.push(day.getDay() !== dayOfWeek);
        }
      }
      return validity.indexOf(false) < 0;
    },
    /*
    * Emit select event with chosen date as payload
    */
    emitChosenDate(day) {
      if (this.disabled) return;
      if (this.selectableDate(day)) {
        this.$emit("select", day);
      }
    },
    // TODO: return undefined instead of boolean if no events
    eventsDateMatch(day) {
      if (!this.events || !this.events.length) return false;
      const dayEvents = [];
      for (let i = 0; i < this.events.length; i++) {
        if (this.events[i].date.getDay() === day.getDay()) {
          dayEvents.push(this.events[i]);
        }
      }
      if (!dayEvents.length) {
        return false;
      }
      return dayEvents;
    },
    /*
    * Build classObject for cell using validations
    */
    classObject(day) {
      function dateMatch(dateOne, dateTwo, multiple) {
        if (!dateOne || !dateTwo || multiple) {
          return false;
        }
        if (Array.isArray(dateTwo)) {
          return dateTwo.some((date) => dateOne.getDate() === date.getDate() && dateOne.getFullYear() === date.getFullYear() && dateOne.getMonth() === date.getMonth());
        }
        return dateOne.getDate() === dateTwo.getDate() && dateOne.getFullYear() === dateTwo.getFullYear() && dateOne.getMonth() === dateTwo.getMonth();
      }
      function dateWithin(dateOne, dates, multiple) {
        if (!Array.isArray(dates) || multiple) {
          return false;
        }
        return dateOne > dates[0] && dateOne < dates[1];
      }
      return {
        "is-selected": dateMatch(day, this.selectedDate) || dateWithin(day, this.selectedDate, this.multiple),
        "is-first-selected": dateMatch(
          day,
          Array.isArray(this.selectedDate) ? this.selectedDate[0] : void 0,
          this.multiple
        ),
        "is-within-selected": dateWithin(day, this.selectedDate, this.multiple),
        "is-last-selected": dateMatch(
          day,
          Array.isArray(this.selectedDate) ? this.selectedDate[1] : void 0,
          this.multiple
        ),
        "is-within-hovered-range": this.hoveredDateRange && this.hoveredDateRange.length === 2 && (dateMatch(day, this.hoveredDateRange) || dateWithin(day, this.hoveredDateRange)),
        "is-first-hovered": dateMatch(
          day,
          Array.isArray(this.hoveredDateRange) ? this.hoveredDateRange[0] : void 0
        ),
        "is-within-hovered": dateWithin(day, this.hoveredDateRange),
        "is-last-hovered": dateMatch(
          day,
          Array.isArray(this.hoveredDateRange) ? this.hoveredDateRange[1] : void 0
        ),
        "is-today": dateMatch(day, this.dateCreator()),
        "is-selectable": this.selectableDate(day) && !this.disabled,
        "is-unselectable": !this.selectableDate(day) || this.disabled,
        "is-invisible": !this.nearbyMonthDays && day.getMonth() !== this.month,
        "is-nearby": this.nearbySelectableMonthDays && day.getMonth() !== this.month,
        "has-event": this.eventsDateMatch(day),
        [this.indicators]: this.eventsDateMatch(day)
      };
    },
    setRangeHoverEndDate(day) {
      if (this.range) {
        this.$emit("rangeHoverEndDate", day);
      }
    },
    manageKeydown(event, weekDay) {
      const { key } = event;
      let preventDefault = true;
      switch (key) {
        case "Tab": {
          preventDefault = false;
          break;
        }
        case " ":
        case "Space":
        case "Spacebar":
        case "Enter": {
          this.emitChosenDate(weekDay);
          break;
        }
        case "ArrowLeft":
        case "Left": {
          this.changeFocus(weekDay, -1);
          break;
        }
        case "ArrowRight":
        case "Right": {
          this.changeFocus(weekDay, 1);
          break;
        }
        case "ArrowUp":
        case "Up": {
          this.changeFocus(weekDay, -7);
          break;
        }
        case "ArrowDown":
        case "Down": {
          this.changeFocus(weekDay, 7);
          break;
        }
      }
      if (preventDefault) {
        event.preventDefault();
      }
    },
    changeFocus(day, inc) {
      const nextDay = new Date(day.getTime());
      nextDay.setDate(day.getDate() + inc);
      while ((!this.minDate || nextDay > this.minDate) && (!this.maxDate || nextDay < this.maxDate) && !this.selectableDate(nextDay)) {
        nextDay.setDate(nextDay.getDate() + Math.sign(inc));
      }
      this.setRangeHoverEndDate(nextDay);
      this.$emit("change-focus", nextDay);
    }
  }
});

const _hoisted_1$3 = { class: "datepicker-row" };
const _hoisted_2$3 = ["disabled", "onClick", "onMouseenter", "onKeydown", "tabindex"];
const _hoisted_3$2 = {
  key: 0,
  class: "events"
};
const _hoisted_4$2 = {
  key: 0,
  class: "events"
};
function _sfc_render$3(_ctx, _cache, $props, $setup, $data, $options) {
  return vue.openBlock(), vue.createElementBlock(
    vue.Fragment,
    null,
    [
      vue.createCommentVNode(" eslint-disable max-len "),
      vue.createElementVNode("div", _hoisted_1$3, [
        _ctx.showWeekNumber ? (vue.openBlock(), vue.createElementBlock(
          "a",
          {
            key: 0,
            class: vue.normalizeClass(["datepicker-cell is-week-number", { "is-clickable": _ctx.weekNumberClickable }]),
            onClick: _cache[0] || (_cache[0] = vue.withModifiers(($event) => _ctx.clickWeekNumber(_ctx.getWeekNumber(_ctx.week[6])), ["prevent"]))
          },
          [
            vue.createElementVNode(
              "span",
              null,
              vue.toDisplayString(_ctx.getWeekNumber(_ctx.week[6]).week),
              1
              /* TEXT */
            )
          ],
          2
          /* CLASS */
        )) : vue.createCommentVNode("v-if", true),
        (vue.openBlock(true), vue.createElementBlock(
          vue.Fragment,
          null,
          vue.renderList(_ctx.week, (weekDay, index) => {
            return vue.openBlock(), vue.createElementBlock(
              vue.Fragment,
              { key: index },
              [
                _ctx.selectableDate(weekDay) && !_ctx.disabled ? (vue.openBlock(), vue.createElementBlock("a", {
                  key: 0,
                  ref_for: true,
                  ref: `day-${weekDay.getMonth()}-${weekDay.getDate()}`,
                  class: vue.normalizeClass([_ctx.classObject(weekDay), "datepicker-cell"]),
                  role: "button",
                  href: "#",
                  disabled: _ctx.disabled || void 0,
                  onClick: vue.withModifiers(($event) => _ctx.emitChosenDate(weekDay), ["prevent"]),
                  onMouseenter: ($event) => _ctx.setRangeHoverEndDate(weekDay),
                  onKeydown: ($event) => _ctx.manageKeydown($event, weekDay),
                  tabindex: _ctx.day === weekDay.getDate() && _ctx.month === weekDay.getMonth() ? void 0 : -1
                }, [
                  vue.createElementVNode(
                    "span",
                    null,
                    vue.toDisplayString(weekDay.getDate()),
                    1
                    /* TEXT */
                  ),
                  _ctx.eventsDateMatch(weekDay) ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_3$2, [
                    (vue.openBlock(true), vue.createElementBlock(
                      vue.Fragment,
                      null,
                      vue.renderList(_ctx.eventsDateMatch(weekDay), (event, evIdx) => {
                        return vue.openBlock(), vue.createElementBlock(
                          "div",
                          {
                            class: vue.normalizeClass(["event", event.type]),
                            key: evIdx
                          },
                          null,
                          2
                          /* CLASS */
                        );
                      }),
                      128
                      /* KEYED_FRAGMENT */
                    ))
                  ])) : vue.createCommentVNode("v-if", true)
                ], 42, _hoisted_2$3)) : (vue.openBlock(), vue.createElementBlock(
                  "div",
                  {
                    key: 1,
                    class: vue.normalizeClass([_ctx.classObject(weekDay), "datepicker-cell"])
                  },
                  [
                    vue.createElementVNode(
                      "span",
                      null,
                      vue.toDisplayString(weekDay.getDate()),
                      1
                      /* TEXT */
                    ),
                    _ctx.eventsDateMatch(weekDay) ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_4$2, [
                      (vue.openBlock(true), vue.createElementBlock(
                        vue.Fragment,
                        null,
                        vue.renderList(_ctx.eventsDateMatch(weekDay), (event, evIdx) => {
                          return vue.openBlock(), vue.createElementBlock(
                            "div",
                            {
                              class: vue.normalizeClass(["event", event.type]),
                              key: evIdx
                            },
                            null,
                            2
                            /* CLASS */
                          );
                        }),
                        128
                        /* KEYED_FRAGMENT */
                      ))
                    ])) : vue.createCommentVNode("v-if", true)
                  ],
                  2
                  /* CLASS */
                ))
              ],
              64
              /* STABLE_FRAGMENT */
            );
          }),
          128
          /* KEYED_FRAGMENT */
        ))
      ]),
      vue.createCommentVNode(" eslint-enable max-len ")
    ],
    2112
    /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */
  );
}
var BDatepickerTableRow = /* @__PURE__ */ _pluginVue_exportHelper._export_sfc(_sfc_main$3, [["render", _sfc_render$3]]);

var _sfc_main$2 = vue.defineComponent({
  name: "BDatepickerTable",
  components: {
    BDatepickerTableRow
  },
  props: {
    modelValue: {
      type: [Date, Array, null]
    },
    dayNames: [Array, null],
    monthNames: [Array, null],
    firstDayOfWeek: [Number, null],
    events: Array,
    indicators: String,
    minDate: [Date, null],
    maxDate: [Date, null],
    focused: Object,
    disabled: Boolean,
    dateCreator: Function,
    unselectableDates: [Array, Function, null],
    unselectableDaysOfWeek: [Array, null],
    selectableDates: [Array, Function, null],
    nearbyMonthDays: Boolean,
    nearbySelectableMonthDays: Boolean,
    showWeekNumber: Boolean,
    weekNumberClickable: Boolean,
    rulesForFirstWeek: Number,
    range: Boolean,
    multiple: Boolean
  },
  emits: {
    /* eslint-disable @typescript-eslint/no-unused-vars */
    "range-end": (_date) => true,
    "range-start": (_date) => true,
    "update:focused": (_focused) => true,
    "update:modelValue": (_value) => true
    /* eslint-enable @typescript-eslint/no-unused-vars */
  },
  data() {
    return {
      selectedBeginDate: void 0,
      selectedEndDate: void 0,
      hoveredEndDate: void 0
    };
  },
  computed: {
    multipleSelectedDates: {
      get() {
        return this.multiple && this.modelValue ? this.modelValue : [];
      },
      set(value) {
        this.$emit("update:modelValue", value);
      }
    },
    visibleDayNames() {
      const visibleDayNames = [];
      let index = this.firstDayOfWeek;
      while (visibleDayNames.length < this.dayNames.length) {
        const currentDayName = this.dayNames[index % this.dayNames.length];
        visibleDayNames.push(currentDayName);
        index++;
      }
      if (this.showWeekNumber) visibleDayNames.unshift("");
      return visibleDayNames;
    },
    hasEvents() {
      return this.events && this.events.length;
    },
    /*
    * Return array of all events in the specified month
    */
    eventsInThisMonth() {
      if (!this.events) return [];
      const monthEvents = [];
      for (let i = 0; i < this.events.length; i++) {
        let event = this.events[i];
        if (!Object.prototype.hasOwnProperty.call(event, "date")) {
          event = { date: event, type: "is-primary" };
        }
        if (!Object.prototype.hasOwnProperty.call(event, "type")) {
          event.type = "is-primary";
        }
        if (event.date.getMonth() === this.focused.month && event.date.getFullYear() === this.focused.year) {
          monthEvents.push(event);
        }
      }
      return monthEvents;
    },
    /*
    * Return array of all weeks in the specified month
    */
    weeksInThisMonth() {
      this.validateFocusedDay();
      const month = this.focused.month;
      const year = this.focused.year;
      const weeksInThisMonth = [];
      let startingDay = 1;
      while (weeksInThisMonth.length < 6) {
        const newWeek = this.weekBuilder(startingDay, month, year);
        weeksInThisMonth.push(newWeek);
        startingDay += 7;
      }
      return weeksInThisMonth;
    },
    hoveredDateRange() {
      var _a, _b;
      if (!this.range) {
        return [];
      }
      if (!isNaN((_b = (_a = this.selectedEndDate) == null ? void 0 : _a.valueOf()) != null ? _b : NaN)) {
        return [];
      }
      if (this.hoveredEndDate < this.selectedBeginDate) {
        return [this.hoveredEndDate, this.selectedBeginDate].filter(helpers.isDefined);
      }
      return [this.selectedBeginDate, this.hoveredEndDate].filter(helpers.isDefined);
    },
    disabledOrUndefined() {
      return this.disabled || void 0;
    }
  },
  methods: {
    /*
    * Emit input event with selected date as payload for v-model in parent
    */
    updateSelectedDate(date) {
      if (!this.range && !this.multiple) {
        this.$emit("update:modelValue", date);
      } else if (this.range) {
        this.handleSelectRangeDate(date);
      } else if (this.multiple) {
        this.handleSelectMultipleDates(date);
      }
    },
    /*
    * If both begin and end dates are set, reset the end date and set the begin date.
    * If only begin date is selected, emit an array of the begin date and the new date.
    * If not set, only set the begin date.
    */
    handleSelectRangeDate(date) {
      if (this.selectedBeginDate && this.selectedEndDate) {
        this.selectedBeginDate = date;
        this.selectedEndDate = void 0;
        this.$emit("range-start", date);
      } else if (this.selectedBeginDate && !this.selectedEndDate) {
        if (this.selectedBeginDate > date) {
          this.selectedEndDate = this.selectedBeginDate;
          this.selectedBeginDate = date;
        } else {
          this.selectedEndDate = date;
        }
        this.$emit("range-end", date);
        this.$emit("update:modelValue", [this.selectedBeginDate, this.selectedEndDate]);
      } else {
        this.selectedBeginDate = date;
        this.$emit("range-start", date);
      }
    },
    /*
    * If selected date already exists list of selected dates, remove it from the list
    * Otherwise, add date to list of selected dates
    */
    handleSelectMultipleDates(date) {
      const multipleSelect = this.multipleSelectedDates.filter(
        (selectedDate) => selectedDate.getDate() === date.getDate() && selectedDate.getFullYear() === date.getFullYear() && selectedDate.getMonth() === date.getMonth()
      );
      if (multipleSelect.length) {
        this.multipleSelectedDates = this.multipleSelectedDates.filter(
          (selectedDate) => selectedDate.getDate() !== date.getDate() || selectedDate.getFullYear() !== date.getFullYear() || selectedDate.getMonth() !== date.getMonth()
        );
      } else {
        this.multipleSelectedDates = [...this.multipleSelectedDates, date];
      }
    },
    /*
     * Return array of all days in the week that the startingDate is within
     */
    weekBuilder(startingDate, month, year) {
      const thisMonth = new Date(year, month);
      const thisWeek = [];
      const dayOfWeek = new Date(year, month, startingDate).getDay();
      const end = dayOfWeek >= this.firstDayOfWeek ? dayOfWeek - this.firstDayOfWeek : 7 - this.firstDayOfWeek + dayOfWeek;
      let daysAgo = 1;
      for (let i = 0; i < end; i++) {
        thisWeek.unshift(
          new Date(
            thisMonth.getFullYear(),
            thisMonth.getMonth(),
            startingDate - daysAgo
          )
        );
        daysAgo++;
      }
      thisWeek.push(new Date(year, month, startingDate));
      let daysForward = 1;
      while (thisWeek.length < 7) {
        thisWeek.push(new Date(year, month, startingDate + daysForward));
        daysForward++;
      }
      return thisWeek;
    },
    validateFocusedDay() {
      const focusedDate = new Date(this.focused.year, this.focused.month, this.focused.day);
      if (this.selectableDate(focusedDate)) return;
      let day = 0;
      const monthDays = new Date(this.focused.year, this.focused.month + 1, 0).getDate();
      let firstFocusable = null;
      while (!firstFocusable && ++day < monthDays) {
        const date = new Date(this.focused.year, this.focused.month, day);
        if (this.selectableDate(date)) {
          firstFocusable = focusedDate;
          const focused = {
            day: date.getDate(),
            month: date.getMonth(),
            year: date.getFullYear()
          };
          this.$emit("update:focused", focused);
        }
      }
    },
    /*
     * Check that selected day is within earliest/latest params and
     * is within this month
     */
    selectableDate(day) {
      const validity = [];
      if (this.minDate) {
        validity.push(day >= this.minDate);
      }
      if (this.maxDate) {
        validity.push(day <= this.maxDate);
      }
      if (this.nearbyMonthDays && !this.nearbySelectableMonthDays) {
        validity.push(day.getMonth() === this.focused.month);
      }
      if (this.selectableDates) {
        if (typeof this.selectableDates === "function") {
          if (this.selectableDates(day)) {
            return true;
          } else {
            validity.push(false);
          }
        } else {
          for (let i = 0; i < this.selectableDates.length; i++) {
            const enabledDate = this.selectableDates[i];
            if (day.getDate() === enabledDate.getDate() && day.getFullYear() === enabledDate.getFullYear() && day.getMonth() === enabledDate.getMonth()) {
              return true;
            } else {
              validity.push(false);
            }
          }
        }
      }
      if (this.unselectableDates) {
        if (typeof this.unselectableDates === "function") {
          validity.push(!this.unselectableDates(day));
        } else {
          for (let i = 0; i < this.unselectableDates.length; i++) {
            const disabledDate = this.unselectableDates[i];
            validity.push(
              day.getDate() !== disabledDate.getDate() || day.getFullYear() !== disabledDate.getFullYear() || day.getMonth() !== disabledDate.getMonth()
            );
          }
        }
      }
      if (this.unselectableDaysOfWeek) {
        for (let i = 0; i < this.unselectableDaysOfWeek.length; i++) {
          const dayOfWeek = this.unselectableDaysOfWeek[i];
          validity.push(day.getDay() !== dayOfWeek);
        }
      }
      return validity.indexOf(false) < 0;
    },
    eventsInThisWeek(week) {
      return this.eventsInThisMonth.filter((event) => {
        const stripped = new Date(Date.parse(event.date + ""));
        stripped.setHours(0, 0, 0, 0);
        const timed = stripped.getTime();
        return week.some((weekDate) => weekDate.getTime() === timed);
      });
    },
    setRangeHoverEndDate(day) {
      this.hoveredEndDate = day;
    },
    changeFocus(day) {
      const focused = {
        day: day.getDate(),
        month: day.getMonth(),
        year: day.getFullYear()
      };
      this.$emit("update:focused", focused);
    }
  }
});

const _hoisted_1$2 = { class: "datepicker-table" };
const _hoisted_2$2 = { class: "datepicker-header" };
function _sfc_render$2(_ctx, _cache, $props, $setup, $data, $options) {
  const _component_b_datepicker_table_row = vue.resolveComponent("b-datepicker-table-row");
  return vue.openBlock(), vue.createElementBlock("section", _hoisted_1$2, [
    vue.createElementVNode("header", _hoisted_2$2, [
      (vue.openBlock(true), vue.createElementBlock(
        vue.Fragment,
        null,
        vue.renderList(_ctx.visibleDayNames, (day, index) => {
          return vue.openBlock(), vue.createElementBlock("div", {
            key: index,
            class: "datepicker-cell"
          }, [
            vue.createElementVNode(
              "span",
              null,
              vue.toDisplayString(day),
              1
              /* TEXT */
            )
          ]);
        }),
        128
        /* KEYED_FRAGMENT */
      ))
    ]),
    vue.createElementVNode(
      "div",
      {
        class: vue.normalizeClass(["datepicker-body", { "has-events": _ctx.hasEvents }])
      },
      [
        (vue.openBlock(true), vue.createElementBlock(
          vue.Fragment,
          null,
          vue.renderList(_ctx.weeksInThisMonth, (week, index) => {
            return vue.openBlock(), vue.createBlock(_component_b_datepicker_table_row, {
              key: index,
              "selected-date": _ctx.modelValue ?? void 0,
              day: _ctx.focused.day,
              week,
              month: _ctx.focused.month,
              "min-date": _ctx.minDate,
              "max-date": _ctx.maxDate,
              disabled: _ctx.disabledOrUndefined,
              "unselectable-dates": _ctx.unselectableDates,
              "unselectable-days-of-week": _ctx.unselectableDaysOfWeek,
              "selectable-dates": _ctx.selectableDates,
              events: _ctx.eventsInThisWeek(week),
              indicators: _ctx.indicators,
              "date-creator": _ctx.dateCreator,
              "nearby-month-days": _ctx.nearbyMonthDays,
              "nearby-selectable-month-days": _ctx.nearbySelectableMonthDays,
              "show-week-number": _ctx.showWeekNumber,
              "week-number-clickable": _ctx.weekNumberClickable,
              "first-day-of-week": _ctx.firstDayOfWeek,
              "rules-for-first-week": _ctx.rulesForFirstWeek,
              range: _ctx.range,
              "hovered-date-range": _ctx.hoveredDateRange,
              onSelect: _ctx.updateSelectedDate,
              onRangeHoverEndDate: _ctx.setRangeHoverEndDate,
              multiple: _ctx.multiple,
              onChangeFocus: _ctx.changeFocus
            }, null, 8, ["selected-date", "day", "week", "month", "min-date", "max-date", "disabled", "unselectable-dates", "unselectable-days-of-week", "selectable-dates", "events", "indicators", "date-creator", "nearby-month-days", "nearby-selectable-month-days", "show-week-number", "week-number-clickable", "first-day-of-week", "rules-for-first-week", "range", "hovered-date-range", "onSelect", "onRangeHoverEndDate", "multiple", "onChangeFocus"]);
          }),
          128
          /* KEYED_FRAGMENT */
        ))
      ],
      2
      /* CLASS */
    )
  ]);
}
var BDatepickerTable = /* @__PURE__ */ _pluginVue_exportHelper._export_sfc(_sfc_main$2, [["render", _sfc_render$2]]);

var _sfc_main$1 = vue.defineComponent({
  name: "BDatepickerMonth",
  props: {
    modelValue: {
      type: [Date, Array, null]
    },
    monthNames: [Array, null],
    events: Array,
    indicators: String,
    minDate: [Date, null],
    maxDate: [Date, null],
    focused: Object,
    disabled: Boolean,
    dateCreator: Function,
    unselectableDates: [Array, Function, null],
    unselectableDaysOfWeek: [Array, null],
    selectableDates: [Array, Function, null],
    range: Boolean,
    multiple: Boolean
  },
  emits: {
    /* eslint-disable @typescript-eslint/no-unused-vars */
    "change-focus": (_date) => true,
    "range-end": (_date) => true,
    "range-start": (_date) => true,
    "update:modelValue": (_date) => true
    /* eslint-enable @typescript-eslint/no-unused-vars */
  },
  data() {
    return {
      selectedBeginDate: void 0,
      selectedEndDate: void 0,
      hoveredEndDate: void 0,
      multipleSelectedDates: this.multiple && this.modelValue ? this.modelValue : []
    };
  },
  computed: {
    hasEvents() {
      return this.events && this.events.length;
    },
    /*
    * Return array of all events in the specified month
    */
    eventsInThisYear() {
      if (!this.events) return [];
      const yearEvents = [];
      for (let i = 0; i < this.events.length; i++) {
        let event = this.events[i];
        if (!Object.prototype.hasOwnProperty.call(event, "date")) {
          event = { date: event, type: "is-primary" };
        }
        if (!Object.prototype.hasOwnProperty.call(event, "type")) {
          event.type = "is-primary";
        }
        if (event.date.getFullYear() === this.focused.year) {
          yearEvents.push(event);
        }
      }
      return yearEvents;
    },
    monthDates() {
      const year = this.focused.year;
      const months = [];
      for (let i = 0; i < 12; i++) {
        const d = new Date(year, i, 1);
        d.setHours(0, 0, 0, 0);
        months.push(d);
      }
      return months;
    },
    focusedMonth() {
      return this.focused.month;
    },
    hoveredDateRange() {
      var _a, _b;
      if (!this.range) {
        return [];
      }
      if (!isNaN((_b = (_a = this.selectedEndDate) == null ? void 0 : _a.valueOf()) != null ? _b : NaN)) {
        return [];
      }
      if (this.hoveredEndDate < this.selectedBeginDate) {
        return [this.hoveredEndDate, this.selectedBeginDate].filter(helpers.isDefined);
      }
      return [this.selectedBeginDate, this.hoveredEndDate].filter(helpers.isDefined);
    },
    disabledOrUndefined() {
      return this.disabled || void 0;
    }
  },
  watch: {
    focusedMonth(month) {
      const refName = `month-${month}`;
      this.$nextTick(() => {
        let cell;
        if (Array.isArray(this.$refs[refName])) {
          cell = this.$refs[refName][0];
        } else {
          cell = this.$refs[refName];
        }
        if (cell) {
          cell.focus();
        }
      });
    }
  },
  methods: {
    selectMultipleDates(date) {
      const multipleSelect = this.multipleSelectedDates.filter(
        (selectedDate) => selectedDate.getDate() === date.getDate() && selectedDate.getFullYear() === date.getFullYear() && selectedDate.getMonth() === date.getMonth()
      );
      if (multipleSelect.length) {
        this.multipleSelectedDates = this.multipleSelectedDates.filter(
          (selectedDate) => selectedDate.getDate() !== date.getDate() || selectedDate.getFullYear() !== date.getFullYear() || selectedDate.getMonth() !== date.getMonth()
        );
      } else {
        this.multipleSelectedDates.push(date);
      }
      this.$emit("update:modelValue", this.multipleSelectedDates);
    },
    selectableDate(day) {
      const validity = [];
      if (this.minDate) {
        validity.push(day >= this.minDate);
      }
      if (this.maxDate) {
        validity.push(day <= this.maxDate);
      }
      validity.push(day.getFullYear() === this.focused.year);
      if (this.selectableDates) {
        if (typeof this.selectableDates === "function") {
          if (this.selectableDates(day)) {
            return true;
          } else {
            validity.push(false);
          }
        } else {
          for (let i = 0; i < this.selectableDates.length; i++) {
            const enabledDate = this.selectableDates[i];
            if (day.getFullYear() === enabledDate.getFullYear() && day.getMonth() === enabledDate.getMonth()) {
              return true;
            } else {
              validity.push(false);
            }
          }
        }
      }
      if (this.unselectableDates) {
        if (typeof this.unselectableDates === "function") {
          validity.push(!this.unselectableDates(day));
        } else {
          for (let i = 0; i < this.unselectableDates.length; i++) {
            const disabledDate = this.unselectableDates[i];
            validity.push(
              day.getFullYear() !== disabledDate.getFullYear() || day.getMonth() !== disabledDate.getMonth()
            );
          }
        }
      }
      if (this.unselectableDaysOfWeek) {
        for (let i = 0; i < this.unselectableDaysOfWeek.length; i++) {
          const dayOfWeek = this.unselectableDaysOfWeek[i];
          validity.push(day.getDay() !== dayOfWeek);
        }
      }
      return validity.indexOf(false) < 0;
    },
    // TODO: return undefined instead of false if no events
    eventsDateMatch(day) {
      if (!this.eventsInThisYear.length) return false;
      const monthEvents = [];
      for (let i = 0; i < this.eventsInThisYear.length; i++) {
        if (this.eventsInThisYear[i].date.getMonth() === day.getMonth()) {
          monthEvents.push(this.events[i]);
        }
      }
      if (!monthEvents.length) {
        return false;
      }
      return monthEvents;
    },
    /*
    * Build classObject for cell using validations
    */
    classObject(day) {
      function dateMatch(dateOne, dateTwo, multiple) {
        if (!dateOne || !dateTwo || multiple) {
          return false;
        }
        if (Array.isArray(dateTwo)) {
          return dateTwo.some((date) => dateOne.getFullYear() === date.getFullYear() && dateOne.getMonth() === date.getMonth());
        }
        return dateOne.getFullYear() === dateTwo.getFullYear() && dateOne.getMonth() === dateTwo.getMonth();
      }
      function dateWithin(dateOne, dates, multiple) {
        if (!Array.isArray(dates) || multiple) {
          return false;
        }
        return dateOne > dates[0] && dateOne < dates[1];
      }
      function dateMultipleSelected(dateOne, dates, multiple) {
        if (!Array.isArray(dates) || !multiple) {
          return false;
        }
        return dates.some((date) => dateOne.getDate() === date.getDate() && dateOne.getFullYear() === date.getFullYear() && dateOne.getMonth() === date.getMonth());
      }
      return {
        "is-selected": dateMatch(day, this.modelValue, this.multiple) || dateWithin(day, this.modelValue, this.multiple) || dateMultipleSelected(day, this.multipleSelectedDates, this.multiple),
        "is-first-selected": dateMatch(
          day,
          Array.isArray(this.modelValue) ? this.modelValue[0] : void 0,
          this.multiple
        ),
        "is-within-selected": dateWithin(day, this.modelValue, this.multiple),
        "is-last-selected": dateMatch(
          day,
          Array.isArray(this.modelValue) ? this.modelValue[1] : void 0,
          this.multiple
        ),
        "is-within-hovered-range": this.hoveredDateRange && this.hoveredDateRange.length === 2 && (dateMatch(day, this.hoveredDateRange) || dateWithin(day, this.hoveredDateRange)),
        "is-first-hovered": dateMatch(
          day,
          Array.isArray(this.hoveredDateRange) ? this.hoveredDateRange[0] : void 0
        ),
        "is-within-hovered": dateWithin(day, this.hoveredDateRange),
        "is-last-hovered": dateMatch(
          day,
          Array.isArray(this.hoveredDateRange) ? this.hoveredDateRange[1] : void 0
        ),
        "is-today": dateMatch(day, this.dateCreator()),
        "is-selectable": this.selectableDate(day) && !this.disabled,
        "is-unselectable": !this.selectableDate(day) || this.disabled
      };
    },
    manageKeydown({ key }, date) {
      switch (key) {
        case " ":
        case "Space":
        case "Spacebar":
        case "Enter": {
          this.updateSelectedDate(date);
          break;
        }
        case "ArrowLeft":
        case "Left": {
          this.changeFocus(date, -1);
          break;
        }
        case "ArrowRight":
        case "Right": {
          this.changeFocus(date, 1);
          break;
        }
        case "ArrowUp":
        case "Up": {
          this.changeFocus(date, -3);
          break;
        }
        case "ArrowDown":
        case "Down": {
          this.changeFocus(date, 3);
          break;
        }
      }
    },
    /*
    * Emit input event with selected date as payload for v-model in parent
    */
    updateSelectedDate(date) {
      if (!this.range && !this.multiple) {
        this.emitChosenDate(date);
      } else if (this.range) {
        this.handleSelectRangeDate(date);
      } else if (this.multiple) {
        this.selectMultipleDates(date);
      }
    },
    /*
     * Emit select event with chosen date as payload
     */
    emitChosenDate(day) {
      if (this.disabled) return;
      if (!this.multiple) {
        if (this.selectableDate(day)) {
          this.$emit("update:modelValue", day);
        }
      } else {
        this.selectMultipleDates(day);
      }
    },
    /*
    * If both begin and end dates are set, reset the end date and set the begin date.
    * If only begin date is selected, emit an array of the begin date and the new date.
    * If not set, only set the begin date.
    */
    handleSelectRangeDate(date) {
      if (this.disabled) return;
      if (this.selectedBeginDate && this.selectedEndDate) {
        this.selectedBeginDate = date;
        this.selectedEndDate = void 0;
        this.$emit("range-start", date);
      } else if (this.selectedBeginDate && !this.selectedEndDate) {
        if (this.selectedBeginDate > date) {
          this.selectedEndDate = this.selectedBeginDate;
          this.selectedBeginDate = date;
        } else {
          this.selectedEndDate = date;
        }
        this.$emit("range-end", date);
        this.$emit("update:modelValue", [this.selectedBeginDate, this.selectedEndDate]);
      } else {
        this.selectedBeginDate = date;
        this.$emit("range-start", date);
      }
    },
    setRangeHoverEndDate(day) {
      if (this.range) {
        this.hoveredEndDate = day;
      }
    },
    changeFocus(month, inc) {
      const nextMonth = month;
      nextMonth.setMonth(month.getMonth() + inc);
      this.$emit("change-focus", nextMonth);
    }
  }
});

const _hoisted_1$1 = { class: "datepicker-table" };
const _hoisted_2$1 = { class: "datepicker-months" };
const _hoisted_3$1 = ["disabled", "onClick", "onMouseenter", "onKeydown", "tabindex"];
const _hoisted_4$1 = {
  key: 0,
  class: "events"
};
function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
  return vue.openBlock(), vue.createElementBlock("section", _hoisted_1$1, [
    vue.createElementVNode(
      "div",
      {
        class: vue.normalizeClass(["datepicker-body", { "has-events": _ctx.hasEvents }])
      },
      [
        vue.createElementVNode("div", _hoisted_2$1, [
          (vue.openBlock(true), vue.createElementBlock(
            vue.Fragment,
            null,
            vue.renderList(_ctx.monthDates, (date, index) => {
              return vue.openBlock(), vue.createElementBlock(
                vue.Fragment,
                { key: index },
                [
                  _ctx.selectableDate(date) && !_ctx.disabled ? (vue.openBlock(), vue.createElementBlock("a", {
                    key: 0,
                    ref_for: true,
                    ref: `month-${date.getMonth()}`,
                    class: vue.normalizeClass([[
                      _ctx.classObject(date),
                      { "has-event": _ctx.eventsDateMatch(date) },
                      _ctx.indicators
                    ], "datepicker-cell"]),
                    role: "button",
                    href: "#",
                    disabled: _ctx.disabledOrUndefined,
                    onClick: vue.withModifiers(($event) => _ctx.updateSelectedDate(date), ["prevent"]),
                    onMouseenter: ($event) => _ctx.setRangeHoverEndDate(date),
                    onKeydown: vue.withModifiers(($event) => _ctx.manageKeydown($event, date), ["prevent"]),
                    tabindex: _ctx.focused.month === date.getMonth() ? void 0 : -1
                  }, [
                    vue.createTextVNode(
                      vue.toDisplayString(_ctx.monthNames[date.getMonth()]) + " ",
                      1
                      /* TEXT */
                    ),
                    _ctx.eventsDateMatch(date) ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_4$1, [
                      (vue.openBlock(true), vue.createElementBlock(
                        vue.Fragment,
                        null,
                        vue.renderList(_ctx.eventsDateMatch(date), (event, evIdx) => {
                          return vue.openBlock(), vue.createElementBlock(
                            "div",
                            {
                              class: vue.normalizeClass(["event", event.type]),
                              key: evIdx
                            },
                            null,
                            2
                            /* CLASS */
                          );
                        }),
                        128
                        /* KEYED_FRAGMENT */
                      ))
                    ])) : vue.createCommentVNode("v-if", true)
                  ], 42, _hoisted_3$1)) : (vue.openBlock(), vue.createElementBlock(
                    "div",
                    {
                      key: 1,
                      class: vue.normalizeClass([_ctx.classObject(date), "datepicker-cell"])
                    },
                    vue.toDisplayString(_ctx.monthNames[date.getMonth()]),
                    3
                    /* TEXT, CLASS */
                  ))
                ],
                64
                /* STABLE_FRAGMENT */
              );
            }),
            128
            /* KEYED_FRAGMENT */
          ))
        ])
      ],
      2
      /* CLASS */
    )
  ]);
}
var BDatepickerMonth = /* @__PURE__ */ _pluginVue_exportHelper._export_sfc(_sfc_main$1, [["render", _sfc_render$1]]);

const defaultDateFormatter = (date, vm) => {
  const targetDates = Array.isArray(date) ? date : [date];
  const dates = targetDates.map((date2) => {
    const d = new Date(date2.getFullYear(), date2.getMonth(), date2.getDate(), 12);
    return !vm.isTypeMonth ? vm.dtf.format(d) : vm.dtfMonth.format(d);
  });
  return !vm.multiple ? dates.join(" - ") : dates.join(", ");
};
const defaultDateParser = (date, vm) => {
  if (vm.dtf.formatToParts && typeof vm.dtf.formatToParts === "function") {
    const formatRegex = (vm.isTypeMonth ? vm.dtfMonth : vm.dtf).formatToParts(new Date(2e3, 11, 25)).map((part) => {
      if (part.type === "literal") {
        return part.value;
      }
      return `((?!=<${part.type}>)\\d+)`;
    }).join("");
    const dateGroups = helpers.matchWithGroups(formatRegex, date);
    if (dateGroups.year && dateGroups.year.length === 4 && dateGroups.month && +dateGroups.month <= 12) {
      if (vm.isTypeMonth) return new Date(+dateGroups.year, +dateGroups.month - 1);
      else if (dateGroups.day && +dateGroups.day <= 31) {
        return new Date(+dateGroups.year, +dateGroups.month - 1, +dateGroups.day, 12);
      }
    }
  }
  if (!vm.isTypeMonth) return new Date(Date.parse(date));
  if (date) {
    const s = date.split("/");
    const year = s[0].length === 4 ? s[0] : s[1];
    const month = s[0].length === 2 ? s[0] : s[1];
    if (year && month) {
      return new Date(parseInt(year, 10), parseInt(month, 10) - 1, 1, 0, 0, 0, 0);
    }
  }
  return null;
};
var _sfc_main = vue.defineComponent({
  name: "BDatepicker",
  components: {
    BDatepickerTable,
    BDatepickerMonth,
    BInput: Input.BInput,
    BField: Field.Field,
    BSelect: Select.BSelect,
    BIcon: Icon.BIcon,
    BDropdown: Dropdown.BDropdown,
    BDropdownItem: DropdownItem.BDropdownItem
  },
  mixins: [CompatFallthroughMixin.CompatFallthroughMixin, FormElementMixin.FormElementMixin],
  provide() {
    return {
      $datepicker: this
    };
  },
  props: {
    modelValue: {
      type: [Date, Array, null]
    },
    dayNames: {
      type: [Array, null],
      default: () => {
        if (!Array.isArray(config.config.defaultDayNames)) {
          return void 0;
        }
        return config.config.defaultDayNames;
      }
    },
    monthNames: {
      type: [Array, null],
      default: () => {
        if (!Array.isArray(config.config.defaultMonthNames)) {
          return void 0;
        }
        return config.config.defaultMonthNames;
      }
    },
    firstDayOfWeek: {
      type: Number,
      default: () => {
        if (typeof config.config.defaultFirstDayOfWeek === "number") {
          return config.config.defaultFirstDayOfWeek;
        } else {
          return 0;
        }
      }
    },
    inline: Boolean,
    minDate: [Date, null],
    maxDate: [Date, null],
    focusedDate: Date,
    placeholder: String,
    editable: Boolean,
    disabled: Boolean,
    horizontalTimePicker: Boolean,
    unselectableDates: [Array, Function],
    unselectableDaysOfWeek: {
      type: [Array, null],
      default: () => config.config.defaultUnselectableDaysOfWeek
    },
    selectableDates: [Array, Function],
    dateFormatter: {
      type: Function,
      default: (date, vm) => {
        if (typeof config.config.defaultDateFormatter === "function") {
          return config.config.defaultDateFormatter(date);
        } else {
          return defaultDateFormatter(date, vm);
        }
      }
    },
    dateParser: {
      type: Function,
      default: (date, vm) => {
        if (typeof config.config.defaultDateParser === "function") {
          return config.config.defaultDateParser(date);
        } else {
          return defaultDateParser(date, vm);
        }
      }
    },
    dateCreator: {
      type: Function,
      default: () => {
        if (typeof config.config.defaultDateCreator === "function") {
          return config.config.defaultDateCreator();
        } else {
          return /* @__PURE__ */ new Date();
        }
      }
    },
    mobileNative: {
      type: Boolean,
      default: () => config.config.defaultDatepickerMobileNative
    },
    position: String,
    iconRight: String,
    iconRightClickable: Boolean,
    events: Array,
    indicators: {
      type: String,
      default: "dots"
    },
    openOnFocus: Boolean,
    iconPrev: {
      type: String,
      default: () => config.config.defaultIconPrev
    },
    iconNext: {
      type: String,
      default: () => config.config.defaultIconNext
    },
    yearsRange: {
      type: Array,
      default: () => config.config.defaultDatepickerYearsRange
    },
    type: {
      type: String,
      validator: (value) => {
        return [
          "month"
        ].indexOf(value) >= 0;
      }
    },
    nearbyMonthDays: {
      type: Boolean,
      default: () => config.config.defaultDatepickerNearbyMonthDays
    },
    nearbySelectableMonthDays: {
      type: Boolean,
      default: () => config.config.defaultDatepickerNearbySelectableMonthDays
    },
    showWeekNumber: {
      type: Boolean,
      default: () => config.config.defaultDatepickerShowWeekNumber
    },
    weekNumberClickable: {
      type: Boolean,
      default: () => config.config.defaultDatepickerWeekNumberClickable
    },
    rulesForFirstWeek: {
      type: Number,
      default: () => 4
    },
    range: {
      type: Boolean,
      default: false
    },
    closeOnClick: {
      type: Boolean,
      default: true
    },
    multiple: {
      type: Boolean,
      default: false
    },
    mobileModal: {
      type: Boolean,
      default: () => config.config.defaultDatepickerMobileModal
    },
    focusable: {
      type: Boolean,
      default: true
    },
    trapFocus: {
      type: Boolean,
      default: () => config.config.defaultTrapFocus
    },
    appendToBody: Boolean,
    ariaNextLabel: String,
    ariaPreviousLabel: String
  },
  emits: {
    /* eslint-disable @typescript-eslint/no-unused-vars */
    "active-change": (_active) => true,
    "change-month": (_month) => true,
    "change-year": (_year) => true,
    "icon-right-click": (_event) => true,
    "range-end": (_date) => true,
    "range-start": (_date) => true,
    "update:modelValue": (_value) => true,
    "week-number-click": (_week, _year) => true
    // emitted by `DatepickerTableRow`
    /* eslint-enable @typescript-eslint/no-unused-vars */
  },
  data() {
    const focusedDate = (Array.isArray(this.modelValue) ? this.modelValue[0] : this.modelValue) || this.focusedDate || this.dateCreator();
    if (!this.modelValue && this.maxDate && this.maxDate.getFullYear() < focusedDate.getFullYear()) {
      focusedDate.setFullYear(this.maxDate.getFullYear());
    }
    return {
      dateSelected: this.modelValue,
      focusedDateData: {
        day: focusedDate.getDate(),
        month: focusedDate.getMonth(),
        year: focusedDate.getFullYear()
      },
      _elementRef: "input",
      _isDatepicker: true
    };
  },
  computed: {
    computedValue: {
      get() {
        return this.dateSelected;
      },
      set(value) {
        this.updateInternalState(value);
        if (!this.multiple) this.togglePicker(false);
        this.$emit("update:modelValue", value);
        if (this.useHtml5Validation) {
          this.$nextTick(() => {
            this.checkHtml5Validity();
          });
        }
      }
    },
    formattedValue() {
      return this.formatValue(this.computedValue);
    },
    localeOptions() {
      return new Intl.DateTimeFormat(this.locale, {
        year: "numeric",
        month: "numeric"
      }).resolvedOptions();
    },
    dtf() {
      return new Intl.DateTimeFormat(this.locale);
    },
    dtfMonth() {
      return new Intl.DateTimeFormat(this.locale, {
        year: this.localeOptions.year || "numeric",
        month: this.localeOptions.month || "2-digit"
      });
    },
    newMonthNames() {
      if (Array.isArray(this.monthNames)) {
        return this.monthNames;
      }
      return helpers.getMonthNames(this.locale);
    },
    newDayNames() {
      if (Array.isArray(this.dayNames)) {
        return this.dayNames;
      }
      return helpers.getWeekdayNames(this.locale);
    },
    listOfMonths() {
      let minMonth = 0;
      let maxMonth = 12;
      if (this.minDate && this.focusedDateData.year === this.minDate.getFullYear()) {
        minMonth = this.minDate.getMonth();
      }
      if (this.maxDate && this.focusedDateData.year === this.maxDate.getFullYear()) {
        maxMonth = this.maxDate.getMonth();
      }
      return this.newMonthNames.map((name, index) => {
        return {
          name,
          index,
          disabled: index < minMonth || index > maxMonth
        };
      });
    },
    /*
     * Returns an array of years for the year dropdown. If earliest/latest
     * dates are set by props, range of years will fall within those dates.
     */
    listOfYears() {
      let latestYear = this.focusedDateData.year + this.yearsRange[1];
      if (this.maxDate && this.maxDate.getFullYear() < latestYear) {
        latestYear = Math.max(this.maxDate.getFullYear(), this.focusedDateData.year);
      }
      let earliestYear = this.focusedDateData.year + this.yearsRange[0];
      if (this.minDate && this.minDate.getFullYear() > earliestYear) {
        earliestYear = Math.min(this.minDate.getFullYear(), this.focusedDateData.year);
      }
      const arrayOfYears = [];
      for (let i = earliestYear; i <= latestYear; i++) {
        arrayOfYears.push(i);
      }
      return arrayOfYears.reverse();
    },
    showPrev() {
      if (!this.minDate) return false;
      if (this.isTypeMonth) {
        return this.focusedDateData.year <= this.minDate.getFullYear();
      }
      const dateToCheck = new Date(this.focusedDateData.year, this.focusedDateData.month);
      const date = new Date(this.minDate.getFullYear(), this.minDate.getMonth());
      return dateToCheck <= date;
    },
    showNext() {
      if (!this.maxDate) return false;
      if (this.isTypeMonth) {
        return this.focusedDateData.year >= this.maxDate.getFullYear();
      }
      const dateToCheck = new Date(this.focusedDateData.year, this.focusedDateData.month);
      const date = new Date(this.maxDate.getFullYear(), this.maxDate.getMonth());
      return dateToCheck >= date;
    },
    isMobile() {
      return this.mobileNative && helpers.isMobile.any();
    },
    isTypeMonth() {
      return this.type === "month";
    },
    ariaRole() {
      if (!this.inline) {
        return "dialog";
      } else {
        return void 0;
      }
    },
    disabledOrUndefined() {
      return this.disabled || void 0;
    }
  },
  watch: {
    /*
     * When v-model is changed:
     *   1. Update internal value.
     *   2. If it's invalid, validate again.
     */
    modelValue(value) {
      this.updateInternalState(value);
      if (!this.multiple) this.togglePicker(false);
    },
    focusedDate(value) {
      if (value) {
        this.focusedDateData = {
          day: value.getDate(),
          month: value.getMonth(),
          year: value.getFullYear()
        };
      }
    },
    /*
     * Emit input event on month and/or year change
     */
    "focusedDateData.month"(value) {
      this.$emit("change-month", value);
    },
    "focusedDateData.year"(value) {
      this.$emit("change-year", value);
    }
  },
  methods: {
    /*
     * Parse string into date
     */
    onChange(value) {
      const date = this.dateParser(value, this);
      if (date && (!isNaN(date.valueOf()) || Array.isArray(date) && date.length === 2 && !isNaN(date[0]) && !isNaN(date[1]))) {
        this.computedValue = date;
      } else {
        this.computedValue = null;
        if (this.$refs.input) {
          this.$refs.input.newValue = this.computedValue;
        }
      }
    },
    /*
     * Format date into string
     */
    formatValue(value) {
      if (Array.isArray(value)) {
        const isArrayWithValidDates = Array.isArray(value) && value.every((v) => {
          var _a;
          return !isNaN((_a = v == null ? void 0 : v.valueOf()) != null ? _a : NaN);
        });
        return isArrayWithValidDates ? this.dateFormatter([...value], this) : null;
      }
      return value && !isNaN(value.valueOf()) ? this.dateFormatter(value, this) : null;
    },
    /*
     * Either decrement month by 1 if not January or decrement year by 1
     * and set month to 11 (December) or decrement year when 'month'
     */
    prev() {
      if (this.disabled) return;
      if (this.isTypeMonth) {
        this.focusedDateData.year -= 1;
      } else {
        if (this.focusedDateData.month > 0) {
          this.focusedDateData.month -= 1;
        } else {
          this.focusedDateData.month = 11;
          this.focusedDateData.year -= 1;
        }
      }
    },
    /*
     * Either increment month by 1 if not December or increment year by 1
     * and set month to 0 (January) or increment year when 'month'
     */
    next() {
      if (this.disabled) return;
      if (this.isTypeMonth) {
        this.focusedDateData.year += 1;
      } else {
        if (this.focusedDateData.month < 11) {
          this.focusedDateData.month += 1;
        } else {
          this.focusedDateData.month = 0;
          this.focusedDateData.year += 1;
        }
      }
    },
    formatNative(value) {
      return this.isTypeMonth ? this.formatYYYYMM(value) : this.formatYYYYMMDD(value);
    },
    /*
     * Format date into string 'YYYY-MM-DD'
     */
    formatYYYYMMDD(value) {
      const date = new Date(value);
      if (value && !isNaN(date.valueOf())) {
        const year = date.getFullYear();
        const month = date.getMonth() + 1;
        const day = date.getDate();
        return year + "-" + ((month < 10 ? "0" : "") + month) + "-" + ((day < 10 ? "0" : "") + day);
      }
      return "";
    },
    /*
     * Format date into string 'YYYY-MM'
     */
    formatYYYYMM(value) {
      const date = new Date(value);
      if (value && !isNaN(date.valueOf())) {
        const year = date.getFullYear();
        const month = date.getMonth() + 1;
        return year + "-" + ((month < 10 ? "0" : "") + month);
      }
      return "";
    },
    /*
     * Parse date from string
     */
    onChangeNativePicker(event) {
      const date = event.target.value;
      const s = date ? date.split("-") : [];
      if (s.length === 3) {
        const year = parseInt(s[0], 10);
        const month = parseInt(s[1]) - 1;
        const day = parseInt(s[2]);
        this.computedValue = new Date(year, month, day);
      } else {
        this.computedValue = null;
      }
    },
    updateInternalState(value) {
      if (this.dateSelected === value) return;
      const isArray = Array.isArray(value);
      const currentDate = isArray ? !value.length ? this.dateCreator() : value[value.length - 1] : !value ? this.dateCreator() : value;
      if (!isArray || this.dateSelected && value.length > this.dateSelected.length) {
        this.focusedDateData = {
          day: currentDate.getDate(),
          month: currentDate.getMonth(),
          year: currentDate.getFullYear()
        };
      }
      this.dateSelected = value;
    },
    /*
     * Toggle datepicker
     */
    togglePicker(active) {
      if (this.$refs.dropdown) {
        const isActive = typeof active === "boolean" ? active : !this.$refs.dropdown.isActive;
        if (isActive) {
          this.$refs.dropdown.isActive = isActive;
        } else if (this.closeOnClick) {
          this.$refs.dropdown.isActive = isActive;
        }
      }
    },
    /*
     * Call default onFocus method and show datepicker
     */
    handleOnFocus(event) {
      this.onFocus(event);
      if (this.openOnFocus) {
        this.togglePicker(true);
      }
    },
    /*
     * Toggle dropdown
     */
    toggle() {
      if (this.mobileNative && this.isMobile) {
        const input = this.$refs.input.$refs.input;
        input.focus();
        input.click();
        return;
      }
      this.$refs.dropdown.toggle();
    },
    /*
     * Avoid dropdown toggle when is already visible
     */
    onInputClick(event) {
      if (this.$refs.dropdown.isActive) {
        event.stopPropagation();
      }
    },
    /*
     * Keypress event that is bound to the document.
     */
    keyPress({ key }) {
      if (this.$refs.dropdown && this.$refs.dropdown.isActive && (key === "Escape" || key === "Esc")) {
        this.togglePicker(false);
      }
    },
    /*
     * Emit 'blur' event on dropdown is not active (closed)
     */
    onActiveChange(value) {
      if (!value) {
        this.onBlur();
      }
      this.$emit("active-change", value);
    },
    changeFocus(day) {
      this.focusedDateData = {
        day: day.getDate(),
        month: day.getMonth(),
        year: day.getFullYear()
      };
    }
  },
  created() {
    if (typeof window !== "undefined") {
      document.addEventListener("keyup", this.keyPress);
    }
  },
  beforeUnmount() {
    if (typeof window !== "undefined") {
      document.removeEventListener("keyup", this.keyPress);
    }
  }
});

const _hoisted_1 = { class: "datepicker-header" };
const _hoisted_2 = ["disabled", "aria-label"];
const _hoisted_3 = ["disabled", "aria-label"];
const _hoisted_4 = { class: "pagination-list" };
const _hoisted_5 = ["value", "disabled"];
const _hoisted_6 = ["value"];
const _hoisted_7 = { key: 1 };
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
  const _component_b_input = vue.resolveComponent("b-input");
  const _component_b_icon = vue.resolveComponent("b-icon");
  const _component_b_select = vue.resolveComponent("b-select");
  const _component_b_field = vue.resolveComponent("b-field");
  const _component_b_datepicker_table = vue.resolveComponent("b-datepicker-table");
  const _component_b_datepicker_month = vue.resolveComponent("b-datepicker-month");
  const _component_b_dropdown_item = vue.resolveComponent("b-dropdown-item");
  const _component_b_dropdown = vue.resolveComponent("b-dropdown");
  return vue.openBlock(), vue.createElementBlock(
    "div",
    vue.mergeProps({
      class: ["datepicker control", [_ctx.size, { "is-expanded": _ctx.expanded }]]
    }, _ctx.rootAttrs),
    [
      !_ctx.isMobile || _ctx.inline ? (vue.openBlock(), vue.createBlock(_component_b_dropdown, {
        key: 0,
        ref: "dropdown",
        position: _ctx.position,
        disabled: _ctx.disabledOrUndefined,
        inline: _ctx.inline,
        "mobile-modal": _ctx.mobileModal,
        "trap-focus": _ctx.trapFocus,
        "aria-role": _ctx.ariaRole,
        "append-to-body": _ctx.appendToBody,
        "append-to-body-copy-parent": "",
        onActiveChange: _ctx.onActiveChange,
        "trigger-tabindex": -1
      }, vue.createSlots({
        default: vue.withCtx(() => [
          vue.createVNode(_component_b_dropdown_item, {
            disabled: _ctx.disabledOrUndefined,
            focusable: _ctx.focusable,
            custom: "",
            class: vue.normalizeClass({ "dropdown-horizontal-timepicker": _ctx.horizontalTimePicker })
          }, {
            default: vue.withCtx(() => [
              vue.createElementVNode("div", null, [
                vue.createElementVNode("header", _hoisted_1, [
                  _ctx.$slots.header !== void 0 && _ctx.$slots.header([]).length ? vue.renderSlot(_ctx.$slots, "header", { key: 0 }) : (vue.openBlock(), vue.createElementBlock(
                    "div",
                    {
                      key: 1,
                      class: vue.normalizeClass(["pagination field is-centered", _ctx.size])
                    },
                    [
                      vue.withDirectives(vue.createElementVNode("a", {
                        class: "pagination-previous",
                        role: "button",
                        href: "#",
                        disabled: _ctx.disabledOrUndefined,
                        "aria-label": _ctx.ariaPreviousLabel,
                        onClick: _cache[3] || (_cache[3] = vue.withModifiers((...args) => _ctx.prev && _ctx.prev(...args), ["prevent"])),
                        onKeydown: [
                          _cache[4] || (_cache[4] = vue.withKeys(vue.withModifiers((...args) => _ctx.prev && _ctx.prev(...args), ["prevent"]), ["enter"])),
                          _cache[5] || (_cache[5] = vue.withKeys(vue.withModifiers((...args) => _ctx.prev && _ctx.prev(...args), ["prevent"]), ["space"]))
                        ]
                      }, [
                        vue.createVNode(_component_b_icon, {
                          icon: _ctx.iconPrev,
                          pack: _ctx.iconPack,
                          both: "",
                          type: "is-primary is-clickable"
                        }, null, 8, ["icon", "pack"])
                      ], 40, _hoisted_2), [
                        [vue.vShow, !_ctx.showPrev && !_ctx.disabled]
                      ]),
                      vue.withDirectives(vue.createElementVNode("a", {
                        class: "pagination-next",
                        role: "button",
                        href: "#",
                        disabled: _ctx.disabledOrUndefined,
                        "aria-label": _ctx.ariaNextLabel,
                        onClick: _cache[6] || (_cache[6] = vue.withModifiers((...args) => _ctx.next && _ctx.next(...args), ["prevent"])),
                        onKeydown: [
                          _cache[7] || (_cache[7] = vue.withKeys(vue.withModifiers((...args) => _ctx.next && _ctx.next(...args), ["prevent"]), ["enter"])),
                          _cache[8] || (_cache[8] = vue.withKeys(vue.withModifiers((...args) => _ctx.next && _ctx.next(...args), ["prevent"]), ["space"]))
                        ]
                      }, [
                        vue.createVNode(_component_b_icon, {
                          icon: _ctx.iconNext,
                          pack: _ctx.iconPack,
                          both: "",
                          type: "is-primary is-clickable"
                        }, null, 8, ["icon", "pack"])
                      ], 40, _hoisted_3), [
                        [vue.vShow, !_ctx.showNext && !_ctx.disabled]
                      ]),
                      vue.createElementVNode("div", _hoisted_4, [
                        vue.createVNode(_component_b_field, null, {
                          default: vue.withCtx(() => [
                            !_ctx.isTypeMonth ? (vue.openBlock(), vue.createBlock(_component_b_select, {
                              key: 0,
                              modelValue: _ctx.focusedDateData.month,
                              "onUpdate:modelValue": _cache[9] || (_cache[9] = ($event) => _ctx.focusedDateData.month = $event),
                              disabled: _ctx.disabledOrUndefined,
                              size: _ctx.size
                            }, {
                              default: vue.withCtx(() => [
                                (vue.openBlock(true), vue.createElementBlock(
                                  vue.Fragment,
                                  null,
                                  vue.renderList(_ctx.listOfMonths, (month) => {
                                    return vue.openBlock(), vue.createElementBlock("option", {
                                      value: month.index,
                                      key: month.name,
                                      disabled: month.disabled || void 0
                                    }, vue.toDisplayString(month.name), 9, _hoisted_5);
                                  }),
                                  128
                                  /* KEYED_FRAGMENT */
                                ))
                              ]),
                              _: 1
                              /* STABLE */
                            }, 8, ["modelValue", "disabled", "size"])) : vue.createCommentVNode("v-if", true),
                            vue.createVNode(_component_b_select, {
                              modelValue: _ctx.focusedDateData.year,
                              "onUpdate:modelValue": _cache[10] || (_cache[10] = ($event) => _ctx.focusedDateData.year = $event),
                              disabled: _ctx.disabledOrUndefined,
                              size: _ctx.size
                            }, {
                              default: vue.withCtx(() => [
                                (vue.openBlock(true), vue.createElementBlock(
                                  vue.Fragment,
                                  null,
                                  vue.renderList(_ctx.listOfYears, (year) => {
                                    return vue.openBlock(), vue.createElementBlock("option", {
                                      value: year,
                                      key: year
                                    }, vue.toDisplayString(year), 9, _hoisted_6);
                                  }),
                                  128
                                  /* KEYED_FRAGMENT */
                                ))
                              ]),
                              _: 1
                              /* STABLE */
                            }, 8, ["modelValue", "disabled", "size"])
                          ]),
                          _: 1
                          /* STABLE */
                        })
                      ])
                    ],
                    2
                    /* CLASS */
                  ))
                ]),
                !_ctx.isTypeMonth ? (vue.openBlock(), vue.createElementBlock(
                  "div",
                  {
                    key: 0,
                    class: vue.normalizeClass(["datepicker-content", { "content-horizontal-timepicker": _ctx.horizontalTimePicker }])
                  },
                  [
                    vue.createVNode(_component_b_datepicker_table, {
                      modelValue: _ctx.computedValue,
                      "onUpdate:modelValue": _cache[11] || (_cache[11] = ($event) => _ctx.computedValue = $event),
                      "day-names": _ctx.newDayNames,
                      "month-names": _ctx.newMonthNames,
                      "first-day-of-week": _ctx.firstDayOfWeek,
                      "rules-for-first-week": _ctx.rulesForFirstWeek,
                      "min-date": _ctx.minDate,
                      "max-date": _ctx.maxDate,
                      focused: _ctx.focusedDateData,
                      disabled: _ctx.disabledOrUndefined,
                      "unselectable-dates": _ctx.unselectableDates,
                      "unselectable-days-of-week": _ctx.unselectableDaysOfWeek,
                      "selectable-dates": _ctx.selectableDates,
                      events: _ctx.events,
                      indicators: _ctx.indicators,
                      "date-creator": _ctx.dateCreator,
                      "type-month": _ctx.isTypeMonth,
                      "nearby-month-days": _ctx.nearbyMonthDays,
                      "nearby-selectable-month-days": _ctx.nearbySelectableMonthDays,
                      "show-week-number": _ctx.showWeekNumber,
                      "week-number-clickable": _ctx.weekNumberClickable,
                      range: _ctx.range,
                      multiple: _ctx.multiple,
                      onRangeStart: _cache[12] || (_cache[12] = (date) => _ctx.$emit("range-start", date)),
                      onRangeEnd: _cache[13] || (_cache[13] = (date) => _ctx.$emit("range-end", date)),
                      onClose: _cache[14] || (_cache[14] = ($event) => _ctx.togglePicker(false)),
                      "onUpdate:focused": _cache[15] || (_cache[15] = ($event) => _ctx.focusedDateData = $event)
                    }, null, 8, ["modelValue", "day-names", "month-names", "first-day-of-week", "rules-for-first-week", "min-date", "max-date", "focused", "disabled", "unselectable-dates", "unselectable-days-of-week", "selectable-dates", "events", "indicators", "date-creator", "type-month", "nearby-month-days", "nearby-selectable-month-days", "show-week-number", "week-number-clickable", "range", "multiple"])
                  ],
                  2
                  /* CLASS */
                )) : (vue.openBlock(), vue.createElementBlock("div", _hoisted_7, [
                  vue.createVNode(_component_b_datepicker_month, {
                    modelValue: _ctx.computedValue,
                    "onUpdate:modelValue": _cache[16] || (_cache[16] = ($event) => _ctx.computedValue = $event),
                    "month-names": _ctx.newMonthNames,
                    "min-date": _ctx.minDate,
                    "max-date": _ctx.maxDate,
                    focused: _ctx.focusedDateData,
                    disabled: _ctx.disabledOrUndefined,
                    "unselectable-dates": _ctx.unselectableDates,
                    "unselectable-days-of-week": _ctx.unselectableDaysOfWeek,
                    "selectable-dates": _ctx.selectableDates,
                    events: _ctx.events,
                    indicators: _ctx.indicators,
                    "date-creator": _ctx.dateCreator,
                    range: _ctx.range,
                    multiple: _ctx.multiple,
                    onRangeStart: _cache[17] || (_cache[17] = (date) => _ctx.$emit("range-start", date)),
                    onRangeEnd: _cache[18] || (_cache[18] = (date) => _ctx.$emit("range-end", date)),
                    onClose: _cache[19] || (_cache[19] = ($event) => _ctx.togglePicker(false)),
                    onChangeFocus: _ctx.changeFocus,
                    "onUpdate:focused": _cache[20] || (_cache[20] = ($event) => _ctx.focusedDateData = $event)
                  }, null, 8, ["modelValue", "month-names", "min-date", "max-date", "focused", "disabled", "unselectable-dates", "unselectable-days-of-week", "selectable-dates", "events", "indicators", "date-creator", "range", "multiple", "onChangeFocus"])
                ]))
              ]),
              _ctx.$slots.default !== void 0 && _ctx.$slots.default([]).length ? (vue.openBlock(), vue.createElementBlock(
                "footer",
                {
                  key: 0,
                  class: vue.normalizeClass(["datepicker-footer", { "footer-horizontal-timepicker": _ctx.horizontalTimePicker }])
                },
                [
                  vue.renderSlot(_ctx.$slots, "default")
                ],
                2
                /* CLASS */
              )) : vue.createCommentVNode("v-if", true)
            ]),
            _: 3
            /* FORWARDED */
          }, 8, ["disabled", "focusable", "class"])
        ]),
        _: 2
        /* DYNAMIC */
      }, [
        !_ctx.inline ? {
          name: "trigger",
          fn: vue.withCtx((props) => [
            vue.renderSlot(_ctx.$slots, "trigger", vue.normalizeProps(vue.guardReactiveProps(props)), () => [
              vue.createVNode(_component_b_input, vue.mergeProps({
                ref: "input",
                autocomplete: "off",
                "model-value": _ctx.formattedValue,
                placeholder: _ctx.placeholder,
                size: _ctx.size,
                icon: _ctx.icon,
                "icon-right": _ctx.iconRight,
                "icon-right-clickable": _ctx.iconRightClickable,
                "icon-pack": _ctx.iconPack,
                rounded: _ctx.rounded,
                loading: _ctx.loading,
                disabled: _ctx.disabledOrUndefined,
                readonly: !_ctx.editable
              }, _ctx.fallthroughAttrs, {
                "use-html5-validation": false,
                onClick: _ctx.onInputClick,
                onIconRightClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("icon-right-click", $event)),
                onKeyup: _cache[1] || (_cache[1] = vue.withKeys(($event) => _ctx.togglePicker(true), ["enter"])),
                onChange: _cache[2] || (_cache[2] = ($event) => _ctx.onChange($event.target.value)),
                onFocus: _ctx.handleOnFocus
              }), null, 16, ["model-value", "placeholder", "size", "icon", "icon-right", "icon-right-clickable", "icon-pack", "rounded", "loading", "disabled", "readonly", "onClick", "onFocus"])
            ])
          ]),
          key: "0"
        } : void 0
      ]), 1032, ["position", "disabled", "inline", "mobile-modal", "trap-focus", "aria-role", "append-to-body", "onActiveChange"])) : (vue.openBlock(), vue.createBlock(_component_b_input, vue.mergeProps({
        key: 1,
        ref: "input",
        type: !_ctx.isTypeMonth ? "date" : "month",
        autocomplete: "off",
        "model-value": _ctx.formatNative(_ctx.computedValue),
        placeholder: _ctx.placeholder,
        size: _ctx.size,
        icon: _ctx.icon,
        "icon-pack": _ctx.iconPack,
        rounded: _ctx.rounded,
        loading: _ctx.loading,
        max: _ctx.formatNative(_ctx.maxDate),
        min: _ctx.formatNative(_ctx.minDate),
        disabled: _ctx.disabledOrUndefined,
        readonly: false
      }, _ctx.fallthroughAttrs, {
        "use-html5-validation": false,
        onChange: _ctx.onChangeNativePicker,
        onFocus: _ctx.onFocus,
        onBlur: _ctx.onBlur
      }), null, 16, ["type", "model-value", "placeholder", "size", "icon", "icon-pack", "rounded", "loading", "max", "min", "disabled", "onChange", "onFocus", "onBlur"]))
    ],
    16
    /* FULL_PROPS */
  );
}
var BDatepicker = /* @__PURE__ */ _pluginVue_exportHelper._export_sfc(_sfc_main, [["render", _sfc_render]]);

exports.BDatepicker = BDatepicker;