/*!
 * BootstrapVue 2.23.1
 *
 * @link https://bootstrap-vue.org
 * @source https://github.com/bootstrap-vue/bootstrap-vue
 * @copyright (c) 2016-2022 BootstrapVue
 * @license MIT
 * https://github.com/bootstrap-vue/bootstrap-vue/blob/master/LICENSE
 */

(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('../vue/vue')) :
  typeof define === 'function' && define.amd ? define(['../vue/vue'], factory) :
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.bootstrapVue = factory(global.Vue));
}(this, (function (Vue) { 'use strict';

  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

  var Vue__default = /*#__PURE__*/_interopDefaultLegacy(Vue);

  function ownKeys(object, enumerableOnly) {
    var keys = Object.keys(object);

    if (Object.getOwnPropertySymbols) {
      var symbols = Object.getOwnPropertySymbols(object);
      enumerableOnly && (symbols = symbols.filter(function (sym) {
        return Object.getOwnPropertyDescriptor(object, sym).enumerable;
      })), keys.push.apply(keys, symbols);
    }

    return keys;
  }

  function _objectSpread2$3(target) {
    for (var i = 1; i < arguments.length; i++) {
      var source = null != arguments[i] ? arguments[i] : {};
      i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {
        _defineProperty(target, key, source[key]);
      }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {
        Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
      });
    }

    return target;
  }

  function _typeof$1(obj) {
    "@babel/helpers - typeof";

    return _typeof$1 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) {
      return typeof obj;
    } : function (obj) {
      return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
    }, _typeof$1(obj);
  }

  function _classCallCheck(instance, Constructor) {
    if (!(instance instanceof Constructor)) {
      throw new TypeError("Cannot call a class as a function");
    }
  }

  function _defineProperties(target, props) {
    for (var i = 0; i < props.length; i++) {
      var descriptor = props[i];
      descriptor.enumerable = descriptor.enumerable || false;
      descriptor.configurable = true;
      if ("value" in descriptor) descriptor.writable = true;
      Object.defineProperty(target, descriptor.key, descriptor);
    }
  }

  function _createClass(Constructor, protoProps, staticProps) {
    if (protoProps) _defineProperties(Constructor.prototype, protoProps);
    if (staticProps) _defineProperties(Constructor, staticProps);
    Object.defineProperty(Constructor, "prototype", {
      writable: false
    });
    return Constructor;
  }

  function _defineProperty(obj, key, value) {
    if (key in obj) {
      Object.defineProperty(obj, key, {
        value: value,
        enumerable: true,
        configurable: true,
        writable: true
      });
    } else {
      obj[key] = value;
    }

    return obj;
  }

  function _inherits(subClass, superClass) {
    if (typeof superClass !== "function" && superClass !== null) {
      throw new TypeError("Super expression must either be null or a function");
    }

    Object.defineProperty(subClass, "prototype", {
      value: Object.create(superClass && superClass.prototype, {
        constructor: {
          value: subClass,
          writable: true,
          configurable: true
        }
      }),
      writable: false
    });
    if (superClass) _setPrototypeOf(subClass, superClass);
  }

  function _getPrototypeOf(o) {
    _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
      return o.__proto__ || Object.getPrototypeOf(o);
    };
    return _getPrototypeOf(o);
  }

  function _setPrototypeOf(o, p) {
    _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
      o.__proto__ = p;
      return o;
    };

    return _setPrototypeOf(o, p);
  }

  function _isNativeReflectConstruct() {
    if (typeof Reflect === "undefined" || !Reflect.construct) return false;
    if (Reflect.construct.sham) return false;
    if (typeof Proxy === "function") return true;

    try {
      Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
      return true;
    } catch (e) {
      return false;
    }
  }

  function _construct(Parent, args, Class) {
    if (_isNativeReflectConstruct()) {
      _construct = Reflect.construct;
    } else {
      _construct = function _construct(Parent, args, Class) {
        var a = [null];
        a.push.apply(a, args);
        var Constructor = Function.bind.apply(Parent, a);
        var instance = new Constructor();
        if (Class) _setPrototypeOf(instance, Class.prototype);
        return instance;
      };
    }

    return _construct.apply(null, arguments);
  }

  function _isNativeFunction(fn) {
    return Function.toString.call(fn).indexOf("[native code]") !== -1;
  }

  function _wrapNativeSuper(Class) {
    var _cache = typeof Map === "function" ? new Map() : undefined;

    _wrapNativeSuper = function _wrapNativeSuper(Class) {
      if (Class === null || !_isNativeFunction(Class)) return Class;

      if (typeof Class !== "function") {
        throw new TypeError("Super expression must either be null or a function");
      }

      if (typeof _cache !== "undefined") {
        if (_cache.has(Class)) return _cache.get(Class);

        _cache.set(Class, Wrapper);
      }

      function Wrapper() {
        return _construct(Class, arguments, _getPrototypeOf(this).constructor);
      }

      Wrapper.prototype = Object.create(Class.prototype, {
        constructor: {
          value: Wrapper,
          enumerable: false,
          writable: true,
          configurable: true
        }
      });
      return _setPrototypeOf(Wrapper, Class);
    };

    return _wrapNativeSuper(Class);
  }

  function _objectWithoutPropertiesLoose(source, excluded) {
    if (source == null) return {};
    var target = {};
    var sourceKeys = Object.keys(source);
    var key, i;

    for (i = 0; i < sourceKeys.length; i++) {
      key = sourceKeys[i];
      if (excluded.indexOf(key) >= 0) continue;
      target[key] = source[key];
    }

    return target;
  }

  function _objectWithoutProperties(source, excluded) {
    if (source == null) return {};

    var target = _objectWithoutPropertiesLoose(source, excluded);

    var key, i;

    if (Object.getOwnPropertySymbols) {
      var sourceSymbolKeys = Object.getOwnPropertySymbols(source);

      for (i = 0; i < sourceSymbolKeys.length; i++) {
        key = sourceSymbolKeys[i];
        if (excluded.indexOf(key) >= 0) continue;
        if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
        target[key] = source[key];
      }
    }

    return target;
  }

  function _assertThisInitialized(self) {
    if (self === void 0) {
      throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
    }

    return self;
  }

  function _possibleConstructorReturn(self, call) {
    if (call && (typeof call === "object" || typeof call === "function")) {
      return call;
    } else if (call !== void 0) {
      throw new TypeError("Derived constructors may only return object or undefined");
    }

    return _assertThisInitialized(self);
  }

  function _createSuper(Derived) {
    var hasNativeReflectConstruct = _isNativeReflectConstruct();

    return function _createSuperInternal() {
      var Super = _getPrototypeOf(Derived),
          result;

      if (hasNativeReflectConstruct) {
        var NewTarget = _getPrototypeOf(this).constructor;

        result = Reflect.construct(Super, arguments, NewTarget);
      } else {
        result = Super.apply(this, arguments);
      }

      return _possibleConstructorReturn(this, result);
    };
  }

  function _superPropBase(object, property) {
    while (!Object.prototype.hasOwnProperty.call(object, property)) {
      object = _getPrototypeOf(object);
      if (object === null) break;
    }

    return object;
  }

  function _get() {
    if (typeof Reflect !== "undefined" && Reflect.get) {
      _get = Reflect.get;
    } else {
      _get = function _get(target, property, receiver) {
        var base = _superPropBase(target, property);

        if (!base) return;
        var desc = Object.getOwnPropertyDescriptor(base, property);

        if (desc.get) {
          return desc.get.call(arguments.length < 3 ? target : receiver);
        }

        return desc.value;
      };
    }

    return _get.apply(this, arguments);
  }

  function _slicedToArray(arr, i) {
    return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
  }

  function _toConsumableArray$1(arr) {
    return _arrayWithoutHoles$1(arr) || _iterableToArray$1(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread$1();
  }

  function _arrayWithoutHoles$1(arr) {
    if (Array.isArray(arr)) return _arrayLikeToArray(arr);
  }

  function _arrayWithHoles(arr) {
    if (Array.isArray(arr)) return arr;
  }

  function _iterableToArray$1(iter) {
    if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
  }

  function _iterableToArrayLimit(arr, i) {
    var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];

    if (_i == null) return;
    var _arr = [];
    var _n = true;
    var _d = false;

    var _s, _e;

    try {
      for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) {
        _arr.push(_s.value);

        if (i && _arr.length === i) break;
      }
    } catch (err) {
      _d = true;
      _e = err;
    } finally {
      try {
        if (!_n && _i["return"] != null) _i["return"]();
      } finally {
        if (_d) throw _e;
      }
    }

    return _arr;
  }

  function _unsupportedIterableToArray(o, minLen) {
    if (!o) return;
    if (typeof o === "string") return _arrayLikeToArray(o, minLen);
    var n = Object.prototype.toString.call(o).slice(8, -1);
    if (n === "Object" && o.constructor) n = o.constructor.name;
    if (n === "Map" || n === "Set") return Array.from(o);
    if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
  }

  function _arrayLikeToArray(arr, len) {
    if (len == null || len > arr.length) len = arr.length;

    for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];

    return arr2;
  }

  function _nonIterableSpread$1() {
    throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
  }

  function _nonIterableRest() {
    throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
  }

  var e=function(){return (e=Object.assign||function(e){for(var t,r=1,s=arguments.length;r<s;r++)for(var a in t=arguments[r])Object.prototype.hasOwnProperty.call(t,a)&&(e[a]=t[a]);return e}).apply(this,arguments)},t={kebab:/-(\w)/g,styleProp:/:(.*)/,styleList:/;(?![^(]*\))/g};function r(e,t){return t?t.toUpperCase():""}function s(e){for(var s,a={},c=0,o=e.split(t.styleList);c<o.length;c++){var n=o[c].split(t.styleProp),i=n[0],l=n[1];(i=i.trim())&&("string"==typeof l&&(l=l.trim()),a[(s=i,s.replace(t.kebab,r))]=l);}return a}function a(){for(var t,r,a={},c=arguments.length;c--;)for(var o=0,n=Object.keys(arguments[c]);o<n.length;o++)switch(t=n[o]){case"class":case"style":case"directives":if(Array.isArray(a[t])||(a[t]=[]),"style"===t){var i=void 0;i=Array.isArray(arguments[c].style)?arguments[c].style:[arguments[c].style];for(var l=0;l<i.length;l++){var y=i[l];"string"==typeof y&&(i[l]=s(y));}arguments[c].style=i;}a[t]=a[t].concat(arguments[c][t]);break;case"staticClass":if(!arguments[c][t])break;void 0===a[t]&&(a[t]=""),a[t]&&(a[t]+=" "),a[t]+=arguments[c][t].trim();break;case"on":case"nativeOn":a[t]||(a[t]={});for(var p=0,f=Object.keys(arguments[c][t]||{});p<f.length;p++)r=f[p],a[t][r]?a[t][r]=[].concat(a[t][r],arguments[c][t][r]):a[t][r]=arguments[c][t][r];break;case"attrs":case"props":case"domProps":case"scopedSlots":case"staticStyle":case"hook":case"transition":a[t]||(a[t]={}),a[t]=e({},arguments[c][t],a[t]);break;case"slot":case"key":case"ref":case"tag":case"show":case"keepAlive":default:a[t]||(a[t]=arguments[c][t]);}return a}

  var COMPONENT_UID_KEY = '_uid';
  var isVue3 = Vue__default['default'].version.startsWith('3');
  var REF_FOR_KEY = isVue3 ? 'ref_for' : 'refInFor';
  var ALLOWED_FIELDS_IN_DATA = ['class', 'staticClass', 'style', 'attrs', 'props', 'domProps', 'on', 'nativeOn', 'directives', 'scopedSlots', 'slot', 'key', 'ref', 'refInFor'];
  var extend = Vue__default['default'].extend.bind(Vue__default['default']);

  if (isVue3) {
    var originalExtend = Vue__default['default'].extend;
    var KNOWN_COMPONENTS = ['router-link', 'transition', 'transition-group'];
    var originalVModelDynamicCreated = Vue__default['default'].vModelDynamic.created;
    var originalVModelDynamicBeforeUpdate = Vue__default['default'].vModelDynamic.beforeUpdate; // See https://github.com/vuejs/vue-next/pull/4121 for details

    Vue__default['default'].vModelDynamic.created = function (el, binding, vnode) {
      originalVModelDynamicCreated.call(this, el, binding, vnode);

      if (!el._assign) {
        el._assign = function () {};
      }
    };

    Vue__default['default'].vModelDynamic.beforeUpdate = function (el, binding, vnode) {
      originalVModelDynamicBeforeUpdate.call(this, el, binding, vnode);

      if (!el._assign) {
        el._assign = function () {};
      }
    };

    extend = function patchedBootstrapVueExtend(definition) {
      if (_typeof$1(definition) === 'object' && definition.render && !definition.__alreadyPatched) {
        var originalRender = definition.render;
        definition.__alreadyPatched = true;

        definition.render = function (h) {
          var patchedH = function patchedH(tag, dataObjOrChildren, rawSlots) {
            var slots = rawSlots === undefined ? [] : [Array.isArray(rawSlots) ? rawSlots.filter(Boolean) : rawSlots];
            var isTag = typeof tag === 'string' && !KNOWN_COMPONENTS.includes(tag);
            var isSecondArgumentDataObject = dataObjOrChildren && _typeof$1(dataObjOrChildren) === 'object' && !Array.isArray(dataObjOrChildren);

            if (!isSecondArgumentDataObject) {
              return h.apply(void 0, [tag, dataObjOrChildren].concat(slots));
            }

            var attrs = dataObjOrChildren.attrs,
                props = dataObjOrChildren.props,
                restData = _objectWithoutProperties(dataObjOrChildren, ["attrs", "props"]);

            var normalizedData = _objectSpread2$3(_objectSpread2$3({}, restData), {}, {
              attrs: attrs,
              props: isTag ? {} : props
            });

            if (tag === 'router-link' && !normalizedData.slots && !normalizedData.scopedSlots) {
              // terrible workaround to fix router-link rendering with compat vue-router
              normalizedData.scopedSlots = {
                $hasNormal: function $hasNormal() {}
              };
            }

            return h.apply(void 0, [tag, normalizedData].concat(slots));
          };

          if (definition.functional) {
            var _ctx$children, _ctx$children$default;

            var ctx = arguments[1];

            var patchedCtx = _objectSpread2$3({}, ctx);

            patchedCtx.data = {
              attrs: _objectSpread2$3({}, ctx.data.attrs || {}),
              props: _objectSpread2$3({}, ctx.data.props || {})
            };
            Object.keys(ctx.data || {}).forEach(function (key) {
              if (ALLOWED_FIELDS_IN_DATA.includes(key)) {
                patchedCtx.data[key] = ctx.data[key];
              } else if (key in ctx.props) {
                patchedCtx.data.props[key] = ctx.data[key];
              } else if (!key.startsWith('on')) {
                patchedCtx.data.attrs[key] = ctx.data[key];
              }
            });
            var IGNORED_CHILDREN_KEYS = ['_ctx'];
            var children = ((_ctx$children = ctx.children) === null || _ctx$children === void 0 ? void 0 : (_ctx$children$default = _ctx$children.default) === null || _ctx$children$default === void 0 ? void 0 : _ctx$children$default.call(_ctx$children)) || ctx.children;

            if (children && Object.keys(patchedCtx.children).filter(function (k) {
              return !IGNORED_CHILDREN_KEYS.includes(k);
            }).length === 0) {
              delete patchedCtx.children;
            } else {
              patchedCtx.children = children;
            }

            patchedCtx.data.on = ctx.listeners;
            return originalRender.call(this, patchedH, patchedCtx);
          }

          return originalRender.call(this, patchedH);
        };
      }

      return originalExtend.call(this, definition);
    }.bind(Vue__default['default']);
  }

  var nextTick = Vue__default['default'].nextTick;

  var HAS_WINDOW_SUPPORT = typeof window !== 'undefined';
  var HAS_DOCUMENT_SUPPORT = typeof document !== 'undefined';
  var HAS_NAVIGATOR_SUPPORT = typeof navigator !== 'undefined';
  var HAS_PROMISE_SUPPORT = typeof Promise !== 'undefined';
  /* istanbul ignore next: JSDOM always returns false */

  var HAS_MUTATION_OBSERVER_SUPPORT = typeof MutationObserver !== 'undefined' || typeof WebKitMutationObserver !== 'undefined' || typeof MozMutationObserver !== 'undefined';
  var IS_BROWSER = HAS_WINDOW_SUPPORT && HAS_DOCUMENT_SUPPORT && HAS_NAVIGATOR_SUPPORT;
  var WINDOW = HAS_WINDOW_SUPPORT ? window : {};
  var DOCUMENT = HAS_DOCUMENT_SUPPORT ? document : {};
  var NAVIGATOR = HAS_NAVIGATOR_SUPPORT ? navigator : {};
  var USER_AGENT = (NAVIGATOR.userAgent || '').toLowerCase();
  var IS_JSDOM = USER_AGENT.indexOf('jsdom') > 0;
  /msie|trident/.test(USER_AGENT); // Determine if the browser supports the option passive for events

  var HAS_PASSIVE_EVENT_SUPPORT = function () {
    var passiveEventSupported = false;

    if (IS_BROWSER) {
      try {
        var options = {
          // This function will be called when the browser
          // attempts to access the passive property
          get passive() {
            /* istanbul ignore next: will never be called in JSDOM */
            passiveEventSupported = true;
          }

        };
        WINDOW.addEventListener('test', options, options);
        WINDOW.removeEventListener('test', options, options);
      } catch (_unused) {
        /* istanbul ignore next: will never be called in JSDOM */
        passiveEventSupported = false;
      }
    }

    return passiveEventSupported;
  }();
  var HAS_TOUCH_SUPPORT = IS_BROWSER && ('ontouchstart' in DOCUMENT.documentElement || NAVIGATOR.maxTouchPoints > 0);
  var HAS_POINTER_EVENT_SUPPORT = IS_BROWSER && Boolean(WINDOW.PointerEvent || WINDOW.MSPointerEvent);
  /* istanbul ignore next: JSDOM only checks for 'IntersectionObserver' */

  var HAS_INTERACTION_OBSERVER_SUPPORT = IS_BROWSER && 'IntersectionObserver' in WINDOW && 'IntersectionObserverEntry' in WINDOW && // Edge 15 and UC Browser lack support for `isIntersecting`
  // but we an use `intersectionRatio > 0` instead
  // 'isIntersecting' in window.IntersectionObserverEntry.prototype &&
  'intersectionRatio' in WINDOW.IntersectionObserverEntry.prototype;

  var NAME$2 = 'BvConfig';
  var PROP_NAME$2 = '$bvConfig';
  var DEFAULT_BREAKPOINT = ['xs', 'sm', 'md', 'lg', 'xl'];

  // --- General ---
  var RX_ARRAY_NOTATION = /\[(\d+)]/g;
  var RX_BV_PREFIX = /^(BV?)/;
  var RX_DIGITS = /^\d+$/;
  var RX_EXTENSION = /^\..+/;
  var RX_HASH = /^#/;
  var RX_HASH_ID = /^#[A-Za-z]+[\w\-:.]*$/;
  var RX_HTML_TAGS = /(<([^>]+)>)/gi;
  var RX_HYPHENATE = /\B([A-Z])/g;
  var RX_LOWER_UPPER = /([a-z])([A-Z])/g;
  var RX_NUMBER = /^[0-9]*\.?[0-9]+$/;
  var RX_PLUS = /\+/g;
  var RX_REGEXP_REPLACE = /[-/\\^$*+?.()|[\]{}]/g;
  var RX_SPACES = /[\s\uFEFF\xA0]+/g;
  var RX_SPACE_SPLIT = /\s+/;
  var RX_STAR = /\/\*$/;
  var RX_START_SPACE_WORD = /(\s|^)(\w)/g;
  var RX_TRIM_LEFT = /^\s+/;
  var RX_UNDERSCORE = /_/g;
  var RX_UN_KEBAB = /-(\w)/g; // --- Date ---
  // Loose YYYY-MM-DD matching, ignores any appended time inforation
  // Matches '1999-12-20', '1999-1-1', '1999-01-20T22:51:49.118Z', '1999-01-02 13:00:00'

  var RX_DATE = /^\d+-\d\d?-\d\d?(?:\s|T|$)/; // Used to split off the date parts of the YYYY-MM-DD string

  var RX_DATE_SPLIT = /-|\s|T/; // Time string RegEx (optional seconds)

  var RX_TIME = /^([0-1]?[0-9]|2[0-3]):[0-5]?[0-9](:[0-5]?[0-9])?$/; // --- URL ---
  // HREFs must end with a hash followed by at least one non-hash character

  var RX_HREF = /^.*(#[^#]+)$/;
  var RX_ENCODED_COMMA = /%2C/g;
  var RX_ENCODE_REVERSE = /[!'()*]/g;
  var RX_QUERY_START = /^(\?|#|&)/; // --- Aspect ---

  var RX_ASPECT = /^\d+(\.\d*)?[/:]\d+(\.\d*)?$/;
  var RX_ASPECT_SEPARATOR = /[/:]/; // --- Grid ---

  var RX_COL_CLASS = /^col-/; // --- Icon ---

  var RX_ICON_PREFIX = /^BIcon/; // --- Locale ---

  var RX_STRIP_LOCALE_MODS = /-u-.+/;

  /* istanbul ignore next */

  var Element = HAS_WINDOW_SUPPORT ? WINDOW.Element : /*#__PURE__*/function (_Object) {
    _inherits(Element, _Object);

    var _super = _createSuper(Element);

    function Element() {
      _classCallCheck(this, Element);

      return _super.apply(this, arguments);
    }

    return Element;
  }( /*#__PURE__*/_wrapNativeSuper(Object));
  /* istanbul ignore next */

  var HTMLElement = HAS_WINDOW_SUPPORT ? WINDOW.HTMLElement : /*#__PURE__*/function (_Element) {
    _inherits(HTMLElement, _Element);

    var _super2 = _createSuper(HTMLElement);

    function HTMLElement() {
      _classCallCheck(this, HTMLElement);

      return _super2.apply(this, arguments);
    }

    return HTMLElement;
  }(Element);
  /* istanbul ignore next */

  var SVGElement = HAS_WINDOW_SUPPORT ? WINDOW.SVGElement : /*#__PURE__*/function (_Element2) {
    _inherits(SVGElement, _Element2);

    var _super3 = _createSuper(SVGElement);

    function SVGElement() {
      _classCallCheck(this, SVGElement);

      return _super3.apply(this, arguments);
    }

    return SVGElement;
  }(Element);
  /* istanbul ignore next */

  var File = HAS_WINDOW_SUPPORT ? WINDOW.File : /*#__PURE__*/function (_Object2) {
    _inherits(File, _Object2);

    var _super4 = _createSuper(File);

    function File() {
      _classCallCheck(this, File);

      return _super4.apply(this, arguments);
    }

    return File;
  }( /*#__PURE__*/_wrapNativeSuper(Object));

  var toType$1 = function toType(value) {
    return _typeof$1(value);
  };
  var toRawType = function toRawType(value) {
    return Object.prototype.toString.call(value).slice(8, -1);
  };
  var isUndefined = function isUndefined(value) {
    return value === undefined;
  };
  var isNull = function isNull(value) {
    return value === null;
  };
  var isUndefinedOrNull = function isUndefinedOrNull(value) {
    return isUndefined(value) || isNull(value);
  };
  var isFunction$1 = function isFunction(value) {
    return toType$1(value) === 'function';
  };
  var isBoolean = function isBoolean(value) {
    return toType$1(value) === 'boolean';
  };
  var isString = function isString(value) {
    return toType$1(value) === 'string';
  };
  var isNumber = function isNumber(value) {
    return toType$1(value) === 'number';
  };
  var isNumeric$1 = function isNumeric(value) {
    return RX_NUMBER.test(String(value));
  };
  var isArray = function isArray(value) {
    return Array.isArray(value);
  }; // Quick object check
  // This is primarily used to tell Objects from primitive values
  // when we know the value is a JSON-compliant type
  // Note object could be a complex type like array, Date, etc.

  var isObject = function isObject(obj) {
    return obj !== null && _typeof$1(obj) === 'object';
  }; // Strict object type check
  // Only returns true for plain JavaScript objects

  var isPlainObject = function isPlainObject(obj) {
    return Object.prototype.toString.call(obj) === '[object Object]';
  };
  var isDate = function isDate(value) {
    return value instanceof Date;
  };
  var isEvent = function isEvent(value) {
    return value instanceof Event;
  };
  var isFile = function isFile(value) {
    return value instanceof File;
  };
  var isRegExp = function isRegExp(value) {
    return toRawType(value) === 'RegExp';
  };
  var isPromise = function isPromise(value) {
    return !isUndefinedOrNull(value) && isFunction$1(value.then) && isFunction$1(value.catch);
  };

  var assign = function assign() {
    return Object.assign.apply(Object, arguments);
  };
  var create = function create(proto, optionalProps) {
    return Object.create(proto, optionalProps);
  };
  var defineProperties = function defineProperties(obj, props) {
    return Object.defineProperties(obj, props);
  };
  var defineProperty$1 = function defineProperty(obj, prop, descriptor) {
    return Object.defineProperty(obj, prop, descriptor);
  };
  var getOwnPropertyNames = function getOwnPropertyNames(obj) {
    return Object.getOwnPropertyNames(obj);
  };
  var keys = function keys(obj) {
    return Object.keys(obj);
  }; // --- "Instance" ---

  var hasOwnProperty = function hasOwnProperty(obj, prop) {
    return Object.prototype.hasOwnProperty.call(obj, prop);
  };
  var toString$1 = function toString(obj) {
    return Object.prototype.toString.call(obj);
  }; // --- Utilities ---
  // Shallow copy an object

  var clone = function clone(obj) {
    return _objectSpread2$3({}, obj);
  }; // Return a shallow copy of object with the specified properties only
  // See: https://gist.github.com/bisubus/2da8af7e801ffd813fab7ac221aa7afc

  var pick$1 = function pick(obj, props) {
    return keys(obj).filter(function (key) {
      return props.indexOf(key) !== -1;
    }).reduce(function (result, key) {
      return _objectSpread2$3(_objectSpread2$3({}, result), {}, _defineProperty({}, key, obj[key]));
    }, {});
  }; // Return a shallow copy of object with the specified properties omitted
  // See: https://gist.github.com/bisubus/2da8af7e801ffd813fab7ac221aa7afc

  var omit = function omit(obj, props) {
    return keys(obj).filter(function (key) {
      return props.indexOf(key) === -1;
    }).reduce(function (result, key) {
      return _objectSpread2$3(_objectSpread2$3({}, result), {}, _defineProperty({}, key, obj[key]));
    }, {});
  }; // Merges two object deeply together
  // See: https://gist.github.com/Salakar/1d7137de9cb8b704e48a

  var mergeDeep = function mergeDeep(target, source) {
    if (isObject(target) && isObject(source)) {
      keys(source).forEach(function (key) {
        if (isObject(source[key])) {
          if (!target[key] || !isObject(target[key])) {
            target[key] = source[key];
          }

          mergeDeep(target[key], source[key]);
        } else {
          assign(target, _defineProperty({}, key, source[key]));
        }
      });
    }

    return target;
  }; // Returns a shallow copy of the object with keys in sorted order

  var sortKeys = function sortKeys(obj) {
    return keys(obj).sort().reduce(function (result, key) {
      return _objectSpread2$3(_objectSpread2$3({}, result), {}, _defineProperty({}, key, obj[key]));
    }, {});
  }; // Convenience method to create a read-only descriptor

  var readonlyDescriptor = function readonlyDescriptor() {
    return {
      enumerable: true,
      configurable: false,
      writable: false
    };
  };

  var cloneDeep = function cloneDeep(obj) {
    var defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : obj;

    if (isArray(obj)) {
      return obj.reduce(function (result, val) {
        return [].concat(_toConsumableArray$1(result), [cloneDeep(val, val)]);
      }, []);
    }

    if (isPlainObject(obj)) {
      return keys(obj).reduce(function (result, key) {
        return _objectSpread2$3(_objectSpread2$3({}, result), {}, _defineProperty({}, key, cloneDeep(obj[key], obj[key])));
      }, {});
    }

    return defaultValue;
  };

  var identity = function identity(x) {
    return x;
  };

  /**
   * Get property defined by dot/array notation in string, returns undefined if not found
   *
   * @link https://gist.github.com/jeneg/9767afdcca45601ea44930ea03e0febf#gistcomment-1935901
   *
   * @param {Object} obj
   * @param {string|Array} path
   * @return {*}
   */

  var getRaw = function getRaw(obj, path) {
    var defaultValue = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
    // Handle array of path values
    path = isArray(path) ? path.join('.') : path; // If no path or no object passed

    if (!path || !isObject(obj)) {
      return defaultValue;
    } // Handle edge case where user has dot(s) in top-level item field key
    // See https://github.com/bootstrap-vue/bootstrap-vue/issues/2762
    // Switched to `in` operator vs `hasOwnProperty` to handle obj.prototype getters
    // https://github.com/bootstrap-vue/bootstrap-vue/issues/3463


    if (path in obj) {
      return obj[path];
    } // Handle string array notation (numeric indices only)


    path = String(path).replace(RX_ARRAY_NOTATION, '.$1');
    var steps = path.split('.').filter(identity); // Handle case where someone passes a string of only dots

    if (steps.length === 0) {
      return defaultValue;
    } // Traverse path in object to find result
    // Switched to `in` operator vs `hasOwnProperty` to handle obj.prototype getters
    // https://github.com/bootstrap-vue/bootstrap-vue/issues/3463


    return steps.every(function (step) {
      return isObject(obj) && step in obj && !isUndefinedOrNull(obj = obj[step]);
    }) ? obj : isNull(obj) ? null : defaultValue;
  };
  /**
   * Get property defined by dot/array notation in string.
   *
   * @link https://gist.github.com/jeneg/9767afdcca45601ea44930ea03e0febf#gistcomment-1935901
   *
   * @param {Object} obj
   * @param {string|Array} path
   * @param {*} defaultValue (optional)
   * @return {*}
   */

  var get = function get(obj, path) {
    var defaultValue = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
    var value = getRaw(obj, path);
    return isUndefinedOrNull(value) ? defaultValue : value;
  };

  /**
   * Utilities to get information about the current environment
   */
  var getEnv = function getEnv(key) {
    var fallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
    var env = typeof process !== 'undefined' && process ? process.env || {} : {};

    if (!key) {
      /* istanbul ignore next */
      return env;
    }

    return env[key] || fallback;
  };
  var getNoWarn = function getNoWarn() {
    return getEnv('BOOTSTRAP_VUE_NO_WARN') || getEnv('NODE_ENV') === 'production';
  };

  /**
   * Log a warning message to the console with BootstrapVue formatting
   * @param {string} message
   */

  var warn = function warn(message)
  /* istanbul ignore next */
  {
    var source = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;

    if (!getNoWarn()) {
      console.warn("[BootstrapVue warn]: ".concat(source ? "".concat(source, " - ") : '').concat(message));
    }
  };
  /**
   * Warn when no Promise support is given
   * @param {string} source
   * @returns {boolean} warned
   */

  var warnNotClient = function warnNotClient(source) {
    /* istanbul ignore else */
    if (IS_BROWSER) {
      return false;
    } else {
      warn("".concat(source, ": Can not be called during SSR."));
      return true;
    }
  };
  /**
   * Warn when no Promise support is given
   * @param {string} source
   * @returns {boolean} warned
   */

  var warnNoPromiseSupport = function warnNoPromiseSupport(source) {
    /* istanbul ignore else */
    if (HAS_PROMISE_SUPPORT) {
      return false;
    } else {
      warn("".concat(source, ": Requires Promise support."));
      return true;
    }
  };
  /**
   * Warn when no MutationObserver support is given
   * @param {string} source
   * @returns {boolean} warned
   */

  var warnNoMutationObserverSupport = function warnNoMutationObserverSupport(source) {
    /* istanbul ignore else */
    if (HAS_MUTATION_OBSERVER_SUPPORT) {
      return false;
    } else {
      warn("".concat(source, ": Requires MutationObserver support."));
      return true;
    }
  };

  var BvConfig = /*#__PURE__*/function () {
    function BvConfig() {
      _classCallCheck(this, BvConfig);

      this.$_config = {};
    } // Method to merge in user config parameters


    _createClass(BvConfig, [{
      key: "setConfig",
      value: function setConfig() {
        var _this = this;

        var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

        /* istanbul ignore next */
        if (!isPlainObject(config)) {
          return;
        }

        var configKeys = getOwnPropertyNames(config);
        configKeys.forEach(function (key) {
          /* istanbul ignore next */
          var subConfig = config[key];

          if (key === 'breakpoints') {
            /* istanbul ignore if */
            if (!isArray(subConfig) || subConfig.length < 2 || subConfig.some(function (b) {
              return !isString(b) || b.length === 0;
            })) {
              warn('"breakpoints" must be an array of at least 2 breakpoint names', NAME$2);
            } else {
              _this.$_config[key] = cloneDeep(subConfig);
            }
          } else if (isPlainObject(subConfig)) {
            // Component prop defaults
            _this.$_config[key] = getOwnPropertyNames(subConfig).reduce(function (config, prop) {
              if (!isUndefined(subConfig[prop])) {
                config[prop] = cloneDeep(subConfig[prop]);
              }

              return config;
            }, _this.$_config[key] || {});
          }
        });
      } // Clear the config

    }, {
      key: "resetConfig",
      value: function resetConfig() {
        this.$_config = {};
      } // Returns a deep copy of the user config

    }, {
      key: "getConfig",
      value: function getConfig() {
        return cloneDeep(this.$_config);
      } // Returns a deep copy of the config value

    }, {
      key: "getConfigValue",
      value: function getConfigValue(key) {
        var defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
        return cloneDeep(getRaw(this.$_config, key, defaultValue));
      }
    }]);

    return BvConfig;
  }(); // Method for applying a global config


  var setConfig = function setConfig() {
    var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
    var Vue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Vue__default['default'];
    // Ensure we have a `$bvConfig` Object on the Vue prototype
    // We set on Vue and OurVue just in case consumer has not set an alias of `vue`
    Vue.prototype[PROP_NAME$2] = Vue__default['default'].prototype[PROP_NAME$2] = Vue.prototype[PROP_NAME$2] || Vue__default['default'].prototype[PROP_NAME$2] || new BvConfig(); // Apply the config values

    Vue.prototype[PROP_NAME$2].setConfig(config);
  }; // Method for resetting the user config

  /**
   * Checks if there are multiple instances of Vue, and warns (once) about possible issues.
   * @param {object} Vue
   */

  var checkMultipleVue = function () {
    var checkMultipleVueWarned = false;
    var MULTIPLE_VUE_WARNING = ['Multiple instances of Vue detected!', 'You may need to set up an alias for Vue in your bundler config.', 'See: https://bootstrap-vue.org/docs#using-module-bundlers'].join('\n');
    return function (Vue) {
      /* istanbul ignore next */
      if (!checkMultipleVueWarned && Vue__default['default'] !== Vue && !IS_JSDOM) {
        warn(MULTIPLE_VUE_WARNING);
      }

      checkMultipleVueWarned = true;
    };
  }();
  /**
   * Plugin install factory function.
   * @param {object} { components, directives }
   * @returns {function} plugin install function
   */

  var installFactory = function installFactory() {
    var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
        components = _ref.components,
        directives = _ref.directives,
        plugins = _ref.plugins;

    var install = function install(Vue) {
      var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

      if (install.installed) {
        /* istanbul ignore next */
        return;
      }

      install.installed = true;
      checkMultipleVue(Vue);
      setConfig(config, Vue);
      registerComponents(Vue, components);
      registerDirectives(Vue, directives);
      registerPlugins(Vue, plugins);
    };

    install.installed = false;
    return install;
  };
  /**
   * Plugin object factory function.
   * @param {object} { components, directives, plugins }
   * @returns {object} plugin install object
   */

  var pluginFactory = function pluginFactory() {
    var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
    var extend = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
    return _objectSpread2$3(_objectSpread2$3({}, extend), {}, {
      install: installFactory(options)
    });
  };
  /**
   * Load a group of plugins.
   * @param {object} Vue
   * @param {object} Plugin definitions
   */

  var registerPlugins = function registerPlugins(Vue) {
    var plugins = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

    for (var plugin in plugins) {
      if (plugin && plugins[plugin]) {
        Vue.use(plugins[plugin]);
      }
    }
  };
  /**
   * Load a component.
   * @param {object} Vue
   * @param {string} Component name
   * @param {object} Component definition
   */

  var registerComponent = function registerComponent(Vue, name, def) {
    if (Vue && name && def) {
      Vue.component(name, def);
    }
  };
  /**
   * Load a group of components.
   * @param {object} Vue
   * @param {object} Object of component definitions
   */

  var registerComponents = function registerComponents(Vue) {
    var components = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

    for (var component in components) {
      registerComponent(Vue, component, components[component]);
    }
  };
  /**
   * Load a directive.
   * @param {object} Vue
   * @param {string} Directive name
   * @param {object} Directive definition
   */

  var registerDirective = function registerDirective(Vue, name, def) {
    if (Vue && name && def) {
      // Ensure that any leading V is removed from the
      // name, as Vue adds it automatically
      Vue.directive(name.replace(/^VB/, 'B'), def);
    }
  };
  /**
   * Load a group of directives.
   * @param {object} Vue
   * @param {object} Object of directive definitions
   */

  var registerDirectives = function registerDirectives(Vue) {
    var directives = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

    for (var directive in directives) {
      registerDirective(Vue, directive, directives[directive]);
    }
  };
  /**
   * Install plugin if window.Vue available
   * @param {object} Plugin definition
   */

  var vueUse = function vueUse(VuePlugin) {
    /* istanbul ignore next */
    if (HAS_WINDOW_SUPPORT && window.Vue) {
      window.Vue.use(VuePlugin);
    }
    /* istanbul ignore next */


    if (HAS_WINDOW_SUPPORT && VuePlugin.NAME) {
      window[VuePlugin.NAME] = VuePlugin;
    }
  };

  // Component names
  var NAME_ALERT = 'BAlert';
  var NAME_ASPECT = 'BAspect';
  var NAME_AVATAR = 'BAvatar';
  var NAME_AVATAR_GROUP = 'BAvatarGroup';
  var NAME_BADGE = 'BBadge';
  var NAME_BREADCRUMB = 'BBreadcrumb';
  var NAME_BREADCRUMB_ITEM = 'BBreadcrumbItem';
  var NAME_BREADCRUMB_LINK = 'BBreadcrumbLink';
  var NAME_BUTTON = 'BButton';
  var NAME_BUTTON_CLOSE = 'BButtonClose';
  var NAME_BUTTON_GROUP = 'BButtonGroup';
  var NAME_BUTTON_TOOLBAR = 'BButtonToolbar';
  var NAME_CALENDAR = 'BCalendar';
  var NAME_CARD = 'BCard';
  var NAME_CARD_BODY = 'BCardBody';
  var NAME_CARD_FOOTER = 'BCardFooter';
  var NAME_CARD_GROUP = 'BCardGroup';
  var NAME_CARD_HEADER = 'BCardHeader';
  var NAME_CARD_IMG = 'BCardImg';
  var NAME_CARD_IMG_LAZY = 'BCardImgLazy';
  var NAME_CARD_SUB_TITLE = 'BCardSubTitle';
  var NAME_CARD_TEXT = 'BCardText';
  var NAME_CARD_TITLE = 'BCardTitle';
  var NAME_CAROUSEL = 'BCarousel';
  var NAME_CAROUSEL_SLIDE = 'BCarouselSlide';
  var NAME_COL = 'BCol';
  var NAME_COLLAPSE = 'BCollapse';
  var NAME_CONTAINER = 'BContainer';
  var NAME_DROPDOWN = 'BDropdown';
  var NAME_DROPDOWN_DIVIDER = 'BDropdownDivider';
  var NAME_DROPDOWN_FORM = 'BDropdownForm';
  var NAME_DROPDOWN_GROUP = 'BDropdownGroup';
  var NAME_DROPDOWN_HEADER = 'BDropdownHeader';
  var NAME_DROPDOWN_ITEM = 'BDropdownItem';
  var NAME_DROPDOWN_ITEM_BUTTON = 'BDropdownItemButton';
  var NAME_DROPDOWN_TEXT = 'BDropdownText';
  var NAME_EMBED = 'BEmbed';
  var NAME_FORM = 'BForm';
  var NAME_FORM_CHECKBOX = 'BFormCheckbox';
  var NAME_FORM_CHECKBOX_GROUP = 'BFormCheckboxGroup';
  var NAME_FORM_DATALIST = 'BFormDatalist';
  var NAME_FORM_DATEPICKER = 'BFormDatepicker';
  var NAME_FORM_FILE = 'BFormFile';
  var NAME_FORM_GROUP = 'BFormGroup';
  var NAME_FORM_INPUT = 'BFormInput';
  var NAME_FORM_INVALID_FEEDBACK = 'BFormInvalidFeedback';
  var NAME_FORM_RADIO = 'BFormRadio';
  var NAME_FORM_RADIO_GROUP = 'BFormRadioGroup';
  var NAME_FORM_RATING = 'BFormRating';
  var NAME_FORM_ROW = 'BFormRow';
  var NAME_FORM_SELECT = 'BFormSelect';
  var NAME_FORM_SELECT_OPTION = 'BFormSelectOption';
  var NAME_FORM_SELECT_OPTION_GROUP = 'BFormSelectOptionGroup';
  var NAME_FORM_SPINBUTTON = 'BFormSpinbutton';
  var NAME_FORM_TAG = 'BFormTag';
  var NAME_FORM_TAGS = 'BFormTags';
  var NAME_FORM_TEXT = 'BFormText';
  var NAME_FORM_TEXTAREA = 'BFormTextarea';
  var NAME_FORM_TIMEPICKER = 'BFormTimepicker';
  var NAME_FORM_VALID_FEEDBACK = 'BFormValidFeedback';
  var NAME_ICON = 'BIcon';
  var NAME_ICONSTACK = 'BIconstack';
  var NAME_ICON_BASE = 'BIconBase';
  var NAME_IMG = 'BImg';
  var NAME_IMG_LAZY = 'BImgLazy';
  var NAME_INPUT_GROUP = 'BInputGroup';
  var NAME_INPUT_GROUP_ADDON = 'BInputGroupAddon';
  var NAME_INPUT_GROUP_APPEND = 'BInputGroupAppend';
  var NAME_INPUT_GROUP_PREPEND = 'BInputGroupPrepend';
  var NAME_INPUT_GROUP_TEXT = 'BInputGroupText';
  var NAME_JUMBOTRON = 'BJumbotron';
  var NAME_LINK = 'BLink';
  var NAME_LIST_GROUP = 'BListGroup';
  var NAME_LIST_GROUP_ITEM = 'BListGroupItem';
  var NAME_MEDIA = 'BMedia';
  var NAME_MEDIA_ASIDE = 'BMediaAside';
  var NAME_MEDIA_BODY = 'BMediaBody';
  var NAME_MODAL = 'BModal';
  var NAME_MSG_BOX = 'BMsgBox';
  var NAME_NAV = 'BNav';
  var NAME_NAVBAR = 'BNavbar';
  var NAME_NAVBAR_BRAND = 'BNavbarBrand';
  var NAME_NAVBAR_NAV = 'BNavbarNav';
  var NAME_NAVBAR_TOGGLE = 'BNavbarToggle';
  var NAME_NAV_FORM = 'BNavForm';
  var NAME_NAV_ITEM = 'BNavItem';
  var NAME_NAV_ITEM_DROPDOWN = 'BNavItemDropdown';
  var NAME_NAV_TEXT = 'BNavText';
  var NAME_OVERLAY = 'BOverlay';
  var NAME_PAGINATION = 'BPagination';
  var NAME_PAGINATION_NAV = 'BPaginationNav';
  var NAME_POPOVER = 'BPopover';
  var NAME_PROGRESS = 'BProgress';
  var NAME_PROGRESS_BAR = 'BProgressBar';
  var NAME_ROW = 'BRow';
  var NAME_SIDEBAR = 'BSidebar';
  var NAME_SKELETON = 'BSkeleton';
  var NAME_SKELETON_ICON = 'BSkeletonIcon';
  var NAME_SKELETON_IMG = 'BSkeletonImg';
  var NAME_SKELETON_TABLE = 'BSkeletonTable';
  var NAME_SKELETON_WRAPPER = 'BSkeletonWrapper';
  var NAME_SPINNER = 'BSpinner';
  var NAME_TAB = 'BTab';
  var NAME_TABLE = 'BTable';
  var NAME_TABLE_CELL = 'BTableCell';
  var NAME_TABLE_LITE = 'BTableLite';
  var NAME_TABLE_SIMPLE = 'BTableSimple';
  var NAME_TABS = 'BTabs';
  var NAME_TBODY = 'BTbody';
  var NAME_TFOOT = 'BTfoot';
  var NAME_TH = 'BTh';
  var NAME_THEAD = 'BThead';
  var NAME_TIME = 'BTime';
  var NAME_TOAST = 'BToast';
  var NAME_TOASTER = 'BToaster';
  var NAME_TOOLTIP = 'BTooltip';
  var NAME_TR = 'BTr'; // Helper component names

  var NAME_COLLAPSE_HELPER = 'BVCollapse';
  var NAME_FORM_BUTTON_LABEL_CONTROL = 'BVFormBtnLabelControl';
  var NAME_FORM_RATING_STAR = 'BVFormRatingStar';
  var NAME_POPOVER_HELPER = 'BVPopover';
  var NAME_POPOVER_TEMPLATE = 'BVPopoverTemplate';
  var NAME_POPPER = 'BVPopper';
  var NAME_TAB_BUTTON_HELPER = 'BVTabButton';
  var NAME_TOAST_POP = 'BVToastPop';
  var NAME_TOOLTIP_HELPER = 'BVTooltip';
  var NAME_TOOLTIP_TEMPLATE = 'BVTooltipTemplate';
  var NAME_TRANSITION = 'BVTransition';
  var NAME_TRANSPORTER = 'BVTransporter';
  var NAME_TRANSPORTER_TARGET = 'BVTransporterTarget';

  var EVENT_NAME_ACTIVATE_TAB = 'activate-tab';
  var EVENT_NAME_BLUR = 'blur';
  var EVENT_NAME_CANCEL = 'cancel';
  var EVENT_NAME_CHANGE = 'change';
  var EVENT_NAME_CHANGED = 'changed';
  var EVENT_NAME_CLICK = 'click';
  var EVENT_NAME_CLOSE = 'close';
  var EVENT_NAME_CONTEXT = 'context';
  var EVENT_NAME_CONTEXT_CHANGED = 'context-changed';
  var EVENT_NAME_DESTROYED = 'destroyed';
  var EVENT_NAME_DISABLE = 'disable';
  var EVENT_NAME_DISABLED = 'disabled';
  var EVENT_NAME_DISMISSED = 'dismissed';
  var EVENT_NAME_DISMISS_COUNT_DOWN = 'dismiss-count-down';
  var EVENT_NAME_ENABLE = 'enable';
  var EVENT_NAME_ENABLED = 'enabled';
  var EVENT_NAME_FILTERED = 'filtered';
  var EVENT_NAME_FIRST = 'first';
  var EVENT_NAME_FOCUS = 'focus';
  var EVENT_NAME_FOCUSIN = 'focusin';
  var EVENT_NAME_FOCUSOUT = 'focusout';
  var EVENT_NAME_HEAD_CLICKED = 'head-clicked';
  var EVENT_NAME_HIDDEN = 'hidden';
  var EVENT_NAME_HIDE = 'hide';
  var EVENT_NAME_IMG_ERROR = 'img-error';
  var EVENT_NAME_INPUT = 'input';
  var EVENT_NAME_LAST = 'last';
  var EVENT_NAME_MOUSEENTER = 'mouseenter';
  var EVENT_NAME_MOUSELEAVE = 'mouseleave';
  var EVENT_NAME_NEXT = 'next';
  var EVENT_NAME_OK = 'ok';
  var EVENT_NAME_OPEN = 'open';
  var EVENT_NAME_PAGE_CLICK = 'page-click';
  var EVENT_NAME_PAUSED = 'paused';
  var EVENT_NAME_PREV = 'prev';
  var EVENT_NAME_REFRESH = 'refresh';
  var EVENT_NAME_REFRESHED = 'refreshed';
  var EVENT_NAME_REMOVE = 'remove';
  var EVENT_NAME_ROW_CLICKED = 'row-clicked';
  var EVENT_NAME_ROW_CONTEXTMENU = 'row-contextmenu';
  var EVENT_NAME_ROW_DBLCLICKED = 'row-dblclicked';
  var EVENT_NAME_ROW_HOVERED = 'row-hovered';
  var EVENT_NAME_ROW_MIDDLE_CLICKED = 'row-middle-clicked';
  var EVENT_NAME_ROW_SELECTED = 'row-selected';
  var EVENT_NAME_ROW_UNHOVERED = 'row-unhovered';
  var EVENT_NAME_SELECTED = 'selected';
  var EVENT_NAME_SHOW = 'show';
  var EVENT_NAME_SHOWN = 'shown';
  var EVENT_NAME_SLIDING_END = 'sliding-end';
  var EVENT_NAME_SLIDING_START = 'sliding-start';
  var EVENT_NAME_SORT_CHANGED = 'sort-changed';
  var EVENT_NAME_TAG_STATE = 'tag-state';
  var EVENT_NAME_TOGGLE = 'toggle';
  var EVENT_NAME_UNPAUSED = 'unpaused';
  var EVENT_NAME_UPDATE = 'update';
  var HOOK_EVENT_NAME_BEFORE_DESTROY = isVue3 ? 'vnodeBeforeUnmount' : 'hook:beforeDestroy';
  var HOOK_EVENT_NAME_DESTROYED = isVue3 ? 'vNodeUnmounted' : 'hook:destroyed';
  var MODEL_EVENT_NAME_PREFIX = 'update:';
  var ROOT_EVENT_NAME_PREFIX = 'bv';
  var ROOT_EVENT_NAME_SEPARATOR = '::';
  var EVENT_OPTIONS_PASSIVE = {
    passive: true
  };
  var EVENT_OPTIONS_NO_CAPTURE = {
    passive: true,
    capture: false
  };

  // General types
  var PROP_TYPE_ANY = undefined;
  var PROP_TYPE_ARRAY = Array;
  var PROP_TYPE_BOOLEAN = Boolean;
  var PROP_TYPE_DATE = Date;
  var PROP_TYPE_FUNCTION = Function;
  var PROP_TYPE_NUMBER = Number;
  var PROP_TYPE_OBJECT = Object;
  var PROP_TYPE_REG_EXP = RegExp;
  var PROP_TYPE_STRING = String; // Multiple types

  var PROP_TYPE_ARRAY_FUNCTION = [PROP_TYPE_ARRAY, PROP_TYPE_FUNCTION];
  var PROP_TYPE_ARRAY_OBJECT = [PROP_TYPE_ARRAY, PROP_TYPE_OBJECT];
  var PROP_TYPE_ARRAY_OBJECT_STRING = [PROP_TYPE_ARRAY, PROP_TYPE_OBJECT, PROP_TYPE_STRING];
  var PROP_TYPE_ARRAY_STRING = [PROP_TYPE_ARRAY, PROP_TYPE_STRING];
  var PROP_TYPE_BOOLEAN_NUMBER = [PROP_TYPE_BOOLEAN, PROP_TYPE_NUMBER];
  var PROP_TYPE_BOOLEAN_NUMBER_STRING = [PROP_TYPE_BOOLEAN, PROP_TYPE_NUMBER, PROP_TYPE_STRING];
  var PROP_TYPE_BOOLEAN_STRING = [PROP_TYPE_BOOLEAN, PROP_TYPE_STRING];
  var PROP_TYPE_DATE_STRING = [PROP_TYPE_DATE, PROP_TYPE_STRING];
  var PROP_TYPE_FUNCTION_STRING = [PROP_TYPE_FUNCTION, PROP_TYPE_STRING];
  var PROP_TYPE_NUMBER_STRING = [PROP_TYPE_NUMBER, PROP_TYPE_STRING];
  var PROP_TYPE_NUMBER_OBJECT_STRING = [PROP_TYPE_NUMBER, PROP_TYPE_OBJECT, PROP_TYPE_STRING];
  var PROP_TYPE_OBJECT_FUNCTION = [PROP_TYPE_OBJECT, PROP_TYPE_FUNCTION];
  var PROP_TYPE_OBJECT_STRING = [PROP_TYPE_OBJECT, PROP_TYPE_STRING];

  var SLOT_NAME_ADD_BUTTON_TEXT = 'add-button-text';
  var SLOT_NAME_APPEND = 'append';
  var SLOT_NAME_ASIDE = 'aside';
  var SLOT_NAME_BADGE = 'badge';
  var SLOT_NAME_BOTTOM_ROW = 'bottom-row';
  var SLOT_NAME_BUTTON_CONTENT = 'button-content';
  var SLOT_NAME_CUSTOM_FOOT = 'custom-foot';
  var SLOT_NAME_DECREMENT = 'decrement';
  var SLOT_NAME_DEFAULT = 'default';
  var SLOT_NAME_DESCRIPTION = 'description';
  var SLOT_NAME_DISMISS = 'dismiss';
  var SLOT_NAME_DROP_PLACEHOLDER = 'drop-placeholder';
  var SLOT_NAME_ELLIPSIS_TEXT = 'ellipsis-text';
  var SLOT_NAME_EMPTY = 'empty';
  var SLOT_NAME_EMPTYFILTERED = 'emptyfiltered';
  var SLOT_NAME_FILE_NAME = 'file-name';
  var SLOT_NAME_FIRST = 'first';
  var SLOT_NAME_FIRST_TEXT = 'first-text';
  var SLOT_NAME_FOOTER = 'footer';
  var SLOT_NAME_HEADER = 'header';
  var SLOT_NAME_HEADER_CLOSE = 'header-close';
  var SLOT_NAME_ICON_CLEAR = 'icon-clear';
  var SLOT_NAME_ICON_EMPTY = 'icon-empty';
  var SLOT_NAME_ICON_FULL = 'icon-full';
  var SLOT_NAME_ICON_HALF = 'icon-half';
  var SLOT_NAME_IMG = 'img';
  var SLOT_NAME_INCREMENT = 'increment';
  var SLOT_NAME_INVALID_FEEDBACK = 'invalid-feedback';
  var SLOT_NAME_LABEL = 'label';
  var SLOT_NAME_LAST_TEXT = 'last-text';
  var SLOT_NAME_LEAD = 'lead';
  var SLOT_NAME_LOADING = 'loading';
  var SLOT_NAME_MODAL_BACKDROP = 'modal-backdrop';
  var SLOT_NAME_MODAL_CANCEL = 'modal-cancel';
  var SLOT_NAME_MODAL_FOOTER = 'modal-footer';
  var SLOT_NAME_MODAL_HEADER = 'modal-header';
  var SLOT_NAME_MODAL_HEADER_CLOSE = 'modal-header-close';
  var SLOT_NAME_MODAL_OK = 'modal-ok';
  var SLOT_NAME_MODAL_TITLE = 'modal-title';
  var SLOT_NAME_NAV_NEXT_DECADE = 'nav-next-decade';
  var SLOT_NAME_NAV_NEXT_MONTH = 'nav-next-month';
  var SLOT_NAME_NAV_NEXT_YEAR = 'nav-next-year';
  var SLOT_NAME_NAV_PEV_DECADE = 'nav-prev-decade';
  var SLOT_NAME_NAV_PEV_MONTH = 'nav-prev-month';
  var SLOT_NAME_NAV_PEV_YEAR = 'nav-prev-year';
  var SLOT_NAME_NAV_THIS_MONTH = 'nav-this-month';
  var SLOT_NAME_NEXT_TEXT = 'next-text';
  var SLOT_NAME_OVERLAY = 'overlay';
  var SLOT_NAME_PAGE = 'page';
  var SLOT_NAME_PLACEHOLDER = 'placeholder';
  var SLOT_NAME_PREPEND = 'prepend';
  var SLOT_NAME_PREV_TEXT = 'prev-text';
  var SLOT_NAME_ROW_DETAILS = 'row-details';
  var SLOT_NAME_TABLE_BUSY = 'table-busy';
  var SLOT_NAME_TABLE_CAPTION = 'table-caption';
  var SLOT_NAME_TABLE_COLGROUP = 'table-colgroup';
  var SLOT_NAME_TABS_END = 'tabs-end';
  var SLOT_NAME_TABS_START = 'tabs-start';
  var SLOT_NAME_TEXT = 'text';
  var SLOT_NAME_THEAD_TOP = 'thead-top';
  var SLOT_NAME_TITLE = 'title';
  var SLOT_NAME_TOAST_TITLE = 'toast-title';
  var SLOT_NAME_TOP_ROW = 'top-row';
  var SLOT_NAME_VALID_FEEDBACK = 'valid-feedback';

  var from = function from() {
    return Array.from.apply(Array, arguments);
  }; // --- Instance ---

  var arrayIncludes = function arrayIncludes(array, value) {
    return array.indexOf(value) !== -1;
  };
  var concat = function concat() {
    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
      args[_key] = arguments[_key];
    }

    return Array.prototype.concat.apply([], args);
  }; // --- Utilities ---

  var createArray = function createArray(length, fillFn) {
    var mapFn = isFunction$1(fillFn) ? fillFn : function () {
      return fillFn;
    };
    return Array.apply(null, {
      length: length
    }).map(mapFn);
  };
  var flatten = function flatten(array) {
    return array.reduce(function (result, item) {
      return concat(result, item);
    }, []);
  };
  var flattenDeep = function flattenDeep(array) {
    return array.reduce(function (result, item) {
      return concat(result, Array.isArray(item) ? flattenDeep(item) : item);
    }, []);
  };

  // In functional components, `slots` is a function so it must be called
  // first before passing to the below methods. `scopedSlots` is always an
  // object and may be undefined (for Vue < 2.6.x)

  /**
   * Returns true if either scoped or unscoped named slot exists
   *
   * @param {String, Array} name or name[]
   * @param {Object} scopedSlots
   * @param {Object} slots
   * @returns {Array|undefined} VNodes
   */

  var hasNormalizedSlot = function hasNormalizedSlot(names) {
    var $scopedSlots = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
    var $slots = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
    // Ensure names is an array
    names = concat(names).filter(identity); // Returns true if the either a $scopedSlot or $slot exists with the specified name

    return names.some(function (name) {
      return $scopedSlots[name] || $slots[name];
    });
  };
  /**
   * Returns VNodes for named slot either scoped or unscoped
   *
   * @param {String, Array} name or name[]
   * @param {String} scope
   * @param {Object} scopedSlots
   * @param {Object} slots
   * @returns {Array|undefined} VNodes
   */

  var normalizeSlot = function normalizeSlot(names) {
    var scope = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
    var $scopedSlots = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
    var $slots = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
    // Ensure names is an array
    names = concat(names).filter(identity);
    var slot;

    for (var i = 0; i < names.length && !slot; i++) {
      var name = names[i];
      slot = $scopedSlots[name] || $slots[name];
    } // Note: in Vue 2.6.x, all named slots are also scoped slots


    return isFunction$1(slot) ? slot(scope) : slot;
  };

  var normalizeSlotMixin = extend({
    methods: {
      // Returns `true` if the either a `$scopedSlot` or `$slot` exists with the specified name
      // `name` can be a string name or an array of names
      hasNormalizedSlot: function hasNormalizedSlot$1() {
        var name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : SLOT_NAME_DEFAULT;
        var scopedSlots = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.$scopedSlots;
        var slots = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.$slots;
        return hasNormalizedSlot(name, scopedSlots, slots);
      },
      // Returns an array of rendered VNodes if slot found, otherwise `undefined`
      // `name` can be a string name or an array of names
      normalizeSlot: function normalizeSlot$1() {
        var name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : SLOT_NAME_DEFAULT;
        var scope = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
        var scopedSlots = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.$scopedSlots;
        var slots = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : this.$slots;

        var vNodes = normalizeSlot(name, scope, scopedSlots, slots);

        return vNodes ? concat(vNodes) : vNodes;
      }
    }
  });

  // Number utilities
  // Converts a value (string, number, etc.) to an integer number
  // Assumes radix base 10
  var toInteger = function toInteger(value) {
    var defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : NaN;
    var integer = parseInt(value, 10);
    return isNaN(integer) ? defaultValue : integer;
  }; // Converts a value (string, number, etc.) to a number

  var toFloat = function toFloat(value) {
    var defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : NaN;
    var float = parseFloat(value);
    return isNaN(float) ? defaultValue : float;
  }; // Converts a value (string, number, etc.) to a string
  // representation with `precision` digits after the decimal
  // Returns the string 'NaN' if the value cannot be converted

  var toFixed = function toFixed(val, precision) {
    return toFloat(val).toFixed(toInteger(precision, 0));
  };

  // String utilities
  // Converts PascalCase or camelCase to kebab-case

  var kebabCase = function kebabCase(str) {
    return str.replace(RX_HYPHENATE, '-$1').toLowerCase();
  }; // Converts a kebab-case or camelCase string to PascalCase

  var pascalCase = function pascalCase(str) {
    str = kebabCase(str).replace(RX_UN_KEBAB, function (_, c) {
      return c ? c.toUpperCase() : '';
    });
    return str.charAt(0).toUpperCase() + str.slice(1);
  }; // Converts a string, including strings in camelCase or snake_case, into Start Case
  // It keeps original single quote and hyphen in the word
  // https://github.com/UrbanCompass/to-start-case

  var startCase = function startCase(str) {
    return str.replace(RX_UNDERSCORE, ' ').replace(RX_LOWER_UPPER, function (str, $1, $2) {
      return $1 + ' ' + $2;
    }).replace(RX_START_SPACE_WORD, function (str, $1, $2) {
      return $1 + $2.toUpperCase();
    });
  }; // Lowercases the first letter of a string and returns a new string

  var lowerFirst = function lowerFirst(str) {
    str = isString(str) ? str.trim() : String(str);
    return str.charAt(0).toLowerCase() + str.slice(1);
  }; // Uppercases the first letter of a string and returns a new string

  var upperFirst = function upperFirst(str) {
    str = isString(str) ? str.trim() : String(str);
    return str.charAt(0).toUpperCase() + str.slice(1);
  }; // Escape characters to be used in building a regular expression

  var escapeRegExp = function escapeRegExp(str) {
    return str.replace(RX_REGEXP_REPLACE, '\\$&');
  }; // Convert a value to a string that can be rendered
  // `undefined`/`null` will be converted to `''`
  // Plain objects and arrays will be JSON stringified

  var toString = function toString(val) {
    var spaces = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 2;
    return isUndefinedOrNull(val) ? '' : isArray(val) || isPlainObject(val) && val.toString === Object.prototype.toString ? JSON.stringify(val, null, spaces) : String(val);
  }; // Remove leading white space from a string

  var trimLeft = function trimLeft(str) {
    return toString(str).replace(RX_TRIM_LEFT, '');
  }; // Remove Trailing white space from a string

  var trim = function trim(str) {
    return toString(str).trim();
  }; // Lower case a string

  var lowerCase = function lowerCase(str) {
    return toString(str).toLowerCase();
  }; // Upper case a string

  var ELEMENT_PROTO = Element.prototype;
  var TABABLE_SELECTOR = ['button', '[href]:not(.disabled)', 'input', 'select', 'textarea', '[tabindex]', '[contenteditable]'].map(function (s) {
    return "".concat(s, ":not(:disabled):not([disabled])");
  }).join(', '); // --- Normalization utils ---
  // See: https://developer.mozilla.org/en-US/docs/Web/API/Element/matches#Polyfill

  /* istanbul ignore next */

  var matchesEl = ELEMENT_PROTO.matches || ELEMENT_PROTO.msMatchesSelector || ELEMENT_PROTO.webkitMatchesSelector; // See: https://developer.mozilla.org/en-US/docs/Web/API/Element/closest

  /* istanbul ignore next */

  var closestEl = ELEMENT_PROTO.closest || function (sel) {
    var el = this;

    do {
      // Use our "patched" matches function
      if (matches(el, sel)) {
        return el;
      }

      el = el.parentElement || el.parentNode;
    } while (!isNull(el) && el.nodeType === Node.ELEMENT_NODE);

    return null;
  }; // `requestAnimationFrame()` convenience method

  /* istanbul ignore next: JSDOM always returns the first option */

  var requestAF = (WINDOW.requestAnimationFrame || WINDOW.webkitRequestAnimationFrame || WINDOW.mozRequestAnimationFrame || WINDOW.msRequestAnimationFrame || WINDOW.oRequestAnimationFrame || // Fallback, but not a true polyfill
  // Only needed for Opera Mini

  /* istanbul ignore next */
  function (cb) {
    return setTimeout(cb, 16);
  }).bind(WINDOW);
  var MutationObs = WINDOW.MutationObserver || WINDOW.WebKitMutationObserver || WINDOW.MozMutationObserver || null; // --- Utils ---
  // Remove a node from DOM

  var removeNode = function removeNode(el) {
    return el && el.parentNode && el.parentNode.removeChild(el);
  }; // Determine if an element is an HTML element

  var isElement = function isElement(el) {
    return !!(el && el.nodeType === Node.ELEMENT_NODE);
  }; // Get the currently active HTML element

  var getActiveElement = function getActiveElement() {
    var excludes = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
    var activeElement = DOCUMENT.activeElement;
    return activeElement && !excludes.some(function (el) {
      return el === activeElement;
    }) ? activeElement : null;
  }; // Returns `true` if a tag's name equals `name`

  var isTag = function isTag(tag, name) {
    return toString(tag).toLowerCase() === toString(name).toLowerCase();
  }; // Determine if an HTML element is the currently active element

  var isActiveElement = function isActiveElement(el) {
    return isElement(el) && el === getActiveElement();
  }; // Determine if an HTML element is visible - Faster than CSS check

  var isVisible = function isVisible(el) {
    if (!isElement(el) || !el.parentNode || !contains(DOCUMENT.body, el)) {
      // Note this can fail for shadow dom elements since they
      // are not a direct descendant of document.body
      return false;
    }

    if (getStyle(el, 'display') === 'none') {
      // We do this check to help with vue-test-utils when using v-show

      /* istanbul ignore next */
      return false;
    } // All browsers support getBoundingClientRect(), except JSDOM as it returns all 0's for values :(
    // So any tests that need isVisible will fail in JSDOM
    // Except when we override the getBCR prototype in some tests


    var bcr = getBCR(el);
    return !!(bcr && bcr.height > 0 && bcr.width > 0);
  }; // Determine if an element is disabled

  var isDisabled = function isDisabled(el) {
    return !isElement(el) || el.disabled || hasAttr(el, 'disabled') || hasClass(el, 'disabled');
  }; // Cause/wait-for an element to reflow its content (adjusting its height/width)

  var reflow = function reflow(el) {
    // Requesting an elements offsetHight will trigger a reflow of the element content

    /* istanbul ignore next: reflow doesn't happen in JSDOM */
    return isElement(el) && el.offsetHeight;
  }; // Select all elements matching selector. Returns `[]` if none found

  var selectAll = function selectAll(selector, root) {
    return from((isElement(root) ? root : DOCUMENT).querySelectorAll(selector));
  }; // Select a single element, returns `null` if not found

  var select = function select(selector, root) {
    return (isElement(root) ? root : DOCUMENT).querySelector(selector) || null;
  }; // Determine if an element matches a selector

  var matches = function matches(el, selector) {
    return isElement(el) ? matchesEl.call(el, selector) : false;
  }; // Finds closest element matching selector. Returns `null` if not found

  var closest = function closest(selector, root) {
    var includeRoot = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;

    if (!isElement(root)) {
      return null;
    }

    var el = closestEl.call(root, selector); // Native closest behaviour when `includeRoot` is truthy,
    // else emulate jQuery closest and return `null` if match is
    // the passed in root element when `includeRoot` is falsey

    return includeRoot ? el : el === root ? null : el;
  }; // Returns true if the parent element contains the child element

  var contains = function contains(parent, child) {
    return parent && isFunction$1(parent.contains) ? parent.contains(child) : false;
  }; // Get an element given an ID

  var getById = function getById(id) {
    return DOCUMENT.getElementById(/^#/.test(id) ? id.slice(1) : id) || null;
  }; // Add a class to an element

  var addClass = function addClass(el, className) {
    // We are checking for `el.classList` existence here since IE 11
    // returns `undefined` for some elements (e.g. SVG elements)
    // See https://github.com/bootstrap-vue/bootstrap-vue/issues/2713
    if (className && isElement(el) && el.classList) {
      el.classList.add(className);
    }
  }; // Remove a class from an element

  var removeClass = function removeClass(el, className) {
    // We are checking for `el.classList` existence here since IE 11
    // returns `undefined` for some elements (e.g. SVG elements)
    // See https://github.com/bootstrap-vue/bootstrap-vue/issues/2713
    if (className && isElement(el) && el.classList) {
      el.classList.remove(className);
    }
  }; // Test if an element has a class

  var hasClass = function hasClass(el, className) {
    // We are checking for `el.classList` existence here since IE 11
    // returns `undefined` for some elements (e.g. SVG elements)
    // See https://github.com/bootstrap-vue/bootstrap-vue/issues/2713
    if (className && isElement(el) && el.classList) {
      return el.classList.contains(className);
    }

    return false;
  }; // Set an attribute on an element

  var setAttr = function setAttr(el, attr, value) {
    if (attr && isElement(el)) {
      el.setAttribute(attr, value);
    }
  }; // Remove an attribute from an element

  var removeAttr = function removeAttr(el, attr) {
    if (attr && isElement(el)) {
      el.removeAttribute(attr);
    }
  }; // Get an attribute value from an element
  // Returns `null` if not found

  var getAttr = function getAttr(el, attr) {
    return attr && isElement(el) ? el.getAttribute(attr) : null;
  }; // Determine if an attribute exists on an element
  // Returns `true` or `false`, or `null` if element not found

  var hasAttr = function hasAttr(el, attr) {
    return attr && isElement(el) ? el.hasAttribute(attr) : null;
  }; // Set an style property on an element

  var setStyle = function setStyle(el, prop, value) {
    if (prop && isElement(el)) {
      el.style[prop] = value;
    }
  }; // Remove an style property from an element

  var removeStyle = function removeStyle(el, prop) {
    if (prop && isElement(el)) {
      el.style[prop] = '';
    }
  }; // Get an style property value from an element
  // Returns `null` if not found

  var getStyle = function getStyle(el, prop) {
    return prop && isElement(el) ? el.style[prop] || null : null;
  }; // Return the Bounding Client Rect of an element
  // Returns `null` if not an element

  /* istanbul ignore next: getBoundingClientRect() doesn't work in JSDOM */

  var getBCR = function getBCR(el) {
    return isElement(el) ? el.getBoundingClientRect() : null;
  }; // Get computed style object for an element

  /* istanbul ignore next: getComputedStyle() doesn't work in JSDOM */

  var getCS = function getCS(el) {
    var getComputedStyle = WINDOW.getComputedStyle;
    return getComputedStyle && isElement(el) ? getComputedStyle(el) : {};
  }; // Returns a `Selection` object representing the range of text selected
  // Returns `null` if no window support is given

  /* istanbul ignore next: getSelection() doesn't work in JSDOM */

  var getSel = function getSel() {
    var getSelection = WINDOW.getSelection;
    return getSelection ? WINDOW.getSelection() : null;
  }; // Return an element's offset with respect to document element
  // https://j11y.io/jquery/#v=git&fn=jQuery.fn.offset

  var offset$1 = function offset(el)
  /* istanbul ignore next: getBoundingClientRect(), getClientRects() doesn't work in JSDOM */
  {
    var _offset = {
      top: 0,
      left: 0
    };

    if (!isElement(el) || el.getClientRects().length === 0) {
      return _offset;
    }

    var bcr = getBCR(el);

    if (bcr) {
      var win = el.ownerDocument.defaultView;
      _offset.top = bcr.top + win.pageYOffset;
      _offset.left = bcr.left + win.pageXOffset;
    }

    return _offset;
  }; // Return an element's offset with respect to to its offsetParent
  // https://j11y.io/jquery/#v=git&fn=jQuery.fn.position

  var position = function position(el)
  /* istanbul ignore next: getBoundingClientRect() doesn't work in JSDOM */
  {
    var _offset = {
      top: 0,
      left: 0
    };

    if (!isElement(el)) {
      return _offset;
    }

    var parentOffset = {
      top: 0,
      left: 0
    };
    var elStyles = getCS(el);

    if (elStyles.position === 'fixed') {
      _offset = getBCR(el) || _offset;
    } else {
      _offset = offset$1(el);
      var doc = el.ownerDocument;
      var offsetParent = el.offsetParent || doc.documentElement;

      while (offsetParent && (offsetParent === doc.body || offsetParent === doc.documentElement) && getCS(offsetParent).position === 'static') {
        offsetParent = offsetParent.parentNode;
      }

      if (offsetParent && offsetParent !== el && offsetParent.nodeType === Node.ELEMENT_NODE) {
        parentOffset = offset$1(offsetParent);
        var offsetParentStyles = getCS(offsetParent);
        parentOffset.top += toFloat(offsetParentStyles.borderTopWidth, 0);
        parentOffset.left += toFloat(offsetParentStyles.borderLeftWidth, 0);
      }
    }

    return {
      top: _offset.top - parentOffset.top - toFloat(elStyles.marginTop, 0),
      left: _offset.left - parentOffset.left - toFloat(elStyles.marginLeft, 0)
    };
  }; // Find all tabable elements in the given element
  // Assumes users have not used `tabindex` > `0` on elements

  var getTabables = function getTabables() {
    var rootEl = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : document;
    return selectAll(TABABLE_SELECTOR, rootEl).filter(isVisible).filter(function (el) {
      return el.tabIndex > -1 && !el.disabled;
    });
  }; // Attempt to focus an element, and return `true` if successful

  var attemptFocus = function attemptFocus(el) {
    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

    try {
      el.focus(options);
    } catch (_unused) {}

    return isActiveElement(el);
  }; // Attempt to blur an element, and return `true` if successful

  var attemptBlur = function attemptBlur(el) {
    try {
      el.blur();
    } catch (_unused2) {}

    return !isActiveElement(el);
  };

  var memoize = function memoize(fn) {
    var cache = create(null);
    return function () {
      for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
        args[_key] = arguments[_key];
      }

      var argsKey = JSON.stringify(args);
      return cache[argsKey] = cache[argsKey] || fn.apply(null, args);
    };
  };

  var VueProto = Vue__default['default'].prototype; // --- Getter methods ---

  var getConfigValue = function getConfigValue(key) {
    var defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
    var bvConfig = VueProto[PROP_NAME$2];
    return bvConfig ? bvConfig.getConfigValue(key, defaultValue) : cloneDeep(defaultValue);
  }; // Method to grab a config value for a particular component

  var getComponentConfig = function getComponentConfig(key) {
    var propKey = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
    var defaultValue = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
    // Return the particular config value for key if specified,
    // otherwise we return the full config (or an empty object if not found)
    return propKey ? getConfigValue("".concat(key, ".").concat(propKey), defaultValue) : getConfigValue(key, {});
  }; // Get all breakpoint names

  var getBreakpoints = function getBreakpoints() {
    return getConfigValue('breakpoints', DEFAULT_BREAKPOINT);
  }; // Private method for caching breakpoint names

  var _getBreakpointsCached = memoize(function () {
    return getBreakpoints();
  }); // Get all breakpoint names (cached)


  var getBreakpointsCached = function getBreakpointsCached() {
    return cloneDeep(_getBreakpointsCached());
  }; // Get breakpoints with the smallest breakpoint set as ''
  // Useful for components that create breakpoint specific props

  var getBreakpointsUpCached = memoize(function () {
    var breakpoints = getBreakpointsCached();
    breakpoints[0] = '';
    return breakpoints;
  }); // Get breakpoints with the largest breakpoint set as ''

  var prefixPropName = function prefixPropName(prefix, value) {
    return prefix + upperFirst(value);
  }; // Remove a prefix from a property

  var unprefixPropName = function unprefixPropName(prefix, value) {
    return lowerFirst(value.replace(prefix, ''));
  }; // Suffix can be a falsey value so nothing is appended to string
  // (helps when looping over props & some shouldn't change)
  // Use data last parameters to allow for currying

  var suffixPropName = function suffixPropName(suffix, value) {
    return value + (suffix ? upperFirst(suffix) : '');
  }; // Generates a prop object

  var makeProp = function makeProp() {
    var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : PROP_TYPE_ANY;
    var value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
    var requiredOrValidator = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
    var validator = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : undefined;
    var required = requiredOrValidator === true;
    validator = required ? validator : requiredOrValidator;
    return _objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, type ? {
      type: type
    } : {}), required ? {
      required: required
    } : isUndefined(value) ? {} : {
      default: isObject(value) ? function () {
        return value;
      } : value
    }), isUndefined(validator) ? {} : {
      validator: validator
    });
  }; // Copies props from one array/object to a new array/object
  // Prop values are also cloned as new references to prevent possible
  // mutation of original prop object values
  // Optionally accepts a function to transform the prop name

  var copyProps = function copyProps(props) {
    var transformFn = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : identity;

    if (isArray(props)) {
      return props.map(transformFn);
    }

    var copied = {};

    for (var prop in props) {
      /* istanbul ignore else */
      if (hasOwnProperty(props, prop)) {
        // If the prop value is an object, do a shallow clone
        // to prevent potential mutations to the original object
        copied[transformFn(prop)] = isObject(props[prop]) ? clone(props[prop]) : props[prop];
      }
    }

    return copied;
  }; // Given an array of properties or an object of property keys,
  // plucks all the values off the target object, returning a new object
  // that has props that reference the original prop values

  var pluckProps = function pluckProps(keysToPluck, objToPluck) {
    var transformFn = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : identity;
    return (isArray(keysToPluck) ? keysToPluck.slice() : keys(keysToPluck)).reduce(function (memo, prop) {
      memo[transformFn(prop)] = objToPluck[prop];
      return memo;
    }, {});
  }; // Make a prop object configurable by global configuration
  // Replaces the current `default` key of each prop with a `getComponentConfig()`
  // call that falls back to the current default value of the prop

  var makePropConfigurable = function makePropConfigurable(prop, key, componentKey) {
    return _objectSpread2$3(_objectSpread2$3({}, cloneDeep(prop)), {}, {
      default: function bvConfigurablePropDefault() {
        var value = getComponentConfig(componentKey, key, prop.default);
        return isFunction$1(value) ? value() : value;
      }
    });
  }; // Make a props object configurable by global configuration
  // Replaces the current `default` key of each prop with a `getComponentConfig()`
  // call that falls back to the current default value of the prop

  var makePropsConfigurable = function makePropsConfigurable(props, componentKey) {
    return keys(props).reduce(function (result, key) {
      return _objectSpread2$3(_objectSpread2$3({}, result), {}, _defineProperty({}, key, makePropConfigurable(props[key], key, componentKey)));
    }, {});
  }; // Get function name we use in `makePropConfigurable()`
  // for the prop default value override to compare
  // against in `hasPropFunction()`

  var configurablePropDefaultFnName = makePropConfigurable({}, '', '').default.name; // Detect wether the given value is currently a function
  // and isn't the props default function

  var hasPropFunction = function hasPropFunction(fn) {
    return isFunction$1(fn) && fn.name && fn.name !== configurablePropDefaultFnName;
  };

  var makeModelMixin = function makeModelMixin(prop) {
    var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
        _ref$type = _ref.type,
        type = _ref$type === void 0 ? PROP_TYPE_ANY : _ref$type,
        _ref$defaultValue = _ref.defaultValue,
        defaultValue = _ref$defaultValue === void 0 ? undefined : _ref$defaultValue,
        _ref$validator = _ref.validator,
        validator = _ref$validator === void 0 ? undefined : _ref$validator,
        _ref$event = _ref.event,
        event = _ref$event === void 0 ? EVENT_NAME_INPUT : _ref$event;

    var props = _defineProperty({}, prop, makeProp(type, defaultValue, validator)); // @vue/component


    var mixin = extend({
      model: {
        prop: prop,
        event: event
      },
      props: props
    });
    return {
      mixin: mixin,
      props: props,
      prop: prop,
      event: event
    };
  };

  // Normalize event options based on support of passive option
  // Exported only for testing purposes

  var parseEventOptions = function parseEventOptions(options) {
    /* istanbul ignore else: can't test in JSDOM, as it supports passive */
    if (HAS_PASSIVE_EVENT_SUPPORT) {
      return isObject(options) ? options : {
        capture: !!options || false
      };
    } else {
      // Need to translate to actual Boolean value
      return !!(isObject(options) ? options.capture : options);
    }
  }; // Attach an event listener to an element

  var eventOn = function eventOn(el, eventName, handler, options) {
    if (el && el.addEventListener) {
      el.addEventListener(eventName, handler, parseEventOptions(options));
    }
  }; // Remove an event listener from an element

  var eventOff = function eventOff(el, eventName, handler, options) {
    if (el && el.removeEventListener) {
      el.removeEventListener(eventName, handler, parseEventOptions(options));
    }
  }; // Utility method to add/remove a event listener based on first argument (boolean)
  // It passes all other arguments to the `eventOn()` or `eventOff` method

  var eventOnOff = function eventOnOff(on) {
    var method = on ? eventOn : eventOff;

    for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
      args[_key - 1] = arguments[_key];
    }

    method.apply(void 0, args);
  }; // Utility method to prevent the default event handling and propagation

  var stopEvent = function stopEvent(event) {
    var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
        _ref$preventDefault = _ref.preventDefault,
        preventDefault = _ref$preventDefault === void 0 ? true : _ref$preventDefault,
        _ref$propagation = _ref.propagation,
        propagation = _ref$propagation === void 0 ? true : _ref$propagation,
        _ref$immediatePropaga = _ref.immediatePropagation,
        immediatePropagation = _ref$immediatePropaga === void 0 ? false : _ref$immediatePropaga;

    if (preventDefault) {
      event.preventDefault();
    }

    if (propagation) {
      event.stopPropagation();
    }

    if (immediatePropagation) {
      event.stopImmediatePropagation();
    }
  }; // Helper method to convert a component/directive name to a base event name
  // `getBaseEventName('BNavigationItem')` => 'navigation-item'
  // `getBaseEventName('BVToggle')` => 'toggle'

  var getBaseEventName = function getBaseEventName(value) {
    return kebabCase(value.replace(RX_BV_PREFIX, ''));
  }; // Get a root event name by component/directive and event name
  // `getBaseEventName('BModal', 'show')` => 'bv::modal::show'


  var getRootEventName = function getRootEventName(name, eventName) {
    return [ROOT_EVENT_NAME_PREFIX, getBaseEventName(name), eventName].join(ROOT_EVENT_NAME_SEPARATOR);
  }; // Get a root action event name by component/directive and action name
  // `getRootActionEventName('BModal', 'show')` => 'bv::show::modal'

  var getRootActionEventName = function getRootActionEventName(name, actionName) {
    return [ROOT_EVENT_NAME_PREFIX, actionName, getBaseEventName(name)].join(ROOT_EVENT_NAME_SEPARATOR);
  };

  var props$2l = makePropsConfigurable({
    ariaLabel: makeProp(PROP_TYPE_STRING, 'Close'),
    content: makeProp(PROP_TYPE_STRING, '&times;'),
    disabled: makeProp(PROP_TYPE_BOOLEAN, false),
    textVariant: makeProp(PROP_TYPE_STRING)
  }, NAME_BUTTON_CLOSE); // --- Main component ---
  // @vue/component

  var BButtonClose = /*#__PURE__*/extend({
    name: NAME_BUTTON_CLOSE,
    functional: true,
    props: props$2l,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          slots = _ref.slots,
          scopedSlots = _ref.scopedSlots;
      var $slots = slots();
      var $scopedSlots = scopedSlots || {};
      var componentData = {
        staticClass: 'close',
        class: _defineProperty({}, "text-".concat(props.textVariant), props.textVariant),
        attrs: {
          type: 'button',
          disabled: props.disabled,
          'aria-label': props.ariaLabel ? String(props.ariaLabel) : null
        },
        on: {
          click: function click(event) {
            // Ensure click on button HTML content is also disabled

            /* istanbul ignore if: bug in JSDOM still emits click on inner element */
            if (props.disabled && isEvent(event)) {
              stopEvent(event);
            }
          }
        }
      }; // Careful not to override the default slot with innerHTML

      if (!hasNormalizedSlot(SLOT_NAME_DEFAULT, $scopedSlots, $slots)) {
        componentData.domProps = {
          innerHTML: props.content
        };
      }

      return h('button', a(data, componentData), normalizeSlot(SLOT_NAME_DEFAULT, {}, $scopedSlots, $slots));
    }
  });

  var NO_FADE_PROPS = {
    name: '',
    enterClass: '',
    enterActiveClass: '',
    enterToClass: 'show',
    leaveClass: 'show',
    leaveActiveClass: '',
    leaveToClass: ''
  };

  var FADE_PROPS = _objectSpread2$3(_objectSpread2$3({}, NO_FADE_PROPS), {}, {
    enterActiveClass: 'fade',
    leaveActiveClass: 'fade'
  }); // --- Props ---


  var props$2k = {
    // Has no effect if `trans-props` provided
    appear: makeProp(PROP_TYPE_BOOLEAN, false),
    // Can be overridden by user supplied `trans-props`
    mode: makeProp(PROP_TYPE_STRING),
    // Only applicable to the built in transition
    // Has no effect if `trans-props` provided
    noFade: makeProp(PROP_TYPE_BOOLEAN, false),
    // For user supplied transitions (if needed)
    transProps: makeProp(PROP_TYPE_OBJECT)
  }; // --- Main component ---
  // @vue/component

  var BVTransition = /*#__PURE__*/extend({
    name: NAME_TRANSITION,
    functional: true,
    props: props$2k,
    render: function render(h, _ref) {
      var children = _ref.children,
          data = _ref.data,
          props = _ref.props;
      var transProps = props.transProps;

      if (!isPlainObject(transProps)) {
        transProps = props.noFade ? NO_FADE_PROPS : FADE_PROPS;

        if (props.appear) {
          // Default the appear classes to equal the enter classes
          transProps = _objectSpread2$3(_objectSpread2$3({}, transProps), {}, {
            appear: true,
            appearClass: transProps.enterClass,
            appearActiveClass: transProps.enterActiveClass,
            appearToClass: transProps.enterToClass
          });
        }
      }

      transProps = _objectSpread2$3(_objectSpread2$3({
        mode: props.mode
      }, transProps), {}, {
        // We always need `css` true
        css: true
      });

      var dataCopy = _objectSpread2$3({}, data);

      delete dataCopy.props;
      return h('transition', // Any transition event listeners will get merged here
      a(dataCopy, {
        props: transProps
      }), children);
    }
  });

  var _watch$k;

  var _makeModelMixin$k = makeModelMixin('show', {
    type: PROP_TYPE_BOOLEAN_NUMBER_STRING,
    defaultValue: false
  }),
      modelMixin$j = _makeModelMixin$k.mixin,
      modelProps$j = _makeModelMixin$k.props,
      MODEL_PROP_NAME$j = _makeModelMixin$k.prop,
      MODEL_EVENT_NAME$j = _makeModelMixin$k.event; // --- Helper methods ---
  // Convert `show` value to a number


  var parseCountDown = function parseCountDown(show) {
    if (show === '' || isBoolean(show)) {
      return 0;
    }

    show = toInteger(show, 0);
    return show > 0 ? show : 0;
  }; // Convert `show` value to a boolean


  var parseShow = function parseShow(show) {
    if (show === '' || show === true) {
      return true;
    }

    if (toInteger(show, 0) < 1) {
      // Boolean will always return false for the above comparison
      return false;
    }

    return !!show;
  }; // --- Props ---


  var props$2j = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, modelProps$j), {}, {
    dismissLabel: makeProp(PROP_TYPE_STRING, 'Close'),
    dismissible: makeProp(PROP_TYPE_BOOLEAN, false),
    fade: makeProp(PROP_TYPE_BOOLEAN, false),
    variant: makeProp(PROP_TYPE_STRING, 'info')
  })), NAME_ALERT); // --- Main component ---
  // @vue/component

  var BAlert = /*#__PURE__*/extend({
    name: NAME_ALERT,
    mixins: [modelMixin$j, normalizeSlotMixin],
    props: props$2j,
    data: function data() {
      return {
        countDown: 0,
        // If initially shown, we need to set these for SSR
        localShow: parseShow(this[MODEL_PROP_NAME$j])
      };
    },
    watch: (_watch$k = {}, _defineProperty(_watch$k, MODEL_PROP_NAME$j, function (newValue) {
      this.countDown = parseCountDown(newValue);
      this.localShow = parseShow(newValue);
    }), _defineProperty(_watch$k, "countDown", function countDown(newValue) {
      var _this = this;

      this.clearCountDownInterval();
      var show = this[MODEL_PROP_NAME$j]; // Ignore if `show` transitions to a boolean value

      if (isNumeric$1(show)) {
        this.$emit(EVENT_NAME_DISMISS_COUNT_DOWN, newValue); // Update the v-model if needed

        if (show !== newValue) {
          this.$emit(MODEL_EVENT_NAME$j, newValue);
        }

        if (newValue > 0) {
          this.localShow = true;
          this.$_countDownTimeout = setTimeout(function () {
            _this.countDown--;
          }, 1000);
        } else {
          // Slightly delay the hide to allow any UI updates
          this.$nextTick(function () {
            requestAF(function () {
              _this.localShow = false;
            });
          });
        }
      }
    }), _defineProperty(_watch$k, "localShow", function localShow(newValue) {
      var show = this[MODEL_PROP_NAME$j]; // Only emit dismissed events for dismissible or auto-dismissing alerts

      if (!newValue && (this.dismissible || isNumeric$1(show))) {
        this.$emit(EVENT_NAME_DISMISSED);
      } // Only emit booleans if we weren't passed a number via v-model


      if (!isNumeric$1(show) && show !== newValue) {
        this.$emit(MODEL_EVENT_NAME$j, newValue);
      }
    }), _watch$k),
    created: function created() {
      // Create private non-reactive props
      this.$_filterTimer = null;
      var show = this[MODEL_PROP_NAME$j];
      this.countDown = parseCountDown(show);
      this.localShow = parseShow(show);
    },
    beforeDestroy: function beforeDestroy() {
      this.clearCountDownInterval();
    },
    methods: {
      dismiss: function dismiss() {
        this.clearCountDownInterval();
        this.countDown = 0;
        this.localShow = false;
      },
      clearCountDownInterval: function clearCountDownInterval() {
        clearTimeout(this.$_countDownTimeout);
        this.$_countDownTimeout = null;
      }
    },
    render: function render(h) {
      var $alert = h();

      if (this.localShow) {
        var dismissible = this.dismissible,
            variant = this.variant;
        var $dismissButton = h();

        if (dismissible) {
          // Add dismiss button
          $dismissButton = h(BButtonClose, {
            attrs: {
              'aria-label': this.dismissLabel
            },
            on: {
              click: this.dismiss
            }
          }, [this.normalizeSlot(SLOT_NAME_DISMISS)]);
        }

        $alert = h('div', {
          staticClass: 'alert',
          class: _defineProperty({
            'alert-dismissible': dismissible
          }, "alert-".concat(variant), variant),
          attrs: {
            role: 'alert',
            'aria-live': 'polite',
            'aria-atomic': true
          },
          key: this[COMPONENT_UID_KEY]
        }, [$dismissButton, this.normalizeSlot()]);
      }

      return h(BVTransition, {
        props: {
          noFade: !this.fade
        }
      }, [$alert]);
    }
  });

  var AlertPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BAlert: BAlert
    }
  });

  // Math utilty functions
  var mathMin = Math.min;
  var mathMax = Math.max;
  var mathAbs = Math.abs;
  var mathCeil = Math.ceil;
  var mathFloor = Math.floor;
  var mathPow = Math.pow;
  var mathRound = Math.round;

  var CLASS_NAME$3 = 'b-aspect'; // --- Props ---

  var props$2i = makePropsConfigurable({
    // Accepts a number (i.e. `16 / 9`, `1`, `4 / 3`)
    // Or a string (i.e. '16/9', '16:9', '4:3' '1:1')
    aspect: makeProp(PROP_TYPE_NUMBER_STRING, '1:1'),
    tag: makeProp(PROP_TYPE_STRING, 'div')
  }, NAME_ASPECT); // --- Main component ---
  // @vue/component

  var BAspect = /*#__PURE__*/extend({
    name: NAME_ASPECT,
    mixins: [normalizeSlotMixin],
    props: props$2i,
    computed: {
      padding: function padding() {
        var aspect = this.aspect;
        var ratio = 1;

        if (RX_ASPECT.test(aspect)) {
          // Width and/or Height can be a decimal value below `1`, so
          // we only fallback to `1` if the value is `0` or `NaN`
          var _aspect$split$map = aspect.split(RX_ASPECT_SEPARATOR).map(function (v) {
            return toFloat(v) || 1;
          }),
              _aspect$split$map2 = _slicedToArray(_aspect$split$map, 2),
              width = _aspect$split$map2[0],
              height = _aspect$split$map2[1];

          ratio = width / height;
        } else {
          ratio = toFloat(aspect) || 1;
        }

        return "".concat(100 / mathAbs(ratio), "%");
      }
    },
    render: function render(h) {
      var $sizer = h('div', {
        staticClass: "".concat(CLASS_NAME$3, "-sizer flex-grow-1"),
        style: {
          paddingBottom: this.padding,
          height: 0
        }
      });
      var $content = h('div', {
        staticClass: "".concat(CLASS_NAME$3, "-content flex-grow-1 w-100 mw-100"),
        style: {
          marginLeft: '-100%'
        }
      }, this.normalizeSlot());
      return h(this.tag, {
        staticClass: "".concat(CLASS_NAME$3, " d-flex")
      }, [$sizer, $content]);
    }
  });

  var AspectPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BAspect: BAspect
    }
  });

  function safeVueInstance(target) {
    if (!isVue3) {
      return target;
    }

    return new Proxy(target, {
      get: function get(target, prop) {
        return prop in target ? target[prop] : undefined;
      }
    });
  }

  var ANCHOR_TAG = 'a'; // Method to replace reserved chars

  var encodeReserveReplacer = function encodeReserveReplacer(c) {
    return '%' + c.charCodeAt(0).toString(16);
  }; // Fixed encodeURIComponent which is more conformant to RFC3986:
  // - escapes [!'()*]
  // - preserve commas


  var encode = function encode(str) {
    return encodeURIComponent(toString(str)).replace(RX_ENCODE_REVERSE, encodeReserveReplacer).replace(RX_ENCODED_COMMA, ',');
  };

  var decode = decodeURIComponent; // Stringifies an object of query parameters
  // See: https://github.com/vuejs/vue-router/blob/dev/src/util/query.js

  var stringifyQueryObj = function stringifyQueryObj(obj) {
    if (!isPlainObject(obj)) {
      return '';
    }

    var query = keys(obj).map(function (key) {
      var value = obj[key];

      if (isUndefined(value)) {
        return '';
      } else if (isNull(value)) {
        return encode(key);
      } else if (isArray(value)) {
        return value.reduce(function (results, value2) {
          if (isNull(value2)) {
            results.push(encode(key));
          } else if (!isUndefined(value2)) {
            // Faster than string interpolation
            results.push(encode(key) + '=' + encode(value2));
          }

          return results;
        }, []).join('&');
      } // Faster than string interpolation


      return encode(key) + '=' + encode(value);
    })
    /* must check for length, as we only want to filter empty strings, not things that look falsey! */
    .filter(function (x) {
      return x.length > 0;
    }).join('&');
    return query ? "?".concat(query) : '';
  };
  var parseQuery = function parseQuery(query) {
    var parsed = {};
    query = toString(query).trim().replace(RX_QUERY_START, '');

    if (!query) {
      return parsed;
    }

    query.split('&').forEach(function (param) {
      var parts = param.replace(RX_PLUS, ' ').split('=');
      var key = decode(parts.shift());
      var value = parts.length > 0 ? decode(parts.join('=')) : null;

      if (isUndefined(parsed[key])) {
        parsed[key] = value;
      } else if (isArray(parsed[key])) {
        parsed[key].push(value);
      } else {
        parsed[key] = [parsed[key], value];
      }
    });
    return parsed;
  };
  var isLink$1 = function isLink(props) {
    return !!(props.href || props.to);
  };
  var isRouterLink = function isRouterLink(tag) {
    return !!(tag && !isTag(tag, 'a'));
  };
  var computeTag = function computeTag(_ref, thisOrParent) {
    var to = _ref.to,
        disabled = _ref.disabled,
        routerComponentName = _ref.routerComponentName;
    var hasRouter = !!safeVueInstance(thisOrParent).$router;
    var hasNuxt = !!safeVueInstance(thisOrParent).$nuxt;

    if (!hasRouter || hasRouter && (disabled || !to)) {
      return ANCHOR_TAG;
    } // TODO:
    //   Check registered components for existence of user supplied router link component name
    //   We would need to check PascalCase, kebab-case, and camelCase versions of name:
    //   const name = routerComponentName
    //   const names = [name, PascalCase(name), KebabCase(name), CamelCase(name)]
    //   exists = names.some(name => !!thisOrParent.$options.components[name])
    //   And may want to cache the result for performance or we just let the render fail
    //   if the component is not registered


    return routerComponentName || (hasNuxt ? 'nuxt-link' : 'router-link');
  };
  var computeRel = function computeRel() {
    var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
        target = _ref2.target,
        rel = _ref2.rel;

    return target === '_blank' && isNull(rel) ? 'noopener' : rel || null;
  };
  var computeHref = function computeHref() {
    var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
        href = _ref3.href,
        to = _ref3.to;

    var tag = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ANCHOR_TAG;
    var fallback = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '#';
    var toFallback = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : '/';

    // Return `href` when explicitly provided
    if (href) {
      return href;
    } // We've checked for `$router` in `computeTag()`, so `isRouterLink()` indicates a live router
    // When deferring to Vue Router's `<router-link>`, don't use the `href` attribute at all
    // We return `null`, and then remove `href` from the attributes passed to `<router-link>`


    if (isRouterLink(tag)) {
      return null;
    } // Fallback to `to` prop (if `to` is a string)


    if (isString(to)) {
      return to || toFallback;
    } // Fallback to `to.path' + `to.query` + `to.hash` prop (if `to` is an object)


    if (isPlainObject(to) && (to.path || to.query || to.hash)) {
      var path = toString(to.path);
      var query = stringifyQueryObj(to.query);
      var hash = toString(to.hash);
      hash = !hash || hash.charAt(0) === '#' ? hash : "#".concat(hash);
      return "".concat(path).concat(query).concat(hash) || toFallback;
    } // If nothing is provided return the fallback


    return fallback;
  };

  // Base attributes needed on all icons

  var BASE_ATTRS = {
    viewBox: '0 0 16 16',
    width: '1em',
    height: '1em',
    focusable: 'false',
    role: 'img',
    'aria-label': 'icon'
  }; // Attributes that are nulled out when stacked

  var STACKED_ATTRS = {
    width: null,
    height: null,
    focusable: null,
    role: null,
    'aria-label': null
  }; // --- Props ---

  var props$2h = {
    animation: makeProp(PROP_TYPE_STRING),
    content: makeProp(PROP_TYPE_STRING),
    flipH: makeProp(PROP_TYPE_BOOLEAN, false),
    flipV: makeProp(PROP_TYPE_BOOLEAN, false),
    fontScale: makeProp(PROP_TYPE_NUMBER_STRING, 1),
    rotate: makeProp(PROP_TYPE_NUMBER_STRING, 0),
    scale: makeProp(PROP_TYPE_NUMBER_STRING, 1),
    shiftH: makeProp(PROP_TYPE_NUMBER_STRING, 0),
    shiftV: makeProp(PROP_TYPE_NUMBER_STRING, 0),
    stacked: makeProp(PROP_TYPE_BOOLEAN, false),
    title: makeProp(PROP_TYPE_STRING),
    variant: makeProp(PROP_TYPE_STRING)
  }; // --- Main component ---
  // Shared private base component to reduce bundle/runtime size
  // @vue/component

  var BVIconBase = /*#__PURE__*/extend({
    name: NAME_ICON_BASE,
    functional: true,
    props: props$2h,
    render: function render(h, _ref) {
      var _class;

      var data = _ref.data,
          props = _ref.props,
          children = _ref.children;
      var animation = props.animation,
          content = props.content,
          flipH = props.flipH,
          flipV = props.flipV,
          stacked = props.stacked,
          title = props.title,
          variant = props.variant;
      var fontScale = mathMax(toFloat(props.fontScale, 1), 0) || 1;
      var scale = mathMax(toFloat(props.scale, 1), 0) || 1;
      var rotate = toFloat(props.rotate, 0);
      var shiftH = toFloat(props.shiftH, 0);
      var shiftV = toFloat(props.shiftV, 0); // Compute the transforms
      // Note that order is important as SVG transforms are applied in order from
      // left to right and we want flipping/scale to occur before rotation
      // Note shifting is applied separately
      // Assumes that the viewbox is `0 0 16 16` (`8 8` is the center)

      var hasScale = flipH || flipV || scale !== 1;
      var hasTransforms = hasScale || rotate;
      var hasShift = shiftH || shiftV;
      var hasContent = !isUndefinedOrNull(content);
      var transforms = [hasTransforms ? 'translate(8 8)' : null, hasScale ? "scale(".concat((flipH ? -1 : 1) * scale, " ").concat((flipV ? -1 : 1) * scale, ")") : null, rotate ? "rotate(".concat(rotate, ")") : null, hasTransforms ? 'translate(-8 -8)' : null].filter(identity); // We wrap the content in a `<g>` for handling the transforms (except shift)

      var $inner = h('g', {
        attrs: {
          transform: transforms.join(' ') || null
        },
        domProps: hasContent ? {
          innerHTML: content || ''
        } : {}
      }, children); // If needed, we wrap in an additional `<g>` in order to handle the shifting

      if (hasShift) {
        $inner = h('g', {
          attrs: {
            transform: "translate(".concat(16 * shiftH / 16, " ").concat(-16 * shiftV / 16, ")")
          }
        }, [$inner]);
      } // Wrap in an additional `<g>` for proper animation handling if stacked


      if (stacked) {
        $inner = h('g', [$inner]);
      }

      var $title = title ? h('title', title) : null;
      var $content = [$title, $inner].filter(identity);
      return h('svg', a({
        staticClass: 'b-icon bi',
        class: (_class = {}, _defineProperty(_class, "text-".concat(variant), variant), _defineProperty(_class, "b-icon-animation-".concat(animation), animation), _class),
        attrs: BASE_ATTRS,
        style: stacked ? {} : {
          fontSize: fontScale === 1 ? null : "".concat(fontScale * 100, "%")
        }
      }, // Merge in user supplied data
      data, // If icon is stacked, null-out some attrs
      stacked ? {
        attrs: STACKED_ATTRS
      } : {}, // These cannot be overridden by users
      {
        attrs: {
          xmlns: stacked ? null : 'http://www.w3.org/2000/svg',
          fill: 'currentColor'
        }
      }), $content);
    }
  });

  var iconProps$1 = omit(props$2h, ['content']);
  /**
   * Icon component generator function
   *
   * @param {string} icon name (minus the leading `BIcon`)
   * @param {string} raw `innerHTML` for SVG
   * @return {VueComponent}
   */

  var makeIcon = function makeIcon(name, content) {
    // For performance reason we pre-compute some values, so that
    // they are not computed on each render of the icon component
    var kebabName = kebabCase(name);
    var iconName = "BIcon".concat(pascalCase(name));
    var iconNameClass = "bi-".concat(kebabName);
    var iconTitle = kebabName.replace(/-/g, ' ');
    var svgContent = trim(content || '');
    return /*#__PURE__*/extend({
      name: iconName,
      functional: true,
      props: iconProps$1,
      render: function render(h, _ref) {
        var data = _ref.data,
            props = _ref.props;
        return h(BVIconBase, a( // Defaults
        {
          props: {
            title: iconTitle
          },
          attrs: {
            'aria-label': iconTitle
          }
        }, // User data
        data, // Required data
        {
          staticClass: iconNameClass,
          props: _objectSpread2$3(_objectSpread2$3({}, props), {}, {
            content: svgContent
          })
        }));
      }
    });
  };

  // --- BEGIN AUTO-GENERATED FILE ---
  var BIconBlank=/*#__PURE__*/makeIcon('Blank','');// --- Bootstrap Icons ---
  var BIconCalendar=/*#__PURE__*/makeIcon('Calendar','<path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4H1z"/>');// eslint-disable-next-line
  var BIconCalendarFill=/*#__PURE__*/makeIcon('CalendarFill','<path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V5h16V4H0V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5z"/>');// eslint-disable-next-line
  var BIconChevronBarLeft=/*#__PURE__*/makeIcon('ChevronBarLeft','<path fill-rule="evenodd" d="M11.854 3.646a.5.5 0 0 1 0 .708L8.207 8l3.647 3.646a.5.5 0 0 1-.708.708l-4-4a.5.5 0 0 1 0-.708l4-4a.5.5 0 0 1 .708 0zM4.5 1a.5.5 0 0 0-.5.5v13a.5.5 0 0 0 1 0v-13a.5.5 0 0 0-.5-.5z"/>');// eslint-disable-next-line
  var BIconChevronDoubleLeft=/*#__PURE__*/makeIcon('ChevronDoubleLeft','<path fill-rule="evenodd" d="M8.354 1.646a.5.5 0 0 1 0 .708L2.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z"/><path fill-rule="evenodd" d="M12.354 1.646a.5.5 0 0 1 0 .708L6.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z"/>');// eslint-disable-next-line
  var BIconChevronDown=/*#__PURE__*/makeIcon('ChevronDown','<path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z"/>');// eslint-disable-next-line
  var BIconChevronLeft=/*#__PURE__*/makeIcon('ChevronLeft','<path fill-rule="evenodd" d="M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z"/>');// eslint-disable-next-line
  var BIconChevronUp=/*#__PURE__*/makeIcon('ChevronUp','<path fill-rule="evenodd" d="M7.646 4.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1-.708.708L8 5.707l-5.646 5.647a.5.5 0 0 1-.708-.708l6-6z"/>');// eslint-disable-next-line
  var BIconCircleFill=/*#__PURE__*/makeIcon('CircleFill','<circle cx="8" cy="8" r="8"/>');// eslint-disable-next-line
  var BIconClock=/*#__PURE__*/makeIcon('Clock','<path d="M8 3.5a.5.5 0 0 0-1 0V9a.5.5 0 0 0 .252.434l3.5 2a.5.5 0 0 0 .496-.868L8 8.71V3.5z"/><path d="M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16zm7-8A7 7 0 1 1 1 8a7 7 0 0 1 14 0z"/>');// eslint-disable-next-line
  var BIconClockFill=/*#__PURE__*/makeIcon('ClockFill','<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM8 3.5a.5.5 0 0 0-1 0V9a.5.5 0 0 0 .252.434l3.5 2a.5.5 0 0 0 .496-.868L8 8.71V3.5z"/>');// eslint-disable-next-line
  var BIconDash=/*#__PURE__*/makeIcon('Dash','<path d="M4 8a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7A.5.5 0 0 1 4 8z"/>');// eslint-disable-next-line
  var BIconPersonFill=/*#__PURE__*/makeIcon('PersonFill','<path d="M3 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H3zm5-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/>');// eslint-disable-next-line
  var BIconPlus=/*#__PURE__*/makeIcon('Plus','<path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z"/>');// eslint-disable-next-line
  var BIconStar=/*#__PURE__*/makeIcon('Star','<path d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256 4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73 3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356-.83 4.73zm4.905-2.767-3.686 1.894.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957-3.686-1.894a.503.503 0 0 0-.461 0z"/>');// eslint-disable-next-line
  var BIconStarFill=/*#__PURE__*/makeIcon('StarFill','<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>');// eslint-disable-next-line
  var BIconStarHalf=/*#__PURE__*/makeIcon('StarHalf','<path d="M5.354 5.119 7.538.792A.516.516 0 0 1 8 .5c.183 0 .366.097.465.292l2.184 4.327 4.898.696A.537.537 0 0 1 16 6.32a.548.548 0 0 1-.17.445l-3.523 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256a.52.52 0 0 1-.146.05c-.342.06-.668-.254-.6-.642l.83-4.73L.173 6.765a.55.55 0 0 1-.172-.403.58.58 0 0 1 .085-.302.513.513 0 0 1 .37-.245l4.898-.696zM8 12.027a.5.5 0 0 1 .232.056l3.686 1.894-.694-3.957a.565.565 0 0 1 .162-.505l2.907-2.77-4.052-.576a.525.525 0 0 1-.393-.288L8.001 2.223 8 2.226v9.8z"/>');// eslint-disable-next-line
  var BIconX=/*#__PURE__*/makeIcon('X','<path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"/>');// eslint-disable-next-line
  // --- END AUTO-GENERATED FILE ---

  var findIconComponent = function findIconComponent(ctx, iconName) {
    if (!ctx) {
      return Vue__default['default'].component(iconName);
    }

    var components = (ctx.$options || {}).components;
    var iconComponent = components && components[iconName];
    return iconComponent || findIconComponent(ctx.$parent, iconName);
  }; // --- Props ---


  var iconProps = omit(props$2h, ['content']);
  var props$2g = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, iconProps), {}, {
    icon: makeProp(PROP_TYPE_STRING)
  })), NAME_ICON); // --- Main component ---
  // Helper BIcon component
  // Requires the requested icon component to be installed
  // @vue/component

  var BIcon = /*#__PURE__*/extend({
    name: NAME_ICON,
    functional: true,
    props: props$2g,
    render: function render(h, _ref) {
      var data = _ref.data,
          props = _ref.props,
          parent = _ref.parent;
      var icon = pascalCase(trim(props.icon || '')).replace(RX_ICON_PREFIX, ''); // If parent context exists, we check to see if the icon has been registered
      // either locally in the parent component, or globally at the `$root` level
      // If not registered, we render a blank icon

      return h(icon ? findIconComponent(parent, "BIcon".concat(icon)) || BIconBlank : BIconBlank, a(data, {
        props: pluckProps(iconProps, props)
      }));
    }
  });

  var CODE_BACKSPACE = 8;
  var CODE_DELETE = 46;
  var CODE_DOWN = 40;
  var CODE_END = 35;
  var CODE_ENTER = 13;
  var CODE_ESC = 27;
  var CODE_HOME = 36;
  var CODE_LEFT = 37;
  var CODE_PAGEDOWN = 34;
  var CODE_PAGEUP = 33;
  var CODE_RIGHT = 39;
  var CODE_SPACE = 32;
  var CODE_UP = 38;

  // Handles when arrays are "sparse" (array.every(...) doesn't handle sparse)

  var compareArrays = function compareArrays(a, b) {
    if (a.length !== b.length) {
      return false;
    }

    var equal = true;

    for (var i = 0; equal && i < a.length; i++) {
      equal = looseEqual(a[i], b[i]);
    }

    return equal;
  };
  /**
   * Check if two values are loosely equal - that is,
   * if they are plain objects, do they have the same shape?
   * Returns boolean true or false
   */


  var looseEqual = function looseEqual(a, b) {
    if (a === b) {
      return true;
    }

    var aValidType = isDate(a);
    var bValidType = isDate(b);

    if (aValidType || bValidType) {
      return aValidType && bValidType ? a.getTime() === b.getTime() : false;
    }

    aValidType = isArray(a);
    bValidType = isArray(b);

    if (aValidType || bValidType) {
      return aValidType && bValidType ? compareArrays(a, b) : false;
    }

    aValidType = isObject(a);
    bValidType = isObject(b);

    if (aValidType || bValidType) {
      /* istanbul ignore if: this if will probably never be called */
      if (!aValidType || !bValidType) {
        return false;
      }

      var aKeysCount = keys(a).length;
      var bKeysCount = keys(b).length;

      if (aKeysCount !== bKeysCount) {
        return false;
      }

      for (var key in a) {
        var aHasKey = hasOwnProperty(a, key);
        var bHasKey = hasOwnProperty(b, key);

        if (aHasKey && !bHasKey || !aHasKey && bHasKey || !looseEqual(a[key], b[key])) {
          return false;
        }
      }
    }

    return String(a) === String(b);
  };

  var isEmpty = function isEmpty(value) {
    return !value || keys(value).length === 0;
  };

  var makePropWatcher = function makePropWatcher(propName) {
    return {
      handler: function handler(newValue, oldValue) {
        if (looseEqual(newValue, oldValue)) {
          return;
        }

        if (isEmpty(newValue) || isEmpty(oldValue)) {
          this[propName] = cloneDeep(newValue);
          return;
        }

        for (var key in oldValue) {
          if (!hasOwnProperty(newValue, key)) {
            this.$delete(this.$data[propName], key);
          }
        }

        for (var _key in newValue) {
          this.$set(this.$data[propName], _key, newValue[_key]);
        }
      }
    };
  };
  var makePropCacheMixin = function makePropCacheMixin(propName, proxyPropName) {
    return extend({
      data: function data() {
        return _defineProperty({}, proxyPropName, cloneDeep(this[propName]));
      },
      watch: _defineProperty({}, propName, makePropWatcher(proxyPropName))
    });
  };

  var attrsMixinVue2 = makePropCacheMixin('$attrs', 'bvAttrs');
  var attrsMixinVue3 = extend({
    computed: {
      bvAttrs: function bvAttrs() {
        var bvAttrs = _objectSpread2$3({}, this.$attrs);

        Object.keys(bvAttrs).forEach(function (key) {
          if (bvAttrs[key] === undefined) {
            delete bvAttrs[key];
          }
        });
        return bvAttrs;
      }
    }
  });
  var attrsMixin = isVue3 ? attrsMixinVue3 : attrsMixinVue2;

  var getEventRoot = function getEventRoot(vm) {
    return vm.$root.$options.bvEventRoot || vm.$root;
  };

  var PROP$3 = '$_rootListeners'; // --- Mixin ---
  // @vue/component

  var listenOnRootMixin = extend({
    computed: {
      bvEventRoot: function bvEventRoot() {
        return getEventRoot(this);
      }
    },
    created: function created() {
      // Define non-reactive property
      // Object of arrays, keyed by event name,
      // where value is an array of callbacks
      this[PROP$3] = {};
    },
    beforeDestroy: function beforeDestroy() {
      var _this = this;

      // Unregister all registered listeners
      keys(this[PROP$3] || {}).forEach(function (event) {
        _this[PROP$3][event].forEach(function (callback) {
          _this.listenOffRoot(event, callback);
        });
      });
      this[PROP$3] = null;
    },
    methods: {
      registerRootListener: function registerRootListener(event, callback) {
        if (this[PROP$3]) {
          this[PROP$3][event] = this[PROP$3][event] || [];

          if (!arrayIncludes(this[PROP$3][event], callback)) {
            this[PROP$3][event].push(callback);
          }
        }
      },
      unregisterRootListener: function unregisterRootListener(event, callback) {
        if (this[PROP$3] && this[PROP$3][event]) {
          this[PROP$3][event] = this[PROP$3][event].filter(function (cb) {
            return cb !== callback;
          });
        }
      },

      /**
       * Safely register event listeners on the root Vue node
       * While Vue automatically removes listeners for individual components,
       * when a component registers a listener on `$root` and is destroyed,
       * this orphans a callback because the node is gone, but the `$root`
       * does not clear the callback
       *
       * When registering a `$root` listener, it also registers the listener
       * to be removed in the component's `beforeDestroy()` hook
       *
       * @param {string} event
       * @param {function} callback
       */
      listenOnRoot: function listenOnRoot(event, callback) {
        if (this.bvEventRoot) {
          this.bvEventRoot.$on(event, callback);
          this.registerRootListener(event, callback);
        }
      },

      /**
       * Safely register a `$once()` event listener on the root Vue node
       * While Vue automatically removes listeners for individual components,
       * when a component registers a listener on `$root` and is destroyed,
       * this orphans a callback because the node is gone, but the `$root`
       * does not clear the callback
       *
       * When registering a `$root` listener, it also registers the listener
       * to be removed in the component's `beforeDestroy()` hook
       *
       * @param {string} event
       * @param {function} callback
       */
      listenOnRootOnce: function listenOnRootOnce(event, callback) {
        var _this2 = this;

        if (this.bvEventRoot) {
          var _callback = function _callback() {
            _this2.unregisterRootListener(_callback); // eslint-disable-next-line node/no-callback-literal


            callback.apply(void 0, arguments);
          };

          this.bvEventRoot.$once(event, _callback);
          this.registerRootListener(event, _callback);
        }
      },

      /**
       * Safely unregister event listeners from the root Vue node
       *
       * @param {string} event
       * @param {function} callback
       */
      listenOffRoot: function listenOffRoot(event, callback) {
        this.unregisterRootListener(event, callback);

        if (this.bvEventRoot) {
          this.bvEventRoot.$off(event, callback);
        }
      },

      /**
       * Convenience method for calling `vm.$emit()` on `$root`
       *
       * @param {string} event
       * @param {*} args
       */
      emitOnRoot: function emitOnRoot(event) {
        if (this.bvEventRoot) {
          var _this$bvEventRoot;

          for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
            args[_key - 1] = arguments[_key];
          }

          (_this$bvEventRoot = this.bvEventRoot).$emit.apply(_this$bvEventRoot, [event].concat(args));
        }
      }
    }
  });

  var listenersMixinVue2 = makePropCacheMixin('$listeners', 'bvListeners');
  var listenersMixinVue3 = extend({
    data: function data() {
      return {
        bvListeners: {}
      };
    },
    created: function created() {
      this.bvListeners = _objectSpread2$3({}, this.$listeners);
    },
    beforeUpdate: function beforeUpdate() {
      this.bvListeners = _objectSpread2$3({}, this.$listeners);
    }
  });
  var listenersMixin = isVue3 ? listenersMixinVue3 : listenersMixinVue2;

  var ROOT_EVENT_NAME_CLICKED = getRootEventName(NAME_LINK, 'clicked'); // --- Props ---
  // `<router-link>` specific props

  var routerLinkProps = {
    activeClass: makeProp(PROP_TYPE_STRING),
    append: makeProp(PROP_TYPE_BOOLEAN, false),
    event: makeProp(PROP_TYPE_ARRAY_STRING),
    exact: makeProp(PROP_TYPE_BOOLEAN, false),
    exactActiveClass: makeProp(PROP_TYPE_STRING),
    exactPath: makeProp(PROP_TYPE_BOOLEAN, false),
    exactPathActiveClass: makeProp(PROP_TYPE_STRING),
    replace: makeProp(PROP_TYPE_BOOLEAN, false),
    routerTag: makeProp(PROP_TYPE_STRING),
    to: makeProp(PROP_TYPE_OBJECT_STRING)
  }; // `<nuxt-link>` specific props

  var nuxtLinkProps = {
    noPrefetch: makeProp(PROP_TYPE_BOOLEAN, false),
    // Must be `null` to fall back to the value defined in the
    // `nuxt.config.js` configuration file for `router.prefetchLinks`
    // We convert `null` to `undefined`, so that Nuxt.js will use the
    // compiled default
    // Vue treats `undefined` as default of `false` for Boolean props,
    // so we must set it as `null` here to be a true tri-state prop
    prefetch: makeProp(PROP_TYPE_BOOLEAN, null)
  }; // All `<b-link>` props

  var props$2f = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, nuxtLinkProps), routerLinkProps), {}, {
    active: makeProp(PROP_TYPE_BOOLEAN, false),
    disabled: makeProp(PROP_TYPE_BOOLEAN, false),
    href: makeProp(PROP_TYPE_STRING),
    // Must be `null` if no value provided
    rel: makeProp(PROP_TYPE_STRING, null),
    // To support 3rd party router links based on `<router-link>` (i.e. `g-link` for Gridsome)
    // Default is to auto choose between `<router-link>` and `<nuxt-link>`
    // Gridsome doesn't provide a mechanism to auto detect and has caveats
    // such as not supporting FQDN URLs or hash only URLs
    routerComponentName: makeProp(PROP_TYPE_STRING),
    target: makeProp(PROP_TYPE_STRING, '_self')
  })), NAME_LINK); // --- Main component ---
  // @vue/component

  var BLink = /*#__PURE__*/extend({
    name: NAME_LINK,
    // Mixin order is important!
    mixins: [attrsMixin, listenersMixin, listenOnRootMixin, normalizeSlotMixin],
    inheritAttrs: false,
    props: props$2f,
    computed: {
      computedTag: function computedTag() {
        // We don't pass `this` as the first arg as we need reactivity of the props
        var to = this.to,
            disabled = this.disabled,
            routerComponentName = this.routerComponentName;
        return computeTag({
          to: to,
          disabled: disabled,
          routerComponentName: routerComponentName
        }, this);
      },
      isRouterLink: function isRouterLink$1() {
        return isRouterLink(this.computedTag);
      },
      computedRel: function computedRel() {
        // We don't pass `this` as the first arg as we need reactivity of the props
        var target = this.target,
            rel = this.rel;
        return computeRel({
          target: target,
          rel: rel
        });
      },
      computedHref: function computedHref() {
        // We don't pass `this` as the first arg as we need reactivity of the props
        var to = this.to,
            href = this.href;
        return computeHref({
          to: to,
          href: href
        }, this.computedTag);
      },
      computedProps: function computedProps() {
        var event = this.event,
            prefetch = this.prefetch,
            routerTag = this.routerTag;
        return this.isRouterLink ? _objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, pluckProps(omit(_objectSpread2$3(_objectSpread2$3({}, routerLinkProps), this.computedTag === 'nuxt-link' ? nuxtLinkProps : {}), ['event', 'prefetch', 'routerTag']), this)), event ? {
          event: event
        } : {}), isBoolean(prefetch) ? {
          prefetch: prefetch
        } : {}), routerTag ? {
          tag: routerTag
        } : {}) : {};
      },
      computedAttrs: function computedAttrs() {
        var bvAttrs = this.bvAttrs,
            href = this.computedHref,
            rel = this.computedRel,
            disabled = this.disabled,
            target = this.target,
            routerTag = this.routerTag,
            isRouterLink = this.isRouterLink;
        return _objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, bvAttrs), href ? {
          href: href
        } : {}), isRouterLink && routerTag && !isTag(routerTag, 'a') ? {} : {
          rel: rel,
          target: target
        }), {}, {
          tabindex: disabled ? '-1' : isUndefined(bvAttrs.tabindex) ? null : bvAttrs.tabindex,
          'aria-disabled': disabled ? 'true' : null
        });
      },
      computedListeners: function computedListeners() {
        return _objectSpread2$3(_objectSpread2$3({}, this.bvListeners), {}, {
          // We want to overwrite any click handler since our callback
          // will invoke the user supplied handler(s) if `!this.disabled`
          click: this.onClick
        });
      }
    },
    methods: {
      onClick: function onClick(event) {
        var _arguments = arguments;
        var eventIsEvent = isEvent(event);
        var isRouterLink = this.isRouterLink;
        var suppliedHandler = this.bvListeners.click;

        if (eventIsEvent && this.disabled) {
          // Stop event from bubbling up
          // Kill the event loop attached to this specific `EventTarget`
          // Needed to prevent `vue-router` for doing its thing
          stopEvent(event, {
            immediatePropagation: true
          });
        } else {
          // Router links do not emit instance `click` events, so we
          // add in an `$emit('click', event)` on its Vue instance
          //
          // seems not to be required for Vue3 compat build

          /* istanbul ignore next: difficult to test, but we know it works */
          if (isRouterLink) {
            var _event$currentTarget$;

            (_event$currentTarget$ = event.currentTarget.__vue__) === null || _event$currentTarget$ === void 0 ? void 0 : _event$currentTarget$.$emit(EVENT_NAME_CLICK, event);
          } // Call the suppliedHandler(s), if any provided


          concat(suppliedHandler).filter(function (h) {
            return isFunction$1(h);
          }).forEach(function (handler) {
            handler.apply(void 0, _toConsumableArray$1(_arguments));
          }); // Emit the global `$root` click event

          this.emitOnRoot(ROOT_EVENT_NAME_CLICKED, event); // TODO: Remove deprecated 'clicked::link' event with next major release

          this.emitOnRoot('clicked::link', event);
        } // Stop scroll-to-top behavior or navigation on
        // regular links when href is just '#'


        if (eventIsEvent && !isRouterLink && this.computedHref === '#') {
          stopEvent(event, {
            propagation: false
          });
        }
      },
      focus: function focus() {
        attemptFocus(this.$el);
      },
      blur: function blur() {
        attemptBlur(this.$el);
      }
    },
    render: function render(h) {
      var active = this.active,
          disabled = this.disabled;
      return h(this.computedTag, _defineProperty({
        class: {
          active: active,
          disabled: disabled
        },
        attrs: this.computedAttrs,
        props: this.computedProps
      }, this.isRouterLink ? 'nativeOn' : 'on', this.computedListeners), this.normalizeSlot());
    }
  });

  var linkProps$7 = omit(props$2f, ['event', 'routerTag']);
  delete linkProps$7.href.default;
  delete linkProps$7.to.default;
  var props$2e = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, linkProps$7), {}, {
    block: makeProp(PROP_TYPE_BOOLEAN, false),
    disabled: makeProp(PROP_TYPE_BOOLEAN, false),
    pill: makeProp(PROP_TYPE_BOOLEAN, false),
    // Tri-state: `true`, `false` or `null`
    // => On, off, not a toggle
    pressed: makeProp(PROP_TYPE_BOOLEAN, null),
    size: makeProp(PROP_TYPE_STRING),
    squared: makeProp(PROP_TYPE_BOOLEAN, false),
    tag: makeProp(PROP_TYPE_STRING, 'button'),
    type: makeProp(PROP_TYPE_STRING, 'button'),
    variant: makeProp(PROP_TYPE_STRING, 'secondary')
  })), NAME_BUTTON); // --- Helper methods ---
  // Focus handler for toggle buttons
  // Needs class of 'focus' when focused

  var handleFocus = function handleFocus(event) {
    if (event.type === 'focusin') {
      addClass(event.target, 'focus');
    } else if (event.type === 'focusout') {
      removeClass(event.target, 'focus');
    }
  }; // Is the requested button a link?
  // If tag prop is set to `a`, we use a <b-link> to get proper disabled handling


  var isLink = function isLink(props) {
    return isLink$1(props) || isTag(props.tag, 'a');
  }; // Is the button to be a toggle button?


  var isToggle = function isToggle(props) {
    return isBoolean(props.pressed);
  }; // Is the button "really" a button?


  var isButton = function isButton(props) {
    return !(isLink(props) || props.tag && !isTag(props.tag, 'button'));
  }; // Is the requested tag not a button or link?


  var isNonStandardTag$1 = function isNonStandardTag(props) {
    return !isLink(props) && !isButton(props);
  }; // Compute required classes (non static classes)


  var computeClass = function computeClass(props) {
    var _ref;

    return ["btn-".concat(props.variant || 'secondary'), (_ref = {}, _defineProperty(_ref, "btn-".concat(props.size), props.size), _defineProperty(_ref, 'btn-block', props.block), _defineProperty(_ref, 'rounded-pill', props.pill), _defineProperty(_ref, 'rounded-0', props.squared && !props.pill), _defineProperty(_ref, "disabled", props.disabled), _defineProperty(_ref, "active", props.pressed), _ref)];
  }; // Compute the link props to pass to b-link (if required)


  var computeLinkProps = function computeLinkProps(props) {
    return isLink(props) ? pluckProps(linkProps$7, props) : {};
  }; // Compute the attributes for a button


  var computeAttrs = function computeAttrs(props, data) {
    var button = isButton(props);
    var link = isLink(props);
    var toggle = isToggle(props);
    var nonStandardTag = isNonStandardTag$1(props);
    var hashLink = link && props.href === '#';
    var role = data.attrs && data.attrs.role ? data.attrs.role : null;
    var tabindex = data.attrs ? data.attrs.tabindex : null;

    if (nonStandardTag || hashLink) {
      tabindex = '0';
    }

    return {
      // Type only used for "real" buttons
      type: button && !link ? props.type : null,
      // Disabled only set on "real" buttons
      disabled: button ? props.disabled : null,
      // We add a role of button when the tag is not a link or button for ARIA
      // Don't bork any role provided in `data.attrs` when `isLink` or `isButton`
      // Except when link has `href` of `#`
      role: nonStandardTag || hashLink ? 'button' : role,
      // We set the `aria-disabled` state for non-standard tags
      'aria-disabled': nonStandardTag ? String(props.disabled) : null,
      // For toggles, we need to set the pressed state for ARIA
      'aria-pressed': toggle ? String(props.pressed) : null,
      // `autocomplete="off"` is needed in toggle mode to prevent some browsers
      // from remembering the previous setting when using the back button
      autocomplete: toggle ? 'off' : null,
      // `tabindex` is used when the component is not a button
      // Links are tabbable, but don't allow disabled, while non buttons or links
      // are not tabbable, so we mimic that functionality by disabling tabbing
      // when disabled, and adding a `tabindex="0"` to non buttons or non links
      tabindex: props.disabled && !button ? '-1' : tabindex
    };
  }; // --- Main component ---
  // @vue/component


  var BButton = /*#__PURE__*/extend({
    name: NAME_BUTTON,
    functional: true,
    props: props$2e,
    render: function render(h, _ref2) {
      var props = _ref2.props,
          data = _ref2.data,
          listeners = _ref2.listeners,
          children = _ref2.children;
      var toggle = isToggle(props);
      var link = isLink(props);
      var nonStandardTag = isNonStandardTag$1(props);
      var hashLink = link && props.href === '#';
      var on = {
        keydown: function keydown(event) {
          // When the link is a `href="#"` or a non-standard tag (has `role="button"`),
          // we add a keydown handlers for CODE_SPACE/CODE_ENTER

          /* istanbul ignore next */
          if (props.disabled || !(nonStandardTag || hashLink)) {
            return;
          }

          var keyCode = event.keyCode; // Add CODE_SPACE handler for `href="#"` and CODE_ENTER handler for non-standard tags

          if (keyCode === CODE_SPACE || keyCode === CODE_ENTER && nonStandardTag) {
            var target = event.currentTarget || event.target;
            stopEvent(event, {
              propagation: false
            });
            target.click();
          }
        },
        click: function click(event) {
          /* istanbul ignore if: blink/button disabled should handle this */
          if (props.disabled && isEvent(event)) {
            stopEvent(event);
          } else if (toggle && listeners && listeners['update:pressed']) {
            // Send `.sync` updates to any "pressed" prop (if `.sync` listeners)
            // `concat()` will normalize the value to an array without
            // double wrapping an array value in an array
            concat(listeners['update:pressed']).forEach(function (fn) {
              if (isFunction$1(fn)) {
                fn(!props.pressed);
              }
            });
          }
        }
      };

      if (toggle) {
        on.focusin = handleFocus;
        on.focusout = handleFocus;
      }

      var componentData = {
        staticClass: 'btn',
        class: computeClass(props),
        props: computeLinkProps(props),
        attrs: computeAttrs(props, data),
        on: on
      };
      return h(link ? BLink : props.tag, a(_objectSpread2$3(_objectSpread2$3({}, data), {}, {
        props: undefined
      }), componentData), children);
    }
  });

  var CLASS_NAME$2 = 'b-avatar';
  var SIZES = ['sm', null, 'lg'];
  var FONT_SIZE_SCALE = 0.4;
  var BADGE_FONT_SIZE_SCALE = FONT_SIZE_SCALE * 0.7; // --- Helper methods ---

  var computeSize = function computeSize(value) {
    // Parse to number when value is a float-like string
    value = isString(value) && isNumeric$1(value) ? toFloat(value, 0) : value; // Convert all numbers to pixel values

    return isNumber(value) ? "".concat(value, "px") : value || null;
  }; // --- Props ---

  var linkProps$6 = omit(props$2f, ['active', 'event', 'routerTag']);
  var props$2d = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, linkProps$6), {}, {
    alt: makeProp(PROP_TYPE_STRING, 'avatar'),
    ariaLabel: makeProp(PROP_TYPE_STRING),
    badge: makeProp(PROP_TYPE_BOOLEAN_STRING, false),
    badgeLeft: makeProp(PROP_TYPE_BOOLEAN, false),
    badgeOffset: makeProp(PROP_TYPE_STRING),
    badgeTop: makeProp(PROP_TYPE_BOOLEAN, false),
    badgeVariant: makeProp(PROP_TYPE_STRING, 'primary'),
    button: makeProp(PROP_TYPE_BOOLEAN, false),
    buttonType: makeProp(PROP_TYPE_STRING, 'button'),
    icon: makeProp(PROP_TYPE_STRING),
    rounded: makeProp(PROP_TYPE_BOOLEAN_STRING, false),
    size: makeProp(PROP_TYPE_NUMBER_STRING),
    square: makeProp(PROP_TYPE_BOOLEAN, false),
    src: makeProp(PROP_TYPE_STRING),
    text: makeProp(PROP_TYPE_STRING),
    variant: makeProp(PROP_TYPE_STRING, 'secondary')
  })), NAME_AVATAR); // --- Main component ---
  // @vue/component

  var BAvatar = /*#__PURE__*/extend({
    name: NAME_AVATAR,
    mixins: [normalizeSlotMixin],
    inject: {
      getBvAvatarGroup: {
        default: function _default() {
          return function () {
            return null;
          };
        }
      }
    },
    props: props$2d,
    data: function data() {
      return {
        localSrc: this.src || null
      };
    },
    computed: {
      bvAvatarGroup: function bvAvatarGroup() {
        return this.getBvAvatarGroup();
      },
      computedSize: function computedSize() {
        // Always use the avatar group size
        var bvAvatarGroup = this.bvAvatarGroup;
        return computeSize(bvAvatarGroup ? bvAvatarGroup.size : this.size);
      },
      computedVariant: function computedVariant() {
        var bvAvatarGroup = this.bvAvatarGroup;
        return bvAvatarGroup && bvAvatarGroup.variant ? bvAvatarGroup.variant : this.variant;
      },
      computedRounded: function computedRounded() {
        var bvAvatarGroup = this.bvAvatarGroup;
        var square = bvAvatarGroup && bvAvatarGroup.square ? true : this.square;
        var rounded = bvAvatarGroup && bvAvatarGroup.rounded ? bvAvatarGroup.rounded : this.rounded;
        return square ? '0' : rounded === '' ? true : rounded || 'circle';
      },
      fontStyle: function fontStyle() {
        var size = this.computedSize;
        var fontSize = SIZES.indexOf(size) === -1 ? "calc(".concat(size, " * ").concat(FONT_SIZE_SCALE, ")") : null;
        return fontSize ? {
          fontSize: fontSize
        } : {};
      },
      marginStyle: function marginStyle() {
        var size = this.computedSize,
            bvAvatarGroup = this.bvAvatarGroup;
        var overlapScale = bvAvatarGroup ? bvAvatarGroup.overlapScale : 0;
        var value = size && overlapScale ? "calc(".concat(size, " * -").concat(overlapScale, ")") : null;
        return value ? {
          marginLeft: value,
          marginRight: value
        } : {};
      },
      badgeStyle: function badgeStyle() {
        var size = this.computedSize,
            badgeTop = this.badgeTop,
            badgeLeft = this.badgeLeft,
            badgeOffset = this.badgeOffset;
        var offset = badgeOffset || '0px';
        return {
          fontSize: SIZES.indexOf(size) === -1 ? "calc(".concat(size, " * ").concat(BADGE_FONT_SIZE_SCALE, " )") : null,
          top: badgeTop ? offset : null,
          bottom: badgeTop ? null : offset,
          left: badgeLeft ? offset : null,
          right: badgeLeft ? null : offset
        };
      }
    },
    watch: {
      src: function src(newValue, oldValue) {
        if (newValue !== oldValue) {
          this.localSrc = newValue || null;
        }
      }
    },
    methods: {
      onImgError: function onImgError(event) {
        this.localSrc = null;
        this.$emit(EVENT_NAME_IMG_ERROR, event);
      },
      onClick: function onClick(event) {
        this.$emit(EVENT_NAME_CLICK, event);
      }
    },
    render: function render(h) {
      var _class2;

      var variant = this.computedVariant,
          disabled = this.disabled,
          rounded = this.computedRounded,
          icon = this.icon,
          src = this.localSrc,
          text = this.text,
          fontStyle = this.fontStyle,
          marginStyle = this.marginStyle,
          size = this.computedSize,
          button = this.button,
          type = this.buttonType,
          badge = this.badge,
          badgeVariant = this.badgeVariant,
          badgeStyle = this.badgeStyle;
      var link = !button && isLink$1(this);
      var tag = button ? BButton : link ? BLink : 'span';
      var alt = this.alt;
      var ariaLabel = this.ariaLabel || null;
      var $content = null;

      if (this.hasNormalizedSlot()) {
        // Default slot overrides props
        $content = h('span', {
          staticClass: 'b-avatar-custom'
        }, [this.normalizeSlot()]);
      } else if (src) {
        $content = h('img', {
          style: variant ? {} : {
            width: '100%',
            height: '100%'
          },
          attrs: {
            src: src,
            alt: alt
          },
          on: {
            error: this.onImgError
          }
        });
        $content = h('span', {
          staticClass: 'b-avatar-img'
        }, [$content]);
      } else if (icon) {
        $content = h(BIcon, {
          props: {
            icon: icon
          },
          attrs: {
            'aria-hidden': 'true',
            alt: alt
          }
        });
      } else if (text) {
        $content = h('span', {
          staticClass: 'b-avatar-text',
          style: fontStyle
        }, [h('span', text)]);
      } else {
        // Fallback default avatar content
        $content = h(BIconPersonFill, {
          attrs: {
            'aria-hidden': 'true',
            alt: alt
          }
        });
      }

      var $badge = h();
      var hasBadgeSlot = this.hasNormalizedSlot(SLOT_NAME_BADGE);

      if (badge || badge === '' || hasBadgeSlot) {
        var badgeText = badge === true ? '' : badge;
        $badge = h('span', {
          staticClass: 'b-avatar-badge',
          class: _defineProperty({}, "badge-".concat(badgeVariant), badgeVariant),
          style: badgeStyle
        }, [hasBadgeSlot ? this.normalizeSlot(SLOT_NAME_BADGE) : badgeText]);
      }

      var componentData = {
        staticClass: CLASS_NAME$2,
        class: (_class2 = {}, _defineProperty(_class2, "".concat(CLASS_NAME$2, "-").concat(size), size && SIZES.indexOf(size) !== -1), _defineProperty(_class2, "badge-".concat(variant), !button && variant), _defineProperty(_class2, "rounded", rounded === true), _defineProperty(_class2, "rounded-".concat(rounded), rounded && rounded !== true), _defineProperty(_class2, "disabled", disabled), _class2),
        style: _objectSpread2$3(_objectSpread2$3({}, marginStyle), {}, {
          width: size,
          height: size
        }),
        attrs: {
          'aria-label': ariaLabel || null
        },
        props: button ? {
          variant: variant,
          disabled: disabled,
          type: type
        } : link ? pluckProps(linkProps$6, this) : {},
        on: button || link ? {
          click: this.onClick
        } : {}
      };
      return h(tag, componentData, [$content, $badge]);
    }
  });

  var props$2c = makePropsConfigurable({
    overlap: makeProp(PROP_TYPE_NUMBER_STRING, 0.3),
    // Child avatars will prefer this prop (if set) over their own
    rounded: makeProp(PROP_TYPE_BOOLEAN_STRING, false),
    // Child avatars will always use this over their own size
    size: makeProp(PROP_TYPE_STRING),
    // Child avatars will prefer this prop (if set) over their own
    square: makeProp(PROP_TYPE_BOOLEAN, false),
    tag: makeProp(PROP_TYPE_STRING, 'div'),
    // Child avatars will prefer this variant over their own
    variant: makeProp(PROP_TYPE_STRING)
  }, NAME_AVATAR_GROUP); // --- Main component ---
  // @vue/component

  var BAvatarGroup = /*#__PURE__*/extend({
    name: NAME_AVATAR_GROUP,
    mixins: [normalizeSlotMixin],
    provide: function provide() {
      var _this = this;

      return {
        getBvAvatarGroup: function getBvAvatarGroup() {
          return _this;
        }
      };
    },
    props: props$2c,
    computed: {
      computedSize: function computedSize() {
        return computeSize(this.size);
      },
      overlapScale: function overlapScale() {
        return mathMin(mathMax(toFloat(this.overlap, 0), 0), 1) / 2;
      },
      paddingStyle: function paddingStyle() {
        var value = this.computedSize;
        value = value ? "calc(".concat(value, " * ").concat(this.overlapScale, ")") : null;
        return value ? {
          paddingLeft: value,
          paddingRight: value
        } : {};
      }
    },
    render: function render(h) {
      var $inner = h('div', {
        staticClass: 'b-avatar-group-inner',
        style: this.paddingStyle
      }, this.normalizeSlot());
      return h(this.tag, {
        staticClass: 'b-avatar-group',
        attrs: {
          role: 'group'
        }
      }, [$inner]);
    }
  });

  var AvatarPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BAvatar: BAvatar,
      BAvatarGroup: BAvatarGroup
    }
  });

  var linkProps$5 = omit(props$2f, ['event', 'routerTag']);
  delete linkProps$5.href.default;
  delete linkProps$5.to.default;
  var props$2b = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, linkProps$5), {}, {
    pill: makeProp(PROP_TYPE_BOOLEAN, false),
    tag: makeProp(PROP_TYPE_STRING, 'span'),
    variant: makeProp(PROP_TYPE_STRING, 'secondary')
  })), NAME_BADGE); // --- Main component ---
  // @vue/component

  var BBadge = /*#__PURE__*/extend({
    name: NAME_BADGE,
    functional: true,
    props: props$2b,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      var active = props.active,
          disabled = props.disabled;
      var link = isLink$1(props);
      var tag = link ? BLink : props.tag;
      var variant = props.variant || 'secondary';
      return h(tag, a(data, {
        staticClass: 'badge',
        class: ["badge-".concat(variant), {
          'badge-pill': props.pill,
          active: active,
          disabled: disabled
        }],
        props: link ? pluckProps(linkProps$5, props) : {}
      }), children);
    }
  });

  var BadgePlugin = /*#__PURE__*/pluginFactory({
    components: {
      BBadge: BBadge
    }
  });

  var stripTags = function stripTags() {
    var text = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
    return String(text).replace(RX_HTML_TAGS, '');
  }; // Generate a `domProps` object for either `innerHTML`, `textContent` or an empty object

  var htmlOrText = function htmlOrText(innerHTML, textContent) {
    return innerHTML ? {
      innerHTML: innerHTML
    } : textContent ? {
      textContent: textContent
    } : {};
  };

  var props$2a = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, omit(props$2f, ['event', 'routerTag'])), {}, {
    ariaCurrent: makeProp(PROP_TYPE_STRING, 'location'),
    html: makeProp(PROP_TYPE_STRING),
    text: makeProp(PROP_TYPE_STRING)
  })), NAME_BREADCRUMB_LINK); // --- Main component ---
  // @vue/component

  var BBreadcrumbLink = /*#__PURE__*/extend({
    name: NAME_BREADCRUMB_LINK,
    functional: true,
    props: props$2a,
    render: function render(h, _ref) {
      var suppliedProps = _ref.props,
          data = _ref.data,
          children = _ref.children;
      var active = suppliedProps.active;
      var tag = active ? 'span' : BLink;
      var componentData = {
        attrs: {
          'aria-current': active ? suppliedProps.ariaCurrent : null
        },
        props: pluckProps(props$2a, suppliedProps)
      };

      if (!children) {
        componentData.domProps = htmlOrText(suppliedProps.html, suppliedProps.text);
      }

      return h(tag, a(data, componentData), children);
    }
  });

  var props$29 = makePropsConfigurable(props$2a, NAME_BREADCRUMB_ITEM); // --- Main component ---
  // @vue/component

  var BBreadcrumbItem = /*#__PURE__*/extend({
    name: NAME_BREADCRUMB_ITEM,
    functional: true,
    props: props$29,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      return h('li', a(data, {
        staticClass: 'breadcrumb-item',
        class: {
          active: props.active
        }
      }), [h(BBreadcrumbLink, {
        props: props
      }, children)]);
    }
  });

  var props$28 = makePropsConfigurable({
    items: makeProp(PROP_TYPE_ARRAY)
  }, NAME_BREADCRUMB); // --- Main component ---
  // @vue/component

  var BBreadcrumb = /*#__PURE__*/extend({
    name: NAME_BREADCRUMB,
    functional: true,
    props: props$28,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      var items = props.items; // Build child nodes from items, if given

      var childNodes = children;

      if (isArray(items)) {
        var activeDefined = false;
        childNodes = items.map(function (item, idx) {
          if (!isObject(item)) {
            item = {
              text: toString(item)
            };
          } // Copy the value here so we can normalize it


          var _item = item,
              active = _item.active;

          if (active) {
            activeDefined = true;
          } // Auto-detect active by position in list


          if (!active && !activeDefined) {
            active = idx + 1 === items.length;
          }

          return h(BBreadcrumbItem, {
            props: _objectSpread2$3(_objectSpread2$3({}, item), {}, {
              active: active
            })
          });
        });
      }

      return h('ol', a(data, {
        staticClass: 'breadcrumb'
      }), childNodes);
    }
  });

  var BreadcrumbPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BBreadcrumb: BBreadcrumb,
      BBreadcrumbItem: BBreadcrumbItem,
      BBreadcrumbLink: BBreadcrumbLink
    }
  });

  var ButtonPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BButton: BButton,
      BBtn: BButton,
      BButtonClose: BButtonClose,
      BBtnClose: BButtonClose
    }
  });

  var props$27 = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, pick$1(props$2e, ['size'])), {}, {
    ariaRole: makeProp(PROP_TYPE_STRING, 'group'),
    size: makeProp(PROP_TYPE_STRING),
    tag: makeProp(PROP_TYPE_STRING, 'div'),
    vertical: makeProp(PROP_TYPE_BOOLEAN, false)
  })), NAME_BUTTON_GROUP); // --- Main component ---
  // @vue/component

  var BButtonGroup = /*#__PURE__*/extend({
    name: NAME_BUTTON_GROUP,
    functional: true,
    props: props$27,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      return h(props.tag, a(data, {
        class: _defineProperty({
          'btn-group': !props.vertical,
          'btn-group-vertical': props.vertical
        }, "btn-group-".concat(props.size), props.size),
        attrs: {
          role: props.ariaRole
        }
      }), children);
    }
  });

  var ButtonGroupPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BButtonGroup: BButtonGroup,
      BBtnGroup: BButtonGroup
    }
  });

  var ITEM_SELECTOR = ['.btn:not(.disabled):not([disabled]):not(.dropdown-item)', '.form-control:not(.disabled):not([disabled])', 'select:not(.disabled):not([disabled])', 'input[type="checkbox"]:not(.disabled)', 'input[type="radio"]:not(.disabled)'].join(','); // --- Props ---

  var props$26 = makePropsConfigurable({
    justify: makeProp(PROP_TYPE_BOOLEAN, false),
    keyNav: makeProp(PROP_TYPE_BOOLEAN, false)
  }, NAME_BUTTON_TOOLBAR); // --- Main component ---
  // @vue/component

  var BButtonToolbar = /*#__PURE__*/extend({
    name: NAME_BUTTON_TOOLBAR,
    mixins: [normalizeSlotMixin],
    props: props$26,
    mounted: function mounted() {
      // Pre-set the tabindexes if the markup does not include
      // `tabindex="-1"` on the toolbar items
      if (this.keyNav) {
        this.getItems();
      }
    },
    methods: {
      getItems: function getItems() {
        var items = selectAll(ITEM_SELECTOR, this.$el); // Ensure `tabindex="-1"` is set on every item

        items.forEach(function (item) {
          item.tabIndex = -1;
        });
        return items.filter(function (el) {
          return isVisible(el);
        });
      },
      focusFirst: function focusFirst() {
        var items = this.getItems();
        attemptFocus(items[0]);
      },
      focusPrev: function focusPrev(event) {
        var items = this.getItems();
        var index = items.indexOf(event.target);

        if (index > -1) {
          items = items.slice(0, index).reverse();
          attemptFocus(items[0]);
        }
      },
      focusNext: function focusNext(event) {
        var items = this.getItems();
        var index = items.indexOf(event.target);

        if (index > -1) {
          items = items.slice(index + 1);
          attemptFocus(items[0]);
        }
      },
      focusLast: function focusLast() {
        var items = this.getItems().reverse();
        attemptFocus(items[0]);
      },
      onFocusin: function onFocusin(event) {
        var $el = this.$el;

        if (event.target === $el && !contains($el, event.relatedTarget)) {
          stopEvent(event);
          this.focusFirst(event);
        }
      },
      onKeydown: function onKeydown(event) {
        var keyCode = event.keyCode,
            shiftKey = event.shiftKey;

        if (keyCode === CODE_UP || keyCode === CODE_LEFT) {
          stopEvent(event);
          shiftKey ? this.focusFirst(event) : this.focusPrev(event);
        } else if (keyCode === CODE_DOWN || keyCode === CODE_RIGHT) {
          stopEvent(event);
          shiftKey ? this.focusLast(event) : this.focusNext(event);
        }
      }
    },
    render: function render(h) {
      var keyNav = this.keyNav;
      return h('div', {
        staticClass: 'btn-toolbar',
        class: {
          'justify-content-between': this.justify
        },
        attrs: {
          role: 'toolbar',
          tabindex: keyNav ? '0' : null
        },
        on: keyNav ? {
          focusin: this.onFocusin,
          keydown: this.onKeydown
        } : {}
      }, [this.normalizeSlot()]);
    }
  });

  var ButtonToolbarPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BButtonToolbar: BButtonToolbar,
      BBtnToolbar: BButtonToolbar
    }
  });

  var CALENDAR_GREGORY = 'gregory';
  var CALENDAR_LONG = 'long';
  var CALENDAR_NARROW = 'narrow';
  var CALENDAR_SHORT = 'short';
  var DATE_FORMAT_2_DIGIT = '2-digit';
  var DATE_FORMAT_NUMERIC = 'numeric';

  // Create or clone a date (`new Date(...)` shortcut)

  var createDate = function createDate() {
    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
      args[_key] = arguments[_key];
    }

    return _construct(Date, args);
  }; // Parse a date sting, or Date object, into a Date object (with no time information)

  var parseYMD = function parseYMD(date) {
    if (isString(date) && RX_DATE.test(date.trim())) {
      var _date$split$map = date.split(RX_DATE_SPLIT).map(function (v) {
        return toInteger(v, 1);
      }),
          _date$split$map2 = _slicedToArray(_date$split$map, 3),
          year = _date$split$map2[0],
          month = _date$split$map2[1],
          day = _date$split$map2[2];

      return createDate(year, month - 1, day);
    } else if (isDate(date)) {
      return createDate(date.getFullYear(), date.getMonth(), date.getDate());
    }

    return null;
  }; // Format a date object as `YYYY-MM-DD` format

  var formatYMD = function formatYMD(date) {
    date = parseYMD(date);

    if (!date) {
      return null;
    }

    var year = date.getFullYear();
    var month = "0".concat(date.getMonth() + 1).slice(-2);
    var day = "0".concat(date.getDate()).slice(-2);
    return "".concat(year, "-").concat(month, "-").concat(day);
  }; // Given a locale (or locales), resolve the browser available locale

  var resolveLocale = function resolveLocale(locales)
  /* istanbul ignore next */
  {
    var calendar = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : CALENDAR_GREGORY;
    locales = concat(locales).filter(identity);
    var fmt = new Intl.DateTimeFormat(locales, {
      calendar: calendar
    });
    return fmt.resolvedOptions().locale;
  }; // Create a `Intl.DateTimeFormat` formatter function

  var createDateFormatter = function createDateFormatter(locale, options)
  /* istanbul ignore next */
  {
    var dtf = new Intl.DateTimeFormat(locale, options);
    return dtf.format;
  }; // Determine if two dates are the same date (ignoring time portion)

  var datesEqual = function datesEqual(date1, date2) {
    // Returns true of the date portion of two date objects are equal
    // We don't compare the time portion
    return formatYMD(date1) === formatYMD(date2);
  }; // --- Date "math" utility methods (for BCalendar component mainly) ---

  var firstDateOfMonth = function firstDateOfMonth(date) {
    date = createDate(date);
    date.setDate(1);
    return date;
  };
  var lastDateOfMonth = function lastDateOfMonth(date) {
    date = createDate(date);
    date.setMonth(date.getMonth() + 1);
    date.setDate(0);
    return date;
  };
  var addYears = function addYears(date, numberOfYears) {
    date = createDate(date);
    var month = date.getMonth();
    date.setFullYear(date.getFullYear() + numberOfYears); // Handle Feb 29th for leap years

    if (date.getMonth() !== month) {
      date.setDate(0);
    }

    return date;
  };
  var oneMonthAgo = function oneMonthAgo(date) {
    date = createDate(date);
    var month = date.getMonth();
    date.setMonth(month - 1); // Handle when days in month are different

    if (date.getMonth() === month) {
      date.setDate(0);
    }

    return date;
  };
  var oneMonthAhead = function oneMonthAhead(date) {
    date = createDate(date);
    var month = date.getMonth();
    date.setMonth(month + 1); // Handle when days in month are different

    if (date.getMonth() === (month + 2) % 12) {
      date.setDate(0);
    }

    return date;
  };
  var oneYearAgo = function oneYearAgo(date) {
    return addYears(date, -1);
  };
  var oneYearAhead = function oneYearAhead(date) {
    return addYears(date, 1);
  };
  var oneDecadeAgo = function oneDecadeAgo(date) {
    return addYears(date, -10);
  };
  var oneDecadeAhead = function oneDecadeAhead(date) {
    return addYears(date, 10);
  }; // Helper function to constrain a date between two values
  // Always returns a `Date` object or `null` if no date passed

  var constrainDate = function constrainDate(date) {
    var min = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
    var max = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
    // Ensure values are `Date` objects (or `null`)
    date = parseYMD(date);
    min = parseYMD(min) || date;
    max = parseYMD(max) || date; // Return a new `Date` object (or `null`)

    return date ? date < min ? min : date > max ? max : date : null;
  };

  // Localization utilities

  var RTL_LANGS = ['ar', 'az', 'ckb', 'fa', 'he', 'ks', 'lrc', 'mzn', 'ps', 'sd', 'te', 'ug', 'ur', 'yi'].map(function (locale) {
    return locale.toLowerCase();
  }); // Returns true if the locale is RTL

  var isLocaleRTL = function isLocaleRTL(locale) {
    // Determines if the locale is RTL (only single locale supported)
    var parts = toString(locale).toLowerCase().replace(RX_STRIP_LOCALE_MODS, '').split('-');
    var locale1 = parts.slice(0, 2).join('-');
    var locale2 = parts[0];
    return arrayIncludes(RTL_LANGS, locale1) || arrayIncludes(RTL_LANGS, locale2);
  };

  // SSR safe client-side ID attribute generation

  var props$25 = {
    id: makeProp(PROP_TYPE_STRING)
  }; // --- Mixin ---
  // @vue/component

  var idMixin = extend({
    props: props$25,
    data: function data() {
      return {
        localId_: null
      };
    },
    computed: {
      safeId: function safeId() {
        // Computed property that returns a dynamic function for creating the ID
        // Reacts to changes in both `.id` and `.localId_` and regenerates a new function
        var id = this.id || this.localId_; // We return a function that accepts an optional suffix string
        // So this computed prop looks and works like a method
        // but benefits from Vue's computed prop caching

        var fn = function fn(suffix) {
          if (!id) {
            return null;
          }

          suffix = String(suffix || '').replace(/\s+/g, '_');
          return suffix ? id + '_' + suffix : id;
        };

        return fn;
      }
    },
    mounted: function mounted() {
      var _this = this;

      // `mounted()` only occurs client-side
      this.$nextTick(function () {
        // Update DOM with auto-generated ID after mount
        // to prevent SSR hydration errors
        _this.localId_ = "__BVID__".concat(_this[COMPONENT_UID_KEY]);
      });
    }
  });

  var _watch$j;

  var _makeModelMixin$j = makeModelMixin('value', {
    type: PROP_TYPE_DATE_STRING
  }),
      modelMixin$i = _makeModelMixin$j.mixin,
      modelProps$i = _makeModelMixin$j.props,
      MODEL_PROP_NAME$i = _makeModelMixin$j.prop,
      MODEL_EVENT_NAME$i = _makeModelMixin$j.event; // --- Props ---


  var props$24 = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$25), modelProps$i), {}, {
    ariaControls: makeProp(PROP_TYPE_STRING),
    // Makes calendar the full width of its parent container
    block: makeProp(PROP_TYPE_BOOLEAN, false),
    dateDisabledFn: makeProp(PROP_TYPE_FUNCTION),
    // `Intl.DateTimeFormat` object
    dateFormatOptions: makeProp(PROP_TYPE_OBJECT, {
      year: DATE_FORMAT_NUMERIC,
      month: CALENDAR_LONG,
      day: DATE_FORMAT_NUMERIC,
      weekday: CALENDAR_LONG
    }),
    // Function to set a class of (classes) on the date cell
    // if passed a string or an array
    // TODO:
    //   If the function returns an object, look for class prop for classes,
    //   and other props for handling events/details/descriptions
    dateInfoFn: makeProp(PROP_TYPE_FUNCTION),
    // 'ltr', 'rtl', or `null` (for auto detect)
    direction: makeProp(PROP_TYPE_STRING),
    disabled: makeProp(PROP_TYPE_BOOLEAN, false),
    headerTag: makeProp(PROP_TYPE_STRING, 'header'),
    // When `true`, renders a comment node, but keeps the component instance active
    // Mainly for <b-form-date>, so that we can get the component's value and locale
    // But we might just use separate date formatters, using the resolved locale
    // (adjusted for the gregorian calendar)
    hidden: makeProp(PROP_TYPE_BOOLEAN, false),
    // When `true` makes the selected date header `sr-only`
    hideHeader: makeProp(PROP_TYPE_BOOLEAN, false),
    // This specifies the calendar year/month/day that will be shown when
    // first opening the datepicker if no v-model value is provided
    // Default is the current date (or `min`/`max`)
    initialDate: makeProp(PROP_TYPE_DATE_STRING),
    // Labels for buttons and keyboard shortcuts
    labelCalendar: makeProp(PROP_TYPE_STRING, 'Calendar'),
    labelCurrentMonth: makeProp(PROP_TYPE_STRING, 'Current month'),
    labelHelp: makeProp(PROP_TYPE_STRING, 'Use cursor keys to navigate calendar dates'),
    labelNav: makeProp(PROP_TYPE_STRING, 'Calendar navigation'),
    labelNextDecade: makeProp(PROP_TYPE_STRING, 'Next decade'),
    labelNextMonth: makeProp(PROP_TYPE_STRING, 'Next month'),
    labelNextYear: makeProp(PROP_TYPE_STRING, 'Next year'),
    labelNoDateSelected: makeProp(PROP_TYPE_STRING, 'No date selected'),
    labelPrevDecade: makeProp(PROP_TYPE_STRING, 'Previous decade'),
    labelPrevMonth: makeProp(PROP_TYPE_STRING, 'Previous month'),
    labelPrevYear: makeProp(PROP_TYPE_STRING, 'Previous year'),
    labelSelected: makeProp(PROP_TYPE_STRING, 'Selected date'),
    labelToday: makeProp(PROP_TYPE_STRING, 'Today'),
    // Locale(s) to use
    // Default is to use page/browser default setting
    locale: makeProp(PROP_TYPE_ARRAY_STRING),
    max: makeProp(PROP_TYPE_DATE_STRING),
    min: makeProp(PROP_TYPE_DATE_STRING),
    // Variant color to use for the navigation buttons
    navButtonVariant: makeProp(PROP_TYPE_STRING, 'secondary'),
    // Disable highlighting today's date
    noHighlightToday: makeProp(PROP_TYPE_BOOLEAN, false),
    noKeyNav: makeProp(PROP_TYPE_BOOLEAN, false),
    readonly: makeProp(PROP_TYPE_BOOLEAN, false),
    roleDescription: makeProp(PROP_TYPE_STRING),
    // Variant color to use for the selected date
    selectedVariant: makeProp(PROP_TYPE_STRING, 'primary'),
    // When `true` enables the decade navigation buttons
    showDecadeNav: makeProp(PROP_TYPE_BOOLEAN, false),
    // Day of week to start calendar on
    // `0` (Sunday), `1` (Monday), ... `6` (Saturday)
    startWeekday: makeProp(PROP_TYPE_NUMBER_STRING, 0),
    // Variant color to use for today's date (defaults to `selectedVariant`)
    todayVariant: makeProp(PROP_TYPE_STRING),
    // Always return the `v-model` value as a date object
    valueAsDate: makeProp(PROP_TYPE_BOOLEAN, false),
    // Format of the weekday names at the top of the calendar
    // `short` is typically a 3 letter abbreviation,
    // `narrow` is typically a single letter
    // `long` is the full week day name
    // Although some locales may override this (i.e `ar`, etc.)
    weekdayHeaderFormat: makeProp(PROP_TYPE_STRING, CALENDAR_SHORT, function (value) {
      return arrayIncludes([CALENDAR_LONG, CALENDAR_SHORT, CALENDAR_NARROW], value);
    }),
    // Has no effect if prop `block` is set
    width: makeProp(PROP_TYPE_STRING, '270px')
  })), NAME_CALENDAR); // --- Main component ---
  // @vue/component

  var BCalendar = extend({
    name: NAME_CALENDAR,
    // Mixin order is important!
    mixins: [attrsMixin, idMixin, modelMixin$i, normalizeSlotMixin],
    props: props$24,
    data: function data() {
      var selected = formatYMD(this[MODEL_PROP_NAME$i]) || '';
      return {
        // Selected date
        selectedYMD: selected,
        // Date in calendar grid that has `tabindex` of `0`
        activeYMD: selected || formatYMD(constrainDate(this.initialDate || this.getToday()), this.min, this.max),
        // Will be true if the calendar grid has/contains focus
        gridHasFocus: false,
        // Flag to enable the `aria-live` region(s) after mount
        // to prevent screen reader "outbursts" when mounting
        isLive: false
      };
    },
    computed: {
      valueId: function valueId() {
        return this.safeId();
      },
      widgetId: function widgetId() {
        return this.safeId('_calendar-wrapper_');
      },
      navId: function navId() {
        return this.safeId('_calendar-nav_');
      },
      gridId: function gridId() {
        return this.safeId('_calendar-grid_');
      },
      gridCaptionId: function gridCaptionId() {
        return this.safeId('_calendar-grid-caption_');
      },
      gridHelpId: function gridHelpId() {
        return this.safeId('_calendar-grid-help_');
      },
      activeId: function activeId() {
        return this.activeYMD ? this.safeId("_cell-".concat(this.activeYMD, "_")) : null;
      },
      // TODO: Use computed props to convert `YYYY-MM-DD` to `Date` object
      selectedDate: function selectedDate() {
        // Selected as a `Date` object
        return parseYMD(this.selectedYMD);
      },
      activeDate: function activeDate() {
        // Active as a `Date` object
        return parseYMD(this.activeYMD);
      },
      computedMin: function computedMin() {
        return parseYMD(this.min);
      },
      computedMax: function computedMax() {
        return parseYMD(this.max);
      },
      computedWeekStarts: function computedWeekStarts() {
        // `startWeekday` is a prop (constrained to `0` through `6`)
        return mathMax(toInteger(this.startWeekday, 0), 0) % 7;
      },
      computedLocale: function computedLocale() {
        // Returns the resolved locale used by the calendar
        return resolveLocale(concat(this.locale).filter(identity), CALENDAR_GREGORY);
      },
      computedDateDisabledFn: function computedDateDisabledFn() {
        var dateDisabledFn = this.dateDisabledFn;
        return hasPropFunction(dateDisabledFn) ? dateDisabledFn : function () {
          return false;
        };
      },
      // TODO: Change `dateInfoFn` to handle events and notes as well as classes
      computedDateInfoFn: function computedDateInfoFn() {
        var dateInfoFn = this.dateInfoFn;
        return hasPropFunction(dateInfoFn) ? dateInfoFn : function () {
          return {};
        };
      },
      calendarLocale: function calendarLocale() {
        // This locale enforces the gregorian calendar (for use in formatter functions)
        // Needed because IE 11 resolves `ar-IR` as islamic-civil calendar
        // and IE 11 (and some other browsers) do not support the `calendar` option
        // And we currently only support the gregorian calendar
        var fmt = new Intl.DateTimeFormat(this.computedLocale, {
          calendar: CALENDAR_GREGORY
        });
        var calendar = fmt.resolvedOptions().calendar;
        var locale = fmt.resolvedOptions().locale;
        /* istanbul ignore if: mainly for IE 11 and a few other browsers, hard to test in JSDOM */

        if (calendar !== CALENDAR_GREGORY) {
          // Ensure the locale requests the gregorian calendar
          // Mainly for IE 11, and currently we can't handle non-gregorian calendars
          // TODO: Should we always return this value?
          locale = locale.replace(/-u-.+$/i, '').concat('-u-ca-gregory');
        }

        return locale;
      },
      calendarYear: function calendarYear() {
        return this.activeDate.getFullYear();
      },
      calendarMonth: function calendarMonth() {
        return this.activeDate.getMonth();
      },
      calendarFirstDay: function calendarFirstDay() {
        // We set the time for this date to 12pm to work around
        // date formatting issues in Firefox and Safari
        // See: https://github.com/bootstrap-vue/bootstrap-vue/issues/5818
        return createDate(this.calendarYear, this.calendarMonth, 1, 12);
      },
      calendarDaysInMonth: function calendarDaysInMonth() {
        // We create a new date as to not mutate the original
        var date = createDate(this.calendarFirstDay);
        date.setMonth(date.getMonth() + 1, 0);
        return date.getDate();
      },
      computedVariant: function computedVariant() {
        return "btn-".concat(this.selectedVariant || 'primary');
      },
      computedTodayVariant: function computedTodayVariant() {
        return "btn-outline-".concat(this.todayVariant || this.selectedVariant || 'primary');
      },
      computedNavButtonVariant: function computedNavButtonVariant() {
        return "btn-outline-".concat(this.navButtonVariant || 'primary');
      },
      isRTL: function isRTL() {
        // `true` if the language requested is RTL
        var dir = toString(this.direction).toLowerCase();

        if (dir === 'rtl') {
          /* istanbul ignore next */
          return true;
        } else if (dir === 'ltr') {
          /* istanbul ignore next */
          return false;
        }

        return isLocaleRTL(this.computedLocale);
      },
      context: function context() {
        var selectedYMD = this.selectedYMD,
            activeYMD = this.activeYMD;
        var selectedDate = parseYMD(selectedYMD);
        var activeDate = parseYMD(activeYMD);
        return {
          // The current value of the `v-model`
          selectedYMD: selectedYMD,
          selectedDate: selectedDate,
          selectedFormatted: selectedDate ? this.formatDateString(selectedDate) : this.labelNoDateSelected,
          // Which date cell is considered active due to navigation
          activeYMD: activeYMD,
          activeDate: activeDate,
          activeFormatted: activeDate ? this.formatDateString(activeDate) : '',
          // `true` if the date is disabled (when using keyboard navigation)
          disabled: this.dateDisabled(activeDate),
          // Locales used in formatting dates
          locale: this.computedLocale,
          calendarLocale: this.calendarLocale,
          rtl: this.isRTL
        };
      },
      // Computed props that return a function reference
      dateOutOfRange: function dateOutOfRange() {
        // Check whether a date is within the min/max range
        // Returns a new function ref if the pops change
        // We do this as we need to trigger the calendar computed prop
        // to update when these props update
        var min = this.computedMin,
            max = this.computedMax;
        return function (date) {
          // Handle both `YYYY-MM-DD` and `Date` objects
          date = parseYMD(date);
          return min && date < min || max && date > max;
        };
      },
      dateDisabled: function dateDisabled() {
        var _this = this;

        // Returns a function for validating if a date is within range
        // We grab this variables first to ensure a new function ref
        // is generated when the props value changes
        // We do this as we need to trigger the calendar computed prop
        // to update when these props update
        var rangeFn = this.dateOutOfRange; // Return the function ref

        return function (date) {
          // Handle both `YYYY-MM-DD` and `Date` objects
          date = parseYMD(date);
          var ymd = formatYMD(date);
          return !!(rangeFn(date) || _this.computedDateDisabledFn(ymd, date));
        };
      },
      // Computed props that return date formatter functions
      formatDateString: function formatDateString() {
        // Returns a date formatter function
        return createDateFormatter(this.calendarLocale, _objectSpread2$3(_objectSpread2$3({
          // Ensure we have year, month, day shown for screen readers/ARIA
          // If users really want to leave one of these out, they can
          // pass `undefined` for the property value
          year: DATE_FORMAT_NUMERIC,
          month: DATE_FORMAT_2_DIGIT,
          day: DATE_FORMAT_2_DIGIT
        }, this.dateFormatOptions), {}, {
          // Ensure hours/minutes/seconds are not shown
          // As we do not support the time portion (yet)
          hour: undefined,
          minute: undefined,
          second: undefined,
          // Ensure calendar is gregorian
          calendar: CALENDAR_GREGORY
        }));
      },
      formatYearMonth: function formatYearMonth() {
        // Returns a date formatter function
        return createDateFormatter(this.calendarLocale, {
          year: DATE_FORMAT_NUMERIC,
          month: CALENDAR_LONG,
          calendar: CALENDAR_GREGORY
        });
      },
      formatWeekdayName: function formatWeekdayName() {
        // Long weekday name for weekday header aria-label
        return createDateFormatter(this.calendarLocale, {
          weekday: CALENDAR_LONG,
          calendar: CALENDAR_GREGORY
        });
      },
      formatWeekdayNameShort: function formatWeekdayNameShort() {
        // Weekday header cell format
        // defaults to 'short' 3 letter days, where possible
        return createDateFormatter(this.calendarLocale, {
          weekday: this.weekdayHeaderFormat || CALENDAR_SHORT,
          calendar: CALENDAR_GREGORY
        });
      },
      formatDay: function formatDay() {
        // Calendar grid day number formatter
        // We don't use DateTimeFormatter here as it can place extra
        // character(s) after the number (i.e the `zh` locale)
        var nf = new Intl.NumberFormat([this.computedLocale], {
          style: 'decimal',
          minimumIntegerDigits: 1,
          minimumFractionDigits: 0,
          maximumFractionDigits: 0,
          notation: 'standard'
        }); // Return a formatter function instance

        return function (date) {
          return nf.format(date.getDate());
        };
      },
      // Disabled states for the nav buttons
      prevDecadeDisabled: function prevDecadeDisabled() {
        var min = this.computedMin;
        return this.disabled || min && lastDateOfMonth(oneDecadeAgo(this.activeDate)) < min;
      },
      prevYearDisabled: function prevYearDisabled() {
        var min = this.computedMin;
        return this.disabled || min && lastDateOfMonth(oneYearAgo(this.activeDate)) < min;
      },
      prevMonthDisabled: function prevMonthDisabled() {
        var min = this.computedMin;
        return this.disabled || min && lastDateOfMonth(oneMonthAgo(this.activeDate)) < min;
      },
      thisMonthDisabled: function thisMonthDisabled() {
        // TODO: We could/should check if today is out of range
        return this.disabled;
      },
      nextMonthDisabled: function nextMonthDisabled() {
        var max = this.computedMax;
        return this.disabled || max && firstDateOfMonth(oneMonthAhead(this.activeDate)) > max;
      },
      nextYearDisabled: function nextYearDisabled() {
        var max = this.computedMax;
        return this.disabled || max && firstDateOfMonth(oneYearAhead(this.activeDate)) > max;
      },
      nextDecadeDisabled: function nextDecadeDisabled() {
        var max = this.computedMax;
        return this.disabled || max && firstDateOfMonth(oneDecadeAhead(this.activeDate)) > max;
      },
      // Calendar dates generation
      calendar: function calendar() {
        var matrix = [];
        var firstDay = this.calendarFirstDay;
        var calendarYear = firstDay.getFullYear();
        var calendarMonth = firstDay.getMonth();
        var daysInMonth = this.calendarDaysInMonth;
        var startIndex = firstDay.getDay(); // `0`..`6`

        var weekOffset = (this.computedWeekStarts > startIndex ? 7 : 0) - this.computedWeekStarts; // Build the calendar matrix

        var currentDay = 0 - weekOffset - startIndex;

        for (var week = 0; week < 6 && currentDay < daysInMonth; week++) {
          // For each week
          matrix[week] = []; // The following could be a map function

          for (var j = 0; j < 7; j++) {
            // For each day in week
            currentDay++;
            var date = createDate(calendarYear, calendarMonth, currentDay);
            var month = date.getMonth();
            var dayYMD = formatYMD(date);
            var dayDisabled = this.dateDisabled(date); // TODO: This could be a normalizer method

            var dateInfo = this.computedDateInfoFn(dayYMD, parseYMD(dayYMD));
            dateInfo = isString(dateInfo) || isArray(dateInfo) ?
            /* istanbul ignore next */
            {
              class: dateInfo
            } : isPlainObject(dateInfo) ? _objectSpread2$3({
              class: ''
            }, dateInfo) :
            /* istanbul ignore next */
            {
              class: ''
            };
            matrix[week].push({
              ymd: dayYMD,
              // Cell content
              day: this.formatDay(date),
              label: this.formatDateString(date),
              // Flags for styling
              isThisMonth: month === calendarMonth,
              isDisabled: dayDisabled,
              // TODO: Handle other dateInfo properties such as notes/events
              info: dateInfo
            });
          }
        }

        return matrix;
      },
      calendarHeadings: function calendarHeadings() {
        var _this2 = this;

        return this.calendar[0].map(function (d) {
          return {
            text: _this2.formatWeekdayNameShort(parseYMD(d.ymd)),
            label: _this2.formatWeekdayName(parseYMD(d.ymd))
          };
        });
      }
    },
    watch: (_watch$j = {}, _defineProperty(_watch$j, MODEL_PROP_NAME$i, function (newValue, oldValue) {
      var selected = formatYMD(newValue) || '';
      var old = formatYMD(oldValue) || '';

      if (!datesEqual(selected, old)) {
        this.activeYMD = selected || this.activeYMD;
        this.selectedYMD = selected;
      }
    }), _defineProperty(_watch$j, "selectedYMD", function selectedYMD(newYMD, oldYMD) {
      // TODO:
      //   Should we compare to `formatYMD(this.value)` and emit
      //   only if they are different?
      if (newYMD !== oldYMD) {
        this.$emit(MODEL_EVENT_NAME$i, this.valueAsDate ? parseYMD(newYMD) || null : newYMD || '');
      }
    }), _defineProperty(_watch$j, "context", function context(newValue, oldValue) {
      if (!looseEqual(newValue, oldValue)) {
        this.$emit(EVENT_NAME_CONTEXT, newValue);
      }
    }), _defineProperty(_watch$j, "hidden", function hidden(newValue) {
      // Reset the active focused day when hidden
      this.activeYMD = this.selectedYMD || formatYMD(this[MODEL_PROP_NAME$i] || this.constrainDate(this.initialDate || this.getToday())); // Enable/disable the live regions

      this.setLive(!newValue);
    }), _watch$j),
    created: function created() {
      var _this3 = this;

      this.$nextTick(function () {
        _this3.$emit(EVENT_NAME_CONTEXT, _this3.context);
      });
    },
    mounted: function mounted() {
      this.setLive(true);
    },

    /* istanbul ignore next */
    activated: function activated() {
      this.setLive(true);
    },

    /* istanbul ignore next */
    deactivated: function deactivated() {
      this.setLive(false);
    },
    beforeDestroy: function beforeDestroy() {
      this.setLive(false);
    },
    methods: {
      // Public method(s)
      focus: function focus() {
        if (!this.disabled) {
          attemptFocus(this.$refs.grid);
        }
      },
      blur: function blur() {
        if (!this.disabled) {
          attemptBlur(this.$refs.grid);
        }
      },
      // Private methods
      setLive: function setLive(on) {
        var _this4 = this;

        if (on) {
          this.$nextTick(function () {
            requestAF(function () {
              _this4.isLive = true;
            });
          });
        } else {
          this.isLive = false;
        }
      },
      getToday: function getToday() {
        return parseYMD(createDate());
      },
      constrainDate: function constrainDate$1(date) {
        // Constrains a date between min and max
        // returns a new `Date` object instance
        return constrainDate(date, this.computedMin, this.computedMax);
      },
      emitSelected: function emitSelected(date) {
        var _this5 = this;

        // Performed in a `$nextTick()` to (probably) ensure
        // the input event has emitted first
        this.$nextTick(function () {
          _this5.$emit(EVENT_NAME_SELECTED, formatYMD(date) || '', parseYMD(date) || null);
        });
      },
      // Event handlers
      setGridFocusFlag: function setGridFocusFlag(event) {
        // Sets the gridHasFocus flag to make date "button" look focused
        this.gridHasFocus = !this.disabled && event.type === 'focus';
      },
      onKeydownWrapper: function onKeydownWrapper(event) {
        // Calendar keyboard navigation
        // Handles PAGEUP/PAGEDOWN/END/HOME/LEFT/UP/RIGHT/DOWN
        // Focuses grid after updating
        if (this.noKeyNav) {
          /* istanbul ignore next */
          return;
        }

        var altKey = event.altKey,
            ctrlKey = event.ctrlKey,
            keyCode = event.keyCode;

        if (!arrayIncludes([CODE_PAGEUP, CODE_PAGEDOWN, CODE_END, CODE_HOME, CODE_LEFT, CODE_UP, CODE_RIGHT, CODE_DOWN], keyCode)) {
          /* istanbul ignore next */
          return;
        }

        stopEvent(event);
        var activeDate = createDate(this.activeDate);
        var checkDate = createDate(this.activeDate);
        var day = activeDate.getDate();
        var constrainedToday = this.constrainDate(this.getToday());
        var isRTL = this.isRTL;

        if (keyCode === CODE_PAGEUP) {
          // PAGEUP - Previous month/year
          activeDate = (altKey ? ctrlKey ? oneDecadeAgo : oneYearAgo : oneMonthAgo)(activeDate); // We check the first day of month to be in rage

          checkDate = createDate(activeDate);
          checkDate.setDate(1);
        } else if (keyCode === CODE_PAGEDOWN) {
          // PAGEDOWN - Next month/year
          activeDate = (altKey ? ctrlKey ? oneDecadeAhead : oneYearAhead : oneMonthAhead)(activeDate); // We check the last day of month to be in rage

          checkDate = createDate(activeDate);
          checkDate.setMonth(checkDate.getMonth() + 1);
          checkDate.setDate(0);
        } else if (keyCode === CODE_LEFT) {
          // LEFT - Previous day (or next day for RTL)
          activeDate.setDate(day + (isRTL ? 1 : -1));
          activeDate = this.constrainDate(activeDate);
          checkDate = activeDate;
        } else if (keyCode === CODE_RIGHT) {
          // RIGHT - Next day (or previous day for RTL)
          activeDate.setDate(day + (isRTL ? -1 : 1));
          activeDate = this.constrainDate(activeDate);
          checkDate = activeDate;
        } else if (keyCode === CODE_UP) {
          // UP - Previous week
          activeDate.setDate(day - 7);
          activeDate = this.constrainDate(activeDate);
          checkDate = activeDate;
        } else if (keyCode === CODE_DOWN) {
          // DOWN - Next week
          activeDate.setDate(day + 7);
          activeDate = this.constrainDate(activeDate);
          checkDate = activeDate;
        } else if (keyCode === CODE_HOME) {
          // HOME - Today
          activeDate = constrainedToday;
          checkDate = activeDate;
        } else if (keyCode === CODE_END) {
          // END - Selected date, or today if no selected date
          activeDate = parseYMD(this.selectedDate) || constrainedToday;
          checkDate = activeDate;
        }

        if (!this.dateOutOfRange(checkDate) && !datesEqual(activeDate, this.activeDate)) {
          // We only jump to date if within min/max
          // We don't check for individual disabled dates though (via user function)
          this.activeYMD = formatYMD(activeDate);
        } // Ensure grid is focused


        this.focus();
      },
      onKeydownGrid: function onKeydownGrid(event) {
        // Pressing enter/space on grid to select active date
        var keyCode = event.keyCode;
        var activeDate = this.activeDate;

        if (keyCode === CODE_ENTER || keyCode === CODE_SPACE) {
          stopEvent(event);

          if (!this.disabled && !this.readonly && !this.dateDisabled(activeDate)) {
            this.selectedYMD = formatYMD(activeDate);
            this.emitSelected(activeDate);
          } // Ensure grid is focused


          this.focus();
        }
      },
      onClickDay: function onClickDay(day) {
        // Clicking on a date "button" to select it
        var selectedDate = this.selectedDate,
            activeDate = this.activeDate;
        var clickedDate = parseYMD(day.ymd);

        if (!this.disabled && !day.isDisabled && !this.dateDisabled(clickedDate)) {
          if (!this.readonly) {
            // If readonly mode, we don't set the selected date, just the active date
            // If the clicked date is equal to the already selected date, we don't update the model
            this.selectedYMD = formatYMD(datesEqual(clickedDate, selectedDate) ? selectedDate : clickedDate);
            this.emitSelected(clickedDate);
          }

          this.activeYMD = formatYMD(datesEqual(clickedDate, activeDate) ? activeDate : createDate(clickedDate)); // Ensure grid is focused

          this.focus();
        }
      },
      gotoPrevDecade: function gotoPrevDecade() {
        this.activeYMD = formatYMD(this.constrainDate(oneDecadeAgo(this.activeDate)));
      },
      gotoPrevYear: function gotoPrevYear() {
        this.activeYMD = formatYMD(this.constrainDate(oneYearAgo(this.activeDate)));
      },
      gotoPrevMonth: function gotoPrevMonth() {
        this.activeYMD = formatYMD(this.constrainDate(oneMonthAgo(this.activeDate)));
      },
      gotoCurrentMonth: function gotoCurrentMonth() {
        // TODO: Maybe this goto date should be configurable?
        this.activeYMD = formatYMD(this.constrainDate(this.getToday()));
      },
      gotoNextMonth: function gotoNextMonth() {
        this.activeYMD = formatYMD(this.constrainDate(oneMonthAhead(this.activeDate)));
      },
      gotoNextYear: function gotoNextYear() {
        this.activeYMD = formatYMD(this.constrainDate(oneYearAhead(this.activeDate)));
      },
      gotoNextDecade: function gotoNextDecade() {
        this.activeYMD = formatYMD(this.constrainDate(oneDecadeAhead(this.activeDate)));
      },
      onHeaderClick: function onHeaderClick() {
        if (!this.disabled) {
          this.activeYMD = this.selectedYMD || formatYMD(this.getToday());
          this.focus();
        }
      }
    },
    render: function render(h) {
      var _this6 = this;

      // If `hidden` prop is set, render just a placeholder node
      if (this.hidden) {
        return h();
      }

      var valueId = this.valueId,
          widgetId = this.widgetId,
          navId = this.navId,
          gridId = this.gridId,
          gridCaptionId = this.gridCaptionId,
          gridHelpId = this.gridHelpId,
          activeId = this.activeId,
          disabled = this.disabled,
          noKeyNav = this.noKeyNav,
          isLive = this.isLive,
          isRTL = this.isRTL,
          activeYMD = this.activeYMD,
          selectedYMD = this.selectedYMD,
          safeId = this.safeId;
      var hideDecadeNav = !this.showDecadeNav;
      var todayYMD = formatYMD(this.getToday());
      var highlightToday = !this.noHighlightToday; // Header showing current selected date

      var $header = h('output', {
        staticClass: 'form-control form-control-sm text-center',
        class: {
          'text-muted': disabled,
          readonly: this.readonly || disabled
        },
        attrs: {
          id: valueId,
          for: gridId,
          role: 'status',
          tabindex: disabled ? null : '-1',
          // Mainly for testing purposes, as we do not know
          // the exact format `Intl` will format the date string
          'data-selected': toString(selectedYMD),
          // We wait until after mount to enable `aria-live`
          // to prevent initial announcement on page render
          'aria-live': isLive ? 'polite' : 'off',
          'aria-atomic': isLive ? 'true' : null
        },
        on: {
          // Transfer focus/click to focus grid
          // and focus active date (or today if no selection)
          click: this.onHeaderClick,
          focus: this.onHeaderClick
        }
      }, this.selectedDate ? [// We use `bdi` elements here in case the label doesn't match the locale
      // Although IE 11 does not deal with <BDI> at all (equivalent to a span)
      h('bdi', {
        staticClass: 'sr-only'
      }, " (".concat(toString(this.labelSelected), ") ")), h('bdi', this.formatDateString(this.selectedDate))] : this.labelNoDateSelected || "\xA0" // '&nbsp;'
      );
      $header = h(this.headerTag, {
        staticClass: 'b-calendar-header',
        class: {
          'sr-only': this.hideHeader
        },
        attrs: {
          title: this.selectedDate ? this.labelSelected || null : null
        }
      }, [$header]); // Content for the date navigation buttons

      var navScope = {
        isRTL: isRTL
      };
      var navProps = {
        shiftV: 0.5
      };

      var navPrevProps = _objectSpread2$3(_objectSpread2$3({}, navProps), {}, {
        flipH: isRTL
      });

      var navNextProps = _objectSpread2$3(_objectSpread2$3({}, navProps), {}, {
        flipH: !isRTL
      });

      var $prevDecadeIcon = this.normalizeSlot(SLOT_NAME_NAV_PEV_DECADE, navScope) || h(BIconChevronBarLeft, {
        props: navPrevProps
      });
      var $prevYearIcon = this.normalizeSlot(SLOT_NAME_NAV_PEV_YEAR, navScope) || h(BIconChevronDoubleLeft, {
        props: navPrevProps
      });
      var $prevMonthIcon = this.normalizeSlot(SLOT_NAME_NAV_PEV_MONTH, navScope) || h(BIconChevronLeft, {
        props: navPrevProps
      });
      var $thisMonthIcon = this.normalizeSlot(SLOT_NAME_NAV_THIS_MONTH, navScope) || h(BIconCircleFill, {
        props: navProps
      });
      var $nextMonthIcon = this.normalizeSlot(SLOT_NAME_NAV_NEXT_MONTH, navScope) || h(BIconChevronLeft, {
        props: navNextProps
      });
      var $nextYearIcon = this.normalizeSlot(SLOT_NAME_NAV_NEXT_YEAR, navScope) || h(BIconChevronDoubleLeft, {
        props: navNextProps
      });
      var $nextDecadeIcon = this.normalizeSlot(SLOT_NAME_NAV_NEXT_DECADE, navScope) || h(BIconChevronBarLeft, {
        props: navNextProps
      }); // Utility to create the date navigation buttons

      var makeNavBtn = function makeNavBtn(content, label, handler, btnDisabled, shortcut) {
        return h('button', {
          staticClass: 'btn btn-sm border-0 flex-fill',
          class: [_this6.computedNavButtonVariant, {
            disabled: btnDisabled
          }],
          attrs: {
            title: label || null,
            type: 'button',
            tabindex: noKeyNav ? '-1' : null,
            'aria-label': label || null,
            'aria-disabled': btnDisabled ? 'true' : null,
            'aria-keyshortcuts': shortcut || null
          },
          on: btnDisabled ? {} : {
            click: handler
          }
        }, [h('div', {
          attrs: {
            'aria-hidden': 'true'
          }
        }, [content])]);
      }; // Generate the date navigation buttons


      var $nav = h('div', {
        staticClass: 'b-calendar-nav d-flex',
        attrs: {
          id: navId,
          role: 'group',
          tabindex: noKeyNav ? '-1' : null,
          'aria-hidden': disabled ? 'true' : null,
          'aria-label': this.labelNav || null,
          'aria-controls': gridId
        }
      }, [hideDecadeNav ? h() : makeNavBtn($prevDecadeIcon, this.labelPrevDecade, this.gotoPrevDecade, this.prevDecadeDisabled, 'Ctrl+Alt+PageDown'), makeNavBtn($prevYearIcon, this.labelPrevYear, this.gotoPrevYear, this.prevYearDisabled, 'Alt+PageDown'), makeNavBtn($prevMonthIcon, this.labelPrevMonth, this.gotoPrevMonth, this.prevMonthDisabled, 'PageDown'), makeNavBtn($thisMonthIcon, this.labelCurrentMonth, this.gotoCurrentMonth, this.thisMonthDisabled, 'Home'), makeNavBtn($nextMonthIcon, this.labelNextMonth, this.gotoNextMonth, this.nextMonthDisabled, 'PageUp'), makeNavBtn($nextYearIcon, this.labelNextYear, this.gotoNextYear, this.nextYearDisabled, 'Alt+PageUp'), hideDecadeNav ? h() : makeNavBtn($nextDecadeIcon, this.labelNextDecade, this.gotoNextDecade, this.nextDecadeDisabled, 'Ctrl+Alt+PageUp')]); // Caption for calendar grid

      var $gridCaption = h('div', {
        staticClass: 'b-calendar-grid-caption text-center font-weight-bold',
        class: {
          'text-muted': disabled
        },
        attrs: {
          id: gridCaptionId,
          'aria-live': isLive ? 'polite' : null,
          'aria-atomic': isLive ? 'true' : null
        },
        key: 'grid-caption'
      }, this.formatYearMonth(this.calendarFirstDay)); // Calendar weekday headings

      var $gridWeekDays = h('div', {
        staticClass: 'b-calendar-grid-weekdays row no-gutters border-bottom',
        attrs: {
          'aria-hidden': 'true'
        }
      }, this.calendarHeadings.map(function (d, idx) {
        return h('small', {
          staticClass: 'col text-truncate',
          class: {
            'text-muted': disabled
          },
          attrs: {
            title: d.label === d.text ? null : d.label,
            'aria-label': d.label
          },
          key: idx
        }, d.text);
      })); // Calendar day grid

      var $gridBody = this.calendar.map(function (week) {
        var $cells = week.map(function (day, dIndex) {
          var _class;

          var isSelected = day.ymd === selectedYMD;
          var isActive = day.ymd === activeYMD;
          var isToday = day.ymd === todayYMD;
          var idCell = safeId("_cell-".concat(day.ymd, "_")); // "fake" button

          var $btn = h('span', {
            staticClass: 'btn border-0 rounded-circle text-nowrap',
            // Should we add some classes to signify if today/selected/etc?
            class: (_class = {
              // Give the fake button a focus ring
              focus: isActive && _this6.gridHasFocus,
              // Styling
              disabled: day.isDisabled || disabled,
              active: isSelected
            }, _defineProperty(_class, _this6.computedVariant, isSelected), _defineProperty(_class, _this6.computedTodayVariant, isToday && highlightToday && !isSelected && day.isThisMonth), _defineProperty(_class, 'btn-outline-light', !(isToday && highlightToday) && !isSelected && !isActive), _defineProperty(_class, 'btn-light', !(isToday && highlightToday) && !isSelected && isActive), _defineProperty(_class, 'text-muted', !day.isThisMonth && !isSelected), _defineProperty(_class, 'text-dark', !(isToday && highlightToday) && !isSelected && !isActive && day.isThisMonth), _defineProperty(_class, 'font-weight-bold', (isSelected || day.isThisMonth) && !day.isDisabled), _class),
            on: {
              click: function click() {
                return _this6.onClickDay(day);
              }
            }
          }, day.day);
          return h('div', // Cell with button
          {
            staticClass: 'col p-0',
            class: day.isDisabled ? 'bg-light' : day.info.class || '',
            attrs: {
              id: idCell,
              role: 'button',
              'data-date': day.ymd,
              // Primarily for testing purposes
              // Only days in the month are presented as buttons to screen readers
              'aria-hidden': day.isThisMonth ? null : 'true',
              'aria-disabled': day.isDisabled || disabled ? 'true' : null,
              'aria-label': [day.label, isSelected ? "(".concat(_this6.labelSelected, ")") : null, isToday ? "(".concat(_this6.labelToday, ")") : null].filter(identity).join(' '),
              // NVDA doesn't convey `aria-selected`, but does `aria-current`,
              // ChromeVox doesn't convey `aria-current`, but does `aria-selected`,
              // so we set both attributes for robustness
              'aria-selected': isSelected ? 'true' : null,
              'aria-current': isSelected ? 'date' : null
            },
            key: dIndex
          }, [$btn]);
        }); // Return the week "row"
        // We use the first day of the weeks YMD value as a
        // key for efficient DOM patching / element re-use

        return h('div', {
          staticClass: 'row no-gutters',
          key: week[0].ymd
        }, $cells);
      });
      $gridBody = h('div', {
        // A key is only required on the body if we add in transition support
        staticClass: 'b-calendar-grid-body',
        style: disabled ? {
          pointerEvents: 'none'
        } : {} // key: this.activeYMD.slice(0, -3)

      }, $gridBody);
      var $gridHelp = h('div', {
        staticClass: 'b-calendar-grid-help border-top small text-muted text-center bg-light',
        attrs: {
          id: gridHelpId
        }
      }, [h('div', {
        staticClass: 'small'
      }, this.labelHelp)]);
      var $grid = h('div', {
        staticClass: 'b-calendar-grid form-control h-auto text-center',
        attrs: {
          id: gridId,
          role: 'application',
          tabindex: noKeyNav ? '-1' : disabled ? null : '0',
          'data-month': activeYMD.slice(0, -3),
          // `YYYY-MM`, mainly for testing
          'aria-roledescription': this.labelCalendar || null,
          'aria-labelledby': gridCaptionId,
          'aria-describedby': gridHelpId,
          // `aria-readonly` is not considered valid on `role="application"`
          // https://www.w3.org/TR/wai-aria-1.1/#aria-readonly
          // 'aria-readonly': this.readonly && !disabled ? 'true' : null,
          'aria-disabled': disabled ? 'true' : null,
          'aria-activedescendant': activeId
        },
        on: {
          keydown: this.onKeydownGrid,
          focus: this.setGridFocusFlag,
          blur: this.setGridFocusFlag
        },
        ref: 'grid'
      }, [$gridCaption, $gridWeekDays, $gridBody, $gridHelp]); // Optional bottom slot

      var $slot = this.normalizeSlot();
      $slot = $slot ? h('footer', {
        staticClass: 'b-calendar-footer'
      }, $slot) : h();
      var $widget = h('div', {
        staticClass: 'b-calendar-inner',
        style: this.block ? {} : {
          width: this.width
        },
        attrs: {
          id: widgetId,
          dir: isRTL ? 'rtl' : 'ltr',
          lang: this.computedLocale || null,
          role: 'group',
          'aria-disabled': disabled ? 'true' : null,
          // If datepicker controls an input, this will specify the ID of the input
          'aria-controls': this.ariaControls || null,
          // This should be a prop (so it can be changed to Date picker, etc, localized
          'aria-roledescription': this.roleDescription || null,
          'aria-describedby': [// Should the attr (if present) go last?
          // Or should this attr be a prop?
          this.bvAttrs['aria-describedby'], valueId, gridHelpId].filter(identity).join(' ')
        },
        on: {
          keydown: this.onKeydownWrapper
        }
      }, [$header, $nav, $grid, $slot]); // Wrap in an outer div that can be styled

      return h('div', {
        staticClass: 'b-calendar',
        class: {
          'd-block': this.block
        }
      }, [$widget]);
    }
  });

  var CalendarPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BCalendar: BCalendar
    }
  });

  var props$23 = makePropsConfigurable({
    bgVariant: makeProp(PROP_TYPE_STRING),
    borderVariant: makeProp(PROP_TYPE_STRING),
    tag: makeProp(PROP_TYPE_STRING, 'div'),
    textVariant: makeProp(PROP_TYPE_STRING)
  }, NAME_CARD); // --- Mixin ---
  // @vue/component

  extend({
    props: props$23
  });

  var props$22 = makePropsConfigurable({
    title: makeProp(PROP_TYPE_STRING),
    titleTag: makeProp(PROP_TYPE_STRING, 'h4')
  }, NAME_CARD_TITLE); // --- Main component ---
  // @vue/component

  var BCardTitle = /*#__PURE__*/extend({
    name: NAME_CARD_TITLE,
    functional: true,
    props: props$22,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      return h(props.titleTag, a(data, {
        staticClass: 'card-title'
      }), children || toString(props.title));
    }
  });

  var props$21 = makePropsConfigurable({
    subTitle: makeProp(PROP_TYPE_STRING),
    subTitleTag: makeProp(PROP_TYPE_STRING, 'h6'),
    subTitleTextVariant: makeProp(PROP_TYPE_STRING, 'muted')
  }, NAME_CARD_SUB_TITLE); // --- Main component ---
  // @vue/component

  var BCardSubTitle = /*#__PURE__*/extend({
    name: NAME_CARD_SUB_TITLE,
    functional: true,
    props: props$21,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      return h(props.subTitleTag, a(data, {
        staticClass: 'card-subtitle',
        class: [props.subTitleTextVariant ? "text-".concat(props.subTitleTextVariant) : null]
      }), children || toString(props.subTitle));
    }
  });

  var props$20 = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$22), props$21), copyProps(props$23, prefixPropName.bind(null, 'body'))), {}, {
    bodyClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    overlay: makeProp(PROP_TYPE_BOOLEAN, false)
  })), NAME_CARD_BODY); // --- Main component ---
  // @vue/component

  var BCardBody = /*#__PURE__*/extend({
    name: NAME_CARD_BODY,
    functional: true,
    props: props$20,
    render: function render(h, _ref) {
      var _ref2;

      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      var bodyBgVariant = props.bodyBgVariant,
          bodyBorderVariant = props.bodyBorderVariant,
          bodyTextVariant = props.bodyTextVariant;
      var $title = h();

      if (props.title) {
        $title = h(BCardTitle, {
          props: pluckProps(props$22, props)
        });
      }

      var $subTitle = h();

      if (props.subTitle) {
        $subTitle = h(BCardSubTitle, {
          props: pluckProps(props$21, props),
          class: ['mb-2']
        });
      }

      return h(props.bodyTag, a(data, {
        staticClass: 'card-body',
        class: [(_ref2 = {
          'card-img-overlay': props.overlay
        }, _defineProperty(_ref2, "bg-".concat(bodyBgVariant), bodyBgVariant), _defineProperty(_ref2, "border-".concat(bodyBorderVariant), bodyBorderVariant), _defineProperty(_ref2, "text-".concat(bodyTextVariant), bodyTextVariant), _ref2), props.bodyClass]
      }), [$title, $subTitle, children]);
    }
  });

  var props$1$ = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, copyProps(props$23, prefixPropName.bind(null, 'header'))), {}, {
    header: makeProp(PROP_TYPE_STRING),
    headerClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    headerHtml: makeProp(PROP_TYPE_STRING)
  })), NAME_CARD_HEADER); // --- Main component ---
  // @vue/component

  var BCardHeader = /*#__PURE__*/extend({
    name: NAME_CARD_HEADER,
    functional: true,
    props: props$1$,
    render: function render(h, _ref) {
      var _ref2;

      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      var headerBgVariant = props.headerBgVariant,
          headerBorderVariant = props.headerBorderVariant,
          headerTextVariant = props.headerTextVariant;
      return h(props.headerTag, a(data, {
        staticClass: 'card-header',
        class: [props.headerClass, (_ref2 = {}, _defineProperty(_ref2, "bg-".concat(headerBgVariant), headerBgVariant), _defineProperty(_ref2, "border-".concat(headerBorderVariant), headerBorderVariant), _defineProperty(_ref2, "text-".concat(headerTextVariant), headerTextVariant), _ref2)],
        domProps: children ? {} : htmlOrText(props.headerHtml, props.header)
      }), children);
    }
  });

  var props$1_ = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, copyProps(props$23, prefixPropName.bind(null, 'footer'))), {}, {
    footer: makeProp(PROP_TYPE_STRING),
    footerClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    footerHtml: makeProp(PROP_TYPE_STRING)
  })), NAME_CARD_FOOTER); // --- Main component ---
  // @vue/component

  var BCardFooter = /*#__PURE__*/extend({
    name: NAME_CARD_FOOTER,
    functional: true,
    props: props$1_,
    render: function render(h, _ref) {
      var _ref2;

      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      var footerBgVariant = props.footerBgVariant,
          footerBorderVariant = props.footerBorderVariant,
          footerTextVariant = props.footerTextVariant;
      return h(props.footerTag, a(data, {
        staticClass: 'card-footer',
        class: [props.footerClass, (_ref2 = {}, _defineProperty(_ref2, "bg-".concat(footerBgVariant), footerBgVariant), _defineProperty(_ref2, "border-".concat(footerBorderVariant), footerBorderVariant), _defineProperty(_ref2, "text-".concat(footerTextVariant), footerTextVariant), _ref2)],
        domProps: children ? {} : htmlOrText(props.footerHtml, props.footer)
      }), children);
    }
  });

  // Blank image with fill template

  var BLANK_TEMPLATE = '<svg width="%{w}" height="%{h}" ' + 'xmlns="http://www.w3.org/2000/svg" ' + 'viewBox="0 0 %{w} %{h}" preserveAspectRatio="none">' + '<rect width="100%" height="100%" style="fill:%{f};"></rect>' + '</svg>'; // --- Helper methods ---

  var makeBlankImgSrc = function makeBlankImgSrc(width, height, color) {
    var src = encodeURIComponent(BLANK_TEMPLATE.replace('%{w}', toString(width)).replace('%{h}', toString(height)).replace('%{f}', color));
    return "data:image/svg+xml;charset=UTF-8,".concat(src);
  }; // --- Props ---


  var props$1Z = makePropsConfigurable({
    alt: makeProp(PROP_TYPE_STRING),
    blank: makeProp(PROP_TYPE_BOOLEAN, false),
    blankColor: makeProp(PROP_TYPE_STRING, 'transparent'),
    block: makeProp(PROP_TYPE_BOOLEAN, false),
    center: makeProp(PROP_TYPE_BOOLEAN, false),
    fluid: makeProp(PROP_TYPE_BOOLEAN, false),
    // Gives fluid images class `w-100` to make them grow to fit container
    fluidGrow: makeProp(PROP_TYPE_BOOLEAN, false),
    height: makeProp(PROP_TYPE_NUMBER_STRING),
    left: makeProp(PROP_TYPE_BOOLEAN, false),
    right: makeProp(PROP_TYPE_BOOLEAN, false),
    // Possible values:
    //   `false`: no rounding of corners
    //   `true`: slightly rounded corners
    //   'top': top corners rounded
    //   'right': right corners rounded
    //   'bottom': bottom corners rounded
    //   'left': left corners rounded
    //   'circle': circle/oval
    //   '0': force rounding off
    rounded: makeProp(PROP_TYPE_BOOLEAN_STRING, false),
    sizes: makeProp(PROP_TYPE_ARRAY_STRING),
    src: makeProp(PROP_TYPE_STRING),
    srcset: makeProp(PROP_TYPE_ARRAY_STRING),
    thumbnail: makeProp(PROP_TYPE_BOOLEAN, false),
    width: makeProp(PROP_TYPE_NUMBER_STRING)
  }, NAME_IMG); // --- Main component ---
  // @vue/component

  var BImg = /*#__PURE__*/extend({
    name: NAME_IMG,
    functional: true,
    props: props$1Z,
    render: function render(h, _ref) {
      var _class;

      var props = _ref.props,
          data = _ref.data;
      var alt = props.alt,
          src = props.src,
          block = props.block,
          fluidGrow = props.fluidGrow,
          rounded = props.rounded;
      var width = toInteger(props.width) || null;
      var height = toInteger(props.height) || null;
      var align = null;
      var srcset = concat(props.srcset).filter(identity).join(',');
      var sizes = concat(props.sizes).filter(identity).join(',');

      if (props.blank) {
        if (!height && width) {
          height = width;
        } else if (!width && height) {
          width = height;
        }

        if (!width && !height) {
          width = 1;
          height = 1;
        } // Make a blank SVG image


        src = makeBlankImgSrc(width, height, props.blankColor || 'transparent'); // Disable srcset and sizes

        srcset = null;
        sizes = null;
      }

      if (props.left) {
        align = 'float-left';
      } else if (props.right) {
        align = 'float-right';
      } else if (props.center) {
        align = 'mx-auto';
        block = true;
      }

      return h('img', a(data, {
        attrs: {
          src: src,
          alt: alt,
          width: width ? toString(width) : null,
          height: height ? toString(height) : null,
          srcset: srcset || null,
          sizes: sizes || null
        },
        class: (_class = {
          'img-thumbnail': props.thumbnail,
          'img-fluid': props.fluid || fluidGrow,
          'w-100': fluidGrow,
          rounded: rounded === '' || rounded === true
        }, _defineProperty(_class, "rounded-".concat(rounded), isString(rounded) && rounded !== ''), _defineProperty(_class, align, align), _defineProperty(_class, 'd-block', block), _class)
      }));
    }
  });

  var props$1Y = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, pick$1(props$1Z, ['src', 'alt', 'width', 'height', 'left', 'right'])), {}, {
    bottom: makeProp(PROP_TYPE_BOOLEAN, false),
    end: makeProp(PROP_TYPE_BOOLEAN, false),
    start: makeProp(PROP_TYPE_BOOLEAN, false),
    top: makeProp(PROP_TYPE_BOOLEAN, false)
  })), NAME_CARD_IMG); // --- Main component ---
  // @vue/component

  var BCardImg = /*#__PURE__*/extend({
    name: NAME_CARD_IMG,
    functional: true,
    props: props$1Y,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data;
      var src = props.src,
          alt = props.alt,
          width = props.width,
          height = props.height;
      var baseClass = 'card-img';

      if (props.top) {
        baseClass += '-top';
      } else if (props.right || props.end) {
        baseClass += '-right';
      } else if (props.bottom) {
        baseClass += '-bottom';
      } else if (props.left || props.start) {
        baseClass += '-left';
      }

      return h('img', a(data, {
        class: baseClass,
        attrs: {
          src: src,
          alt: alt,
          width: width,
          height: height
        }
      }));
    }
  });

  var cardImgProps = copyProps(props$1Y, prefixPropName.bind(null, 'img'));
  cardImgProps.imgSrc.required = false;
  var props$1X = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$20), props$1$), props$1_), cardImgProps), props$23), {}, {
    align: makeProp(PROP_TYPE_STRING),
    noBody: makeProp(PROP_TYPE_BOOLEAN, false)
  })), NAME_CARD); // --- Main component ---
  // @vue/component

  var BCard = /*#__PURE__*/extend({
    name: NAME_CARD,
    functional: true,
    props: props$1X,
    render: function render(h, _ref) {
      var _class;

      var props = _ref.props,
          data = _ref.data,
          slots = _ref.slots,
          scopedSlots = _ref.scopedSlots;
      var imgSrc = props.imgSrc,
          imgLeft = props.imgLeft,
          imgRight = props.imgRight,
          imgStart = props.imgStart,
          imgEnd = props.imgEnd,
          imgBottom = props.imgBottom,
          header = props.header,
          headerHtml = props.headerHtml,
          footer = props.footer,
          footerHtml = props.footerHtml,
          align = props.align,
          textVariant = props.textVariant,
          bgVariant = props.bgVariant,
          borderVariant = props.borderVariant;
      var $scopedSlots = scopedSlots || {};
      var $slots = slots();
      var slotScope = {};
      var $imgFirst = h();
      var $imgLast = h();

      if (imgSrc) {
        var $img = h(BCardImg, {
          props: pluckProps(cardImgProps, props, unprefixPropName.bind(null, 'img'))
        });

        if (imgBottom) {
          $imgLast = $img;
        } else {
          $imgFirst = $img;
        }
      }

      var $header = h();
      var hasHeaderSlot = hasNormalizedSlot(SLOT_NAME_HEADER, $scopedSlots, $slots);

      if (hasHeaderSlot || header || headerHtml) {
        $header = h(BCardHeader, {
          props: pluckProps(props$1$, props),
          domProps: hasHeaderSlot ? {} : htmlOrText(headerHtml, header)
        }, normalizeSlot(SLOT_NAME_HEADER, slotScope, $scopedSlots, $slots));
      }

      var $content = normalizeSlot(SLOT_NAME_DEFAULT, slotScope, $scopedSlots, $slots); // Wrap content in `<card-body>` when `noBody` prop set

      if (!props.noBody) {
        $content = h(BCardBody, {
          props: pluckProps(props$20, props)
        }, $content); // When the `overlap` prop is set we need to wrap the `<b-card-img>` and `<b-card-body>`
        // into a relative positioned wrapper to don't distract a potential header or footer

        if (props.overlay && imgSrc) {
          $content = h('div', {
            staticClass: 'position-relative'
          }, [$imgFirst, $content, $imgLast]); // Reset image variables since they are already in the wrapper

          $imgFirst = h();
          $imgLast = h();
        }
      }

      var $footer = h();
      var hasFooterSlot = hasNormalizedSlot(SLOT_NAME_FOOTER, $scopedSlots, $slots);

      if (hasFooterSlot || footer || footerHtml) {
        $footer = h(BCardFooter, {
          props: pluckProps(props$1_, props),
          domProps: hasHeaderSlot ? {} : htmlOrText(footerHtml, footer)
        }, normalizeSlot(SLOT_NAME_FOOTER, slotScope, $scopedSlots, $slots));
      }

      return h(props.tag, a(data, {
        staticClass: 'card',
        class: (_class = {
          'flex-row': imgLeft || imgStart,
          'flex-row-reverse': (imgRight || imgEnd) && !(imgLeft || imgStart)
        }, _defineProperty(_class, "text-".concat(align), align), _defineProperty(_class, "bg-".concat(bgVariant), bgVariant), _defineProperty(_class, "border-".concat(borderVariant), borderVariant), _defineProperty(_class, "text-".concat(textVariant), textVariant), _class)
      }), [$imgFirst, $header, $content, $footer, $imgLast]);
    }
  });

  var OBSERVER_PROP_NAME = '__bv__visibility_observer';

  var VisibilityObserver = /*#__PURE__*/function () {
    function VisibilityObserver(el, options) {
      _classCallCheck(this, VisibilityObserver);

      this.el = el;
      this.callback = options.callback;
      this.margin = options.margin || 0;
      this.once = options.once || false;
      this.observer = null;
      this.visible = undefined;
      this.doneOnce = false; // Create the observer instance (if possible)

      this.createObserver();
    }

    _createClass(VisibilityObserver, [{
      key: "createObserver",
      value: function createObserver() {
        var _this = this;

        // Remove any previous observer
        if (this.observer) {
          /* istanbul ignore next */
          this.stop();
        } // Should only be called once and `callback` prop should be a function


        if (this.doneOnce || !isFunction$1(this.callback)) {
          /* istanbul ignore next */
          return;
        } // Create the observer instance


        try {
          // Future: Possibly add in other modifiers for left/right/top/bottom
          // offsets, root element reference, and thresholds
          this.observer = new IntersectionObserver(this.handler.bind(this), {
            // `null` = 'viewport'
            root: null,
            // Pixels away from view port to consider "visible"
            rootMargin: this.margin,
            // Intersection ratio of el and root (as a value from 0 to 1)
            threshold: 0
          });
        } catch (_unused) {
          // No IntersectionObserver support, so just stop trying to observe
          this.doneOnce = true;
          this.observer = undefined;
          this.callback(null);
          return;
        } // Start observing in a `$nextTick()` (to allow DOM to complete rendering)

        /* istanbul ignore next: IntersectionObserver not supported in JSDOM */


        nextTick(function () {
          requestAF(function () {
            // Placed in an `if` just in case we were destroyed before
            // this `requestAnimationFrame` runs
            if (_this.observer) {
              _this.observer.observe(_this.el);
            }
          });
        });
      }
      /* istanbul ignore next */

    }, {
      key: "handler",
      value: function handler(entries) {
        var entry = entries ? entries[0] : {};
        var isIntersecting = Boolean(entry.isIntersecting || entry.intersectionRatio > 0.0);

        if (isIntersecting !== this.visible) {
          this.visible = isIntersecting;
          this.callback(isIntersecting);

          if (this.once && this.visible) {
            this.doneOnce = true;
            this.stop();
          }
        }
      }
    }, {
      key: "stop",
      value: function stop() {
        /* istanbul ignore next */
        this.observer && this.observer.disconnect();
        this.observer = null;
      }
    }]);

    return VisibilityObserver;
  }();

  var destroy$1 = function destroy(el) {
    var observer = el[OBSERVER_PROP_NAME];

    if (observer && observer.stop) {
      observer.stop();
    }

    delete el[OBSERVER_PROP_NAME];
  };

  var bind$1 = function bind(el, _ref) {
    var value = _ref.value,
        modifiers = _ref.modifiers;
    // `value` is the callback function
    var options = {
      margin: '0px',
      once: false,
      callback: value
    }; // Parse modifiers

    keys(modifiers).forEach(function (mod) {
      /* istanbul ignore else: Until <b-img-lazy> is switched to use this directive */
      if (RX_DIGITS.test(mod)) {
        options.margin = "".concat(mod, "px");
      } else if (mod.toLowerCase() === 'once') {
        options.once = true;
      }
    }); // Destroy any previous observer

    destroy$1(el); // Create new observer

    el[OBSERVER_PROP_NAME] = new VisibilityObserver(el, options); // Store the current modifiers on the object (cloned)

    el[OBSERVER_PROP_NAME]._prevModifiers = clone(modifiers);
  }; // When the directive options may have been updated (or element)


  var componentUpdated$1 = function componentUpdated(el, _ref2, vnode) {
    var value = _ref2.value,
        oldValue = _ref2.oldValue,
        modifiers = _ref2.modifiers;
    // Compare value/oldValue and modifiers to see if anything has changed
    // and if so, destroy old observer and create new observer

    /* istanbul ignore next */
    modifiers = clone(modifiers);
    /* istanbul ignore next */

    if (el && (value !== oldValue || !el[OBSERVER_PROP_NAME] || !looseEqual(modifiers, el[OBSERVER_PROP_NAME]._prevModifiers))) {
      // Re-bind on element
      bind$1(el, {
        value: value,
        modifiers: modifiers
      });
    }
  }; // When directive un-binds from element


  var unbind$1 = function unbind(el) {
    // Remove the observer
    destroy$1(el);
  }; // Export the directive


  var VBVisible = {
    bind: bind$1,
    componentUpdated: componentUpdated$1,
    unbind: unbind$1
  };

  var _watch$i;

  var MODEL_PROP_NAME_SHOW$1 = 'show';
  var MODEL_EVENT_NAME_SHOW$1 = MODEL_EVENT_NAME_PREFIX + MODEL_PROP_NAME_SHOW$1; // --- Props ---

  var imgProps$1 = omit(props$1Z, ['blank']);
  var props$1W = makePropsConfigurable(_objectSpread2$3(_objectSpread2$3({}, imgProps$1), {}, _defineProperty({
    blankHeight: makeProp(PROP_TYPE_NUMBER_STRING),
    // If `null`, a blank image is generated
    blankSrc: makeProp(PROP_TYPE_STRING, null),
    blankWidth: makeProp(PROP_TYPE_NUMBER_STRING),
    // Distance away from viewport (in pixels)
    // before being considered "visible"
    offset: makeProp(PROP_TYPE_NUMBER_STRING, 360)
  }, MODEL_PROP_NAME_SHOW$1, makeProp(PROP_TYPE_BOOLEAN, false))), NAME_IMG_LAZY); // --- Main component ---
  // @vue/component

  var BImgLazy = /*#__PURE__*/extend({
    name: NAME_IMG_LAZY,
    directives: {
      'b-visible': VBVisible
    },
    props: props$1W,
    data: function data() {
      return {
        isShown: this[MODEL_PROP_NAME_SHOW$1]
      };
    },
    computed: {
      computedSrc: function computedSrc() {
        var blankSrc = this.blankSrc;
        return !blankSrc || this.isShown ? this.src : blankSrc;
      },
      computedBlank: function computedBlank() {
        return !(this.isShown || this.blankSrc);
      },
      computedWidth: function computedWidth() {
        var width = this.width;
        return this.isShown ? width : this.blankWidth || width;
      },
      computedHeight: function computedHeight() {
        var height = this.height;
        return this.isShown ? height : this.blankHeight || height;
      },
      computedSrcset: function computedSrcset() {
        var srcset = concat(this.srcset).filter(identity).join(',');
        return srcset && (!this.blankSrc || this.isShown) ? srcset : null;
      },
      computedSizes: function computedSizes() {
        var sizes = concat(this.sizes).filter(identity).join(',');
        return sizes && (!this.blankSrc || this.isShown) ? sizes : null;
      }
    },
    watch: (_watch$i = {}, _defineProperty(_watch$i, MODEL_PROP_NAME_SHOW$1, function (newValue, oldValue) {
      if (newValue !== oldValue) {
        // If `IntersectionObserver` support is not available, image is always shown
        var visible = HAS_INTERACTION_OBSERVER_SUPPORT ? newValue : true;
        this.isShown = visible; // Ensure the show prop is synced (when no `IntersectionObserver`)

        if (newValue !== visible) {
          this.$nextTick(this.updateShowProp);
        }
      }
    }), _defineProperty(_watch$i, "isShown", function isShown(newValue, oldValue) {
      // Update synched show prop
      if (newValue !== oldValue) {
        this.updateShowProp();
      }
    }), _watch$i),
    mounted: function mounted() {
      var _this = this;

      // If `IntersectionObserver` is not available, image is always shown
      this.$nextTick(function () {
        _this.isShown = HAS_INTERACTION_OBSERVER_SUPPORT ? _this[MODEL_PROP_NAME_SHOW$1] : true;
      });
    },
    methods: {
      updateShowProp: function updateShowProp() {
        this.$emit(MODEL_EVENT_NAME_SHOW$1, this.isShown);
      },
      doShow: function doShow(visible) {
        var _this2 = this;

        // If IntersectionObserver is not supported, the callback
        // will be called with `null` rather than `true` or `false`
        if ((visible || visible === null) && !this.isShown) {
          // In a `requestAF()` to render the `blank` placeholder properly
          // for fast loading images in some browsers (i.e. Firefox)
          requestAF(function () {
            _this2.isShown = true;
          });
        }
      }
    },
    render: function render(h) {
      var directives = [];

      if (!this.isShown) {
        var _modifiers;

        // We only add the visible directive if we are not shown
        directives.push({
          // Visible directive will silently do nothing if
          // `IntersectionObserver` is not supported
          name: 'b-visible',
          // Value expects a callback (passed one arg of `visible` = `true` or `false`)
          value: this.doShow,
          modifiers: (_modifiers = {}, _defineProperty(_modifiers, "".concat(toInteger(this.offset, 0)), true), _defineProperty(_modifiers, "once", true), _modifiers)
        });
      }

      return h(BImg, {
        directives: directives,
        props: _objectSpread2$3(_objectSpread2$3({}, pluckProps(imgProps$1, this.$props)), {}, {
          // Computed value props
          src: this.computedSrc,
          blank: this.computedBlank,
          width: this.computedWidth,
          height: this.computedHeight,
          srcset: this.computedSrcset,
          sizes: this.computedSizes
        })
      });
    }
  });

  var props$1V = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, omit(props$1W, keys(props$1Z))), omit(props$1Y, ['src', 'alt', 'width', 'height']))), NAME_CARD_IMG_LAZY); // --- Main component ---
  // @vue/component

  var BCardImgLazy = /*#__PURE__*/extend({
    name: NAME_CARD_IMG_LAZY,
    functional: true,
    props: props$1V,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data;
      var baseClass = 'card-img';

      if (props.top) {
        baseClass += '-top';
      } else if (props.right || props.end) {
        baseClass += '-right';
      } else if (props.bottom) {
        baseClass += '-bottom';
      } else if (props.left || props.start) {
        baseClass += '-left';
      }

      return h(BImgLazy, a(data, {
        class: [baseClass],
        // Exclude `left` and `right` props before passing to `<b-img-lazy>`
        props: omit(props, ['left', 'right'])
      }));
    }
  });

  var props$1U = makePropsConfigurable({
    textTag: makeProp(PROP_TYPE_STRING, 'p')
  }, NAME_CARD_TEXT); // --- Main component ---
  // @vue/component

  var BCardText = /*#__PURE__*/extend({
    name: NAME_CARD_TEXT,
    functional: true,
    props: props$1U,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      return h(props.textTag, a(data, {
        staticClass: 'card-text'
      }), children);
    }
  });

  var props$1T = makePropsConfigurable({
    columns: makeProp(PROP_TYPE_BOOLEAN, false),
    deck: makeProp(PROP_TYPE_BOOLEAN, false),
    tag: makeProp(PROP_TYPE_STRING, 'div')
  }, NAME_CARD_GROUP); // --- Main component ---
  // @vue/component

  var BCardGroup = /*#__PURE__*/extend({
    name: NAME_CARD_GROUP,
    functional: true,
    props: props$1T,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      return h(props.tag, a(data, {
        class: props.deck ? 'card-deck' : props.columns ? 'card-columns' : 'card-group'
      }), children);
    }
  });

  var CardPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BCard: BCard,
      BCardHeader: BCardHeader,
      BCardBody: BCardBody,
      BCardTitle: BCardTitle,
      BCardSubTitle: BCardSubTitle,
      BCardFooter: BCardFooter,
      BCardImg: BCardImg,
      BCardImgLazy: BCardImgLazy,
      BCardText: BCardText,
      BCardGroup: BCardGroup
    }
  });

  var noop = function noop() {};

  /**
   * Observe a DOM element changes, falls back to eventListener mode
   * @param {Element} el The DOM element to observe
   * @param {Function} callback callback to be called on change
   * @param {object} [options={childList: true, subtree: true}] observe options
   * @see https://stackoverflow.com/questions/3219758
   */

  var observeDom = function observeDom(el, callback, options)
  /* istanbul ignore next: difficult to test in JSDOM */
  {
    // Handle cases where we might be passed a Vue instance
    el = el ? el.$el || el : null; // Early exit when we have no element

    /* istanbul ignore next: difficult to test in JSDOM */

    if (!isElement(el)) {
      return null;
    } // Exit and throw a warning when `MutationObserver` isn't available


    if (warnNoMutationObserverSupport('observeDom')) {
      return null;
    } // Define a new observer


    var obs = new MutationObs(function (mutations) {
      var changed = false; // A mutation can contain several change records, so we loop
      // through them to see what has changed
      // We break out of the loop early if any "significant" change
      // has been detected

      for (var i = 0; i < mutations.length && !changed; i++) {
        // The mutation record
        var mutation = mutations[i]; // Mutation type

        var type = mutation.type; // DOM node (could be any DOM node type - HTMLElement, Text, comment, etc.)

        var target = mutation.target; // Detect whether a change happened based on type and target

        if (type === 'characterData' && target.nodeType === Node.TEXT_NODE) {
          // We ignore nodes that are not TEXT (i.e. comments, etc.)
          // as they don't change layout
          changed = true;
        } else if (type === 'attributes') {
          changed = true;
        } else if (type === 'childList' && (mutation.addedNodes.length > 0 || mutation.removedNodes.length > 0)) {
          // This includes HTMLElement and text nodes being
          // added/removed/re-arranged
          changed = true;
        }
      } // We only call the callback if a change that could affect
      // layout/size truly happened


      if (changed) {
        callback();
      }
    }); // Have the observer observe foo for changes in children, etc

    obs.observe(el, _objectSpread2$3({
      childList: true,
      subtree: true
    }, options)); // We return a reference to the observer so that `obs.disconnect()`
    // can be called if necessary
    // To reduce overhead when the root element is hidden

    return obs;
  };

  var _watch$h;

  var _makeModelMixin$i = makeModelMixin('value', {
    type: PROP_TYPE_NUMBER,
    defaultValue: 0
  }),
      modelMixin$h = _makeModelMixin$i.mixin,
      modelProps$h = _makeModelMixin$i.props,
      MODEL_PROP_NAME$h = _makeModelMixin$i.prop,
      MODEL_EVENT_NAME$h = _makeModelMixin$i.event; // Slide directional classes


  var DIRECTION = {
    next: {
      dirClass: 'carousel-item-left',
      overlayClass: 'carousel-item-next'
    },
    prev: {
      dirClass: 'carousel-item-right',
      overlayClass: 'carousel-item-prev'
    }
  }; // Fallback Transition duration (with a little buffer) in ms

  var TRANS_DURATION = 600 + 50; // Time for mouse compat events to fire after touch

  var TOUCH_EVENT_COMPAT_WAIT = 500; // Number of pixels to consider touch move a swipe

  var SWIPE_THRESHOLD = 40; // PointerEvent pointer types

  var PointerType = {
    TOUCH: 'touch',
    PEN: 'pen'
  }; // Transition Event names

  var TransitionEndEvents$1 = {
    WebkitTransition: 'webkitTransitionEnd',
    MozTransition: 'transitionend',
    OTransition: 'otransitionend oTransitionEnd',
    transition: 'transitionend'
  }; // --- Helper methods ---
  // Return the browser specific transitionEnd event name

  var getTransitionEndEvent = function getTransitionEndEvent(el) {
    for (var name in TransitionEndEvents$1) {
      if (!isUndefined(el.style[name])) {
        return TransitionEndEvents$1[name];
      }
    } // Fallback

    /* istanbul ignore next */


    return null;
  }; // --- Props ---


  var props$1S = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$25), modelProps$h), {}, {
    background: makeProp(PROP_TYPE_STRING),
    controls: makeProp(PROP_TYPE_BOOLEAN, false),
    // Enable cross-fade animation instead of slide animation
    fade: makeProp(PROP_TYPE_BOOLEAN, false),
    // Sniffed by carousel-slide
    imgHeight: makeProp(PROP_TYPE_NUMBER_STRING),
    // Sniffed by carousel-slide
    imgWidth: makeProp(PROP_TYPE_NUMBER_STRING),
    indicators: makeProp(PROP_TYPE_BOOLEAN, false),
    interval: makeProp(PROP_TYPE_NUMBER, 5000),
    labelGotoSlide: makeProp(PROP_TYPE_STRING, 'Goto slide'),
    labelIndicators: makeProp(PROP_TYPE_STRING, 'Select a slide to display'),
    labelNext: makeProp(PROP_TYPE_STRING, 'Next slide'),
    labelPrev: makeProp(PROP_TYPE_STRING, 'Previous slide'),
    // Disable slide/fade animation
    noAnimation: makeProp(PROP_TYPE_BOOLEAN, false),
    // Disable pause on hover
    noHoverPause: makeProp(PROP_TYPE_BOOLEAN, false),
    // Sniffed by carousel-slide
    noTouch: makeProp(PROP_TYPE_BOOLEAN, false),
    // Disable wrapping/looping when start/end is reached
    noWrap: makeProp(PROP_TYPE_BOOLEAN, false)
  })), NAME_CAROUSEL); // --- Main component ---
  // @vue/component

  var BCarousel = /*#__PURE__*/extend({
    name: NAME_CAROUSEL,
    mixins: [idMixin, modelMixin$h, normalizeSlotMixin],
    provide: function provide() {
      var _this = this;

      return {
        getBvCarousel: function getBvCarousel() {
          return _this;
        }
      };
    },
    props: props$1S,
    data: function data() {
      return {
        index: this[MODEL_PROP_NAME$h] || 0,
        isSliding: false,
        transitionEndEvent: null,
        slides: [],
        direction: null,
        isPaused: !(toInteger(this.interval, 0) > 0),
        // Touch event handling values
        touchStartX: 0,
        touchDeltaX: 0
      };
    },
    computed: {
      numSlides: function numSlides() {
        return this.slides.length;
      }
    },
    watch: (_watch$h = {}, _defineProperty(_watch$h, MODEL_PROP_NAME$h, function (newValue, oldValue) {
      if (newValue !== oldValue) {
        this.setSlide(toInteger(newValue, 0));
      }
    }), _defineProperty(_watch$h, "interval", function interval(newValue, oldValue) {
      /* istanbul ignore next */
      if (newValue === oldValue) {
        return;
      }

      if (!newValue) {
        // Pausing slide show
        this.pause(false);
      } else {
        // Restarting or Changing interval
        this.pause(true);
        this.start(false);
      }
    }), _defineProperty(_watch$h, "isPaused", function isPaused(newValue, oldValue) {
      if (newValue !== oldValue) {
        this.$emit(newValue ? EVENT_NAME_PAUSED : EVENT_NAME_UNPAUSED);
      }
    }), _defineProperty(_watch$h, "index", function index(to, from) {
      /* istanbul ignore next */
      if (to === from || this.isSliding) {
        return;
      }

      this.doSlide(to, from);
    }), _watch$h),
    created: function created() {
      // Create private non-reactive props
      this.$_interval = null;
      this.$_animationTimeout = null;
      this.$_touchTimeout = null;
      this.$_observer = null; // Set initial paused state

      this.isPaused = !(toInteger(this.interval, 0) > 0);
    },
    mounted: function mounted() {
      // Cache current browser transitionend event name
      this.transitionEndEvent = getTransitionEndEvent(this.$el) || null; // Get all slides

      this.updateSlides(); // Observe child changes so we can update slide list

      this.setObserver(true);
    },
    beforeDestroy: function beforeDestroy() {
      this.clearInterval();
      this.clearAnimationTimeout();
      this.clearTouchTimeout();
      this.setObserver(false);
    },
    methods: {
      clearInterval: function (_clearInterval) {
        function clearInterval() {
          return _clearInterval.apply(this, arguments);
        }

        clearInterval.toString = function () {
          return _clearInterval.toString();
        };

        return clearInterval;
      }(function () {
        clearInterval(this.$_interval);
        this.$_interval = null;
      }),
      clearAnimationTimeout: function clearAnimationTimeout() {
        clearTimeout(this.$_animationTimeout);
        this.$_animationTimeout = null;
      },
      clearTouchTimeout: function clearTouchTimeout() {
        clearTimeout(this.$_touchTimeout);
        this.$_touchTimeout = null;
      },
      setObserver: function setObserver() {
        var on = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
        this.$_observer && this.$_observer.disconnect();
        this.$_observer = null;

        if (on) {
          this.$_observer = observeDom(this.$refs.inner, this.updateSlides.bind(this), {
            subtree: false,
            childList: true,
            attributes: true,
            attributeFilter: ['id']
          });
        }
      },
      // Set slide
      setSlide: function setSlide(slide) {
        var _this2 = this;

        var direction = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;

        // Don't animate when page is not visible

        /* istanbul ignore if: difficult to test */
        if (IS_BROWSER && document.visibilityState && document.hidden) {
          return;
        }

        var noWrap = this.noWrap;
        var numSlides = this.numSlides; // Make sure we have an integer (you never know!)

        slide = mathFloor(slide); // Don't do anything if nothing to slide to

        if (numSlides === 0) {
          return;
        } // Don't change slide while transitioning, wait until transition is done


        if (this.isSliding) {
          // Schedule slide after sliding complete
          this.$once(EVENT_NAME_SLIDING_END, function () {
            // Wrap in `requestAF()` to allow the slide to properly finish to avoid glitching
            requestAF(function () {
              return _this2.setSlide(slide, direction);
            });
          });
          return;
        }

        this.direction = direction; // Set new slide index
        // Wrap around if necessary (if no-wrap not enabled)

        this.index = slide >= numSlides ? noWrap ? numSlides - 1 : 0 : slide < 0 ? noWrap ? 0 : numSlides - 1 : slide; // Ensure the v-model is synched up if no-wrap is enabled
        // and user tried to slide pass either ends

        if (noWrap && this.index !== slide && this.index !== this[MODEL_PROP_NAME$h]) {
          this.$emit(MODEL_EVENT_NAME$h, this.index);
        }
      },
      // Previous slide
      prev: function prev() {
        this.setSlide(this.index - 1, 'prev');
      },
      // Next slide
      next: function next() {
        this.setSlide(this.index + 1, 'next');
      },
      // Pause auto rotation
      pause: function pause(event) {
        if (!event) {
          this.isPaused = true;
        }

        this.clearInterval();
      },
      // Start auto rotate slides
      start: function start(event) {
        if (!event) {
          this.isPaused = false;
        }
        /* istanbul ignore next: most likely will never happen, but just in case */


        this.clearInterval(); // Don't start if no interval, or less than 2 slides

        if (this.interval && this.numSlides > 1) {
          this.$_interval = setInterval(this.next, mathMax(1000, this.interval));
        }
      },
      // Restart auto rotate slides when focus/hover leaves the carousel

      /* istanbul ignore next */
      restart: function restart() {
        if (!this.$el.contains(getActiveElement())) {
          this.start();
        }
      },
      doSlide: function doSlide(to, from) {
        var _this3 = this;

        var isCycling = Boolean(this.interval); // Determine sliding direction

        var direction = this.calcDirection(this.direction, from, to);
        var overlayClass = direction.overlayClass;
        var dirClass = direction.dirClass; // Determine current and next slides

        var currentSlide = this.slides[from];
        var nextSlide = this.slides[to]; // Don't do anything if there aren't any slides to slide to

        if (!currentSlide || !nextSlide) {
          /* istanbul ignore next */
          return;
        } // Start animating


        this.isSliding = true;

        if (isCycling) {
          this.pause(false);
        }

        this.$emit(EVENT_NAME_SLIDING_START, to); // Update v-model

        this.$emit(MODEL_EVENT_NAME$h, this.index);

        if (this.noAnimation) {
          addClass(nextSlide, 'active');
          removeClass(currentSlide, 'active');
          this.isSliding = false; // Notify ourselves that we're done sliding (slid)

          this.$nextTick(function () {
            return _this3.$emit(EVENT_NAME_SLIDING_END, to);
          });
        } else {
          addClass(nextSlide, overlayClass); // Trigger a reflow of next slide

          reflow(nextSlide);
          addClass(currentSlide, dirClass);
          addClass(nextSlide, dirClass); // Transition End handler

          var called = false;
          /* istanbul ignore next: difficult to test */

          var onceTransEnd = function onceTransEnd() {
            if (called) {
              return;
            }

            called = true;
            /* istanbul ignore if: transition events cant be tested in JSDOM */

            if (_this3.transitionEndEvent) {
              var events = _this3.transitionEndEvent.split(/\s+/);

              events.forEach(function (event) {
                return eventOff(nextSlide, event, onceTransEnd, EVENT_OPTIONS_NO_CAPTURE);
              });
            }

            _this3.clearAnimationTimeout();

            removeClass(nextSlide, dirClass);
            removeClass(nextSlide, overlayClass);
            addClass(nextSlide, 'active');
            removeClass(currentSlide, 'active');
            removeClass(currentSlide, dirClass);
            removeClass(currentSlide, overlayClass);
            setAttr(currentSlide, 'aria-current', 'false');
            setAttr(nextSlide, 'aria-current', 'true');
            setAttr(currentSlide, 'aria-hidden', 'true');
            setAttr(nextSlide, 'aria-hidden', 'false');
            _this3.isSliding = false;
            _this3.direction = null; // Notify ourselves that we're done sliding (slid)

            _this3.$nextTick(function () {
              return _this3.$emit(EVENT_NAME_SLIDING_END, to);
            });
          }; // Set up transitionend handler

          /* istanbul ignore if: transition events cant be tested in JSDOM */


          if (this.transitionEndEvent) {
            var events = this.transitionEndEvent.split(/\s+/);
            events.forEach(function (event) {
              return eventOn(nextSlide, event, onceTransEnd, EVENT_OPTIONS_NO_CAPTURE);
            });
          } // Fallback to setTimeout()


          this.$_animationTimeout = setTimeout(onceTransEnd, TRANS_DURATION);
        }

        if (isCycling) {
          this.start(false);
        }
      },
      // Update slide list
      updateSlides: function updateSlides() {
        this.pause(true); // Get all slides as DOM elements

        this.slides = selectAll('.carousel-item', this.$refs.inner);
        var numSlides = this.slides.length; // Keep slide number in range

        var index = mathMax(0, mathMin(mathFloor(this.index), numSlides - 1));
        this.slides.forEach(function (slide, idx) {
          var n = idx + 1;

          if (idx === index) {
            addClass(slide, 'active');
            setAttr(slide, 'aria-current', 'true');
          } else {
            removeClass(slide, 'active');
            setAttr(slide, 'aria-current', 'false');
          }

          setAttr(slide, 'aria-posinset', String(n));
          setAttr(slide, 'aria-setsize', String(numSlides));
        }); // Set slide as active

        this.setSlide(index);
        this.start(this.isPaused);
      },
      calcDirection: function calcDirection() {
        var direction = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
        var curIndex = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
        var nextIndex = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;

        if (!direction) {
          return nextIndex > curIndex ? DIRECTION.next : DIRECTION.prev;
        }

        return DIRECTION[direction];
      },
      handleClick: function handleClick(event, fn) {
        var keyCode = event.keyCode;

        if (event.type === 'click' || keyCode === CODE_SPACE || keyCode === CODE_ENTER) {
          stopEvent(event);
          fn();
        }
      },

      /* istanbul ignore next: JSDOM doesn't support touch events */
      handleSwipe: function handleSwipe() {
        var absDeltaX = mathAbs(this.touchDeltaX);

        if (absDeltaX <= SWIPE_THRESHOLD) {
          return;
        }

        var direction = absDeltaX / this.touchDeltaX; // Reset touch delta X
        // https://github.com/twbs/bootstrap/pull/28558

        this.touchDeltaX = 0;

        if (direction > 0) {
          // Swipe left
          this.prev();
        } else if (direction < 0) {
          // Swipe right
          this.next();
        }
      },

      /* istanbul ignore next: JSDOM doesn't support touch events */
      touchStart: function touchStart(event) {
        if (HAS_POINTER_EVENT_SUPPORT && PointerType[event.pointerType.toUpperCase()]) {
          this.touchStartX = event.clientX;
        } else if (!HAS_POINTER_EVENT_SUPPORT) {
          this.touchStartX = event.touches[0].clientX;
        }
      },

      /* istanbul ignore next: JSDOM doesn't support touch events */
      touchMove: function touchMove(event) {
        // Ensure swiping with one touch and not pinching
        if (event.touches && event.touches.length > 1) {
          this.touchDeltaX = 0;
        } else {
          this.touchDeltaX = event.touches[0].clientX - this.touchStartX;
        }
      },

      /* istanbul ignore next: JSDOM doesn't support touch events */
      touchEnd: function touchEnd(event) {
        if (HAS_POINTER_EVENT_SUPPORT && PointerType[event.pointerType.toUpperCase()]) {
          this.touchDeltaX = event.clientX - this.touchStartX;
        }

        this.handleSwipe(); // If it's a touch-enabled device, mouseenter/leave are fired as
        // part of the mouse compatibility events on first tap - the carousel
        // would stop cycling until user tapped out of it;
        // here, we listen for touchend, explicitly pause the carousel
        // (as if it's the second time we tap on it, mouseenter compat event
        // is NOT fired) and after a timeout (to allow for mouse compatibility
        // events to fire) we explicitly restart cycling

        this.pause(false);
        this.clearTouchTimeout();
        this.$_touchTimeout = setTimeout(this.start, TOUCH_EVENT_COMPAT_WAIT + mathMax(1000, this.interval));
      }
    },
    render: function render(h) {
      var _this4 = this;

      var indicators = this.indicators,
          background = this.background,
          noAnimation = this.noAnimation,
          noHoverPause = this.noHoverPause,
          noTouch = this.noTouch,
          index = this.index,
          isSliding = this.isSliding,
          pause = this.pause,
          restart = this.restart,
          touchStart = this.touchStart,
          touchEnd = this.touchEnd;
      var idInner = this.safeId('__BV_inner_'); // Wrapper for slides

      var $inner = h('div', {
        staticClass: 'carousel-inner',
        attrs: {
          id: idInner,
          role: 'list'
        },
        ref: 'inner'
      }, [this.normalizeSlot()]); // Prev and next controls

      var $controls = h();

      if (this.controls) {
        var makeControl = function makeControl(direction, label, handler) {
          var handlerWrapper = function handlerWrapper(event) {
            /* istanbul ignore next */
            if (!isSliding) {
              _this4.handleClick(event, handler);
            } else {
              stopEvent(event, {
                propagation: false
              });
            }
          };

          return h('a', {
            staticClass: "carousel-control-".concat(direction),
            attrs: {
              href: '#',
              role: 'button',
              'aria-controls': idInner,
              'aria-disabled': isSliding ? 'true' : null
            },
            on: {
              click: handlerWrapper,
              keydown: handlerWrapper
            }
          }, [h('span', {
            staticClass: "carousel-control-".concat(direction, "-icon"),
            attrs: {
              'aria-hidden': 'true'
            }
          }), h('span', {
            class: 'sr-only'
          }, [label])]);
        };

        $controls = [makeControl('prev', this.labelPrev, this.prev), makeControl('next', this.labelNext, this.next)];
      } // Indicators


      var $indicators = h('ol', {
        staticClass: 'carousel-indicators',
        directives: [{
          name: 'show',
          value: indicators
        }],
        attrs: {
          id: this.safeId('__BV_indicators_'),
          'aria-hidden': indicators ? 'false' : 'true',
          'aria-label': this.labelIndicators,
          'aria-owns': idInner
        }
      }, this.slides.map(function (slide, i) {
        var handler = function handler(event) {
          _this4.handleClick(event, function () {
            _this4.setSlide(i);
          });
        };

        return h('li', {
          class: {
            active: i === index
          },
          attrs: {
            role: 'button',
            id: _this4.safeId("__BV_indicator_".concat(i + 1, "_")),
            tabindex: indicators ? '0' : '-1',
            'aria-current': i === index ? 'true' : 'false',
            'aria-label': "".concat(_this4.labelGotoSlide, " ").concat(i + 1),
            'aria-describedby': slide.id || null,
            'aria-controls': idInner
          },
          on: {
            click: handler,
            keydown: handler
          },
          key: "slide_".concat(i)
        });
      }));
      var on = {
        mouseenter: noHoverPause ? noop : pause,
        mouseleave: noHoverPause ? noop : restart,
        focusin: pause,
        focusout: restart,
        keydown: function keydown(event) {
          /* istanbul ignore next */
          if (/input|textarea/i.test(event.target.tagName)) {
            return;
          }

          var keyCode = event.keyCode;

          if (keyCode === CODE_LEFT || keyCode === CODE_RIGHT) {
            stopEvent(event);

            _this4[keyCode === CODE_LEFT ? 'prev' : 'next']();
          }
        }
      }; // Touch support event handlers for environment

      if (HAS_TOUCH_SUPPORT && !noTouch) {
        // Attach appropriate listeners (prepend event name with '&' for passive mode)

        /* istanbul ignore next: JSDOM doesn't support touch events */
        if (HAS_POINTER_EVENT_SUPPORT) {
          on['&pointerdown'] = touchStart;
          on['&pointerup'] = touchEnd;
        } else {
          on['&touchstart'] = touchStart;
          on['&touchmove'] = this.touchMove;
          on['&touchend'] = touchEnd;
        }
      } // Return the carousel


      return h('div', {
        staticClass: 'carousel',
        class: {
          slide: !noAnimation,
          'carousel-fade': !noAnimation && this.fade,
          'pointer-event': HAS_TOUCH_SUPPORT && HAS_POINTER_EVENT_SUPPORT && !noTouch
        },
        style: {
          background: background
        },
        attrs: {
          role: 'region',
          id: this.safeId(),
          'aria-busy': isSliding ? 'true' : 'false'
        },
        on: on
      }, [$inner, $controls, $indicators]);
    }
  });

  var imgProps = {
    imgAlt: makeProp(PROP_TYPE_STRING),
    imgBlank: makeProp(PROP_TYPE_BOOLEAN, false),
    imgBlankColor: makeProp(PROP_TYPE_STRING, 'transparent'),
    imgHeight: makeProp(PROP_TYPE_NUMBER_STRING),
    imgSrc: makeProp(PROP_TYPE_STRING),
    imgWidth: makeProp(PROP_TYPE_NUMBER_STRING)
  };
  var props$1R = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$25), imgProps), {}, {
    background: makeProp(PROP_TYPE_STRING),
    caption: makeProp(PROP_TYPE_STRING),
    captionHtml: makeProp(PROP_TYPE_STRING),
    captionTag: makeProp(PROP_TYPE_STRING, 'h3'),
    contentTag: makeProp(PROP_TYPE_STRING, 'div'),
    contentVisibleUp: makeProp(PROP_TYPE_STRING),
    text: makeProp(PROP_TYPE_STRING),
    textHtml: makeProp(PROP_TYPE_STRING),
    textTag: makeProp(PROP_TYPE_STRING, 'p')
  })), NAME_CAROUSEL_SLIDE); // --- Main component ---
  // @vue/component

  var BCarouselSlide = /*#__PURE__*/extend({
    name: NAME_CAROUSEL_SLIDE,
    mixins: [idMixin, normalizeSlotMixin],
    inject: {
      getBvCarousel: {
        // Explicitly disable touch if not a child of carousel
        default: function _default() {
          return function () {
            return {
              noTouch: true
            };
          };
        }
      }
    },
    props: props$1R,
    computed: {
      bvCarousel: function bvCarousel() {
        return this.getBvCarousel();
      },
      contentClasses: function contentClasses() {
        return [this.contentVisibleUp ? 'd-none' : '', this.contentVisibleUp ? "d-".concat(this.contentVisibleUp, "-block") : ''];
      },
      computedWidth: function computedWidth() {
        // Use local width, or try parent width
        return this.imgWidth || this.bvCarousel.imgWidth || null;
      },
      computedHeight: function computedHeight() {
        // Use local height, or try parent height
        return this.imgHeight || this.bvCarousel.imgHeight || null;
      }
    },
    render: function render(h) {
      var $img = this.normalizeSlot(SLOT_NAME_IMG);

      if (!$img && (this.imgSrc || this.imgBlank)) {
        var on = {}; // Touch support event handler

        /* istanbul ignore if: difficult to test in JSDOM */

        if (!this.bvCarousel.noTouch && HAS_TOUCH_SUPPORT) {
          on.dragstart = function (event) {
            return stopEvent(event, {
              propagation: false
            });
          };
        }

        $img = h(BImg, {
          props: _objectSpread2$3(_objectSpread2$3({}, pluckProps(imgProps, this.$props, unprefixPropName.bind(null, 'img'))), {}, {
            width: this.computedWidth,
            height: this.computedHeight,
            fluidGrow: true,
            block: true
          }),
          on: on
        });
      }

      var $contentChildren = [// Caption
      this.caption || this.captionHtml ? h(this.captionTag, {
        domProps: htmlOrText(this.captionHtml, this.caption)
      }) : false, // Text
      this.text || this.textHtml ? h(this.textTag, {
        domProps: htmlOrText(this.textHtml, this.text)
      }) : false, // Children
      this.normalizeSlot() || false];
      var $content = h();

      if ($contentChildren.some(identity)) {
        $content = h(this.contentTag, {
          staticClass: 'carousel-caption',
          class: this.contentClasses
        }, $contentChildren.map(function ($child) {
          return $child || h();
        }));
      }

      return h('div', {
        staticClass: 'carousel-item',
        style: {
          background: this.background || this.bvCarousel.background || null
        },
        attrs: {
          id: this.safeId(),
          role: 'listitem'
        }
      }, [$img, $content]);
    }
  });

  var CarouselPlugin =
  /*#__PURE*/
  pluginFactory({
    components: {
      BCarousel: BCarousel,
      BCarouselSlide: BCarouselSlide
    }
  });

  var CLASS_NAME_SHOW = 'show';

  // Generic collapse transion helper component
  // Transition event handler helpers

  var onEnter = function onEnter(el) {
    setStyle(el, 'height', 0); // In a `requestAF()` for `appear` to work

    requestAF(function () {
      reflow(el);
      setStyle(el, 'height', "".concat(el.scrollHeight, "px"));
    });
  };

  var onAfterEnter = function onAfterEnter(el) {
    removeStyle(el, 'height');
  };

  var onLeave = function onLeave(el) {
    setStyle(el, 'height', 'auto');
    setStyle(el, 'display', 'block');
    setStyle(el, 'height', "".concat(getBCR(el).height, "px"));
    reflow(el);
    setStyle(el, 'height', 0);
  };

  var onAfterLeave = function onAfterLeave(el) {
    removeStyle(el, 'height');
  }; // --- Constants ---
  // Default transition props
  // `appear` will use the enter classes


  var TRANSITION_PROPS = {
    css: true,
    enterClass: '',
    enterActiveClass: 'collapsing',
    enterToClass: 'collapse show',
    leaveClass: 'collapse show',
    leaveActiveClass: 'collapsing',
    leaveToClass: 'collapse'
  }; // Default transition handlers
  // `appear` will use the enter handlers

  var TRANSITION_HANDLERS = {
    enter: onEnter,
    afterEnter: onAfterEnter,
    leave: onLeave,
    afterLeave: onAfterLeave
  }; // --- Main component ---

  var props$1Q = {
    // // If `true` (and `visible` is `true` on mount), animate initially visible
    appear: makeProp(PROP_TYPE_BOOLEAN, false)
  }; // --- Main component ---
  // @vue/component

  var BVCollapse = /*#__PURE__*/extend({
    name: NAME_COLLAPSE_HELPER,
    functional: true,
    props: props$1Q,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      return h('transition', // We merge in the `appear` prop last
      a(data, {
        props: TRANSITION_PROPS,
        on: TRANSITION_HANDLERS
      }, {
        props: props
      }), // Note: `<transition>` supports a single root element only
      children);
    }
  });

  var _watch$g;

  var ROOT_ACTION_EVENT_NAME_TOGGLE$2 = getRootActionEventName(NAME_COLLAPSE, 'toggle');
  var ROOT_ACTION_EVENT_NAME_REQUEST_STATE$2 = getRootActionEventName(NAME_COLLAPSE, 'request-state');
  var ROOT_EVENT_NAME_ACCORDION = getRootEventName(NAME_COLLAPSE, 'accordion');
  var ROOT_EVENT_NAME_STATE$3 = getRootEventName(NAME_COLLAPSE, 'state');
  var ROOT_EVENT_NAME_SYNC_STATE$3 = getRootEventName(NAME_COLLAPSE, 'sync-state');

  var _makeModelMixin$h = makeModelMixin('visible', {
    type: PROP_TYPE_BOOLEAN,
    defaultValue: false
  }),
      modelMixin$g = _makeModelMixin$h.mixin,
      modelProps$g = _makeModelMixin$h.props,
      MODEL_PROP_NAME$g = _makeModelMixin$h.prop,
      MODEL_EVENT_NAME$g = _makeModelMixin$h.event; // --- Props ---


  var props$1P = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$25), modelProps$g), {}, {
    // If `true` (and `visible` is `true` on mount), animate initially visible
    accordion: makeProp(PROP_TYPE_STRING),
    appear: makeProp(PROP_TYPE_BOOLEAN, false),
    isNav: makeProp(PROP_TYPE_BOOLEAN, false),
    tag: makeProp(PROP_TYPE_STRING, 'div')
  })), NAME_COLLAPSE); // --- Main component ---
  // @vue/component

  var BCollapse = /*#__PURE__*/extend({
    name: NAME_COLLAPSE,
    mixins: [idMixin, modelMixin$g, normalizeSlotMixin, listenOnRootMixin],
    props: props$1P,
    data: function data() {
      return {
        show: this[MODEL_PROP_NAME$g],
        transitioning: false
      };
    },
    computed: {
      classObject: function classObject() {
        var transitioning = this.transitioning;
        return {
          'navbar-collapse': this.isNav,
          collapse: !transitioning,
          show: this.show && !transitioning
        };
      },
      slotScope: function slotScope() {
        var _this = this;

        return {
          visible: this.show,
          close: function close() {
            _this.show = false;
          }
        };
      }
    },
    watch: (_watch$g = {}, _defineProperty(_watch$g, MODEL_PROP_NAME$g, function (newValue) {
      if (newValue !== this.show) {
        this.show = newValue;
      }
    }), _defineProperty(_watch$g, "show", function show(newValue, oldValue) {
      if (newValue !== oldValue) {
        this.emitState();
      }
    }), _watch$g),
    created: function created() {
      this.show = this[MODEL_PROP_NAME$g];
    },
    mounted: function mounted() {
      var _this2 = this;

      this.show = this[MODEL_PROP_NAME$g]; // Listen for toggle events to open/close us

      this.listenOnRoot(ROOT_ACTION_EVENT_NAME_TOGGLE$2, this.handleToggleEvent); // Listen to other collapses for accordion events

      this.listenOnRoot(ROOT_EVENT_NAME_ACCORDION, this.handleAccordionEvent);

      if (this.isNav) {
        // Set up handlers
        this.setWindowEvents(true);
        this.handleResize();
      }

      this.$nextTick(function () {
        _this2.emitState();
      }); // Listen for "Sync state" requests from `v-b-toggle`

      this.listenOnRoot(ROOT_ACTION_EVENT_NAME_REQUEST_STATE$2, function (id) {
        if (id === _this2.safeId()) {
          _this2.$nextTick(_this2.emitSync);
        }
      });
    },
    updated: function updated() {
      // Emit a private event every time this component updates to ensure
      // the toggle button is in sync with the collapse's state
      // It is emitted regardless if the visible state changes
      this.emitSync();
    },

    /* istanbul ignore next */
    deactivated: function deactivated() {
      if (this.isNav) {
        this.setWindowEvents(false);
      }
    },

    /* istanbul ignore next */
    activated: function activated() {
      if (this.isNav) {
        this.setWindowEvents(true);
      }

      this.emitSync();
    },
    beforeDestroy: function beforeDestroy() {
      // Trigger state emit if needed
      this.show = false;

      if (this.isNav && IS_BROWSER) {
        this.setWindowEvents(false);
      }
    },
    methods: {
      setWindowEvents: function setWindowEvents(on) {
        eventOnOff(on, window, 'resize', this.handleResize, EVENT_OPTIONS_NO_CAPTURE);
        eventOnOff(on, window, 'orientationchange', this.handleResize, EVENT_OPTIONS_NO_CAPTURE);
      },
      toggle: function toggle() {
        this.show = !this.show;
      },
      onEnter: function onEnter() {
        this.transitioning = true; // This should be moved out so we can add cancellable events

        this.$emit(EVENT_NAME_SHOW);
      },
      onAfterEnter: function onAfterEnter() {
        this.transitioning = false;
        this.$emit(EVENT_NAME_SHOWN);
      },
      onLeave: function onLeave() {
        this.transitioning = true; // This should be moved out so we can add cancellable events

        this.$emit(EVENT_NAME_HIDE);
      },
      onAfterLeave: function onAfterLeave() {
        this.transitioning = false;
        this.$emit(EVENT_NAME_HIDDEN);
      },
      emitState: function emitState() {
        var show = this.show,
            accordion = this.accordion;
        var id = this.safeId();
        this.$emit(MODEL_EVENT_NAME$g, show); // Let `v-b-toggle` know the state of this collapse

        this.emitOnRoot(ROOT_EVENT_NAME_STATE$3, id, show);

        if (accordion && show) {
          // Tell the other collapses in this accordion to close
          this.emitOnRoot(ROOT_EVENT_NAME_ACCORDION, id, accordion);
        }
      },
      emitSync: function emitSync() {
        // Emit a private event every time this component updates to ensure
        // the toggle button is in sync with the collapse's state
        // It is emitted regardless if the visible state changes
        this.emitOnRoot(ROOT_EVENT_NAME_SYNC_STATE$3, this.safeId(), this.show);
      },
      checkDisplayBlock: function checkDisplayBlock() {
        // Check to see if the collapse has `display: block !important` set
        // We can't set `display: none` directly on `this.$el`, as it would
        // trigger a new transition to start (or cancel a current one)
        var $el = this.$el;
        var restore = hasClass($el, CLASS_NAME_SHOW);
        removeClass($el, CLASS_NAME_SHOW);
        var isBlock = getCS($el).display === 'block';

        if (restore) {
          addClass($el, CLASS_NAME_SHOW);
        }

        return isBlock;
      },
      clickHandler: function clickHandler(event) {
        var el = event.target; // If we are in a nav/navbar, close the collapse when non-disabled link clicked

        /* istanbul ignore next: can't test `getComputedStyle()` in JSDOM */

        if (!this.isNav || !el || getCS(this.$el).display !== 'block') {
          return;
        } // Only close the collapse if it is not forced to be `display: block !important`


        if ((matches(el, '.nav-link,.dropdown-item') || closest('.nav-link,.dropdown-item', el)) && !this.checkDisplayBlock()) {
          this.show = false;
        }
      },
      handleToggleEvent: function handleToggleEvent(id) {
        if (id === this.safeId()) {
          this.toggle();
        }
      },
      handleAccordionEvent: function handleAccordionEvent(openedId, openAccordion) {
        var accordion = this.accordion,
            show = this.show;

        if (!accordion || accordion !== openAccordion) {
          return;
        }

        var isThis = openedId === this.safeId(); // Open this collapse if not shown or
        // close this collapse if shown

        if (isThis && !show || !isThis && show) {
          this.toggle();
        }
      },
      handleResize: function handleResize() {
        // Handler for orientation/resize to set collapsed state in nav/navbar
        this.show = getCS(this.$el).display === 'block';
      }
    },
    render: function render(h) {
      var appear = this.appear;
      var $content = h(this.tag, {
        class: this.classObject,
        directives: [{
          name: 'show',
          value: this.show
        }],
        attrs: {
          id: this.safeId()
        },
        on: {
          click: this.clickHandler
        }
      }, this.normalizeSlot(SLOT_NAME_DEFAULT, this.slotScope));
      return h(BVCollapse, {
        props: {
          appear: appear
        },
        on: {
          enter: this.onEnter,
          afterEnter: this.onAfterEnter,
          leave: this.onLeave,
          afterLeave: this.onAfterLeave
        }
      }, [$content]);
    }
  });

  var getInstanceFromDirective = function getInstanceFromDirective(vnode, bindings) {
    return isVue3 ? bindings.instance : vnode.context;
  };

  // Classes to apply to trigger element

  var CLASS_BV_TOGGLE_COLLAPSED = 'collapsed';
  var CLASS_BV_TOGGLE_NOT_COLLAPSED = 'not-collapsed'; // Property key for handler storage

  var BV_BASE = '__BV_toggle'; // Root event listener property (Function)

  var BV_TOGGLE_ROOT_HANDLER = "".concat(BV_BASE, "_HANDLER__"); // Trigger element click handler property (Function)

  var BV_TOGGLE_CLICK_HANDLER = "".concat(BV_BASE, "_CLICK__"); // Target visibility state property (Boolean)

  var BV_TOGGLE_STATE = "".concat(BV_BASE, "_STATE__"); // Target ID list property (Array)

  var BV_TOGGLE_TARGETS = "".concat(BV_BASE, "_TARGETS__"); // Commonly used strings

  var STRING_FALSE = 'false';
  var STRING_TRUE = 'true'; // Commonly used attribute names

  var ATTR_ARIA_CONTROLS = 'aria-controls';
  var ATTR_ARIA_EXPANDED = 'aria-expanded';
  var ATTR_ROLE = 'role';
  var ATTR_TABINDEX = 'tabindex'; // Commonly used style properties

  var STYLE_OVERFLOW_ANCHOR = 'overflow-anchor'; // Emitted control event for collapse (emitted to collapse)

  var ROOT_ACTION_EVENT_NAME_TOGGLE$1 = getRootActionEventName(NAME_COLLAPSE, 'toggle'); // Listen to event for toggle state update (emitted by collapse)

  var ROOT_EVENT_NAME_STATE$2 = getRootEventName(NAME_COLLAPSE, 'state'); // Private event emitted on `$root` to ensure the toggle state is always synced
  // Gets emitted even if the state of b-collapse has not changed
  // This event is NOT to be documented as people should not be using it

  var ROOT_EVENT_NAME_SYNC_STATE$2 = getRootEventName(NAME_COLLAPSE, 'sync-state'); // Private event we send to collapse to request state update sync event

  var ROOT_ACTION_EVENT_NAME_REQUEST_STATE$1 = getRootActionEventName(NAME_COLLAPSE, 'request-state');
  var KEYDOWN_KEY_CODES = [CODE_ENTER, CODE_SPACE]; // --- Helper methods ---

  var isNonStandardTag = function isNonStandardTag(el) {
    return !arrayIncludes(['button', 'a'], el.tagName.toLowerCase());
  };

  var getTargets = function getTargets(_ref, el) {
    var modifiers = _ref.modifiers,
        arg = _ref.arg,
        value = _ref.value;
    // Any modifiers are considered target IDs
    var targets = keys(modifiers || {}); // If value is a string, split out individual targets (if space delimited)

    value = isString(value) ? value.split(RX_SPACE_SPLIT) : value; // Support target ID as link href (`href="#id"`)

    if (isTag(el.tagName, 'a')) {
      var href = getAttr(el, 'href') || '';

      if (RX_HASH_ID.test(href)) {
        targets.push(href.replace(RX_HASH, ''));
      }
    } // Add ID from `arg` (if provided), and support value
    // as a single string ID or an array of string IDs
    // If `value` is not an array or string, then it gets filtered out


    concat(arg, value).forEach(function (t) {
      return isString(t) && targets.push(t);
    }); // Return only unique and truthy target IDs

    return targets.filter(function (t, index, arr) {
      return t && arr.indexOf(t) === index;
    });
  };

  var removeClickListener = function removeClickListener(el) {
    var handler = el[BV_TOGGLE_CLICK_HANDLER];

    if (handler) {
      eventOff(el, 'click', handler, EVENT_OPTIONS_PASSIVE);
      eventOff(el, 'keydown', handler, EVENT_OPTIONS_PASSIVE);
    }

    el[BV_TOGGLE_CLICK_HANDLER] = null;
  };

  var addClickListener = function addClickListener(el, instance) {
    removeClickListener(el);

    if (instance) {
      var handler = function handler(event) {
        if (!(event.type === 'keydown' && !arrayIncludes(KEYDOWN_KEY_CODES, event.keyCode)) && !isDisabled(el)) {
          var targets = el[BV_TOGGLE_TARGETS] || [];
          targets.forEach(function (target) {
            getEventRoot(instance).$emit(ROOT_ACTION_EVENT_NAME_TOGGLE$1, target);
          });
        }
      };

      el[BV_TOGGLE_CLICK_HANDLER] = handler;
      eventOn(el, 'click', handler, EVENT_OPTIONS_PASSIVE);

      if (isNonStandardTag(el)) {
        eventOn(el, 'keydown', handler, EVENT_OPTIONS_PASSIVE);
      }
    }
  };

  var removeRootListeners = function removeRootListeners(el, instance) {
    if (el[BV_TOGGLE_ROOT_HANDLER] && instance) {
      getEventRoot(instance).$off([ROOT_EVENT_NAME_STATE$2, ROOT_EVENT_NAME_SYNC_STATE$2], el[BV_TOGGLE_ROOT_HANDLER]);
    }

    el[BV_TOGGLE_ROOT_HANDLER] = null;
  };

  var addRootListeners = function addRootListeners(el, instance) {
    removeRootListeners(el, instance);

    if (instance) {
      var handler = function handler(id, state) {
        // `state` will be `true` if target is expanded
        if (arrayIncludes(el[BV_TOGGLE_TARGETS] || [], id)) {
          // Set/Clear 'collapsed' visibility class state
          el[BV_TOGGLE_STATE] = state; // Set `aria-expanded` and class state on trigger element

          setToggleState(el, state);
        }
      };

      el[BV_TOGGLE_ROOT_HANDLER] = handler; // Listen for toggle state changes (public) and sync (private)

      getEventRoot(instance).$on([ROOT_EVENT_NAME_STATE$2, ROOT_EVENT_NAME_SYNC_STATE$2], handler);
    }
  };

  var setToggleState = function setToggleState(el, state) {
    // State refers to the visibility of the collapse/sidebar
    if (state) {
      removeClass(el, CLASS_BV_TOGGLE_COLLAPSED);
      addClass(el, CLASS_BV_TOGGLE_NOT_COLLAPSED);
      setAttr(el, ATTR_ARIA_EXPANDED, STRING_TRUE);
    } else {
      removeClass(el, CLASS_BV_TOGGLE_NOT_COLLAPSED);
      addClass(el, CLASS_BV_TOGGLE_COLLAPSED);
      setAttr(el, ATTR_ARIA_EXPANDED, STRING_FALSE);
    }
  }; // Reset and remove a property from the provided element


  var resetProp = function resetProp(el, prop) {
    el[prop] = null;
    delete el[prop];
  }; // Handle directive updates


  var handleUpdate = function handleUpdate(el, binding, vnode) {
    /* istanbul ignore next: should never happen */
    if (!IS_BROWSER || !getInstanceFromDirective(vnode, binding)) {
      return;
    } // If element is not a button or link, we add `role="button"`
    // and `tabindex="0"` for accessibility reasons


    if (isNonStandardTag(el)) {
      if (!hasAttr(el, ATTR_ROLE)) {
        setAttr(el, ATTR_ROLE, 'button');
      }

      if (!hasAttr(el, ATTR_TABINDEX)) {
        setAttr(el, ATTR_TABINDEX, '0');
      }
    } // Ensure the collapse class and `aria-*` attributes persist
    // after element is updated (either by parent re-rendering
    // or changes to this element or its contents)


    setToggleState(el, el[BV_TOGGLE_STATE]); // Parse list of target IDs

    var targets = getTargets(binding, el); // Ensure the `aria-controls` hasn't been overwritten
    // or removed when vnode updates
    // Also ensure to set `overflow-anchor` to `none` to prevent
    // the browser's scroll anchoring behavior

    /* istanbul ignore else */

    if (targets.length > 0) {
      setAttr(el, ATTR_ARIA_CONTROLS, targets.join(' '));
      setStyle(el, STYLE_OVERFLOW_ANCHOR, 'none');
    } else {
      removeAttr(el, ATTR_ARIA_CONTROLS);
      removeStyle(el, STYLE_OVERFLOW_ANCHOR);
    } // Add/Update our click listener(s)
    // Wrap in a `requestAF()` to allow any previous
    // click handling to occur first


    requestAF(function () {
      addClickListener(el, getInstanceFromDirective(vnode, binding));
    }); // If targets array has changed, update

    if (!looseEqual(targets, el[BV_TOGGLE_TARGETS])) {
      // Update targets array to element storage
      el[BV_TOGGLE_TARGETS] = targets; // Ensure `aria-controls` is up to date
      // Request a state update from targets so that we can
      // ensure expanded state is correct (in most cases)

      targets.forEach(function (target) {
        getEventRoot(getInstanceFromDirective(vnode, binding)).$emit(ROOT_ACTION_EVENT_NAME_REQUEST_STATE$1, target);
      });
    }
  };
  /*
   * Export our directive
   */


  var VBToggle = {
    bind: function bind(el, binding, vnode) {
      // State is initially collapsed until we receive a state event
      el[BV_TOGGLE_STATE] = false; // Assume no targets initially

      el[BV_TOGGLE_TARGETS] = []; // Add our root listeners

      addRootListeners(el, getInstanceFromDirective(vnode, binding)); // Initial update of trigger

      handleUpdate(el, binding, vnode);
    },
    componentUpdated: handleUpdate,
    updated: handleUpdate,
    unbind: function unbind(el, binding, vnode) {
      removeClickListener(el); // Remove our $root listener

      removeRootListeners(el, getInstanceFromDirective(vnode, binding)); // Reset custom props

      resetProp(el, BV_TOGGLE_ROOT_HANDLER);
      resetProp(el, BV_TOGGLE_CLICK_HANDLER);
      resetProp(el, BV_TOGGLE_STATE);
      resetProp(el, BV_TOGGLE_TARGETS); // Reset classes/attrs/styles

      removeClass(el, CLASS_BV_TOGGLE_COLLAPSED);
      removeClass(el, CLASS_BV_TOGGLE_NOT_COLLAPSED);
      removeAttr(el, ATTR_ARIA_EXPANDED);
      removeAttr(el, ATTR_ARIA_CONTROLS);
      removeAttr(el, ATTR_ROLE);
      removeStyle(el, STYLE_OVERFLOW_ANCHOR);
    }
  };

  var VBTogglePlugin = /*#__PURE__*/pluginFactory({
    directives: {
      VBToggle: VBToggle
    }
  });

  var CollapsePlugin = /*#__PURE__*/pluginFactory({
    components: {
      BCollapse: BCollapse
    },
    plugins: {
      VBTogglePlugin: VBTogglePlugin
    }
  });

  /**!
   * @fileOverview Kickass library to create and place poppers near their reference elements.
   * @version 1.16.1
   * @license
   * Copyright (c) 2016 Federico Zivolo and contributors
   *
   * Permission is hereby granted, free of charge, to any person obtaining a copy
   * of this software and associated documentation files (the "Software"), to deal
   * in the Software without restriction, including without limitation the rights
   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   * copies of the Software, and to permit persons to whom the Software is
   * furnished to do so, subject to the following conditions:
   *
   * The above copyright notice and this permission notice shall be included in all
   * copies or substantial portions of the Software.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   * SOFTWARE.
   */
  var isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined' && typeof navigator !== 'undefined';

  var timeoutDuration = function () {
    var longerTimeoutBrowsers = ['Edge', 'Trident', 'Firefox'];
    for (var i = 0; i < longerTimeoutBrowsers.length; i += 1) {
      if (isBrowser && navigator.userAgent.indexOf(longerTimeoutBrowsers[i]) >= 0) {
        return 1;
      }
    }
    return 0;
  }();

  function microtaskDebounce(fn) {
    var called = false;
    return function () {
      if (called) {
        return;
      }
      called = true;
      window.Promise.resolve().then(function () {
        called = false;
        fn();
      });
    };
  }

  function taskDebounce(fn) {
    var scheduled = false;
    return function () {
      if (!scheduled) {
        scheduled = true;
        setTimeout(function () {
          scheduled = false;
          fn();
        }, timeoutDuration);
      }
    };
  }

  var supportsMicroTasks = isBrowser && window.Promise;

  /**
  * Create a debounced version of a method, that's asynchronously deferred
  * but called in the minimum time possible.
  *
  * @method
  * @memberof Popper.Utils
  * @argument {Function} fn
  * @returns {Function}
  */
  var debounce = supportsMicroTasks ? microtaskDebounce : taskDebounce;

  /**
   * Check if the given variable is a function
   * @method
   * @memberof Popper.Utils
   * @argument {Any} functionToCheck - variable to check
   * @returns {Boolean} answer to: is a function?
   */
  function isFunction(functionToCheck) {
    var getType = {};
    return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
  }

  /**
   * Get CSS computed property of the given element
   * @method
   * @memberof Popper.Utils
   * @argument {Eement} element
   * @argument {String} property
   */
  function getStyleComputedProperty(element, property) {
    if (element.nodeType !== 1) {
      return [];
    }
    // NOTE: 1 DOM access here
    var window = element.ownerDocument.defaultView;
    var css = window.getComputedStyle(element, null);
    return property ? css[property] : css;
  }

  /**
   * Returns the parentNode or the host of the element
   * @method
   * @memberof Popper.Utils
   * @argument {Element} element
   * @returns {Element} parent
   */
  function getParentNode(element) {
    if (element.nodeName === 'HTML') {
      return element;
    }
    return element.parentNode || element.host;
  }

  /**
   * Returns the scrolling parent of the given element
   * @method
   * @memberof Popper.Utils
   * @argument {Element} element
   * @returns {Element} scroll parent
   */
  function getScrollParent(element) {
    // Return body, `getScroll` will take care to get the correct `scrollTop` from it
    if (!element) {
      return document.body;
    }

    switch (element.nodeName) {
      case 'HTML':
      case 'BODY':
        return element.ownerDocument.body;
      case '#document':
        return element.body;
    }

    // Firefox want us to check `-x` and `-y` variations as well

    var _getStyleComputedProp = getStyleComputedProperty(element),
        overflow = _getStyleComputedProp.overflow,
        overflowX = _getStyleComputedProp.overflowX,
        overflowY = _getStyleComputedProp.overflowY;

    if (/(auto|scroll|overlay)/.test(overflow + overflowY + overflowX)) {
      return element;
    }

    return getScrollParent(getParentNode(element));
  }

  /**
   * Returns the reference node of the reference object, or the reference object itself.
   * @method
   * @memberof Popper.Utils
   * @param {Element|Object} reference - the reference element (the popper will be relative to this)
   * @returns {Element} parent
   */
  function getReferenceNode(reference) {
    return reference && reference.referenceNode ? reference.referenceNode : reference;
  }

  var isIE11 = isBrowser && !!(window.MSInputMethodContext && document.documentMode);
  var isIE10 = isBrowser && /MSIE 10/.test(navigator.userAgent);

  /**
   * Determines if the browser is Internet Explorer
   * @method
   * @memberof Popper.Utils
   * @param {Number} version to check
   * @returns {Boolean} isIE
   */
  function isIE(version) {
    if (version === 11) {
      return isIE11;
    }
    if (version === 10) {
      return isIE10;
    }
    return isIE11 || isIE10;
  }

  /**
   * Returns the offset parent of the given element
   * @method
   * @memberof Popper.Utils
   * @argument {Element} element
   * @returns {Element} offset parent
   */
  function getOffsetParent(element) {
    if (!element) {
      return document.documentElement;
    }

    var noOffsetParent = isIE(10) ? document.body : null;

    // NOTE: 1 DOM access here
    var offsetParent = element.offsetParent || null;
    // Skip hidden elements which don't have an offsetParent
    while (offsetParent === noOffsetParent && element.nextElementSibling) {
      offsetParent = (element = element.nextElementSibling).offsetParent;
    }

    var nodeName = offsetParent && offsetParent.nodeName;

    if (!nodeName || nodeName === 'BODY' || nodeName === 'HTML') {
      return element ? element.ownerDocument.documentElement : document.documentElement;
    }

    // .offsetParent will return the closest TH, TD or TABLE in case
    // no offsetParent is present, I hate this job...
    if (['TH', 'TD', 'TABLE'].indexOf(offsetParent.nodeName) !== -1 && getStyleComputedProperty(offsetParent, 'position') === 'static') {
      return getOffsetParent(offsetParent);
    }

    return offsetParent;
  }

  function isOffsetContainer(element) {
    var nodeName = element.nodeName;

    if (nodeName === 'BODY') {
      return false;
    }
    return nodeName === 'HTML' || getOffsetParent(element.firstElementChild) === element;
  }

  /**
   * Finds the root node (document, shadowDOM root) of the given element
   * @method
   * @memberof Popper.Utils
   * @argument {Element} node
   * @returns {Element} root node
   */
  function getRoot(node) {
    if (node.parentNode !== null) {
      return getRoot(node.parentNode);
    }

    return node;
  }

  /**
   * Finds the offset parent common to the two provided nodes
   * @method
   * @memberof Popper.Utils
   * @argument {Element} element1
   * @argument {Element} element2
   * @returns {Element} common offset parent
   */
  function findCommonOffsetParent(element1, element2) {
    // This check is needed to avoid errors in case one of the elements isn't defined for any reason
    if (!element1 || !element1.nodeType || !element2 || !element2.nodeType) {
      return document.documentElement;
    }

    // Here we make sure to give as "start" the element that comes first in the DOM
    var order = element1.compareDocumentPosition(element2) & Node.DOCUMENT_POSITION_FOLLOWING;
    var start = order ? element1 : element2;
    var end = order ? element2 : element1;

    // Get common ancestor container
    var range = document.createRange();
    range.setStart(start, 0);
    range.setEnd(end, 0);
    var commonAncestorContainer = range.commonAncestorContainer;

    // Both nodes are inside #document

    if (element1 !== commonAncestorContainer && element2 !== commonAncestorContainer || start.contains(end)) {
      if (isOffsetContainer(commonAncestorContainer)) {
        return commonAncestorContainer;
      }

      return getOffsetParent(commonAncestorContainer);
    }

    // one of the nodes is inside shadowDOM, find which one
    var element1root = getRoot(element1);
    if (element1root.host) {
      return findCommonOffsetParent(element1root.host, element2);
    } else {
      return findCommonOffsetParent(element1, getRoot(element2).host);
    }
  }

  /**
   * Gets the scroll value of the given element in the given side (top and left)
   * @method
   * @memberof Popper.Utils
   * @argument {Element} element
   * @argument {String} side `top` or `left`
   * @returns {number} amount of scrolled pixels
   */
  function getScroll(element) {
    var side = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'top';

    var upperSide = side === 'top' ? 'scrollTop' : 'scrollLeft';
    var nodeName = element.nodeName;

    if (nodeName === 'BODY' || nodeName === 'HTML') {
      var html = element.ownerDocument.documentElement;
      var scrollingElement = element.ownerDocument.scrollingElement || html;
      return scrollingElement[upperSide];
    }

    return element[upperSide];
  }

  /*
   * Sum or subtract the element scroll values (left and top) from a given rect object
   * @method
   * @memberof Popper.Utils
   * @param {Object} rect - Rect object you want to change
   * @param {HTMLElement} element - The element from the function reads the scroll values
   * @param {Boolean} subtract - set to true if you want to subtract the scroll values
   * @return {Object} rect - The modifier rect object
   */
  function includeScroll(rect, element) {
    var subtract = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;

    var scrollTop = getScroll(element, 'top');
    var scrollLeft = getScroll(element, 'left');
    var modifier = subtract ? -1 : 1;
    rect.top += scrollTop * modifier;
    rect.bottom += scrollTop * modifier;
    rect.left += scrollLeft * modifier;
    rect.right += scrollLeft * modifier;
    return rect;
  }

  /*
   * Helper to detect borders of a given element
   * @method
   * @memberof Popper.Utils
   * @param {CSSStyleDeclaration} styles
   * Result of `getStyleComputedProperty` on the given element
   * @param {String} axis - `x` or `y`
   * @return {number} borders - The borders size of the given axis
   */

  function getBordersSize(styles, axis) {
    var sideA = axis === 'x' ? 'Left' : 'Top';
    var sideB = sideA === 'Left' ? 'Right' : 'Bottom';

    return parseFloat(styles['border' + sideA + 'Width']) + parseFloat(styles['border' + sideB + 'Width']);
  }

  function getSize(axis, body, html, computedStyle) {
    return Math.max(body['offset' + axis], body['scroll' + axis], html['client' + axis], html['offset' + axis], html['scroll' + axis], isIE(10) ? parseInt(html['offset' + axis]) + parseInt(computedStyle['margin' + (axis === 'Height' ? 'Top' : 'Left')]) + parseInt(computedStyle['margin' + (axis === 'Height' ? 'Bottom' : 'Right')]) : 0);
  }

  function getWindowSizes(document) {
    var body = document.body;
    var html = document.documentElement;
    var computedStyle = isIE(10) && getComputedStyle(html);

    return {
      height: getSize('Height', body, html, computedStyle),
      width: getSize('Width', body, html, computedStyle)
    };
  }

  var classCallCheck = function (instance, Constructor) {
    if (!(instance instanceof Constructor)) {
      throw new TypeError("Cannot call a class as a function");
    }
  };

  var createClass = function () {
    function defineProperties(target, props) {
      for (var i = 0; i < props.length; i++) {
        var descriptor = props[i];
        descriptor.enumerable = descriptor.enumerable || false;
        descriptor.configurable = true;
        if ("value" in descriptor) descriptor.writable = true;
        Object.defineProperty(target, descriptor.key, descriptor);
      }
    }

    return function (Constructor, protoProps, staticProps) {
      if (protoProps) defineProperties(Constructor.prototype, protoProps);
      if (staticProps) defineProperties(Constructor, staticProps);
      return Constructor;
    };
  }();





  var defineProperty = function (obj, key, value) {
    if (key in obj) {
      Object.defineProperty(obj, key, {
        value: value,
        enumerable: true,
        configurable: true,
        writable: true
      });
    } else {
      obj[key] = value;
    }

    return obj;
  };

  var _extends = Object.assign || function (target) {
    for (var i = 1; i < arguments.length; i++) {
      var source = arguments[i];

      for (var key in source) {
        if (Object.prototype.hasOwnProperty.call(source, key)) {
          target[key] = source[key];
        }
      }
    }

    return target;
  };

  /**
   * Given element offsets, generate an output similar to getBoundingClientRect
   * @method
   * @memberof Popper.Utils
   * @argument {Object} offsets
   * @returns {Object} ClientRect like output
   */
  function getClientRect(offsets) {
    return _extends({}, offsets, {
      right: offsets.left + offsets.width,
      bottom: offsets.top + offsets.height
    });
  }

  /**
   * Get bounding client rect of given element
   * @method
   * @memberof Popper.Utils
   * @param {HTMLElement} element
   * @return {Object} client rect
   */
  function getBoundingClientRect(element) {
    var rect = {};

    // IE10 10 FIX: Please, don't ask, the element isn't
    // considered in DOM in some circumstances...
    // This isn't reproducible in IE10 compatibility mode of IE11
    try {
      if (isIE(10)) {
        rect = element.getBoundingClientRect();
        var scrollTop = getScroll(element, 'top');
        var scrollLeft = getScroll(element, 'left');
        rect.top += scrollTop;
        rect.left += scrollLeft;
        rect.bottom += scrollTop;
        rect.right += scrollLeft;
      } else {
        rect = element.getBoundingClientRect();
      }
    } catch (e) {}

    var result = {
      left: rect.left,
      top: rect.top,
      width: rect.right - rect.left,
      height: rect.bottom - rect.top
    };

    // subtract scrollbar size from sizes
    var sizes = element.nodeName === 'HTML' ? getWindowSizes(element.ownerDocument) : {};
    var width = sizes.width || element.clientWidth || result.width;
    var height = sizes.height || element.clientHeight || result.height;

    var horizScrollbar = element.offsetWidth - width;
    var vertScrollbar = element.offsetHeight - height;

    // if an hypothetical scrollbar is detected, we must be sure it's not a `border`
    // we make this check conditional for performance reasons
    if (horizScrollbar || vertScrollbar) {
      var styles = getStyleComputedProperty(element);
      horizScrollbar -= getBordersSize(styles, 'x');
      vertScrollbar -= getBordersSize(styles, 'y');

      result.width -= horizScrollbar;
      result.height -= vertScrollbar;
    }

    return getClientRect(result);
  }

  function getOffsetRectRelativeToArbitraryNode(children, parent) {
    var fixedPosition = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;

    var isIE10 = isIE(10);
    var isHTML = parent.nodeName === 'HTML';
    var childrenRect = getBoundingClientRect(children);
    var parentRect = getBoundingClientRect(parent);
    var scrollParent = getScrollParent(children);

    var styles = getStyleComputedProperty(parent);
    var borderTopWidth = parseFloat(styles.borderTopWidth);
    var borderLeftWidth = parseFloat(styles.borderLeftWidth);

    // In cases where the parent is fixed, we must ignore negative scroll in offset calc
    if (fixedPosition && isHTML) {
      parentRect.top = Math.max(parentRect.top, 0);
      parentRect.left = Math.max(parentRect.left, 0);
    }
    var offsets = getClientRect({
      top: childrenRect.top - parentRect.top - borderTopWidth,
      left: childrenRect.left - parentRect.left - borderLeftWidth,
      width: childrenRect.width,
      height: childrenRect.height
    });
    offsets.marginTop = 0;
    offsets.marginLeft = 0;

    // Subtract margins of documentElement in case it's being used as parent
    // we do this only on HTML because it's the only element that behaves
    // differently when margins are applied to it. The margins are included in
    // the box of the documentElement, in the other cases not.
    if (!isIE10 && isHTML) {
      var marginTop = parseFloat(styles.marginTop);
      var marginLeft = parseFloat(styles.marginLeft);

      offsets.top -= borderTopWidth - marginTop;
      offsets.bottom -= borderTopWidth - marginTop;
      offsets.left -= borderLeftWidth - marginLeft;
      offsets.right -= borderLeftWidth - marginLeft;

      // Attach marginTop and marginLeft because in some circumstances we may need them
      offsets.marginTop = marginTop;
      offsets.marginLeft = marginLeft;
    }

    if (isIE10 && !fixedPosition ? parent.contains(scrollParent) : parent === scrollParent && scrollParent.nodeName !== 'BODY') {
      offsets = includeScroll(offsets, parent);
    }

    return offsets;
  }

  function getViewportOffsetRectRelativeToArtbitraryNode(element) {
    var excludeScroll = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;

    var html = element.ownerDocument.documentElement;
    var relativeOffset = getOffsetRectRelativeToArbitraryNode(element, html);
    var width = Math.max(html.clientWidth, window.innerWidth || 0);
    var height = Math.max(html.clientHeight, window.innerHeight || 0);

    var scrollTop = !excludeScroll ? getScroll(html) : 0;
    var scrollLeft = !excludeScroll ? getScroll(html, 'left') : 0;

    var offset = {
      top: scrollTop - relativeOffset.top + relativeOffset.marginTop,
      left: scrollLeft - relativeOffset.left + relativeOffset.marginLeft,
      width: width,
      height: height
    };

    return getClientRect(offset);
  }

  /**
   * Check if the given element is fixed or is inside a fixed parent
   * @method
   * @memberof Popper.Utils
   * @argument {Element} element
   * @argument {Element} customContainer
   * @returns {Boolean} answer to "isFixed?"
   */
  function isFixed(element) {
    var nodeName = element.nodeName;
    if (nodeName === 'BODY' || nodeName === 'HTML') {
      return false;
    }
    if (getStyleComputedProperty(element, 'position') === 'fixed') {
      return true;
    }
    var parentNode = getParentNode(element);
    if (!parentNode) {
      return false;
    }
    return isFixed(parentNode);
  }

  /**
   * Finds the first parent of an element that has a transformed property defined
   * @method
   * @memberof Popper.Utils
   * @argument {Element} element
   * @returns {Element} first transformed parent or documentElement
   */

  function getFixedPositionOffsetParent(element) {
    // This check is needed to avoid errors in case one of the elements isn't defined for any reason
    if (!element || !element.parentElement || isIE()) {
      return document.documentElement;
    }
    var el = element.parentElement;
    while (el && getStyleComputedProperty(el, 'transform') === 'none') {
      el = el.parentElement;
    }
    return el || document.documentElement;
  }

  /**
   * Computed the boundaries limits and return them
   * @method
   * @memberof Popper.Utils
   * @param {HTMLElement} popper
   * @param {HTMLElement} reference
   * @param {number} padding
   * @param {HTMLElement} boundariesElement - Element used to define the boundaries
   * @param {Boolean} fixedPosition - Is in fixed position mode
   * @returns {Object} Coordinates of the boundaries
   */
  function getBoundaries(popper, reference, padding, boundariesElement) {
    var fixedPosition = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;

    // NOTE: 1 DOM access here

    var boundaries = { top: 0, left: 0 };
    var offsetParent = fixedPosition ? getFixedPositionOffsetParent(popper) : findCommonOffsetParent(popper, getReferenceNode(reference));

    // Handle viewport case
    if (boundariesElement === 'viewport') {
      boundaries = getViewportOffsetRectRelativeToArtbitraryNode(offsetParent, fixedPosition);
    } else {
      // Handle other cases based on DOM element used as boundaries
      var boundariesNode = void 0;
      if (boundariesElement === 'scrollParent') {
        boundariesNode = getScrollParent(getParentNode(reference));
        if (boundariesNode.nodeName === 'BODY') {
          boundariesNode = popper.ownerDocument.documentElement;
        }
      } else if (boundariesElement === 'window') {
        boundariesNode = popper.ownerDocument.documentElement;
      } else {
        boundariesNode = boundariesElement;
      }

      var offsets = getOffsetRectRelativeToArbitraryNode(boundariesNode, offsetParent, fixedPosition);

      // In case of HTML, we need a different computation
      if (boundariesNode.nodeName === 'HTML' && !isFixed(offsetParent)) {
        var _getWindowSizes = getWindowSizes(popper.ownerDocument),
            height = _getWindowSizes.height,
            width = _getWindowSizes.width;

        boundaries.top += offsets.top - offsets.marginTop;
        boundaries.bottom = height + offsets.top;
        boundaries.left += offsets.left - offsets.marginLeft;
        boundaries.right = width + offsets.left;
      } else {
        // for all the other DOM elements, this one is good
        boundaries = offsets;
      }
    }

    // Add paddings
    padding = padding || 0;
    var isPaddingNumber = typeof padding === 'number';
    boundaries.left += isPaddingNumber ? padding : padding.left || 0;
    boundaries.top += isPaddingNumber ? padding : padding.top || 0;
    boundaries.right -= isPaddingNumber ? padding : padding.right || 0;
    boundaries.bottom -= isPaddingNumber ? padding : padding.bottom || 0;

    return boundaries;
  }

  function getArea(_ref) {
    var width = _ref.width,
        height = _ref.height;

    return width * height;
  }

  /**
   * Utility used to transform the `auto` placement to the placement with more
   * available space.
   * @method
   * @memberof Popper.Utils
   * @argument {Object} data - The data object generated by update method
   * @argument {Object} options - Modifiers configuration and options
   * @returns {Object} The data object, properly modified
   */
  function computeAutoPlacement(placement, refRect, popper, reference, boundariesElement) {
    var padding = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0;

    if (placement.indexOf('auto') === -1) {
      return placement;
    }

    var boundaries = getBoundaries(popper, reference, padding, boundariesElement);

    var rects = {
      top: {
        width: boundaries.width,
        height: refRect.top - boundaries.top
      },
      right: {
        width: boundaries.right - refRect.right,
        height: boundaries.height
      },
      bottom: {
        width: boundaries.width,
        height: boundaries.bottom - refRect.bottom
      },
      left: {
        width: refRect.left - boundaries.left,
        height: boundaries.height
      }
    };

    var sortedAreas = Object.keys(rects).map(function (key) {
      return _extends({
        key: key
      }, rects[key], {
        area: getArea(rects[key])
      });
    }).sort(function (a, b) {
      return b.area - a.area;
    });

    var filteredAreas = sortedAreas.filter(function (_ref2) {
      var width = _ref2.width,
          height = _ref2.height;
      return width >= popper.clientWidth && height >= popper.clientHeight;
    });

    var computedPlacement = filteredAreas.length > 0 ? filteredAreas[0].key : sortedAreas[0].key;

    var variation = placement.split('-')[1];

    return computedPlacement + (variation ? '-' + variation : '');
  }

  /**
   * Get offsets to the reference element
   * @method
   * @memberof Popper.Utils
   * @param {Object} state
   * @param {Element} popper - the popper element
   * @param {Element} reference - the reference element (the popper will be relative to this)
   * @param {Element} fixedPosition - is in fixed position mode
   * @returns {Object} An object containing the offsets which will be applied to the popper
   */
  function getReferenceOffsets(state, popper, reference) {
    var fixedPosition = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;

    var commonOffsetParent = fixedPosition ? getFixedPositionOffsetParent(popper) : findCommonOffsetParent(popper, getReferenceNode(reference));
    return getOffsetRectRelativeToArbitraryNode(reference, commonOffsetParent, fixedPosition);
  }

  /**
   * Get the outer sizes of the given element (offset size + margins)
   * @method
   * @memberof Popper.Utils
   * @argument {Element} element
   * @returns {Object} object containing width and height properties
   */
  function getOuterSizes(element) {
    var window = element.ownerDocument.defaultView;
    var styles = window.getComputedStyle(element);
    var x = parseFloat(styles.marginTop || 0) + parseFloat(styles.marginBottom || 0);
    var y = parseFloat(styles.marginLeft || 0) + parseFloat(styles.marginRight || 0);
    var result = {
      width: element.offsetWidth + y,
      height: element.offsetHeight + x
    };
    return result;
  }

  /**
   * Get the opposite placement of the given one
   * @method
   * @memberof Popper.Utils
   * @argument {String} placement
   * @returns {String} flipped placement
   */
  function getOppositePlacement(placement) {
    var hash = { left: 'right', right: 'left', bottom: 'top', top: 'bottom' };
    return placement.replace(/left|right|bottom|top/g, function (matched) {
      return hash[matched];
    });
  }

  /**
   * Get offsets to the popper
   * @method
   * @memberof Popper.Utils
   * @param {Object} position - CSS position the Popper will get applied
   * @param {HTMLElement} popper - the popper element
   * @param {Object} referenceOffsets - the reference offsets (the popper will be relative to this)
   * @param {String} placement - one of the valid placement options
   * @returns {Object} popperOffsets - An object containing the offsets which will be applied to the popper
   */
  function getPopperOffsets(popper, referenceOffsets, placement) {
    placement = placement.split('-')[0];

    // Get popper node sizes
    var popperRect = getOuterSizes(popper);

    // Add position, width and height to our offsets object
    var popperOffsets = {
      width: popperRect.width,
      height: popperRect.height
    };

    // depending by the popper placement we have to compute its offsets slightly differently
    var isHoriz = ['right', 'left'].indexOf(placement) !== -1;
    var mainSide = isHoriz ? 'top' : 'left';
    var secondarySide = isHoriz ? 'left' : 'top';
    var measurement = isHoriz ? 'height' : 'width';
    var secondaryMeasurement = !isHoriz ? 'height' : 'width';

    popperOffsets[mainSide] = referenceOffsets[mainSide] + referenceOffsets[measurement] / 2 - popperRect[measurement] / 2;
    if (placement === secondarySide) {
      popperOffsets[secondarySide] = referenceOffsets[secondarySide] - popperRect[secondaryMeasurement];
    } else {
      popperOffsets[secondarySide] = referenceOffsets[getOppositePlacement(secondarySide)];
    }

    return popperOffsets;
  }

  /**
   * Mimics the `find` method of Array
   * @method
   * @memberof Popper.Utils
   * @argument {Array} arr
   * @argument prop
   * @argument value
   * @returns index or -1
   */
  function find(arr, check) {
    // use native find if supported
    if (Array.prototype.find) {
      return arr.find(check);
    }

    // use `filter` to obtain the same behavior of `find`
    return arr.filter(check)[0];
  }

  /**
   * Return the index of the matching object
   * @method
   * @memberof Popper.Utils
   * @argument {Array} arr
   * @argument prop
   * @argument value
   * @returns index or -1
   */
  function findIndex(arr, prop, value) {
    // use native findIndex if supported
    if (Array.prototype.findIndex) {
      return arr.findIndex(function (cur) {
        return cur[prop] === value;
      });
    }

    // use `find` + `indexOf` if `findIndex` isn't supported
    var match = find(arr, function (obj) {
      return obj[prop] === value;
    });
    return arr.indexOf(match);
  }

  /**
   * Loop trough the list of modifiers and run them in order,
   * each of them will then edit the data object.
   * @method
   * @memberof Popper.Utils
   * @param {dataObject} data
   * @param {Array} modifiers
   * @param {String} ends - Optional modifier name used as stopper
   * @returns {dataObject}
   */
  function runModifiers(modifiers, data, ends) {
    var modifiersToRun = ends === undefined ? modifiers : modifiers.slice(0, findIndex(modifiers, 'name', ends));

    modifiersToRun.forEach(function (modifier) {
      if (modifier['function']) {
        // eslint-disable-line dot-notation
        console.warn('`modifier.function` is deprecated, use `modifier.fn`!');
      }
      var fn = modifier['function'] || modifier.fn; // eslint-disable-line dot-notation
      if (modifier.enabled && isFunction(fn)) {
        // Add properties to offsets to make them a complete clientRect object
        // we do this before each modifier to make sure the previous one doesn't
        // mess with these values
        data.offsets.popper = getClientRect(data.offsets.popper);
        data.offsets.reference = getClientRect(data.offsets.reference);

        data = fn(data, modifier);
      }
    });

    return data;
  }

  /**
   * Updates the position of the popper, computing the new offsets and applying
   * the new style.<br />
   * Prefer `scheduleUpdate` over `update` because of performance reasons.
   * @method
   * @memberof Popper
   */
  function update() {
    // if popper is destroyed, don't perform any further update
    if (this.state.isDestroyed) {
      return;
    }

    var data = {
      instance: this,
      styles: {},
      arrowStyles: {},
      attributes: {},
      flipped: false,
      offsets: {}
    };

    // compute reference element offsets
    data.offsets.reference = getReferenceOffsets(this.state, this.popper, this.reference, this.options.positionFixed);

    // compute auto placement, store placement inside the data object,
    // modifiers will be able to edit `placement` if needed
    // and refer to originalPlacement to know the original value
    data.placement = computeAutoPlacement(this.options.placement, data.offsets.reference, this.popper, this.reference, this.options.modifiers.flip.boundariesElement, this.options.modifiers.flip.padding);

    // store the computed placement inside `originalPlacement`
    data.originalPlacement = data.placement;

    data.positionFixed = this.options.positionFixed;

    // compute the popper offsets
    data.offsets.popper = getPopperOffsets(this.popper, data.offsets.reference, data.placement);

    data.offsets.popper.position = this.options.positionFixed ? 'fixed' : 'absolute';

    // run the modifiers
    data = runModifiers(this.modifiers, data);

    // the first `update` will call `onCreate` callback
    // the other ones will call `onUpdate` callback
    if (!this.state.isCreated) {
      this.state.isCreated = true;
      this.options.onCreate(data);
    } else {
      this.options.onUpdate(data);
    }
  }

  /**
   * Helper used to know if the given modifier is enabled.
   * @method
   * @memberof Popper.Utils
   * @returns {Boolean}
   */
  function isModifierEnabled(modifiers, modifierName) {
    return modifiers.some(function (_ref) {
      var name = _ref.name,
          enabled = _ref.enabled;
      return enabled && name === modifierName;
    });
  }

  /**
   * Get the prefixed supported property name
   * @method
   * @memberof Popper.Utils
   * @argument {String} property (camelCase)
   * @returns {String} prefixed property (camelCase or PascalCase, depending on the vendor prefix)
   */
  function getSupportedPropertyName(property) {
    var prefixes = [false, 'ms', 'Webkit', 'Moz', 'O'];
    var upperProp = property.charAt(0).toUpperCase() + property.slice(1);

    for (var i = 0; i < prefixes.length; i++) {
      var prefix = prefixes[i];
      var toCheck = prefix ? '' + prefix + upperProp : property;
      if (typeof document.body.style[toCheck] !== 'undefined') {
        return toCheck;
      }
    }
    return null;
  }

  /**
   * Destroys the popper.
   * @method
   * @memberof Popper
   */
  function destroy() {
    this.state.isDestroyed = true;

    // touch DOM only if `applyStyle` modifier is enabled
    if (isModifierEnabled(this.modifiers, 'applyStyle')) {
      this.popper.removeAttribute('x-placement');
      this.popper.style.position = '';
      this.popper.style.top = '';
      this.popper.style.left = '';
      this.popper.style.right = '';
      this.popper.style.bottom = '';
      this.popper.style.willChange = '';
      this.popper.style[getSupportedPropertyName('transform')] = '';
    }

    this.disableEventListeners();

    // remove the popper if user explicitly asked for the deletion on destroy
    // do not use `remove` because IE11 doesn't support it
    if (this.options.removeOnDestroy) {
      this.popper.parentNode.removeChild(this.popper);
    }
    return this;
  }

  /**
   * Get the window associated with the element
   * @argument {Element} element
   * @returns {Window}
   */
  function getWindow(element) {
    var ownerDocument = element.ownerDocument;
    return ownerDocument ? ownerDocument.defaultView : window;
  }

  function attachToScrollParents(scrollParent, event, callback, scrollParents) {
    var isBody = scrollParent.nodeName === 'BODY';
    var target = isBody ? scrollParent.ownerDocument.defaultView : scrollParent;
    target.addEventListener(event, callback, { passive: true });

    if (!isBody) {
      attachToScrollParents(getScrollParent(target.parentNode), event, callback, scrollParents);
    }
    scrollParents.push(target);
  }

  /**
   * Setup needed event listeners used to update the popper position
   * @method
   * @memberof Popper.Utils
   * @private
   */
  function setupEventListeners(reference, options, state, updateBound) {
    // Resize event listener on window
    state.updateBound = updateBound;
    getWindow(reference).addEventListener('resize', state.updateBound, { passive: true });

    // Scroll event listener on scroll parents
    var scrollElement = getScrollParent(reference);
    attachToScrollParents(scrollElement, 'scroll', state.updateBound, state.scrollParents);
    state.scrollElement = scrollElement;
    state.eventsEnabled = true;

    return state;
  }

  /**
   * It will add resize/scroll events and start recalculating
   * position of the popper element when they are triggered.
   * @method
   * @memberof Popper
   */
  function enableEventListeners() {
    if (!this.state.eventsEnabled) {
      this.state = setupEventListeners(this.reference, this.options, this.state, this.scheduleUpdate);
    }
  }

  /**
   * Remove event listeners used to update the popper position
   * @method
   * @memberof Popper.Utils
   * @private
   */
  function removeEventListeners(reference, state) {
    // Remove resize event listener on window
    getWindow(reference).removeEventListener('resize', state.updateBound);

    // Remove scroll event listener on scroll parents
    state.scrollParents.forEach(function (target) {
      target.removeEventListener('scroll', state.updateBound);
    });

    // Reset state
    state.updateBound = null;
    state.scrollParents = [];
    state.scrollElement = null;
    state.eventsEnabled = false;
    return state;
  }

  /**
   * It will remove resize/scroll events and won't recalculate popper position
   * when they are triggered. It also won't trigger `onUpdate` callback anymore,
   * unless you call `update` method manually.
   * @method
   * @memberof Popper
   */
  function disableEventListeners() {
    if (this.state.eventsEnabled) {
      cancelAnimationFrame(this.scheduleUpdate);
      this.state = removeEventListeners(this.reference, this.state);
    }
  }

  /**
   * Tells if a given input is a number
   * @method
   * @memberof Popper.Utils
   * @param {*} input to check
   * @return {Boolean}
   */
  function isNumeric(n) {
    return n !== '' && !isNaN(parseFloat(n)) && isFinite(n);
  }

  /**
   * Set the style to the given popper
   * @method
   * @memberof Popper.Utils
   * @argument {Element} element - Element to apply the style to
   * @argument {Object} styles
   * Object with a list of properties and values which will be applied to the element
   */
  function setStyles(element, styles) {
    Object.keys(styles).forEach(function (prop) {
      var unit = '';
      // add unit if the value is numeric and is one of the following
      if (['width', 'height', 'top', 'right', 'bottom', 'left'].indexOf(prop) !== -1 && isNumeric(styles[prop])) {
        unit = 'px';
      }
      element.style[prop] = styles[prop] + unit;
    });
  }

  /**
   * Set the attributes to the given popper
   * @method
   * @memberof Popper.Utils
   * @argument {Element} element - Element to apply the attributes to
   * @argument {Object} styles
   * Object with a list of properties and values which will be applied to the element
   */
  function setAttributes(element, attributes) {
    Object.keys(attributes).forEach(function (prop) {
      var value = attributes[prop];
      if (value !== false) {
        element.setAttribute(prop, attributes[prop]);
      } else {
        element.removeAttribute(prop);
      }
    });
  }

  /**
   * @function
   * @memberof Modifiers
   * @argument {Object} data - The data object generated by `update` method
   * @argument {Object} data.styles - List of style properties - values to apply to popper element
   * @argument {Object} data.attributes - List of attribute properties - values to apply to popper element
   * @argument {Object} options - Modifiers configuration and options
   * @returns {Object} The same data object
   */
  function applyStyle(data) {
    // any property present in `data.styles` will be applied to the popper,
    // in this way we can make the 3rd party modifiers add custom styles to it
    // Be aware, modifiers could override the properties defined in the previous
    // lines of this modifier!
    setStyles(data.instance.popper, data.styles);

    // any property present in `data.attributes` will be applied to the popper,
    // they will be set as HTML attributes of the element
    setAttributes(data.instance.popper, data.attributes);

    // if arrowElement is defined and arrowStyles has some properties
    if (data.arrowElement && Object.keys(data.arrowStyles).length) {
      setStyles(data.arrowElement, data.arrowStyles);
    }

    return data;
  }

  /**
   * Set the x-placement attribute before everything else because it could be used
   * to add margins to the popper margins needs to be calculated to get the
   * correct popper offsets.
   * @method
   * @memberof Popper.modifiers
   * @param {HTMLElement} reference - The reference element used to position the popper
   * @param {HTMLElement} popper - The HTML element used as popper
   * @param {Object} options - Popper.js options
   */
  function applyStyleOnLoad(reference, popper, options, modifierOptions, state) {
    // compute reference element offsets
    var referenceOffsets = getReferenceOffsets(state, popper, reference, options.positionFixed);

    // compute auto placement, store placement inside the data object,
    // modifiers will be able to edit `placement` if needed
    // and refer to originalPlacement to know the original value
    var placement = computeAutoPlacement(options.placement, referenceOffsets, popper, reference, options.modifiers.flip.boundariesElement, options.modifiers.flip.padding);

    popper.setAttribute('x-placement', placement);

    // Apply `position` to popper before anything else because
    // without the position applied we can't guarantee correct computations
    setStyles(popper, { position: options.positionFixed ? 'fixed' : 'absolute' });

    return options;
  }

  /**
   * @function
   * @memberof Popper.Utils
   * @argument {Object} data - The data object generated by `update` method
   * @argument {Boolean} shouldRound - If the offsets should be rounded at all
   * @returns {Object} The popper's position offsets rounded
   *
   * The tale of pixel-perfect positioning. It's still not 100% perfect, but as
   * good as it can be within reason.
   * Discussion here: https://github.com/FezVrasta/popper.js/pull/715
   *
   * Low DPI screens cause a popper to be blurry if not using full pixels (Safari
   * as well on High DPI screens).
   *
   * Firefox prefers no rounding for positioning and does not have blurriness on
   * high DPI screens.
   *
   * Only horizontal placement and left/right values need to be considered.
   */
  function getRoundedOffsets(data, shouldRound) {
    var _data$offsets = data.offsets,
        popper = _data$offsets.popper,
        reference = _data$offsets.reference;
    var round = Math.round,
        floor = Math.floor;

    var noRound = function noRound(v) {
      return v;
    };

    var referenceWidth = round(reference.width);
    var popperWidth = round(popper.width);

    var isVertical = ['left', 'right'].indexOf(data.placement) !== -1;
    var isVariation = data.placement.indexOf('-') !== -1;
    var sameWidthParity = referenceWidth % 2 === popperWidth % 2;
    var bothOddWidth = referenceWidth % 2 === 1 && popperWidth % 2 === 1;

    var horizontalToInteger = !shouldRound ? noRound : isVertical || isVariation || sameWidthParity ? round : floor;
    var verticalToInteger = !shouldRound ? noRound : round;

    return {
      left: horizontalToInteger(bothOddWidth && !isVariation && shouldRound ? popper.left - 1 : popper.left),
      top: verticalToInteger(popper.top),
      bottom: verticalToInteger(popper.bottom),
      right: horizontalToInteger(popper.right)
    };
  }

  var isFirefox = isBrowser && /Firefox/i.test(navigator.userAgent);

  /**
   * @function
   * @memberof Modifiers
   * @argument {Object} data - The data object generated by `update` method
   * @argument {Object} options - Modifiers configuration and options
   * @returns {Object} The data object, properly modified
   */
  function computeStyle(data, options) {
    var x = options.x,
        y = options.y;
    var popper = data.offsets.popper;

    // Remove this legacy support in Popper.js v2

    var legacyGpuAccelerationOption = find(data.instance.modifiers, function (modifier) {
      return modifier.name === 'applyStyle';
    }).gpuAcceleration;
    if (legacyGpuAccelerationOption !== undefined) {
      console.warn('WARNING: `gpuAcceleration` option moved to `computeStyle` modifier and will not be supported in future versions of Popper.js!');
    }
    var gpuAcceleration = legacyGpuAccelerationOption !== undefined ? legacyGpuAccelerationOption : options.gpuAcceleration;

    var offsetParent = getOffsetParent(data.instance.popper);
    var offsetParentRect = getBoundingClientRect(offsetParent);

    // Styles
    var styles = {
      position: popper.position
    };

    var offsets = getRoundedOffsets(data, window.devicePixelRatio < 2 || !isFirefox);

    var sideA = x === 'bottom' ? 'top' : 'bottom';
    var sideB = y === 'right' ? 'left' : 'right';

    // if gpuAcceleration is set to `true` and transform is supported,
    //  we use `translate3d` to apply the position to the popper we
    // automatically use the supported prefixed version if needed
    var prefixedProperty = getSupportedPropertyName('transform');

    // now, let's make a step back and look at this code closely (wtf?)
    // If the content of the popper grows once it's been positioned, it
    // may happen that the popper gets misplaced because of the new content
    // overflowing its reference element
    // To avoid this problem, we provide two options (x and y), which allow
    // the consumer to define the offset origin.
    // If we position a popper on top of a reference element, we can set
    // `x` to `top` to make the popper grow towards its top instead of
    // its bottom.
    var left = void 0,
        top = void 0;
    if (sideA === 'bottom') {
      // when offsetParent is <html> the positioning is relative to the bottom of the screen (excluding the scrollbar)
      // and not the bottom of the html element
      if (offsetParent.nodeName === 'HTML') {
        top = -offsetParent.clientHeight + offsets.bottom;
      } else {
        top = -offsetParentRect.height + offsets.bottom;
      }
    } else {
      top = offsets.top;
    }
    if (sideB === 'right') {
      if (offsetParent.nodeName === 'HTML') {
        left = -offsetParent.clientWidth + offsets.right;
      } else {
        left = -offsetParentRect.width + offsets.right;
      }
    } else {
      left = offsets.left;
    }
    if (gpuAcceleration && prefixedProperty) {
      styles[prefixedProperty] = 'translate3d(' + left + 'px, ' + top + 'px, 0)';
      styles[sideA] = 0;
      styles[sideB] = 0;
      styles.willChange = 'transform';
    } else {
      // othwerise, we use the standard `top`, `left`, `bottom` and `right` properties
      var invertTop = sideA === 'bottom' ? -1 : 1;
      var invertLeft = sideB === 'right' ? -1 : 1;
      styles[sideA] = top * invertTop;
      styles[sideB] = left * invertLeft;
      styles.willChange = sideA + ', ' + sideB;
    }

    // Attributes
    var attributes = {
      'x-placement': data.placement
    };

    // Update `data` attributes, styles and arrowStyles
    data.attributes = _extends({}, attributes, data.attributes);
    data.styles = _extends({}, styles, data.styles);
    data.arrowStyles = _extends({}, data.offsets.arrow, data.arrowStyles);

    return data;
  }

  /**
   * Helper used to know if the given modifier depends from another one.<br />
   * It checks if the needed modifier is listed and enabled.
   * @method
   * @memberof Popper.Utils
   * @param {Array} modifiers - list of modifiers
   * @param {String} requestingName - name of requesting modifier
   * @param {String} requestedName - name of requested modifier
   * @returns {Boolean}
   */
  function isModifierRequired(modifiers, requestingName, requestedName) {
    var requesting = find(modifiers, function (_ref) {
      var name = _ref.name;
      return name === requestingName;
    });

    var isRequired = !!requesting && modifiers.some(function (modifier) {
      return modifier.name === requestedName && modifier.enabled && modifier.order < requesting.order;
    });

    if (!isRequired) {
      var _requesting = '`' + requestingName + '`';
      var requested = '`' + requestedName + '`';
      console.warn(requested + ' modifier is required by ' + _requesting + ' modifier in order to work, be sure to include it before ' + _requesting + '!');
    }
    return isRequired;
  }

  /**
   * @function
   * @memberof Modifiers
   * @argument {Object} data - The data object generated by update method
   * @argument {Object} options - Modifiers configuration and options
   * @returns {Object} The data object, properly modified
   */
  function arrow(data, options) {
    var _data$offsets$arrow;

    // arrow depends on keepTogether in order to work
    if (!isModifierRequired(data.instance.modifiers, 'arrow', 'keepTogether')) {
      return data;
    }

    var arrowElement = options.element;

    // if arrowElement is a string, suppose it's a CSS selector
    if (typeof arrowElement === 'string') {
      arrowElement = data.instance.popper.querySelector(arrowElement);

      // if arrowElement is not found, don't run the modifier
      if (!arrowElement) {
        return data;
      }
    } else {
      // if the arrowElement isn't a query selector we must check that the
      // provided DOM node is child of its popper node
      if (!data.instance.popper.contains(arrowElement)) {
        console.warn('WARNING: `arrow.element` must be child of its popper element!');
        return data;
      }
    }

    var placement = data.placement.split('-')[0];
    var _data$offsets = data.offsets,
        popper = _data$offsets.popper,
        reference = _data$offsets.reference;

    var isVertical = ['left', 'right'].indexOf(placement) !== -1;

    var len = isVertical ? 'height' : 'width';
    var sideCapitalized = isVertical ? 'Top' : 'Left';
    var side = sideCapitalized.toLowerCase();
    var altSide = isVertical ? 'left' : 'top';
    var opSide = isVertical ? 'bottom' : 'right';
    var arrowElementSize = getOuterSizes(arrowElement)[len];

    //
    // extends keepTogether behavior making sure the popper and its
    // reference have enough pixels in conjunction
    //

    // top/left side
    if (reference[opSide] - arrowElementSize < popper[side]) {
      data.offsets.popper[side] -= popper[side] - (reference[opSide] - arrowElementSize);
    }
    // bottom/right side
    if (reference[side] + arrowElementSize > popper[opSide]) {
      data.offsets.popper[side] += reference[side] + arrowElementSize - popper[opSide];
    }
    data.offsets.popper = getClientRect(data.offsets.popper);

    // compute center of the popper
    var center = reference[side] + reference[len] / 2 - arrowElementSize / 2;

    // Compute the sideValue using the updated popper offsets
    // take popper margin in account because we don't have this info available
    var css = getStyleComputedProperty(data.instance.popper);
    var popperMarginSide = parseFloat(css['margin' + sideCapitalized]);
    var popperBorderSide = parseFloat(css['border' + sideCapitalized + 'Width']);
    var sideValue = center - data.offsets.popper[side] - popperMarginSide - popperBorderSide;

    // prevent arrowElement from being placed not contiguously to its popper
    sideValue = Math.max(Math.min(popper[len] - arrowElementSize, sideValue), 0);

    data.arrowElement = arrowElement;
    data.offsets.arrow = (_data$offsets$arrow = {}, defineProperty(_data$offsets$arrow, side, Math.round(sideValue)), defineProperty(_data$offsets$arrow, altSide, ''), _data$offsets$arrow);

    return data;
  }

  /**
   * Get the opposite placement variation of the given one
   * @method
   * @memberof Popper.Utils
   * @argument {String} placement variation
   * @returns {String} flipped placement variation
   */
  function getOppositeVariation(variation) {
    if (variation === 'end') {
      return 'start';
    } else if (variation === 'start') {
      return 'end';
    }
    return variation;
  }

  /**
   * List of accepted placements to use as values of the `placement` option.<br />
   * Valid placements are:
   * - `auto`
   * - `top`
   * - `right`
   * - `bottom`
   * - `left`
   *
   * Each placement can have a variation from this list:
   * - `-start`
   * - `-end`
   *
   * Variations are interpreted easily if you think of them as the left to right
   * written languages. Horizontally (`top` and `bottom`), `start` is left and `end`
   * is right.<br />
   * Vertically (`left` and `right`), `start` is top and `end` is bottom.
   *
   * Some valid examples are:
   * - `top-end` (on top of reference, right aligned)
   * - `right-start` (on right of reference, top aligned)
   * - `bottom` (on bottom, centered)
   * - `auto-end` (on the side with more space available, alignment depends by placement)
   *
   * @static
   * @type {Array}
   * @enum {String}
   * @readonly
   * @method placements
   * @memberof Popper
   */
  var placements = ['auto-start', 'auto', 'auto-end', 'top-start', 'top', 'top-end', 'right-start', 'right', 'right-end', 'bottom-end', 'bottom', 'bottom-start', 'left-end', 'left', 'left-start'];

  // Get rid of `auto` `auto-start` and `auto-end`
  var validPlacements = placements.slice(3);

  /**
   * Given an initial placement, returns all the subsequent placements
   * clockwise (or counter-clockwise).
   *
   * @method
   * @memberof Popper.Utils
   * @argument {String} placement - A valid placement (it accepts variations)
   * @argument {Boolean} counter - Set to true to walk the placements counterclockwise
   * @returns {Array} placements including their variations
   */
  function clockwise(placement) {
    var counter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;

    var index = validPlacements.indexOf(placement);
    var arr = validPlacements.slice(index + 1).concat(validPlacements.slice(0, index));
    return counter ? arr.reverse() : arr;
  }

  var BEHAVIORS = {
    FLIP: 'flip',
    CLOCKWISE: 'clockwise',
    COUNTERCLOCKWISE: 'counterclockwise'
  };

  /**
   * @function
   * @memberof Modifiers
   * @argument {Object} data - The data object generated by update method
   * @argument {Object} options - Modifiers configuration and options
   * @returns {Object} The data object, properly modified
   */
  function flip(data, options) {
    // if `inner` modifier is enabled, we can't use the `flip` modifier
    if (isModifierEnabled(data.instance.modifiers, 'inner')) {
      return data;
    }

    if (data.flipped && data.placement === data.originalPlacement) {
      // seems like flip is trying to loop, probably there's not enough space on any of the flippable sides
      return data;
    }

    var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, options.boundariesElement, data.positionFixed);

    var placement = data.placement.split('-')[0];
    var placementOpposite = getOppositePlacement(placement);
    var variation = data.placement.split('-')[1] || '';

    var flipOrder = [];

    switch (options.behavior) {
      case BEHAVIORS.FLIP:
        flipOrder = [placement, placementOpposite];
        break;
      case BEHAVIORS.CLOCKWISE:
        flipOrder = clockwise(placement);
        break;
      case BEHAVIORS.COUNTERCLOCKWISE:
        flipOrder = clockwise(placement, true);
        break;
      default:
        flipOrder = options.behavior;
    }

    flipOrder.forEach(function (step, index) {
      if (placement !== step || flipOrder.length === index + 1) {
        return data;
      }

      placement = data.placement.split('-')[0];
      placementOpposite = getOppositePlacement(placement);

      var popperOffsets = data.offsets.popper;
      var refOffsets = data.offsets.reference;

      // using floor because the reference offsets may contain decimals we are not going to consider here
      var floor = Math.floor;
      var overlapsRef = placement === 'left' && floor(popperOffsets.right) > floor(refOffsets.left) || placement === 'right' && floor(popperOffsets.left) < floor(refOffsets.right) || placement === 'top' && floor(popperOffsets.bottom) > floor(refOffsets.top) || placement === 'bottom' && floor(popperOffsets.top) < floor(refOffsets.bottom);

      var overflowsLeft = floor(popperOffsets.left) < floor(boundaries.left);
      var overflowsRight = floor(popperOffsets.right) > floor(boundaries.right);
      var overflowsTop = floor(popperOffsets.top) < floor(boundaries.top);
      var overflowsBottom = floor(popperOffsets.bottom) > floor(boundaries.bottom);

      var overflowsBoundaries = placement === 'left' && overflowsLeft || placement === 'right' && overflowsRight || placement === 'top' && overflowsTop || placement === 'bottom' && overflowsBottom;

      // flip the variation if required
      var isVertical = ['top', 'bottom'].indexOf(placement) !== -1;

      // flips variation if reference element overflows boundaries
      var flippedVariationByRef = !!options.flipVariations && (isVertical && variation === 'start' && overflowsLeft || isVertical && variation === 'end' && overflowsRight || !isVertical && variation === 'start' && overflowsTop || !isVertical && variation === 'end' && overflowsBottom);

      // flips variation if popper content overflows boundaries
      var flippedVariationByContent = !!options.flipVariationsByContent && (isVertical && variation === 'start' && overflowsRight || isVertical && variation === 'end' && overflowsLeft || !isVertical && variation === 'start' && overflowsBottom || !isVertical && variation === 'end' && overflowsTop);

      var flippedVariation = flippedVariationByRef || flippedVariationByContent;

      if (overlapsRef || overflowsBoundaries || flippedVariation) {
        // this boolean to detect any flip loop
        data.flipped = true;

        if (overlapsRef || overflowsBoundaries) {
          placement = flipOrder[index + 1];
        }

        if (flippedVariation) {
          variation = getOppositeVariation(variation);
        }

        data.placement = placement + (variation ? '-' + variation : '');

        // this object contains `position`, we want to preserve it along with
        // any additional property we may add in the future
        data.offsets.popper = _extends({}, data.offsets.popper, getPopperOffsets(data.instance.popper, data.offsets.reference, data.placement));

        data = runModifiers(data.instance.modifiers, data, 'flip');
      }
    });
    return data;
  }

  /**
   * @function
   * @memberof Modifiers
   * @argument {Object} data - The data object generated by update method
   * @argument {Object} options - Modifiers configuration and options
   * @returns {Object} The data object, properly modified
   */
  function keepTogether(data) {
    var _data$offsets = data.offsets,
        popper = _data$offsets.popper,
        reference = _data$offsets.reference;

    var placement = data.placement.split('-')[0];
    var floor = Math.floor;
    var isVertical = ['top', 'bottom'].indexOf(placement) !== -1;
    var side = isVertical ? 'right' : 'bottom';
    var opSide = isVertical ? 'left' : 'top';
    var measurement = isVertical ? 'width' : 'height';

    if (popper[side] < floor(reference[opSide])) {
      data.offsets.popper[opSide] = floor(reference[opSide]) - popper[measurement];
    }
    if (popper[opSide] > floor(reference[side])) {
      data.offsets.popper[opSide] = floor(reference[side]);
    }

    return data;
  }

  /**
   * Converts a string containing value + unit into a px value number
   * @function
   * @memberof {modifiers~offset}
   * @private
   * @argument {String} str - Value + unit string
   * @argument {String} measurement - `height` or `width`
   * @argument {Object} popperOffsets
   * @argument {Object} referenceOffsets
   * @returns {Number|String}
   * Value in pixels, or original string if no values were extracted
   */
  function toValue(str, measurement, popperOffsets, referenceOffsets) {
    // separate value from unit
    var split = str.match(/((?:\-|\+)?\d*\.?\d*)(.*)/);
    var value = +split[1];
    var unit = split[2];

    // If it's not a number it's an operator, I guess
    if (!value) {
      return str;
    }

    if (unit.indexOf('%') === 0) {
      var element = void 0;
      switch (unit) {
        case '%p':
          element = popperOffsets;
          break;
        case '%':
        case '%r':
        default:
          element = referenceOffsets;
      }

      var rect = getClientRect(element);
      return rect[measurement] / 100 * value;
    } else if (unit === 'vh' || unit === 'vw') {
      // if is a vh or vw, we calculate the size based on the viewport
      var size = void 0;
      if (unit === 'vh') {
        size = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
      } else {
        size = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
      }
      return size / 100 * value;
    } else {
      // if is an explicit pixel unit, we get rid of the unit and keep the value
      // if is an implicit unit, it's px, and we return just the value
      return value;
    }
  }

  /**
   * Parse an `offset` string to extrapolate `x` and `y` numeric offsets.
   * @function
   * @memberof {modifiers~offset}
   * @private
   * @argument {String} offset
   * @argument {Object} popperOffsets
   * @argument {Object} referenceOffsets
   * @argument {String} basePlacement
   * @returns {Array} a two cells array with x and y offsets in numbers
   */
  function parseOffset(offset, popperOffsets, referenceOffsets, basePlacement) {
    var offsets = [0, 0];

    // Use height if placement is left or right and index is 0 otherwise use width
    // in this way the first offset will use an axis and the second one
    // will use the other one
    var useHeight = ['right', 'left'].indexOf(basePlacement) !== -1;

    // Split the offset string to obtain a list of values and operands
    // The regex addresses values with the plus or minus sign in front (+10, -20, etc)
    var fragments = offset.split(/(\+|\-)/).map(function (frag) {
      return frag.trim();
    });

    // Detect if the offset string contains a pair of values or a single one
    // they could be separated by comma or space
    var divider = fragments.indexOf(find(fragments, function (frag) {
      return frag.search(/,|\s/) !== -1;
    }));

    if (fragments[divider] && fragments[divider].indexOf(',') === -1) {
      console.warn('Offsets separated by white space(s) are deprecated, use a comma (,) instead.');
    }

    // If divider is found, we divide the list of values and operands to divide
    // them by ofset X and Y.
    var splitRegex = /\s*,\s*|\s+/;
    var ops = divider !== -1 ? [fragments.slice(0, divider).concat([fragments[divider].split(splitRegex)[0]]), [fragments[divider].split(splitRegex)[1]].concat(fragments.slice(divider + 1))] : [fragments];

    // Convert the values with units to absolute pixels to allow our computations
    ops = ops.map(function (op, index) {
      // Most of the units rely on the orientation of the popper
      var measurement = (index === 1 ? !useHeight : useHeight) ? 'height' : 'width';
      var mergeWithPrevious = false;
      return op
      // This aggregates any `+` or `-` sign that aren't considered operators
      // e.g.: 10 + +5 => [10, +, +5]
      .reduce(function (a, b) {
        if (a[a.length - 1] === '' && ['+', '-'].indexOf(b) !== -1) {
          a[a.length - 1] = b;
          mergeWithPrevious = true;
          return a;
        } else if (mergeWithPrevious) {
          a[a.length - 1] += b;
          mergeWithPrevious = false;
          return a;
        } else {
          return a.concat(b);
        }
      }, [])
      // Here we convert the string values into number values (in px)
      .map(function (str) {
        return toValue(str, measurement, popperOffsets, referenceOffsets);
      });
    });

    // Loop trough the offsets arrays and execute the operations
    ops.forEach(function (op, index) {
      op.forEach(function (frag, index2) {
        if (isNumeric(frag)) {
          offsets[index] += frag * (op[index2 - 1] === '-' ? -1 : 1);
        }
      });
    });
    return offsets;
  }

  /**
   * @function
   * @memberof Modifiers
   * @argument {Object} data - The data object generated by update method
   * @argument {Object} options - Modifiers configuration and options
   * @argument {Number|String} options.offset=0
   * The offset value as described in the modifier description
   * @returns {Object} The data object, properly modified
   */
  function offset(data, _ref) {
    var offset = _ref.offset;
    var placement = data.placement,
        _data$offsets = data.offsets,
        popper = _data$offsets.popper,
        reference = _data$offsets.reference;

    var basePlacement = placement.split('-')[0];

    var offsets = void 0;
    if (isNumeric(+offset)) {
      offsets = [+offset, 0];
    } else {
      offsets = parseOffset(offset, popper, reference, basePlacement);
    }

    if (basePlacement === 'left') {
      popper.top += offsets[0];
      popper.left -= offsets[1];
    } else if (basePlacement === 'right') {
      popper.top += offsets[0];
      popper.left += offsets[1];
    } else if (basePlacement === 'top') {
      popper.left += offsets[0];
      popper.top -= offsets[1];
    } else if (basePlacement === 'bottom') {
      popper.left += offsets[0];
      popper.top += offsets[1];
    }

    data.popper = popper;
    return data;
  }

  /**
   * @function
   * @memberof Modifiers
   * @argument {Object} data - The data object generated by `update` method
   * @argument {Object} options - Modifiers configuration and options
   * @returns {Object} The data object, properly modified
   */
  function preventOverflow(data, options) {
    var boundariesElement = options.boundariesElement || getOffsetParent(data.instance.popper);

    // If offsetParent is the reference element, we really want to
    // go one step up and use the next offsetParent as reference to
    // avoid to make this modifier completely useless and look like broken
    if (data.instance.reference === boundariesElement) {
      boundariesElement = getOffsetParent(boundariesElement);
    }

    // NOTE: DOM access here
    // resets the popper's position so that the document size can be calculated excluding
    // the size of the popper element itself
    var transformProp = getSupportedPropertyName('transform');
    var popperStyles = data.instance.popper.style; // assignment to help minification
    var top = popperStyles.top,
        left = popperStyles.left,
        transform = popperStyles[transformProp];

    popperStyles.top = '';
    popperStyles.left = '';
    popperStyles[transformProp] = '';

    var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, boundariesElement, data.positionFixed);

    // NOTE: DOM access here
    // restores the original style properties after the offsets have been computed
    popperStyles.top = top;
    popperStyles.left = left;
    popperStyles[transformProp] = transform;

    options.boundaries = boundaries;

    var order = options.priority;
    var popper = data.offsets.popper;

    var check = {
      primary: function primary(placement) {
        var value = popper[placement];
        if (popper[placement] < boundaries[placement] && !options.escapeWithReference) {
          value = Math.max(popper[placement], boundaries[placement]);
        }
        return defineProperty({}, placement, value);
      },
      secondary: function secondary(placement) {
        var mainSide = placement === 'right' ? 'left' : 'top';
        var value = popper[mainSide];
        if (popper[placement] > boundaries[placement] && !options.escapeWithReference) {
          value = Math.min(popper[mainSide], boundaries[placement] - (placement === 'right' ? popper.width : popper.height));
        }
        return defineProperty({}, mainSide, value);
      }
    };

    order.forEach(function (placement) {
      var side = ['left', 'top'].indexOf(placement) !== -1 ? 'primary' : 'secondary';
      popper = _extends({}, popper, check[side](placement));
    });

    data.offsets.popper = popper;

    return data;
  }

  /**
   * @function
   * @memberof Modifiers
   * @argument {Object} data - The data object generated by `update` method
   * @argument {Object} options - Modifiers configuration and options
   * @returns {Object} The data object, properly modified
   */
  function shift(data) {
    var placement = data.placement;
    var basePlacement = placement.split('-')[0];
    var shiftvariation = placement.split('-')[1];

    // if shift shiftvariation is specified, run the modifier
    if (shiftvariation) {
      var _data$offsets = data.offsets,
          reference = _data$offsets.reference,
          popper = _data$offsets.popper;

      var isVertical = ['bottom', 'top'].indexOf(basePlacement) !== -1;
      var side = isVertical ? 'left' : 'top';
      var measurement = isVertical ? 'width' : 'height';

      var shiftOffsets = {
        start: defineProperty({}, side, reference[side]),
        end: defineProperty({}, side, reference[side] + reference[measurement] - popper[measurement])
      };

      data.offsets.popper = _extends({}, popper, shiftOffsets[shiftvariation]);
    }

    return data;
  }

  /**
   * @function
   * @memberof Modifiers
   * @argument {Object} data - The data object generated by update method
   * @argument {Object} options - Modifiers configuration and options
   * @returns {Object} The data object, properly modified
   */
  function hide(data) {
    if (!isModifierRequired(data.instance.modifiers, 'hide', 'preventOverflow')) {
      return data;
    }

    var refRect = data.offsets.reference;
    var bound = find(data.instance.modifiers, function (modifier) {
      return modifier.name === 'preventOverflow';
    }).boundaries;

    if (refRect.bottom < bound.top || refRect.left > bound.right || refRect.top > bound.bottom || refRect.right < bound.left) {
      // Avoid unnecessary DOM access if visibility hasn't changed
      if (data.hide === true) {
        return data;
      }

      data.hide = true;
      data.attributes['x-out-of-boundaries'] = '';
    } else {
      // Avoid unnecessary DOM access if visibility hasn't changed
      if (data.hide === false) {
        return data;
      }

      data.hide = false;
      data.attributes['x-out-of-boundaries'] = false;
    }

    return data;
  }

  /**
   * @function
   * @memberof Modifiers
   * @argument {Object} data - The data object generated by `update` method
   * @argument {Object} options - Modifiers configuration and options
   * @returns {Object} The data object, properly modified
   */
  function inner(data) {
    var placement = data.placement;
    var basePlacement = placement.split('-')[0];
    var _data$offsets = data.offsets,
        popper = _data$offsets.popper,
        reference = _data$offsets.reference;

    var isHoriz = ['left', 'right'].indexOf(basePlacement) !== -1;

    var subtractLength = ['top', 'left'].indexOf(basePlacement) === -1;

    popper[isHoriz ? 'left' : 'top'] = reference[basePlacement] - (subtractLength ? popper[isHoriz ? 'width' : 'height'] : 0);

    data.placement = getOppositePlacement(placement);
    data.offsets.popper = getClientRect(popper);

    return data;
  }

  /**
   * Modifier function, each modifier can have a function of this type assigned
   * to its `fn` property.<br />
   * These functions will be called on each update, this means that you must
   * make sure they are performant enough to avoid performance bottlenecks.
   *
   * @function ModifierFn
   * @argument {dataObject} data - The data object generated by `update` method
   * @argument {Object} options - Modifiers configuration and options
   * @returns {dataObject} The data object, properly modified
   */

  /**
   * Modifiers are plugins used to alter the behavior of your poppers.<br />
   * Popper.js uses a set of 9 modifiers to provide all the basic functionalities
   * needed by the library.
   *
   * Usually you don't want to override the `order`, `fn` and `onLoad` props.
   * All the other properties are configurations that could be tweaked.
   * @namespace modifiers
   */
  var modifiers = {
    /**
     * Modifier used to shift the popper on the start or end of its reference
     * element.<br />
     * It will read the variation of the `placement` property.<br />
     * It can be one either `-end` or `-start`.
     * @memberof modifiers
     * @inner
     */
    shift: {
      /** @prop {number} order=100 - Index used to define the order of execution */
      order: 100,
      /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
      enabled: true,
      /** @prop {ModifierFn} */
      fn: shift
    },

    /**
     * The `offset` modifier can shift your popper on both its axis.
     *
     * It accepts the following units:
     * - `px` or unit-less, interpreted as pixels
     * - `%` or `%r`, percentage relative to the length of the reference element
     * - `%p`, percentage relative to the length of the popper element
     * - `vw`, CSS viewport width unit
     * - `vh`, CSS viewport height unit
     *
     * For length is intended the main axis relative to the placement of the popper.<br />
     * This means that if the placement is `top` or `bottom`, the length will be the
     * `width`. In case of `left` or `right`, it will be the `height`.
     *
     * You can provide a single value (as `Number` or `String`), or a pair of values
     * as `String` divided by a comma or one (or more) white spaces.<br />
     * The latter is a deprecated method because it leads to confusion and will be
     * removed in v2.<br />
     * Additionally, it accepts additions and subtractions between different units.
     * Note that multiplications and divisions aren't supported.
     *
     * Valid examples are:
     * ```
     * 10
     * '10%'
     * '10, 10'
     * '10%, 10'
     * '10 + 10%'
     * '10 - 5vh + 3%'
     * '-10px + 5vh, 5px - 6%'
     * ```
     * > **NB**: If you desire to apply offsets to your poppers in a way that may make them overlap
     * > with their reference element, unfortunately, you will have to disable the `flip` modifier.
     * > You can read more on this at this [issue](https://github.com/FezVrasta/popper.js/issues/373).
     *
     * @memberof modifiers
     * @inner
     */
    offset: {
      /** @prop {number} order=200 - Index used to define the order of execution */
      order: 200,
      /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
      enabled: true,
      /** @prop {ModifierFn} */
      fn: offset,
      /** @prop {Number|String} offset=0
       * The offset value as described in the modifier description
       */
      offset: 0
    },

    /**
     * Modifier used to prevent the popper from being positioned outside the boundary.
     *
     * A scenario exists where the reference itself is not within the boundaries.<br />
     * We can say it has "escaped the boundaries" — or just "escaped".<br />
     * In this case we need to decide whether the popper should either:
     *
     * - detach from the reference and remain "trapped" in the boundaries, or
     * - if it should ignore the boundary and "escape with its reference"
     *
     * When `escapeWithReference` is set to`true` and reference is completely
     * outside its boundaries, the popper will overflow (or completely leave)
     * the boundaries in order to remain attached to the edge of the reference.
     *
     * @memberof modifiers
     * @inner
     */
    preventOverflow: {
      /** @prop {number} order=300 - Index used to define the order of execution */
      order: 300,
      /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
      enabled: true,
      /** @prop {ModifierFn} */
      fn: preventOverflow,
      /**
       * @prop {Array} [priority=['left','right','top','bottom']]
       * Popper will try to prevent overflow following these priorities by default,
       * then, it could overflow on the left and on top of the `boundariesElement`
       */
      priority: ['left', 'right', 'top', 'bottom'],
      /**
       * @prop {number} padding=5
       * Amount of pixel used to define a minimum distance between the boundaries
       * and the popper. This makes sure the popper always has a little padding
       * between the edges of its container
       */
      padding: 5,
      /**
       * @prop {String|HTMLElement} boundariesElement='scrollParent'
       * Boundaries used by the modifier. Can be `scrollParent`, `window`,
       * `viewport` or any DOM element.
       */
      boundariesElement: 'scrollParent'
    },

    /**
     * Modifier used to make sure the reference and its popper stay near each other
     * without leaving any gap between the two. Especially useful when the arrow is
     * enabled and you want to ensure that it points to its reference element.
     * It cares only about the first axis. You can still have poppers with margin
     * between the popper and its reference element.
     * @memberof modifiers
     * @inner
     */
    keepTogether: {
      /** @prop {number} order=400 - Index used to define the order of execution */
      order: 400,
      /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
      enabled: true,
      /** @prop {ModifierFn} */
      fn: keepTogether
    },

    /**
     * This modifier is used to move the `arrowElement` of the popper to make
     * sure it is positioned between the reference element and its popper element.
     * It will read the outer size of the `arrowElement` node to detect how many
     * pixels of conjunction are needed.
     *
     * It has no effect if no `arrowElement` is provided.
     * @memberof modifiers
     * @inner
     */
    arrow: {
      /** @prop {number} order=500 - Index used to define the order of execution */
      order: 500,
      /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
      enabled: true,
      /** @prop {ModifierFn} */
      fn: arrow,
      /** @prop {String|HTMLElement} element='[x-arrow]' - Selector or node used as arrow */
      element: '[x-arrow]'
    },

    /**
     * Modifier used to flip the popper's placement when it starts to overlap its
     * reference element.
     *
     * Requires the `preventOverflow` modifier before it in order to work.
     *
     * **NOTE:** this modifier will interrupt the current update cycle and will
     * restart it if it detects the need to flip the placement.
     * @memberof modifiers
     * @inner
     */
    flip: {
      /** @prop {number} order=600 - Index used to define the order of execution */
      order: 600,
      /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
      enabled: true,
      /** @prop {ModifierFn} */
      fn: flip,
      /**
       * @prop {String|Array} behavior='flip'
       * The behavior used to change the popper's placement. It can be one of
       * `flip`, `clockwise`, `counterclockwise` or an array with a list of valid
       * placements (with optional variations)
       */
      behavior: 'flip',
      /**
       * @prop {number} padding=5
       * The popper will flip if it hits the edges of the `boundariesElement`
       */
      padding: 5,
      /**
       * @prop {String|HTMLElement} boundariesElement='viewport'
       * The element which will define the boundaries of the popper position.
       * The popper will never be placed outside of the defined boundaries
       * (except if `keepTogether` is enabled)
       */
      boundariesElement: 'viewport',
      /**
       * @prop {Boolean} flipVariations=false
       * The popper will switch placement variation between `-start` and `-end` when
       * the reference element overlaps its boundaries.
       *
       * The original placement should have a set variation.
       */
      flipVariations: false,
      /**
       * @prop {Boolean} flipVariationsByContent=false
       * The popper will switch placement variation between `-start` and `-end` when
       * the popper element overlaps its reference boundaries.
       *
       * The original placement should have a set variation.
       */
      flipVariationsByContent: false
    },

    /**
     * Modifier used to make the popper flow toward the inner of the reference element.
     * By default, when this modifier is disabled, the popper will be placed outside
     * the reference element.
     * @memberof modifiers
     * @inner
     */
    inner: {
      /** @prop {number} order=700 - Index used to define the order of execution */
      order: 700,
      /** @prop {Boolean} enabled=false - Whether the modifier is enabled or not */
      enabled: false,
      /** @prop {ModifierFn} */
      fn: inner
    },

    /**
     * Modifier used to hide the popper when its reference element is outside of the
     * popper boundaries. It will set a `x-out-of-boundaries` attribute which can
     * be used to hide with a CSS selector the popper when its reference is
     * out of boundaries.
     *
     * Requires the `preventOverflow` modifier before it in order to work.
     * @memberof modifiers
     * @inner
     */
    hide: {
      /** @prop {number} order=800 - Index used to define the order of execution */
      order: 800,
      /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
      enabled: true,
      /** @prop {ModifierFn} */
      fn: hide
    },

    /**
     * Computes the style that will be applied to the popper element to gets
     * properly positioned.
     *
     * Note that this modifier will not touch the DOM, it just prepares the styles
     * so that `applyStyle` modifier can apply it. This separation is useful
     * in case you need to replace `applyStyle` with a custom implementation.
     *
     * This modifier has `850` as `order` value to maintain backward compatibility
     * with previous versions of Popper.js. Expect the modifiers ordering method
     * to change in future major versions of the library.
     *
     * @memberof modifiers
     * @inner
     */
    computeStyle: {
      /** @prop {number} order=850 - Index used to define the order of execution */
      order: 850,
      /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
      enabled: true,
      /** @prop {ModifierFn} */
      fn: computeStyle,
      /**
       * @prop {Boolean} gpuAcceleration=true
       * If true, it uses the CSS 3D transformation to position the popper.
       * Otherwise, it will use the `top` and `left` properties
       */
      gpuAcceleration: true,
      /**
       * @prop {string} [x='bottom']
       * Where to anchor the X axis (`bottom` or `top`). AKA X offset origin.
       * Change this if your popper should grow in a direction different from `bottom`
       */
      x: 'bottom',
      /**
       * @prop {string} [x='left']
       * Where to anchor the Y axis (`left` or `right`). AKA Y offset origin.
       * Change this if your popper should grow in a direction different from `right`
       */
      y: 'right'
    },

    /**
     * Applies the computed styles to the popper element.
     *
     * All the DOM manipulations are limited to this modifier. This is useful in case
     * you want to integrate Popper.js inside a framework or view library and you
     * want to delegate all the DOM manipulations to it.
     *
     * Note that if you disable this modifier, you must make sure the popper element
     * has its position set to `absolute` before Popper.js can do its work!
     *
     * Just disable this modifier and define your own to achieve the desired effect.
     *
     * @memberof modifiers
     * @inner
     */
    applyStyle: {
      /** @prop {number} order=900 - Index used to define the order of execution */
      order: 900,
      /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
      enabled: true,
      /** @prop {ModifierFn} */
      fn: applyStyle,
      /** @prop {Function} */
      onLoad: applyStyleOnLoad,
      /**
       * @deprecated since version 1.10.0, the property moved to `computeStyle` modifier
       * @prop {Boolean} gpuAcceleration=true
       * If true, it uses the CSS 3D transformation to position the popper.
       * Otherwise, it will use the `top` and `left` properties
       */
      gpuAcceleration: undefined
    }
  };

  /**
   * The `dataObject` is an object containing all the information used by Popper.js.
   * This object is passed to modifiers and to the `onCreate` and `onUpdate` callbacks.
   * @name dataObject
   * @property {Object} data.instance The Popper.js instance
   * @property {String} data.placement Placement applied to popper
   * @property {String} data.originalPlacement Placement originally defined on init
   * @property {Boolean} data.flipped True if popper has been flipped by flip modifier
   * @property {Boolean} data.hide True if the reference element is out of boundaries, useful to know when to hide the popper
   * @property {HTMLElement} data.arrowElement Node used as arrow by arrow modifier
   * @property {Object} data.styles Any CSS property defined here will be applied to the popper. It expects the JavaScript nomenclature (eg. `marginBottom`)
   * @property {Object} data.arrowStyles Any CSS property defined here will be applied to the popper arrow. It expects the JavaScript nomenclature (eg. `marginBottom`)
   * @property {Object} data.boundaries Offsets of the popper boundaries
   * @property {Object} data.offsets The measurements of popper, reference and arrow elements
   * @property {Object} data.offsets.popper `top`, `left`, `width`, `height` values
   * @property {Object} data.offsets.reference `top`, `left`, `width`, `height` values
   * @property {Object} data.offsets.arrow] `top` and `left` offsets, only one of them will be different from 0
   */

  /**
   * Default options provided to Popper.js constructor.<br />
   * These can be overridden using the `options` argument of Popper.js.<br />
   * To override an option, simply pass an object with the same
   * structure of the `options` object, as the 3rd argument. For example:
   * ```
   * new Popper(ref, pop, {
   *   modifiers: {
   *     preventOverflow: { enabled: false }
   *   }
   * })
   * ```
   * @type {Object}
   * @static
   * @memberof Popper
   */
  var Defaults = {
    /**
     * Popper's placement.
     * @prop {Popper.placements} placement='bottom'
     */
    placement: 'bottom',

    /**
     * Set this to true if you want popper to position it self in 'fixed' mode
     * @prop {Boolean} positionFixed=false
     */
    positionFixed: false,

    /**
     * Whether events (resize, scroll) are initially enabled.
     * @prop {Boolean} eventsEnabled=true
     */
    eventsEnabled: true,

    /**
     * Set to true if you want to automatically remove the popper when
     * you call the `destroy` method.
     * @prop {Boolean} removeOnDestroy=false
     */
    removeOnDestroy: false,

    /**
     * Callback called when the popper is created.<br />
     * By default, it is set to no-op.<br />
     * Access Popper.js instance with `data.instance`.
     * @prop {onCreate}
     */
    onCreate: function onCreate() {},

    /**
     * Callback called when the popper is updated. This callback is not called
     * on the initialization/creation of the popper, but only on subsequent
     * updates.<br />
     * By default, it is set to no-op.<br />
     * Access Popper.js instance with `data.instance`.
     * @prop {onUpdate}
     */
    onUpdate: function onUpdate() {},

    /**
     * List of modifiers used to modify the offsets before they are applied to the popper.
     * They provide most of the functionalities of Popper.js.
     * @prop {modifiers}
     */
    modifiers: modifiers
  };

  /**
   * @callback onCreate
   * @param {dataObject} data
   */

  /**
   * @callback onUpdate
   * @param {dataObject} data
   */

  // Utils
  // Methods
  var Popper = function () {
    /**
     * Creates a new Popper.js instance.
     * @class Popper
     * @param {Element|referenceObject} reference - The reference element used to position the popper
     * @param {Element} popper - The HTML / XML element used as the popper
     * @param {Object} options - Your custom options to override the ones defined in [Defaults](#defaults)
     * @return {Object} instance - The generated Popper.js instance
     */
    function Popper(reference, popper) {
      var _this = this;

      var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
      classCallCheck(this, Popper);

      this.scheduleUpdate = function () {
        return requestAnimationFrame(_this.update);
      };

      // make update() debounced, so that it only runs at most once-per-tick
      this.update = debounce(this.update.bind(this));

      // with {} we create a new object with the options inside it
      this.options = _extends({}, Popper.Defaults, options);

      // init state
      this.state = {
        isDestroyed: false,
        isCreated: false,
        scrollParents: []
      };

      // get reference and popper elements (allow jQuery wrappers)
      this.reference = reference && reference.jquery ? reference[0] : reference;
      this.popper = popper && popper.jquery ? popper[0] : popper;

      // Deep merge modifiers options
      this.options.modifiers = {};
      Object.keys(_extends({}, Popper.Defaults.modifiers, options.modifiers)).forEach(function (name) {
        _this.options.modifiers[name] = _extends({}, Popper.Defaults.modifiers[name] || {}, options.modifiers ? options.modifiers[name] : {});
      });

      // Refactoring modifiers' list (Object => Array)
      this.modifiers = Object.keys(this.options.modifiers).map(function (name) {
        return _extends({
          name: name
        }, _this.options.modifiers[name]);
      })
      // sort the modifiers by order
      .sort(function (a, b) {
        return a.order - b.order;
      });

      // modifiers have the ability to execute arbitrary code when Popper.js get inited
      // such code is executed in the same order of its modifier
      // they could add new properties to their options configuration
      // BE AWARE: don't add options to `options.modifiers.name` but to `modifierOptions`!
      this.modifiers.forEach(function (modifierOptions) {
        if (modifierOptions.enabled && isFunction(modifierOptions.onLoad)) {
          modifierOptions.onLoad(_this.reference, _this.popper, _this.options, modifierOptions, _this.state);
        }
      });

      // fire the first update to position the popper in the right place
      this.update();

      var eventsEnabled = this.options.eventsEnabled;
      if (eventsEnabled) {
        // setup event listeners, they will take care of update the position in specific situations
        this.enableEventListeners();
      }

      this.state.eventsEnabled = eventsEnabled;
    }

    // We can't use class properties because they don't get listed in the
    // class prototype and break stuff like Sinon stubs


    createClass(Popper, [{
      key: 'update',
      value: function update$$1() {
        return update.call(this);
      }
    }, {
      key: 'destroy',
      value: function destroy$$1() {
        return destroy.call(this);
      }
    }, {
      key: 'enableEventListeners',
      value: function enableEventListeners$$1() {
        return enableEventListeners.call(this);
      }
    }, {
      key: 'disableEventListeners',
      value: function disableEventListeners$$1() {
        return disableEventListeners.call(this);
      }

      /**
       * Schedules an update. It will run on the next UI update available.
       * @method scheduleUpdate
       * @memberof Popper
       */


      /**
       * Collection of utilities useful when writing custom modifiers.
       * Starting from version 1.7, this method is available only if you
       * include `popper-utils.js` before `popper.js`.
       *
       * **DEPRECATION**: This way to access PopperUtils is deprecated
       * and will be removed in v2! Use the PopperUtils module directly instead.
       * Due to the high instability of the methods contained in Utils, we can't
       * guarantee them to follow semver. Use them at your own risk!
       * @static
       * @private
       * @type {Object}
       * @deprecated since version 1.8
       * @member Utils
       * @memberof Popper
       */

    }]);
    return Popper;
  }();

  /**
   * The `referenceObject` is an object that provides an interface compatible with Popper.js
   * and lets you use it as replacement of a real DOM node.<br />
   * You can use this method to position a popper relatively to a set of coordinates
   * in case you don't have a DOM node to use as reference.
   *
   * ```
   * new Popper(referenceObject, popperNode);
   * ```
   *
   * NB: This feature isn't supported in Internet Explorer 10.
   * @name referenceObject
   * @property {Function} data.getBoundingClientRect
   * A function that returns a set of coordinates compatible with the native `getBoundingClientRect` method.
   * @property {number} data.clientWidth
   * An ES6 getter that will return the width of the virtual reference element.
   * @property {number} data.clientHeight
   * An ES6 getter that will return the height of the virtual reference element.
   */


  Popper.Utils = (typeof window !== 'undefined' ? window : global).PopperUtils;
  Popper.placements = placements;
  Popper.Defaults = Defaults;

  var PLACEMENT_TOP_START = 'top-start';
  var PLACEMENT_TOP_END = 'top-end';
  var PLACEMENT_BOTTOM_START = 'bottom-start';
  var PLACEMENT_BOTTOM_END = 'bottom-end';
  var PLACEMENT_RIGHT_START = 'right-start';
  var PLACEMENT_LEFT_START = 'left-start';

  var BvEvent = /*#__PURE__*/function () {
    function BvEvent(type) {
      var eventInit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

      _classCallCheck(this, BvEvent);

      // Start by emulating native Event constructor
      if (!type) {
        /* istanbul ignore next */
        throw new TypeError("Failed to construct '".concat(this.constructor.name, "'. 1 argument required, ").concat(arguments.length, " given."));
      } // Merge defaults first, the eventInit, and the type last
      // so it can't be overwritten


      assign(this, BvEvent.Defaults, this.constructor.Defaults, eventInit, {
        type: type
      }); // Freeze some props as readonly, but leave them enumerable

      defineProperties(this, {
        type: readonlyDescriptor(),
        cancelable: readonlyDescriptor(),
        nativeEvent: readonlyDescriptor(),
        target: readonlyDescriptor(),
        relatedTarget: readonlyDescriptor(),
        vueTarget: readonlyDescriptor(),
        componentId: readonlyDescriptor()
      }); // Create a private variable using closure scoping

      var defaultPrevented = false; // Recreate preventDefault method. One way setter

      this.preventDefault = function preventDefault() {
        if (this.cancelable) {
          defaultPrevented = true;
        }
      }; // Create `defaultPrevented` publicly accessible prop that
      // can only be altered by the preventDefault method


      defineProperty$1(this, 'defaultPrevented', {
        enumerable: true,
        get: function get() {
          return defaultPrevented;
        }
      });
    }

    _createClass(BvEvent, null, [{
      key: "Defaults",
      get: function get() {
        return {
          type: '',
          cancelable: true,
          nativeEvent: null,
          target: null,
          relatedTarget: null,
          vueTarget: null,
          componentId: null
        };
      }
    }]);

    return BvEvent;
  }();

  var clickOutMixin = extend({
    data: function data() {
      return {
        listenForClickOut: false
      };
    },
    watch: {
      listenForClickOut: function listenForClickOut(newValue, oldValue) {
        if (newValue !== oldValue) {
          eventOff(this.clickOutElement, this.clickOutEventName, this._clickOutHandler, EVENT_OPTIONS_NO_CAPTURE);

          if (newValue) {
            eventOn(this.clickOutElement, this.clickOutEventName, this._clickOutHandler, EVENT_OPTIONS_NO_CAPTURE);
          }
        }
      }
    },
    beforeCreate: function beforeCreate() {
      // Declare non-reactive properties
      this.clickOutElement = null;
      this.clickOutEventName = null;
    },
    mounted: function mounted() {
      if (!this.clickOutElement) {
        this.clickOutElement = document;
      }

      if (!this.clickOutEventName) {
        this.clickOutEventName = 'click';
      }

      if (this.listenForClickOut) {
        eventOn(this.clickOutElement, this.clickOutEventName, this._clickOutHandler, EVENT_OPTIONS_NO_CAPTURE);
      }
    },
    beforeDestroy: function beforeDestroy() {
      eventOff(this.clickOutElement, this.clickOutEventName, this._clickOutHandler, EVENT_OPTIONS_NO_CAPTURE);
    },
    methods: {
      isClickOut: function isClickOut(event) {
        return !contains(this.$el, event.target);
      },
      _clickOutHandler: function _clickOutHandler(event) {
        if (this.clickOutHandler && this.isClickOut(event)) {
          this.clickOutHandler(event);
        }
      }
    }
  });

  var focusInMixin = extend({
    data: function data() {
      return {
        listenForFocusIn: false
      };
    },
    watch: {
      listenForFocusIn: function listenForFocusIn(newValue, oldValue) {
        if (newValue !== oldValue) {
          eventOff(this.focusInElement, 'focusin', this._focusInHandler, EVENT_OPTIONS_NO_CAPTURE);

          if (newValue) {
            eventOn(this.focusInElement, 'focusin', this._focusInHandler, EVENT_OPTIONS_NO_CAPTURE);
          }
        }
      }
    },
    beforeCreate: function beforeCreate() {
      // Declare non-reactive properties
      this.focusInElement = null;
    },
    mounted: function mounted() {
      if (!this.focusInElement) {
        this.focusInElement = document;
      }

      if (this.listenForFocusIn) {
        eventOn(this.focusInElement, 'focusin', this._focusInHandler, EVENT_OPTIONS_NO_CAPTURE);
      }
    },
    beforeDestroy: function beforeDestroy() {
      eventOff(this.focusInElement, 'focusin', this._focusInHandler, EVENT_OPTIONS_NO_CAPTURE);
    },
    methods: {
      _focusInHandler: function _focusInHandler(event) {
        if (this.focusInHandler) {
          this.focusInHandler(event);
        }
      }
    }
  });

  var registry = null;

  if (isVue3) {
    registry = new WeakMap();
  }

  var registerElementToInstance = function registerElementToInstance(element, instance) {
    if (!isVue3) {
      return;
    }

    registry.set(element, instance);
  };
  var removeElementToInstance = function removeElementToInstance(element) {
    if (!isVue3) {
      return;
    }

    registry.delete(element);
  };
  var getInstanceFromElement = function getInstanceFromElement(element) {
    if (!isVue3) {
      return element.__vue__;
    }

    var currentElement = element;

    while (currentElement) {
      if (registry.has(currentElement)) {
        /* istanbul ignore next */
        return registry.get(currentElement);
      }

      currentElement = currentElement.parentNode;
    }

    return null;
  };

  var ROOT_EVENT_NAME_SHOWN = getRootEventName(NAME_DROPDOWN, EVENT_NAME_SHOWN);
  var ROOT_EVENT_NAME_HIDDEN = getRootEventName(NAME_DROPDOWN, EVENT_NAME_HIDDEN); // CSS selectors

  var SELECTOR_FORM_CHILD = '.dropdown form';
  var SELECTOR_ITEM = ['.dropdown-item', '.b-dropdown-form'].map(function (selector) {
    return "".concat(selector, ":not(.disabled):not([disabled])");
  }).join(', '); // --- Helper methods ---
  // Return an array of visible items

  var filterVisibles = function filterVisibles(els) {
    return (els || []).filter(isVisible);
  }; // --- Props ---


  var props$1O = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, props$25), {}, {
    // String: `scrollParent`, `window` or `viewport`
    // HTMLElement: HTML Element reference
    boundary: makeProp([HTMLElement, PROP_TYPE_STRING], 'scrollParent'),
    disabled: makeProp(PROP_TYPE_BOOLEAN, false),
    // Place left if possible
    dropleft: makeProp(PROP_TYPE_BOOLEAN, false),
    // Place right if possible
    dropright: makeProp(PROP_TYPE_BOOLEAN, false),
    // Place on top if possible
    dropup: makeProp(PROP_TYPE_BOOLEAN, false),
    // Disable auto-flipping of menu from bottom <=> top
    noFlip: makeProp(PROP_TYPE_BOOLEAN, false),
    // Number of pixels or a CSS unit value to offset menu
    // (i.e. `1px`, `1rem`, etc.)
    offset: makeProp(PROP_TYPE_NUMBER_STRING, 0),
    popperOpts: makeProp(PROP_TYPE_OBJECT, {}),
    // Right align menu (default is left align)
    right: makeProp(PROP_TYPE_BOOLEAN, false)
  })), NAME_DROPDOWN); // --- Mixin ---
  // @vue/component

  var dropdownMixin = extend({
    mixins: [idMixin, listenOnRootMixin, clickOutMixin, focusInMixin],
    provide: function provide() {
      var _this = this;

      return {
        getBvDropdown: function getBvDropdown() {
          return _this;
        }
      };
    },
    inject: {
      getBvNavbar: {
        default: function _default() {
          return function () {
            return null;
          };
        }
      }
    },
    props: props$1O,
    data: function data() {
      return {
        visible: false,
        visibleChangePrevented: false
      };
    },
    computed: {
      bvNavbar: function bvNavbar() {
        return this.getBvNavbar();
      },
      inNavbar: function inNavbar() {
        return !isNull(this.bvNavbar);
      },
      toggler: function toggler() {
        var toggle = this.$refs.toggle;
        return toggle ? toggle.$el || toggle : null;
      },
      directionClass: function directionClass() {
        if (this.dropup) {
          return 'dropup';
        } else if (this.dropright) {
          return 'dropright';
        } else if (this.dropleft) {
          return 'dropleft';
        }

        return '';
      },
      boundaryClass: function boundaryClass() {
        // Position `static` is needed to allow menu to "breakout" of the `scrollParent`
        // boundaries when boundary is anything other than `scrollParent`
        // See: https://github.com/twbs/bootstrap/issues/24251#issuecomment-341413786
        return this.boundary !== 'scrollParent' && !this.inNavbar ? 'position-static' : '';
      },
      hideDelay: function hideDelay() {
        return this.inNavbar ? HAS_TOUCH_SUPPORT ? 300 : 50 : 0;
      }
    },
    watch: {
      visible: function visible(newValue, oldValue) {
        if (this.visibleChangePrevented) {
          this.visibleChangePrevented = false;
          return;
        }

        if (newValue !== oldValue) {
          var eventName = newValue ? EVENT_NAME_SHOW : EVENT_NAME_HIDE;
          var bvEvent = new BvEvent(eventName, {
            cancelable: true,
            vueTarget: this,
            target: this.$refs.menu,
            relatedTarget: null,
            componentId: this.safeId ? this.safeId() : this.id || null
          });
          this.emitEvent(bvEvent);

          if (bvEvent.defaultPrevented) {
            // Reset value and exit if canceled
            this.visibleChangePrevented = true;
            this.visible = oldValue; // Just in case a child element triggered `this.hide(true)`

            this.$off(EVENT_NAME_HIDDEN, this.focusToggler);
            return;
          }

          if (newValue) {
            this.showMenu();
          } else {
            this.hideMenu();
          }
        }
      },
      disabled: function disabled(newValue, oldValue) {
        if (newValue !== oldValue && newValue && this.visible) {
          // Hide dropdown if disabled changes to true
          this.visible = false;
        }
      }
    },
    created: function created() {
      // Create private non-reactive props
      this.$_popper = null;
      this.$_hideTimeout = null;
    },

    /* istanbul ignore next */
    deactivated: function deactivated() {
      // In case we are inside a `<keep-alive>`
      this.visible = false;
      this.whileOpenListen(false);
      this.destroyPopper();
    },
    mounted: function mounted() {
      registerElementToInstance(this.$el, this);
    },
    beforeDestroy: function beforeDestroy() {
      this.visible = false;
      this.whileOpenListen(false);
      this.destroyPopper();
      this.clearHideTimeout();
      removeElementToInstance(this.$el);
    },
    methods: {
      // Event emitter
      emitEvent: function emitEvent(bvEvent) {
        var type = bvEvent.type;
        this.emitOnRoot(getRootEventName(NAME_DROPDOWN, type), bvEvent);
        this.$emit(type, bvEvent);
      },
      showMenu: function showMenu() {
        var _this2 = this;

        if (this.disabled) {
          /* istanbul ignore next */
          return;
        } // Only instantiate Popper.js when dropdown is not in `<b-navbar>`


        if (!this.inNavbar) {
          if (typeof Popper === 'undefined') {
            /* istanbul ignore next */
            warn('Popper.js not found. Falling back to CSS positioning', NAME_DROPDOWN);
          } else {
            // For dropup with alignment we use the parent element as popper container
            var el = this.dropup && this.right || this.split ? this.$el : this.$refs.toggle; // Make sure we have a reference to an element, not a component!

            el = el.$el || el; // Instantiate Popper.js

            this.createPopper(el);
          }
        } // Ensure other menus are closed


        this.emitOnRoot(ROOT_EVENT_NAME_SHOWN, this); // Enable listeners

        this.whileOpenListen(true); // Wrap in `$nextTick()` to ensure menu is fully rendered/shown

        this.$nextTick(function () {
          // Focus on the menu container on show
          _this2.focusMenu(); // Emit the shown event


          _this2.$emit(EVENT_NAME_SHOWN);
        });
      },
      hideMenu: function hideMenu() {
        this.whileOpenListen(false);
        this.emitOnRoot(ROOT_EVENT_NAME_HIDDEN, this);
        this.$emit(EVENT_NAME_HIDDEN);
        this.destroyPopper();
      },
      createPopper: function createPopper(element) {
        this.destroyPopper();
        this.$_popper = new Popper(element, this.$refs.menu, this.getPopperConfig());
      },
      // Ensure popper event listeners are removed cleanly
      destroyPopper: function destroyPopper() {
        this.$_popper && this.$_popper.destroy();
        this.$_popper = null;
      },
      // Instructs popper to re-computes the dropdown position
      // useful if the content changes size
      updatePopper: function updatePopper() {
        try {
          this.$_popper.scheduleUpdate();
        } catch (_unused) {}
      },
      clearHideTimeout: function clearHideTimeout() {
        clearTimeout(this.$_hideTimeout);
        this.$_hideTimeout = null;
      },
      getPopperConfig: function getPopperConfig() {
        var placement = PLACEMENT_BOTTOM_START;

        if (this.dropup) {
          placement = this.right ? PLACEMENT_TOP_END : PLACEMENT_TOP_START;
        } else if (this.dropright) {
          placement = PLACEMENT_RIGHT_START;
        } else if (this.dropleft) {
          placement = PLACEMENT_LEFT_START;
        } else if (this.right) {
          placement = PLACEMENT_BOTTOM_END;
        }

        var popperConfig = {
          placement: placement,
          modifiers: {
            offset: {
              offset: this.offset || 0
            },
            flip: {
              enabled: !this.noFlip
            }
          }
        };
        var boundariesElement = this.boundary;

        if (boundariesElement) {
          popperConfig.modifiers.preventOverflow = {
            boundariesElement: boundariesElement
          };
        }

        return mergeDeep(popperConfig, this.popperOpts || {});
      },
      // Turn listeners on/off while open
      whileOpenListen: function whileOpenListen(isOpen) {
        // Hide the dropdown when clicked outside
        this.listenForClickOut = isOpen; // Hide the dropdown when it loses focus

        this.listenForFocusIn = isOpen; // Hide the dropdown when another dropdown is opened

        var method = isOpen ? 'listenOnRoot' : 'listenOffRoot';
        this[method](ROOT_EVENT_NAME_SHOWN, this.rootCloseListener);
      },
      rootCloseListener: function rootCloseListener(vm) {
        if (vm !== this) {
          this.visible = false;
        }
      },
      // Public method to show dropdown
      show: function show() {
        var _this3 = this;

        if (this.disabled) {
          return;
        } // Wrap in a `requestAF()` to allow any previous
        // click handling to occur first


        requestAF(function () {
          _this3.visible = true;
        });
      },
      // Public method to hide dropdown
      hide: function hide() {
        var refocus = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;

        /* istanbul ignore next */
        if (this.disabled) {
          return;
        }

        this.visible = false;

        if (refocus) {
          // Child element is closing the dropdown on click
          this.$once(EVENT_NAME_HIDDEN, this.focusToggler);
        }
      },
      // Called only by a button that toggles the menu
      toggle: function toggle(event) {
        event = event || {}; // Early exit when not a click event or ENTER, SPACE or DOWN were pressed

        var _event = event,
            type = _event.type,
            keyCode = _event.keyCode;

        if (type !== 'click' && !(type === 'keydown' && [CODE_ENTER, CODE_SPACE, CODE_DOWN].indexOf(keyCode) !== -1)) {
          /* istanbul ignore next */
          return;
        }
        /* istanbul ignore next */


        if (this.disabled) {
          this.visible = false;
          return;
        }

        this.$emit(EVENT_NAME_TOGGLE, event);
        stopEvent(event); // Toggle visibility

        if (this.visible) {
          this.hide(true);
        } else {
          this.show();
        }
      },
      // Mousedown handler for the toggle

      /* istanbul ignore next */
      onMousedown: function onMousedown(event) {
        // We prevent the 'mousedown' event for the toggle to stop the
        // 'focusin' event from being fired
        // The event would otherwise be picked up by the global 'focusin'
        // listener and there is no cross-browser solution to detect it
        // relates to the toggle click
        // The 'click' event will still be fired and we handle closing
        // other dropdowns there too
        // See https://github.com/bootstrap-vue/bootstrap-vue/issues/4328
        stopEvent(event, {
          propagation: false
        });
      },
      // Called from dropdown menu context
      onKeydown: function onKeydown(event) {
        var keyCode = event.keyCode;

        if (keyCode === CODE_ESC) {
          // Close on ESC
          this.onEsc(event);
        } else if (keyCode === CODE_DOWN) {
          // Down Arrow
          this.focusNext(event, false);
        } else if (keyCode === CODE_UP) {
          // Up Arrow
          this.focusNext(event, true);
        }
      },
      // If user presses ESC, close the menu
      onEsc: function onEsc(event) {
        if (this.visible) {
          this.visible = false;
          stopEvent(event); // Return focus to original trigger button

          this.$once(EVENT_NAME_HIDDEN, this.focusToggler);
        }
      },
      // Called only in split button mode, for the split button
      onSplitClick: function onSplitClick(event) {
        /* istanbul ignore next */
        if (this.disabled) {
          this.visible = false;
          return;
        }

        this.$emit(EVENT_NAME_CLICK, event);
      },
      // Shared hide handler between click-out and focus-in events
      hideHandler: function hideHandler(event) {
        var _this4 = this;

        var target = event.target;

        if (this.visible && !contains(this.$refs.menu, target) && !contains(this.toggler, target)) {
          this.clearHideTimeout();
          this.$_hideTimeout = setTimeout(function () {
            return _this4.hide();
          }, this.hideDelay);
        }
      },
      // Document click-out listener
      clickOutHandler: function clickOutHandler(event) {
        this.hideHandler(event);
      },
      // Document focus-in listener
      focusInHandler: function focusInHandler(event) {
        this.hideHandler(event);
      },
      // Keyboard nav
      focusNext: function focusNext(event, up) {
        var _this5 = this;

        // Ignore key up/down on form elements
        var target = event.target;

        if (!this.visible || event && closest(SELECTOR_FORM_CHILD, target)) {
          /* istanbul ignore next: should never happen */
          return;
        }

        stopEvent(event);
        this.$nextTick(function () {
          var items = _this5.getItems();

          if (items.length < 1) {
            /* istanbul ignore next: should never happen */
            return;
          }

          var index = items.indexOf(target);

          if (up && index > 0) {
            index--;
          } else if (!up && index < items.length - 1) {
            index++;
          }

          if (index < 0) {
            /* istanbul ignore next: should never happen */
            index = 0;
          }

          _this5.focusItem(index, items);
        });
      },
      focusItem: function focusItem(index, items) {
        var el = items.find(function (el, i) {
          return i === index;
        });
        attemptFocus(el);
      },
      getItems: function getItems() {
        // Get all items
        return filterVisibles(selectAll(SELECTOR_ITEM, this.$refs.menu));
      },
      focusMenu: function focusMenu() {
        attemptFocus(this.$refs.menu);
      },
      focusToggler: function focusToggler() {
        var _this6 = this;

        this.$nextTick(function () {
          attemptFocus(_this6.toggler);
        });
      }
    }
  });

  var props$1N = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$25), props$1O), {}, {
    block: makeProp(PROP_TYPE_BOOLEAN, false),
    html: makeProp(PROP_TYPE_STRING),
    // If `true`, only render menu contents when open
    lazy: makeProp(PROP_TYPE_BOOLEAN, false),
    menuClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    noCaret: makeProp(PROP_TYPE_BOOLEAN, false),
    role: makeProp(PROP_TYPE_STRING, 'menu'),
    size: makeProp(PROP_TYPE_STRING),
    split: makeProp(PROP_TYPE_BOOLEAN, false),
    splitButtonType: makeProp(PROP_TYPE_STRING, 'button', function (value) {
      return arrayIncludes(['button', 'submit', 'reset'], value);
    }),
    splitClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    splitHref: makeProp(PROP_TYPE_STRING),
    splitTo: makeProp(PROP_TYPE_OBJECT_STRING),
    splitVariant: makeProp(PROP_TYPE_STRING),
    text: makeProp(PROP_TYPE_STRING),
    toggleAttrs: makeProp(PROP_TYPE_OBJECT, {}),
    toggleClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    toggleTag: makeProp(PROP_TYPE_STRING, 'button'),
    // TODO: This really should be `toggleLabel`
    toggleText: makeProp(PROP_TYPE_STRING, 'Toggle dropdown'),
    variant: makeProp(PROP_TYPE_STRING, 'secondary')
  })), NAME_DROPDOWN); // --- Main component ---
  // @vue/component

  var BDropdown = /*#__PURE__*/extend({
    name: NAME_DROPDOWN,
    mixins: [idMixin, dropdownMixin, normalizeSlotMixin],
    props: props$1N,
    computed: {
      dropdownClasses: function dropdownClasses() {
        var block = this.block,
            split = this.split;
        return [this.directionClass, this.boundaryClass, {
          show: this.visible,
          // The 'btn-group' class is required in `split` mode for button alignment
          // It needs also to be applied when `block` is disabled to allow multiple
          // dropdowns to be aligned one line
          'btn-group': split || !block,
          // When `block` is enabled and we are in `split` mode the 'd-flex' class
          // needs to be applied to allow the buttons to stretch to full width
          'd-flex': block && split
        }];
      },
      menuClasses: function menuClasses() {
        return [this.menuClass, {
          'dropdown-menu-right': this.right,
          show: this.visible
        }];
      },
      toggleClasses: function toggleClasses() {
        var split = this.split;
        return [this.toggleClass, {
          'dropdown-toggle-split': split,
          'dropdown-toggle-no-caret': this.noCaret && !split
        }];
      }
    },
    render: function render(h) {
      var visible = this.visible,
          variant = this.variant,
          size = this.size,
          block = this.block,
          disabled = this.disabled,
          split = this.split,
          role = this.role,
          hide = this.hide,
          toggle = this.toggle;
      var commonProps = {
        variant: variant,
        size: size,
        block: block,
        disabled: disabled
      };
      var $buttonChildren = this.normalizeSlot(SLOT_NAME_BUTTON_CONTENT);
      var buttonContentDomProps = this.hasNormalizedSlot(SLOT_NAME_BUTTON_CONTENT) ? {} : htmlOrText(this.html, this.text);
      var $split = h();

      if (split) {
        var splitTo = this.splitTo,
            splitHref = this.splitHref,
            splitButtonType = this.splitButtonType;

        var btnProps = _objectSpread2$3(_objectSpread2$3({}, commonProps), {}, {
          variant: this.splitVariant || variant
        }); // We add these as needed due to <router-link> issues with
        // defined property with `undefined`/`null` values


        if (splitTo) {
          btnProps.to = splitTo;
        } else if (splitHref) {
          btnProps.href = splitHref;
        } else if (splitButtonType) {
          btnProps.type = splitButtonType;
        }

        $split = h(BButton, {
          class: this.splitClass,
          attrs: {
            id: this.safeId('_BV_button_')
          },
          props: btnProps,
          domProps: buttonContentDomProps,
          on: {
            click: this.onSplitClick
          },
          ref: 'button'
        }, $buttonChildren); // Overwrite button content for the toggle when in `split` mode

        $buttonChildren = [h('span', {
          class: ['sr-only']
        }, [this.toggleText])];
        buttonContentDomProps = {};
      }

      var ariaHasPopupRoles = ['menu', 'listbox', 'tree', 'grid', 'dialog'];
      var $toggle = h(BButton, {
        staticClass: 'dropdown-toggle',
        class: this.toggleClasses,
        attrs: _objectSpread2$3(_objectSpread2$3({}, this.toggleAttrs), {}, {
          // Must have attributes
          id: this.safeId('_BV_toggle_'),
          'aria-haspopup': ariaHasPopupRoles.includes(role) ? role : 'false',
          'aria-expanded': toString(visible)
        }),
        props: _objectSpread2$3(_objectSpread2$3({}, commonProps), {}, {
          tag: this.toggleTag,
          block: block && !split
        }),
        domProps: buttonContentDomProps,
        on: {
          mousedown: this.onMousedown,
          click: toggle,
          keydown: toggle // Handle ENTER, SPACE and DOWN

        },
        ref: 'toggle'
      }, $buttonChildren);
      var $menu = h('ul', {
        staticClass: 'dropdown-menu',
        class: this.menuClasses,
        attrs: {
          role: role,
          tabindex: '-1',
          'aria-labelledby': this.safeId(split ? '_BV_button_' : '_BV_toggle_')
        },
        on: {
          keydown: this.onKeydown // Handle UP, DOWN and ESC

        },
        ref: 'menu'
      }, [!this.lazy || visible ? this.normalizeSlot(SLOT_NAME_DEFAULT, {
        hide: hide
      }) : h()]);
      return h('div', {
        staticClass: 'dropdown b-dropdown',
        class: this.dropdownClasses,
        attrs: {
          id: this.safeId()
        }
      }, [$split, $toggle, $menu]);
    }
  });

  var linkProps$4 = omit(props$2f, ['event', 'routerTag']);
  var props$1M = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, linkProps$4), {}, {
    linkClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    variant: makeProp(PROP_TYPE_STRING)
  })), NAME_DROPDOWN_ITEM); // --- Main component ---
  // @vue/component

  var BDropdownItem = /*#__PURE__*/extend({
    name: NAME_DROPDOWN_ITEM,
    mixins: [attrsMixin, normalizeSlotMixin],
    inject: {
      getBvDropdown: {
        default: function _default() {
          return function () {
            return null;
          };
        }
      }
    },
    inheritAttrs: false,
    props: props$1M,
    computed: {
      bvDropdown: function bvDropdown() {
        return this.getBvDropdown();
      },
      computedAttrs: function computedAttrs() {
        return _objectSpread2$3(_objectSpread2$3({}, this.bvAttrs), {}, {
          role: 'menuitem'
        });
      }
    },
    methods: {
      closeDropdown: function closeDropdown() {
        var _this = this;

        // Close on next animation frame to allow <b-link> time to process
        requestAF(function () {
          if (_this.bvDropdown) {
            _this.bvDropdown.hide(true);
          }
        });
      },
      onClick: function onClick(event) {
        this.$emit(EVENT_NAME_CLICK, event);
        this.closeDropdown();
      }
    },
    render: function render(h) {
      var linkClass = this.linkClass,
          variant = this.variant,
          active = this.active,
          disabled = this.disabled,
          onClick = this.onClick,
          bvAttrs = this.bvAttrs;
      return h('li', {
        class: bvAttrs.class,
        style: bvAttrs.style,
        attrs: {
          role: 'presentation'
        }
      }, [h(BLink, {
        staticClass: 'dropdown-item',
        class: [linkClass, _defineProperty({}, "text-".concat(variant), variant && !(active || disabled))],
        props: pluckProps(linkProps$4, this.$props),
        attrs: this.computedAttrs,
        on: {
          click: onClick
        },
        ref: 'item'
      }, this.normalizeSlot())]);
    }
  });

  var props$1L = makePropsConfigurable({
    active: makeProp(PROP_TYPE_BOOLEAN, false),
    activeClass: makeProp(PROP_TYPE_STRING, 'active'),
    buttonClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    disabled: makeProp(PROP_TYPE_BOOLEAN, false),
    variant: makeProp(PROP_TYPE_STRING)
  }, NAME_DROPDOWN_ITEM_BUTTON); // --- Main component ---
  // @vue/component

  var BDropdownItemButton = /*#__PURE__*/extend({
    name: NAME_DROPDOWN_ITEM_BUTTON,
    mixins: [attrsMixin, normalizeSlotMixin],
    inject: {
      getBvDropdown: {
        default: function _default() {
          return function () {
            return null;
          };
        }
      }
    },
    inheritAttrs: false,
    props: props$1L,
    computed: {
      bvDropdown: function bvDropdown() {
        return this.getBvDropdown();
      },
      computedAttrs: function computedAttrs() {
        return _objectSpread2$3(_objectSpread2$3({}, this.bvAttrs), {}, {
          role: 'menuitem',
          type: 'button',
          disabled: this.disabled
        });
      }
    },
    methods: {
      closeDropdown: function closeDropdown() {
        if (this.bvDropdown) {
          this.bvDropdown.hide(true);
        }
      },
      onClick: function onClick(event) {
        this.$emit(EVENT_NAME_CLICK, event);
        this.closeDropdown();
      }
    },
    render: function render(h) {
      var _ref;

      var active = this.active,
          variant = this.variant,
          bvAttrs = this.bvAttrs;
      return h('li', {
        class: bvAttrs.class,
        style: bvAttrs.style,
        attrs: {
          role: 'presentation'
        }
      }, [h('button', {
        staticClass: 'dropdown-item',
        class: [this.buttonClass, (_ref = {}, _defineProperty(_ref, this.activeClass, active), _defineProperty(_ref, "text-".concat(variant), variant && !(active || this.disabled)), _ref)],
        attrs: this.computedAttrs,
        on: {
          click: this.onClick
        },
        ref: 'button'
      }, this.normalizeSlot())]);
    }
  });

  var props$1K = makePropsConfigurable({
    id: makeProp(PROP_TYPE_STRING),
    tag: makeProp(PROP_TYPE_STRING, 'header'),
    variant: makeProp(PROP_TYPE_STRING)
  }, NAME_DROPDOWN_HEADER); // --- Main component ---
  // @vue/component

  var BDropdownHeader = /*#__PURE__*/extend({
    name: NAME_DROPDOWN_HEADER,
    functional: true,
    props: props$1K,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      var tag = props.tag,
          variant = props.variant;
      return h('li', a(omit(data, ['attrs']), {
        attrs: {
          role: 'presentation'
        }
      }), [h(tag, {
        staticClass: 'dropdown-header',
        class: _defineProperty({}, "text-".concat(variant), variant),
        attrs: _objectSpread2$3(_objectSpread2$3({}, data.attrs || {}), {}, {
          id: props.id || null,
          role: isTag(tag, 'header') ? null : 'heading'
        }),
        ref: 'header'
      }, children)]);
    }
  });

  var props$1J = makePropsConfigurable({
    tag: makeProp(PROP_TYPE_STRING, 'hr')
  }, NAME_DROPDOWN_DIVIDER); // --- Main component ---
  // @vue/component

  var BDropdownDivider = /*#__PURE__*/extend({
    name: NAME_DROPDOWN_DIVIDER,
    functional: true,
    props: props$1J,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data;
      return h('li', a(omit(data, ['attrs']), {
        attrs: {
          role: 'presentation'
        }
      }), [h(props.tag, {
        staticClass: 'dropdown-divider',
        attrs: _objectSpread2$3(_objectSpread2$3({}, data.attrs || {}), {}, {
          role: 'separator',
          'aria-orientation': 'horizontal'
        }),
        ref: 'divider'
      })]);
    }
  });

  var props$1I = makePropsConfigurable({
    id: makeProp(PROP_TYPE_STRING),
    inline: makeProp(PROP_TYPE_BOOLEAN, false),
    novalidate: makeProp(PROP_TYPE_BOOLEAN, false),
    validated: makeProp(PROP_TYPE_BOOLEAN, false)
  }, NAME_FORM); // --- Main component ---
  // @vue/component

  var BForm = /*#__PURE__*/extend({
    name: NAME_FORM,
    functional: true,
    props: props$1I,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      return h('form', a(data, {
        class: {
          'form-inline': props.inline,
          'was-validated': props.validated
        },
        attrs: {
          id: props.id,
          novalidate: props.novalidate
        }
      }), children);
    }
  });

  var props$1H = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, props$1I), {}, {
    disabled: makeProp(PROP_TYPE_BOOLEAN, false),
    formClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING)
  })), NAME_DROPDOWN_FORM); // --- Main component ---
  // @vue/component

  var BDropdownForm = /*#__PURE__*/extend({
    name: NAME_DROPDOWN_FORM,
    functional: true,
    props: props$1H,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          listeners = _ref.listeners,
          children = _ref.children;
      return h('li', a(omit(data, ['attrs', 'on']), {
        attrs: {
          role: 'presentation'
        }
      }), [h(BForm, {
        staticClass: 'b-dropdown-form',
        class: [props.formClass, {
          disabled: props.disabled
        }],
        props: props,
        attrs: _objectSpread2$3(_objectSpread2$3({}, data.attrs || {}), {}, {
          disabled: props.disabled,
          // Tab index of -1 for keyboard navigation
          tabindex: props.disabled ? null : '-1'
        }),
        on: listeners,
        ref: 'form'
      }, children)]);
    }
  });

  var props$1G = makePropsConfigurable({
    tag: makeProp(PROP_TYPE_STRING, 'p'),
    textClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    variant: makeProp(PROP_TYPE_STRING)
  }, NAME_DROPDOWN_TEXT); // --- Main component ---
  // @vue/component

  var BDropdownText = /*#__PURE__*/extend({
    name: NAME_DROPDOWN_TEXT,
    functional: true,
    props: props$1G,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      var tag = props.tag,
          textClass = props.textClass,
          variant = props.variant;
      return h('li', a(omit(data, ['attrs']), {
        attrs: {
          role: 'presentation'
        }
      }), [h(tag, {
        staticClass: 'b-dropdown-text',
        class: [textClass, _defineProperty({}, "text-".concat(variant), variant)],
        props: props,
        attrs: data.attrs || {},
        ref: 'text'
      }, children)]);
    }
  });

  var props$1F = makePropsConfigurable({
    ariaDescribedby: makeProp(PROP_TYPE_STRING),
    header: makeProp(PROP_TYPE_STRING),
    headerClasses: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    headerTag: makeProp(PROP_TYPE_STRING, 'header'),
    headerVariant: makeProp(PROP_TYPE_STRING),
    id: makeProp(PROP_TYPE_STRING)
  }, NAME_DROPDOWN_GROUP); // --- Main component ---
  // @vue/component

  var BDropdownGroup = /*#__PURE__*/extend({
    name: NAME_DROPDOWN_GROUP,
    functional: true,
    props: props$1F,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          slots = _ref.slots,
          scopedSlots = _ref.scopedSlots;
      var id = props.id,
          variant = props.variant,
          header = props.header,
          headerTag = props.headerTag;
      var $slots = slots();
      var $scopedSlots = scopedSlots || {};
      var slotScope = {};
      var headerId = id ? "_bv_".concat(id, "_group_dd_header") : null;
      var $header = h();

      if (hasNormalizedSlot(SLOT_NAME_HEADER, $scopedSlots, $slots) || header) {
        $header = h(headerTag, {
          staticClass: 'dropdown-header',
          class: [props.headerClasses, _defineProperty({}, "text-".concat(variant), variant)],
          attrs: {
            id: headerId,
            role: isTag(headerTag, 'header') ? null : 'heading'
          }
        }, normalizeSlot(SLOT_NAME_HEADER, slotScope, $scopedSlots, $slots) || header);
      }

      return h('li', a(omit(data, ['attrs']), {
        attrs: {
          role: 'presentation'
        }
      }), [$header, h('ul', {
        staticClass: 'list-unstyled',
        attrs: _objectSpread2$3(_objectSpread2$3({}, data.attrs || {}), {}, {
          id: id,
          role: 'group',
          'aria-describedby': [headerId, props.ariaDescribedBy].filter(identity).join(' ').trim() || null
        })
      }, normalizeSlot(SLOT_NAME_DEFAULT, slotScope, $scopedSlots, $slots))]);
    }
  });

  var DropdownPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BDropdown: BDropdown,
      BDd: BDropdown,
      BDropdownItem: BDropdownItem,
      BDdItem: BDropdownItem,
      BDropdownItemButton: BDropdownItemButton,
      BDropdownItemBtn: BDropdownItemButton,
      BDdItemButton: BDropdownItemButton,
      BDdItemBtn: BDropdownItemButton,
      BDropdownHeader: BDropdownHeader,
      BDdHeader: BDropdownHeader,
      BDropdownDivider: BDropdownDivider,
      BDdDivider: BDropdownDivider,
      BDropdownForm: BDropdownForm,
      BDdForm: BDropdownForm,
      BDropdownText: BDropdownText,
      BDdText: BDropdownText,
      BDropdownGroup: BDropdownGroup,
      BDdGroup: BDropdownGroup
    }
  });

  var TYPES$2 = ['iframe', 'embed', 'video', 'object', 'img', 'b-img', 'b-img-lazy']; // --- Props ---

  var props$1E = makePropsConfigurable({
    aspect: makeProp(PROP_TYPE_STRING, '16by9'),
    tag: makeProp(PROP_TYPE_STRING, 'div'),
    type: makeProp(PROP_TYPE_STRING, 'iframe', function (value) {
      return arrayIncludes(TYPES$2, value);
    })
  }, NAME_EMBED); // --- Main component ---
  // @vue/component

  var BEmbed = /*#__PURE__*/extend({
    name: NAME_EMBED,
    functional: true,
    props: props$1E,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      var aspect = props.aspect;
      return h(props.tag, {
        staticClass: 'embed-responsive',
        class: _defineProperty({}, "embed-responsive-".concat(aspect), aspect),
        ref: data.ref
      }, [h(props.type, a(omit(data, ['ref']), {
        staticClass: 'embed-responsive-item'
      }), children)]);
    }
  });

  var EmbedPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BEmbed: BEmbed
    }
  });

  var OPTIONS_OBJECT_DEPRECATED_MSG = 'Setting prop "options" to an object is deprecated. Use the array format instead.'; // --- Props ---

  var props$1D = makePropsConfigurable({
    disabledField: makeProp(PROP_TYPE_STRING, 'disabled'),
    htmlField: makeProp(PROP_TYPE_STRING, 'html'),
    options: makeProp(PROP_TYPE_ARRAY_OBJECT, []),
    textField: makeProp(PROP_TYPE_STRING, 'text'),
    valueField: makeProp(PROP_TYPE_STRING, 'value')
  }, 'formOptionControls'); // --- Mixin ---
  // @vue/component

  var formOptionsMixin = extend({
    props: props$1D,
    computed: {
      formOptions: function formOptions() {
        return this.normalizeOptions(this.options);
      }
    },
    methods: {
      normalizeOption: function normalizeOption(option) {
        var key = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;

        // When the option is an object, normalize it
        if (isPlainObject(option)) {
          var value = get(option, this.valueField);
          var text = get(option, this.textField);
          return {
            value: isUndefined(value) ? key || text : value,
            text: stripTags(String(isUndefined(text) ? key : text)),
            html: get(option, this.htmlField),
            disabled: Boolean(get(option, this.disabledField))
          };
        } // Otherwise create an `<option>` object from the given value


        return {
          value: key || option,
          text: stripTags(String(option)),
          disabled: false
        };
      },
      normalizeOptions: function normalizeOptions(options) {
        var _this = this;

        // Normalize the given options array
        if (isArray(options)) {
          return options.map(function (option) {
            return _this.normalizeOption(option);
          });
        } else if (isPlainObject(options)) {
          // Deprecate the object options format
          warn(OPTIONS_OBJECT_DEPRECATED_MSG, this.$options.name); // Normalize a `options` object to an array of options

          return keys(options).map(function (key) {
            return _this.normalizeOption(options[key] || {}, key);
          });
        } // If not an array or object, return an empty array

        /* istanbul ignore next */


        return [];
      }
    }
  });

  var props$1C = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, props$1D), {}, {
    id: makeProp(PROP_TYPE_STRING, undefined, true) // Required

  })), NAME_FORM_DATALIST); // --- Main component ---
  // @vue/component

  var BFormDatalist = /*#__PURE__*/extend({
    name: NAME_FORM_DATALIST,
    mixins: [formOptionsMixin, normalizeSlotMixin],
    props: props$1C,
    render: function render(h) {
      var id = this.id;
      var $options = this.formOptions.map(function (option, index) {
        var value = option.value,
            text = option.text,
            html = option.html,
            disabled = option.disabled;
        return h('option', {
          attrs: {
            value: value,
            disabled: disabled
          },
          domProps: htmlOrText(html, text),
          key: "option_".concat(index)
        });
      });
      return h('datalist', {
        attrs: {
          id: id
        }
      }, [$options, this.normalizeSlot()]);
    }
  });

  var props$1B = makePropsConfigurable({
    id: makeProp(PROP_TYPE_STRING),
    inline: makeProp(PROP_TYPE_BOOLEAN, false),
    tag: makeProp(PROP_TYPE_STRING, 'small'),
    textVariant: makeProp(PROP_TYPE_STRING, 'muted')
  }, NAME_FORM_TEXT); // --- Main component ---
  // @vue/component

  var BFormText = /*#__PURE__*/extend({
    name: NAME_FORM_TEXT,
    functional: true,
    props: props$1B,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      return h(props.tag, a(data, {
        class: _defineProperty({
          'form-text': !props.inline
        }, "text-".concat(props.textVariant), props.textVariant),
        attrs: {
          id: props.id
        }
      }), children);
    }
  });

  var props$1A = makePropsConfigurable({
    ariaLive: makeProp(PROP_TYPE_STRING),
    forceShow: makeProp(PROP_TYPE_BOOLEAN, false),
    id: makeProp(PROP_TYPE_STRING),
    role: makeProp(PROP_TYPE_STRING),
    // Tri-state prop: `true`, `false`, or `null`
    state: makeProp(PROP_TYPE_BOOLEAN, null),
    tag: makeProp(PROP_TYPE_STRING, 'div'),
    tooltip: makeProp(PROP_TYPE_BOOLEAN, false)
  }, NAME_FORM_INVALID_FEEDBACK); // --- Main component ---
  // @vue/component

  var BFormInvalidFeedback = /*#__PURE__*/extend({
    name: NAME_FORM_INVALID_FEEDBACK,
    functional: true,
    props: props$1A,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      var tooltip = props.tooltip,
          ariaLive = props.ariaLive;
      var show = props.forceShow === true || props.state === false;
      return h(props.tag, a(data, {
        class: {
          'd-block': show,
          'invalid-feedback': !tooltip,
          'invalid-tooltip': tooltip
        },
        attrs: {
          id: props.id || null,
          role: props.role || null,
          'aria-live': ariaLive || null,
          'aria-atomic': ariaLive ? 'true' : null
        }
      }), children);
    }
  });

  var props$1z = makePropsConfigurable({
    ariaLive: makeProp(PROP_TYPE_STRING),
    forceShow: makeProp(PROP_TYPE_BOOLEAN, false),
    id: makeProp(PROP_TYPE_STRING),
    role: makeProp(PROP_TYPE_STRING),
    // Tri-state prop: `true`, `false`, or `null`
    state: makeProp(PROP_TYPE_BOOLEAN, null),
    tag: makeProp(PROP_TYPE_STRING, 'div'),
    tooltip: makeProp(PROP_TYPE_BOOLEAN, false)
  }, NAME_FORM_VALID_FEEDBACK); // --- Main component ---
  // @vue/component

  var BFormValidFeedback = /*#__PURE__*/extend({
    name: NAME_FORM_VALID_FEEDBACK,
    functional: true,
    props: props$1z,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      var tooltip = props.tooltip,
          ariaLive = props.ariaLive;
      var show = props.forceShow === true || props.state === true;
      return h(props.tag, a(data, {
        class: {
          'd-block': show,
          'valid-feedback': !tooltip,
          'valid-tooltip': tooltip
        },
        attrs: {
          id: props.id || null,
          role: props.role || null,
          'aria-live': ariaLive || null,
          'aria-atomic': ariaLive ? 'true' : null
        }
      }), children);
    }
  });

  var props$1y = makePropsConfigurable({
    tag: makeProp(PROP_TYPE_STRING, 'div')
  }, NAME_FORM_ROW); // --- Main component ---
  // @vue/component

  var BFormRow = /*#__PURE__*/extend({
    name: NAME_FORM_ROW,
    functional: true,
    props: props$1y,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      return h(props.tag, a(data, {
        staticClass: 'form-row'
      }), children);
    }
  });

  var FormPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BForm: BForm,
      BFormDatalist: BFormDatalist,
      BDatalist: BFormDatalist,
      BFormText: BFormText,
      BFormInvalidFeedback: BFormInvalidFeedback,
      BFormFeedback: BFormInvalidFeedback,
      BFormValidFeedback: BFormValidFeedback,
      // Added here for convenience
      BFormRow: BFormRow
    }
  }); // BFormRow is not exported here as a named export, as it is exported by Layout

  var looseIndexOf = function looseIndexOf(array, value) {
    for (var i = 0; i < array.length; i++) {
      if (looseEqual(array[i], value)) {
        return i;
      }
    }

    return -1;
  };

  var SELECTOR = 'input, textarea, select'; // --- Props ---

  var props$1x = makePropsConfigurable({
    autofocus: makeProp(PROP_TYPE_BOOLEAN, false),
    disabled: makeProp(PROP_TYPE_BOOLEAN, false),
    form: makeProp(PROP_TYPE_STRING),
    id: makeProp(PROP_TYPE_STRING),
    name: makeProp(PROP_TYPE_STRING),
    required: makeProp(PROP_TYPE_BOOLEAN, false)
  }, 'formControls'); // --- Mixin ---
  // @vue/component

  var formControlMixin = extend({
    props: props$1x,
    mounted: function mounted() {
      this.handleAutofocus();
    },

    /* istanbul ignore next */
    activated: function activated() {
      this.handleAutofocus();
    },
    methods: {
      handleAutofocus: function handleAutofocus() {
        var _this = this;

        this.$nextTick(function () {
          requestAF(function () {
            var el = _this.$el;

            if (_this.autofocus && isVisible(el)) {
              if (!matches(el, SELECTOR)) {
                el = select(SELECTOR, el);
              }

              attemptFocus(el);
            }
          });
        });
      }
    }
  });

  var props$1w = makePropsConfigurable({
    plain: makeProp(PROP_TYPE_BOOLEAN, false)
  }, 'formControls'); // --- Mixin ---
  // @vue/component

  var formCustomMixin = extend({
    props: props$1w,
    computed: {
      custom: function custom() {
        return !this.plain;
      }
    }
  });

  var props$1v = makePropsConfigurable({
    size: makeProp(PROP_TYPE_STRING)
  }, 'formControls'); // --- Mixin ---
  // @vue/component

  var formSizeMixin = extend({
    props: props$1v,
    computed: {
      sizeFormClass: function sizeFormClass() {
        return [this.size ? "form-control-".concat(this.size) : null];
      }
    }
  });

  /* Form control contextual state class computation
   *
   * Returned class is either 'is-valid' or 'is-invalid' based on the 'state' prop
   * state can be one of five values:
   *  - true for is-valid
   *  - false for is-invalid
   *  - null for no contextual state
   */

  var props$1u = makePropsConfigurable({
    // Tri-state prop: true, false, null (or undefined)
    state: makeProp(PROP_TYPE_BOOLEAN, null)
  }, 'formState'); // --- Mixin ---
  // @vue/component

  var formStateMixin = extend({
    props: props$1u,
    computed: {
      computedState: function computedState() {
        // If not a boolean, ensure that value is null
        return isBoolean(this.state) ? this.state : null;
      },
      stateClass: function stateClass() {
        var state = this.computedState;
        return state === true ? 'is-valid' : state === false ? 'is-invalid' : null;
      },
      computedAriaInvalid: function computedAriaInvalid() {
        var ariaInvalid = safeVueInstance(this).ariaInvalid;

        if (ariaInvalid === true || ariaInvalid === 'true' || ariaInvalid === '') {
          return 'true';
        }

        return this.computedState === false ? 'true' : ariaInvalid;
      }
    }
  });

  var _watch$f, _methods;

  var _makeModelMixin$g = makeModelMixin('checked', {
    defaultValue: null
  }),
      modelMixin$f = _makeModelMixin$g.mixin,
      modelProps$f = _makeModelMixin$g.props,
      MODEL_PROP_NAME$f = _makeModelMixin$g.prop,
      MODEL_EVENT_NAME$f = _makeModelMixin$g.event;

  var props$1t = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$25), modelProps$f), props$1x), props$1v), props$1u), props$1w), {}, {
    ariaLabel: makeProp(PROP_TYPE_STRING),
    ariaLabelledby: makeProp(PROP_TYPE_STRING),
    // Only applicable in standalone mode (non group)
    button: makeProp(PROP_TYPE_BOOLEAN, false),
    // Only applicable when rendered with button style
    buttonVariant: makeProp(PROP_TYPE_STRING),
    inline: makeProp(PROP_TYPE_BOOLEAN, false),
    value: makeProp(PROP_TYPE_ANY)
  })), 'formRadioCheckControls'); // --- Mixin ---
  // @vue/component

  var formRadioCheckMixin = extend({
    mixins: [attrsMixin, idMixin, modelMixin$f, normalizeSlotMixin, formControlMixin, formSizeMixin, formStateMixin, formCustomMixin],
    inheritAttrs: false,
    props: props$1t,
    data: function data() {
      return {
        localChecked: this.isGroup ? this.bvGroup[MODEL_PROP_NAME$f] : this[MODEL_PROP_NAME$f],
        hasFocus: false
      };
    },
    computed: {
      computedLocalChecked: {
        get: function get() {
          return this.isGroup ? this.bvGroup.localChecked : this.localChecked;
        },
        set: function set(value) {
          if (this.isGroup) {
            this.bvGroup.localChecked = value;
          } else {
            this.localChecked = value;
          }
        }
      },
      isChecked: function isChecked() {
        return looseEqual(this.value, this.computedLocalChecked);
      },
      isRadio: function isRadio() {
        return true;
      },
      isGroup: function isGroup() {
        // Is this check/radio a child of check-group or radio-group?
        return !!this.bvGroup;
      },
      isBtnMode: function isBtnMode() {
        // Support button style in single input mode
        return this.isGroup ? this.bvGroup.buttons : this.button;
      },
      isPlain: function isPlain() {
        return this.isBtnMode ? false : this.isGroup ? this.bvGroup.plain : this.plain;
      },
      isCustom: function isCustom() {
        return this.isBtnMode ? false : !this.isPlain;
      },
      isSwitch: function isSwitch() {
        // Custom switch styling (checkboxes only)
        return this.isBtnMode || this.isRadio || this.isPlain ? false : this.isGroup ? this.bvGroup.switches : this.switch;
      },
      isInline: function isInline() {
        return this.isGroup ? this.bvGroup.inline : this.inline;
      },
      isDisabled: function isDisabled() {
        // Child can be disabled while parent isn't, but is always disabled if group is
        return this.isGroup ? this.bvGroup.disabled || this.disabled : this.disabled;
      },
      isRequired: function isRequired() {
        // Required only works when a name is provided for the input(s)
        // Child can only be required when parent is
        // Groups will always have a name (either user supplied or auto generated)
        return this.computedName && (this.isGroup ? this.bvGroup.required : this.required);
      },
      computedName: function computedName() {
        // Group name preferred over local name
        return (this.isGroup ? this.bvGroup.groupName : this.name) || null;
      },
      computedForm: function computedForm() {
        return (this.isGroup ? this.bvGroup.form : this.form) || null;
      },
      computedSize: function computedSize() {
        return (this.isGroup ? this.bvGroup.size : this.size) || '';
      },
      computedState: function computedState() {
        return this.isGroup ? this.bvGroup.computedState : isBoolean(this.state) ? this.state : null;
      },
      computedButtonVariant: function computedButtonVariant() {
        // Local variant preferred over group variant
        var buttonVariant = this.buttonVariant;

        if (buttonVariant) {
          return buttonVariant;
        }

        if (this.isGroup && this.bvGroup.buttonVariant) {
          return this.bvGroup.buttonVariant;
        }

        return 'secondary';
      },
      buttonClasses: function buttonClasses() {
        var _ref;

        var computedSize = this.computedSize;
        return ['btn', "btn-".concat(this.computedButtonVariant), (_ref = {}, _defineProperty(_ref, "btn-".concat(computedSize), computedSize), _defineProperty(_ref, "disabled", this.isDisabled), _defineProperty(_ref, "active", this.isChecked), _defineProperty(_ref, "focus", this.hasFocus), _ref)];
      },
      computedAttrs: function computedAttrs() {
        var disabled = this.isDisabled,
            required = this.isRequired;
        return _objectSpread2$3(_objectSpread2$3({}, this.bvAttrs), {}, {
          id: this.safeId(),
          type: this.isRadio ? 'radio' : 'checkbox',
          name: this.computedName,
          form: this.computedForm,
          disabled: disabled,
          required: required,
          'aria-required': required || null,
          'aria-label': this.ariaLabel || null,
          'aria-labelledby': this.ariaLabelledby || null
        });
      }
    },
    watch: (_watch$f = {}, _defineProperty(_watch$f, MODEL_PROP_NAME$f, function () {
      this["".concat(MODEL_PROP_NAME$f, "Watcher")].apply(this, arguments);
    }), _defineProperty(_watch$f, "computedLocalChecked", function computedLocalChecked() {
      this.computedLocalCheckedWatcher.apply(this, arguments);
    }), _watch$f),
    methods: (_methods = {}, _defineProperty(_methods, "".concat(MODEL_PROP_NAME$f, "Watcher"), function Watcher(newValue) {
      if (!looseEqual(newValue, this.computedLocalChecked)) {
        this.computedLocalChecked = newValue;
      }
    }), _defineProperty(_methods, "computedLocalCheckedWatcher", function computedLocalCheckedWatcher(newValue, oldValue) {
      if (!looseEqual(newValue, oldValue)) {
        this.$emit(MODEL_EVENT_NAME$f, newValue);
      }
    }), _defineProperty(_methods, "handleChange", function handleChange(_ref2) {
      var _this = this;

      var checked = _ref2.target.checked;
      var value = this.value;
      var localChecked = checked ? value : null;
      this.computedLocalChecked = value; // Fire events in a `$nextTick()` to ensure the `v-model` is updated

      this.$nextTick(function () {
        // Change is only emitted on user interaction
        _this.$emit(EVENT_NAME_CHANGE, localChecked); // If this is a child of a group, we emit a change event on it as well


        if (_this.isGroup) {
          _this.bvGroup.$emit(EVENT_NAME_CHANGE, localChecked);
        }
      });
    }), _defineProperty(_methods, "handleFocus", function handleFocus(event) {
      // When in buttons mode, we need to add 'focus' class to label when input focused
      // As it is the hidden input which has actual focus
      if (event.target) {
        if (event.type === 'focus') {
          this.hasFocus = true;
        } else if (event.type === 'blur') {
          this.hasFocus = false;
        }
      }
    }), _defineProperty(_methods, "focus", function focus() {
      if (!this.isDisabled) {
        attemptFocus(this.$refs.input);
      }
    }), _defineProperty(_methods, "blur", function blur() {
      if (!this.isDisabled) {
        attemptBlur(this.$refs.input);
      }
    }), _methods),
    render: function render(h) {
      var isRadio = this.isRadio,
          isBtnMode = this.isBtnMode,
          isPlain = this.isPlain,
          isCustom = this.isCustom,
          isInline = this.isInline,
          isSwitch = this.isSwitch,
          computedSize = this.computedSize,
          bvAttrs = this.bvAttrs;
      var $content = this.normalizeSlot();
      var $input = h('input', {
        class: [{
          'form-check-input': isPlain,
          'custom-control-input': isCustom,
          // https://github.com/bootstrap-vue/bootstrap-vue/issues/2911
          'position-static': isPlain && !$content
        }, isBtnMode ? '' : this.stateClass],
        directives: [{
          name: 'model',
          value: this.computedLocalChecked
        }],
        attrs: this.computedAttrs,
        domProps: {
          value: this.value,
          checked: this.isChecked
        },
        on: _objectSpread2$3({
          change: this.handleChange
        }, isBtnMode ? {
          focus: this.handleFocus,
          blur: this.handleFocus
        } : {}),
        key: 'input',
        ref: 'input'
      });

      if (isBtnMode) {
        var $button = h('label', {
          class: this.buttonClasses
        }, [$input, $content]);

        if (!this.isGroup) {
          // Standalone button mode, so wrap in 'btn-group-toggle'
          // and flag it as inline-block to mimic regular buttons
          $button = h('div', {
            class: ['btn-group-toggle', 'd-inline-block']
          }, [$button]);
        }

        return $button;
      } // If no label content in plain mode we dont render the label
      // See: https://github.com/bootstrap-vue/bootstrap-vue/issues/2911


      var $label = h();

      if (!(isPlain && !$content)) {
        $label = h('label', {
          class: {
            'form-check-label': isPlain,
            'custom-control-label': isCustom
          },
          attrs: {
            for: this.safeId()
          }
        }, $content);
      }

      return h('div', {
        class: [_defineProperty({
          'form-check': isPlain,
          'form-check-inline': isPlain && isInline,
          'custom-control': isCustom,
          'custom-control-inline': isCustom && isInline,
          'custom-checkbox': isCustom && !isRadio && !isSwitch,
          'custom-switch': isSwitch,
          'custom-radio': isCustom && isRadio
        }, "b-custom-control-".concat(computedSize), computedSize && !isBtnMode), bvAttrs.class],
        style: bvAttrs.style
      }, [$input, $label]);
    }
  });

  var _objectSpread2$2;

  var MODEL_PROP_NAME_INDETERMINATE = 'indeterminate';
  var MODEL_EVENT_NAME_INDETERMINATE = MODEL_EVENT_NAME_PREFIX + MODEL_PROP_NAME_INDETERMINATE; // --- Props ---

  var props$1s = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, props$1t), {}, (_objectSpread2$2 = {}, _defineProperty(_objectSpread2$2, MODEL_PROP_NAME_INDETERMINATE, makeProp(PROP_TYPE_BOOLEAN, false)), _defineProperty(_objectSpread2$2, "switch", makeProp(PROP_TYPE_BOOLEAN, false)), _defineProperty(_objectSpread2$2, "uncheckedValue", makeProp(PROP_TYPE_ANY, false)), _defineProperty(_objectSpread2$2, "value", makeProp(PROP_TYPE_ANY, true)), _objectSpread2$2))), NAME_FORM_CHECKBOX); // --- Main component ---
  // @vue/component

  var BFormCheckbox = /*#__PURE__*/extend({
    name: NAME_FORM_CHECKBOX,
    mixins: [formRadioCheckMixin],
    inject: {
      getBvGroup: {
        from: 'getBvCheckGroup',
        default: function _default() {
          return function () {
            return null;
          };
        }
      }
    },
    props: props$1s,
    computed: {
      bvGroup: function bvGroup() {
        return this.getBvGroup();
      },
      isChecked: function isChecked() {
        var value = this.value,
            checked = this.computedLocalChecked;
        return isArray(checked) ? looseIndexOf(checked, value) > -1 : looseEqual(checked, value);
      },
      isRadio: function isRadio() {
        return false;
      }
    },
    watch: _defineProperty({}, MODEL_PROP_NAME_INDETERMINATE, function (newValue, oldValue) {
      if (!looseEqual(newValue, oldValue)) {
        this.setIndeterminate(newValue);
      }
    }),
    mounted: function mounted() {
      // Set initial indeterminate state
      this.setIndeterminate(this[MODEL_PROP_NAME_INDETERMINATE]);
    },
    methods: {
      computedLocalCheckedWatcher: function computedLocalCheckedWatcher(newValue, oldValue) {
        if (!looseEqual(newValue, oldValue)) {
          this.$emit(MODEL_EVENT_NAME$f, newValue);
          var $input = this.$refs.input;

          if ($input) {
            this.$emit(MODEL_EVENT_NAME_INDETERMINATE, $input.indeterminate);
          }
        }
      },
      handleChange: function handleChange(_ref) {
        var _this = this;

        var _ref$target = _ref.target,
            checked = _ref$target.checked,
            indeterminate = _ref$target.indeterminate;
        var value = this.value,
            uncheckedValue = this.uncheckedValue; // Update `computedLocalChecked`

        var localChecked = this.computedLocalChecked;

        if (isArray(localChecked)) {
          var index = looseIndexOf(localChecked, value);

          if (checked && index < 0) {
            // Add value to array
            localChecked = localChecked.concat(value);
          } else if (!checked && index > -1) {
            // Remove value from array
            localChecked = localChecked.slice(0, index).concat(localChecked.slice(index + 1));
          }
        } else {
          localChecked = checked ? value : uncheckedValue;
        }

        this.computedLocalChecked = localChecked; // Fire events in a `$nextTick()` to ensure the `v-model` is updated

        this.$nextTick(function () {
          // Change is only emitted on user interaction
          _this.$emit(EVENT_NAME_CHANGE, localChecked); // If this is a child of a group, we emit a change event on it as well


          if (_this.isGroup) {
            _this.bvGroup.$emit(EVENT_NAME_CHANGE, localChecked);
          }

          _this.$emit(MODEL_EVENT_NAME_INDETERMINATE, indeterminate);
        });
      },
      setIndeterminate: function setIndeterminate(state) {
        // Indeterminate only supported in single checkbox mode
        if (isArray(this.computedLocalChecked)) {
          state = false;
        }

        var $input = this.$refs.input;

        if ($input) {
          $input.indeterminate = state; // Emit update event to prop

          this.$emit(MODEL_EVENT_NAME_INDETERMINATE, state);
        }
      }
    }
  });

  var props$1r = makePropsConfigurable(props$1t, NAME_FORM_RADIO); // --- Main component ---
  // @vue/component

  var BFormRadio = /*#__PURE__*/extend({
    name: NAME_FORM_RADIO,
    mixins: [formRadioCheckMixin],
    inject: {
      getBvGroup: {
        from: 'getBvRadioGroup',
        default: function _default() {
          return function () {
            return null;
          };
        }
      }
    },
    props: props$1r,
    computed: {
      bvGroup: function bvGroup() {
        return this.getBvGroup();
      }
    }
  });

  var _watch$e;
  // Attributes to pass down to checks/radios instead of applying them to the group

  var PASS_DOWN_ATTRS = ['aria-describedby', 'aria-labelledby'];

  var _makeModelMixin$f = makeModelMixin('checked'),
      modelMixin$e = _makeModelMixin$f.mixin,
      modelProps$e = _makeModelMixin$f.props,
      MODEL_PROP_NAME$e = _makeModelMixin$f.prop,
      MODEL_EVENT_NAME$e = _makeModelMixin$f.event;

  var props$1q = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$25), modelProps$e), props$1x), props$1D), props$1v), props$1u), props$1w), {}, {
    ariaInvalid: makeProp(PROP_TYPE_BOOLEAN_STRING, false),
    // Only applicable when rendered with button style
    buttonVariant: makeProp(PROP_TYPE_STRING),
    // Render as button style
    buttons: makeProp(PROP_TYPE_BOOLEAN, false),
    stacked: makeProp(PROP_TYPE_BOOLEAN, false),
    validated: makeProp(PROP_TYPE_BOOLEAN, false)
  })), 'formRadioCheckGroups'); // --- Mixin ---
  // @vue/component

  var formRadioCheckGroupMixin = extend({
    mixins: [idMixin, modelMixin$e, normalizeSlotMixin, formControlMixin, formOptionsMixin, formSizeMixin, formStateMixin, formCustomMixin],
    inheritAttrs: false,
    props: props$1q,
    data: function data() {
      return {
        localChecked: this[MODEL_PROP_NAME$e]
      };
    },
    computed: {
      inline: function inline() {
        return !this.stacked;
      },
      groupName: function groupName() {
        // Checks/Radios tied to the same model must have the same name,
        // especially for ARIA accessibility
        return this.name || this.safeId();
      },
      groupClasses: function groupClasses() {
        var inline = this.inline,
            size = this.size,
            validated = this.validated;
        var classes = {
          'was-validated': validated
        };

        if (this.buttons) {
          classes = [classes, 'btn-group-toggle', _defineProperty({
            'btn-group': inline,
            'btn-group-vertical': !inline
          }, "btn-group-".concat(size), size)];
        }

        return classes;
      }
    },
    watch: (_watch$e = {}, _defineProperty(_watch$e, MODEL_PROP_NAME$e, function (newValue) {
      if (!looseEqual(newValue, this.localChecked)) {
        this.localChecked = newValue;
      }
    }), _defineProperty(_watch$e, "localChecked", function localChecked(newValue, oldValue) {
      if (!looseEqual(newValue, oldValue)) {
        this.$emit(MODEL_EVENT_NAME$e, newValue);
      }
    }), _watch$e),
    render: function render(h) {
      var _this = this;

      var isRadioGroup = this.isRadioGroup;
      var attrs = pick$1(this.$attrs, PASS_DOWN_ATTRS);
      var optionComponent = isRadioGroup ? BFormRadio : BFormCheckbox;
      var $inputs = this.formOptions.map(function (option, index) {
        var key = "BV_option_".concat(index);
        return h(optionComponent, {
          props: {
            // Individual radios or checks can be disabled in a group
            disabled: option.disabled || false,
            id: _this.safeId(key),
            value: option.value // We don't need to include these, since the input's will know they are inside here
            // form: this.form || null,
            // name: this.groupName,
            // required: Boolean(this.name && this.required),
            // state: this.state

          },
          attrs: attrs,
          key: key
        }, [h('span', {
          domProps: htmlOrText(option.html, option.text)
        })]);
      });
      return h('div', {
        class: [this.groupClasses, 'bv-no-focus-ring'],
        attrs: _objectSpread2$3(_objectSpread2$3({}, omit(this.$attrs, PASS_DOWN_ATTRS)), {}, {
          'aria-invalid': this.computedAriaInvalid,
          'aria-required': this.required ? 'true' : null,
          id: this.safeId(),
          role: isRadioGroup ? 'radiogroup' : 'group',
          // Add `tabindex="-1"` to allow group to be focused if needed by screen readers
          tabindex: '-1'
        })
      }, [this.normalizeSlot(SLOT_NAME_FIRST), $inputs, this.normalizeSlot()]);
    }
  });

  var _objectSpread2$1;

  var props$1p = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, props$1q), {}, (_objectSpread2$1 = {}, _defineProperty(_objectSpread2$1, MODEL_PROP_NAME$e, makeProp(PROP_TYPE_ARRAY, [])), _defineProperty(_objectSpread2$1, "switches", makeProp(PROP_TYPE_BOOLEAN, false)), _objectSpread2$1))), NAME_FORM_CHECKBOX_GROUP); // --- Main component ---
  // @vue/component

  var BFormCheckboxGroup = /*#__PURE__*/extend({
    name: NAME_FORM_CHECKBOX_GROUP,
    // Includes render function
    mixins: [formRadioCheckGroupMixin],
    provide: function provide() {
      var _this = this;

      return {
        getBvCheckGroup: function getBvCheckGroup() {
          return _this;
        }
      };
    },
    props: props$1p,
    computed: {
      isRadioGroup: function isRadioGroup() {
        return false;
      }
    }
  });

  var FormCheckboxPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BFormCheckbox: BFormCheckbox,
      BCheckbox: BFormCheckbox,
      BCheck: BFormCheckbox,
      BFormCheckboxGroup: BFormCheckboxGroup,
      BCheckboxGroup: BFormCheckboxGroup,
      BCheckGroup: BFormCheckboxGroup
    }
  });

  // v-b-hover directive

  var PROP$2 = '__BV_hover_handler__';
  var MOUSEENTER = 'mouseenter';
  var MOUSELEAVE = 'mouseleave'; // --- Helper methods ---

  var createListener = function createListener(handler) {
    var listener = function listener(event) {
      handler(event.type === MOUSEENTER, event);
    };

    listener.fn = handler;
    return listener;
  };

  var updateListeners = function updateListeners(on, el, listener) {
    eventOnOff(on, el, MOUSEENTER, listener, EVENT_OPTIONS_NO_CAPTURE);
    eventOnOff(on, el, MOUSELEAVE, listener, EVENT_OPTIONS_NO_CAPTURE);
  }; // --- Directive bind/unbind/update handler ---


  var directive = function directive(el, _ref) {
    var _ref$value = _ref.value,
        handler = _ref$value === void 0 ? null : _ref$value;

    if (IS_BROWSER) {
      var listener = el[PROP$2];
      var hasListener = isFunction$1(listener);
      var handlerChanged = !(hasListener && listener.fn === handler);

      if (hasListener && handlerChanged) {
        updateListeners(false, el, listener);
        delete el[PROP$2];
      }

      if (isFunction$1(handler) && handlerChanged) {
        el[PROP$2] = createListener(handler);
        updateListeners(true, el, el[PROP$2]);
      }
    }
  }; // VBHover directive


  var VBHover = {
    bind: directive,
    componentUpdated: directive,
    unbind: function unbind(el) {
      directive(el, {
        value: null
      });
    }
  };

  var props$1o = sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$25), props$1v), props$1u), omit(props$1O, ['disabled'])), omit(props$1x, ['autofocus'])), {}, {
    // When `true`, renders a `btn-group` wrapper and visually hides the label
    buttonOnly: makeProp(PROP_TYPE_BOOLEAN, false),
    // Applicable in button mode only
    buttonVariant: makeProp(PROP_TYPE_STRING, 'secondary'),
    // This is the value shown in the label
    // Defaults back to `value`
    formattedValue: makeProp(PROP_TYPE_STRING),
    // Value placed in `.sr-only` span inside label when value is present
    labelSelected: makeProp(PROP_TYPE_STRING),
    lang: makeProp(PROP_TYPE_STRING),
    // Extra classes to apply to the `dropdown-menu` div
    menuClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    // This is the value placed on the hidden input when no value selected
    placeholder: makeProp(PROP_TYPE_STRING),
    readonly: makeProp(PROP_TYPE_BOOLEAN, false),
    // Tri-state prop: `true`, `false` or `null`
    rtl: makeProp(PROP_TYPE_BOOLEAN, null),
    value: makeProp(PROP_TYPE_STRING, '')
  })); // --- Main component ---
  // @vue/component

  var BVFormBtnLabelControl = /*#__PURE__*/extend({
    name: NAME_FORM_BUTTON_LABEL_CONTROL,
    directives: {
      'b-hover': VBHover
    },
    mixins: [idMixin, formSizeMixin, formStateMixin, dropdownMixin, normalizeSlotMixin],
    props: props$1o,
    data: function data() {
      return {
        isHovered: false,
        hasFocus: false
      };
    },
    computed: {
      idButton: function idButton() {
        return this.safeId();
      },
      idLabel: function idLabel() {
        return this.safeId('_value_');
      },
      idMenu: function idMenu() {
        return this.safeId('_dialog_');
      },
      idWrapper: function idWrapper() {
        return this.safeId('_outer_');
      },
      computedDir: function computedDir() {
        return this.rtl === true ? 'rtl' : this.rtl === false ? 'ltr' : null;
      }
    },
    methods: {
      focus: function focus() {
        if (!this.disabled) {
          attemptFocus(this.$refs.toggle);
        }
      },
      blur: function blur() {
        if (!this.disabled) {
          attemptBlur(this.$refs.toggle);
        }
      },
      setFocus: function setFocus(event) {
        this.hasFocus = event.type === 'focus';
      },
      handleHover: function handleHover(hovered) {
        this.isHovered = hovered;
      }
    },
    render: function render(h) {
      var _class;

      var idButton = this.idButton,
          idLabel = this.idLabel,
          idMenu = this.idMenu,
          idWrapper = this.idWrapper,
          disabled = this.disabled,
          readonly = this.readonly,
          required = this.required,
          name = this.name,
          state = this.state,
          visible = this.visible,
          size = this.size,
          isHovered = this.isHovered,
          hasFocus = this.hasFocus,
          labelSelected = this.labelSelected,
          buttonVariant = this.buttonVariant,
          buttonOnly = this.buttonOnly;
      var value = toString(this.value) || '';
      var invalid = state === false || required && !value;
      var btnScope = {
        isHovered: isHovered,
        hasFocus: hasFocus,
        state: state,
        opened: visible
      };
      var $button = h('button', {
        staticClass: 'btn',
        class: (_class = {}, _defineProperty(_class, "btn-".concat(buttonVariant), buttonOnly), _defineProperty(_class, "btn-".concat(size), size), _defineProperty(_class, 'h-auto', !buttonOnly), _defineProperty(_class, 'dropdown-toggle', buttonOnly), _defineProperty(_class, 'dropdown-toggle-no-caret', buttonOnly), _class),
        attrs: {
          id: idButton,
          type: 'button',
          disabled: disabled,
          'aria-haspopup': 'dialog',
          'aria-expanded': visible ? 'true' : 'false',
          'aria-invalid': invalid ? 'true' : null,
          'aria-required': required ? 'true' : null
        },
        directives: [{
          name: 'b-hover',
          value: this.handleHover
        }],
        on: {
          mousedown: this.onMousedown,
          click: this.toggle,
          keydown: this.toggle,
          // Handle ENTER, SPACE and DOWN
          '!focus': this.setFocus,
          '!blur': this.setFocus
        },
        ref: 'toggle'
      }, [this.hasNormalizedSlot(SLOT_NAME_BUTTON_CONTENT) ? this.normalizeSlot(SLOT_NAME_BUTTON_CONTENT, btnScope) :
      /* istanbul ignore next */
      h(BIconChevronDown, {
        props: {
          scale: 1.25
        }
      })]); // Hidden input

      var $hidden = h();

      if (name && !disabled) {
        $hidden = h('input', {
          attrs: {
            type: 'hidden',
            name: name || null,
            form: this.form || null,
            value: value
          }
        });
      } // Dropdown content


      var $menu = h('div', {
        staticClass: 'dropdown-menu',
        class: [this.menuClass, {
          show: visible,
          'dropdown-menu-right': this.right
        }],
        attrs: {
          id: idMenu,
          role: 'dialog',
          tabindex: '-1',
          'aria-modal': 'false',
          'aria-labelledby': idLabel
        },
        on: {
          keydown: this.onKeydown // Handle ESC

        },
        ref: 'menu'
      }, [this.normalizeSlot(SLOT_NAME_DEFAULT, {
        opened: visible
      })]); // Value label

      var $label = h('label', {
        class: buttonOnly ? 'sr-only' // Hidden in button only mode
        : ['form-control', // Mute the text if showing the placeholder
        {
          'text-muted': !value
        }, this.stateClass, this.sizeFormClass],
        attrs: {
          id: idLabel,
          for: idButton,
          'aria-invalid': invalid ? 'true' : null,
          'aria-required': required ? 'true' : null
        },
        directives: [{
          name: 'b-hover',
          value: this.handleHover
        }],
        on: {
          // Disable bubbling of the click event to
          // prevent menu from closing and re-opening
          '!click':
          /* istanbul ignore next */
          function click(event) {
            stopEvent(event, {
              preventDefault: false
            });
          }
        }
      }, [value ? this.formattedValue || value : this.placeholder || '', // Add the selected label for screen readers when a value is provided
      value && labelSelected ? h('bdi', {
        staticClass: 'sr-only'
      }, labelSelected) : '']); // Return the custom form control wrapper

      return h('div', {
        staticClass: 'b-form-btn-label-control dropdown',
        class: [this.directionClass, this.boundaryClass, [{
          'btn-group': buttonOnly,
          'form-control': !buttonOnly,
          focus: hasFocus && !buttonOnly,
          show: visible,
          'is-valid': state === true,
          'is-invalid': state === false
        }, buttonOnly ? null : this.sizeFormClass]],
        attrs: {
          id: idWrapper,
          role: buttonOnly ? null : 'group',
          lang: this.lang || null,
          dir: this.computedDir,
          'aria-disabled': disabled,
          'aria-readonly': readonly && !disabled,
          'aria-labelledby': idLabel,
          'aria-invalid': state === false || required && !value ? 'true' : null,
          'aria-required': required ? 'true' : null
        }
      }, [$button, $hidden, $menu, $label]);
    }
  });

  var _watch$d;

  var _makeModelMixin$e = makeModelMixin('value', {
    type: PROP_TYPE_DATE_STRING
  }),
      modelMixin$d = _makeModelMixin$e.mixin,
      modelProps$d = _makeModelMixin$e.props,
      MODEL_PROP_NAME$d = _makeModelMixin$e.prop,
      MODEL_EVENT_NAME$d = _makeModelMixin$e.event; // --- Props ---


  var calendarProps = omit(props$24, ['block', 'hidden', 'id', 'noKeyNav', 'roleDescription', 'value', 'width']);
  var formBtnLabelControlProps$1 = omit(props$1o, ['formattedValue', 'id', 'lang', 'rtl', 'value']);
  var props$1n = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$25), modelProps$d), calendarProps), formBtnLabelControlProps$1), {}, {
    // Width of the calendar dropdown
    calendarWidth: makeProp(PROP_TYPE_STRING, '270px'),
    closeButton: makeProp(PROP_TYPE_BOOLEAN, false),
    closeButtonVariant: makeProp(PROP_TYPE_STRING, 'outline-secondary'),
    // Dark mode
    dark: makeProp(PROP_TYPE_BOOLEAN, false),
    labelCloseButton: makeProp(PROP_TYPE_STRING, 'Close'),
    labelResetButton: makeProp(PROP_TYPE_STRING, 'Reset'),
    labelTodayButton: makeProp(PROP_TYPE_STRING, 'Select today'),
    noCloseOnSelect: makeProp(PROP_TYPE_BOOLEAN, false),
    resetButton: makeProp(PROP_TYPE_BOOLEAN, false),
    resetButtonVariant: makeProp(PROP_TYPE_STRING, 'outline-danger'),
    resetValue: makeProp(PROP_TYPE_DATE_STRING),
    todayButton: makeProp(PROP_TYPE_BOOLEAN, false),
    todayButtonVariant: makeProp(PROP_TYPE_STRING, 'outline-primary')
  })), NAME_FORM_DATEPICKER); // --- Main component ---
  // @vue/component

  var BFormDatepicker = /*#__PURE__*/extend({
    name: NAME_FORM_DATEPICKER,
    mixins: [idMixin, modelMixin$d],
    props: props$1n,
    data: function data() {
      return {
        // We always use `YYYY-MM-DD` value internally
        localYMD: formatYMD(this[MODEL_PROP_NAME$d]) || '',
        // If the popup is open
        isVisible: false,
        // Context data from BCalendar
        localLocale: null,
        isRTL: false,
        formattedValue: '',
        activeYMD: ''
      };
    },
    computed: {
      calendarYM: function calendarYM() {
        // Returns the calendar year/month
        // Returns the `YYYY-MM` portion of the active calendar date
        return this.activeYMD.slice(0, -3);
      },
      computedLang: function computedLang() {
        return (this.localLocale || '').replace(/-u-.*$/i, '') || null;
      },
      computedResetValue: function computedResetValue() {
        return formatYMD(constrainDate(this.resetValue)) || '';
      }
    },
    watch: (_watch$d = {}, _defineProperty(_watch$d, MODEL_PROP_NAME$d, function (newValue) {
      this.localYMD = formatYMD(newValue) || '';
    }), _defineProperty(_watch$d, "localYMD", function localYMD(newValue) {
      // We only update the v-model when the datepicker is open
      if (this.isVisible) {
        this.$emit(MODEL_EVENT_NAME$d, this.valueAsDate ? parseYMD(newValue) || null : newValue || '');
      }
    }), _defineProperty(_watch$d, "calendarYM", function calendarYM(newValue, oldValue) {
      // Displayed calendar month has changed
      // So possibly the calendar height has changed...
      // We need to update popper computed position
      if (newValue !== oldValue && oldValue) {
        try {
          this.$refs.control.updatePopper();
        } catch (_unused) {}
      }
    }), _watch$d),
    methods: {
      // Public methods
      focus: function focus() {
        if (!this.disabled) {
          attemptFocus(this.$refs.control);
        }
      },
      blur: function blur() {
        if (!this.disabled) {
          attemptBlur(this.$refs.control);
        }
      },
      // Private methods
      setAndClose: function setAndClose(ymd) {
        var _this = this;

        this.localYMD = ymd; // Close calendar popup, unless `noCloseOnSelect`

        if (!this.noCloseOnSelect) {
          this.$nextTick(function () {
            _this.$refs.control.hide(true);
          });
        }
      },
      onSelected: function onSelected(ymd) {
        var _this2 = this;

        this.$nextTick(function () {
          _this2.setAndClose(ymd);
        });
      },
      onInput: function onInput(ymd) {
        if (this.localYMD !== ymd) {
          this.localYMD = ymd;
        }
      },
      onContext: function onContext(ctx) {
        var activeYMD = ctx.activeYMD,
            isRTL = ctx.isRTL,
            locale = ctx.locale,
            selectedYMD = ctx.selectedYMD,
            selectedFormatted = ctx.selectedFormatted;
        this.isRTL = isRTL;
        this.localLocale = locale;
        this.formattedValue = selectedFormatted;
        this.localYMD = selectedYMD;
        this.activeYMD = activeYMD; // Re-emit the context event

        this.$emit(EVENT_NAME_CONTEXT, ctx);
      },
      onTodayButton: function onTodayButton() {
        // Set to today (or min/max if today is out of range)
        this.setAndClose(formatYMD(constrainDate(createDate(), this.min, this.max)));
      },
      onResetButton: function onResetButton() {
        this.setAndClose(this.computedResetValue);
      },
      onCloseButton: function onCloseButton() {
        this.$refs.control.hide(true);
      },
      // Menu handlers
      onShow: function onShow() {
        this.isVisible = true;
      },
      onShown: function onShown() {
        var _this3 = this;

        this.$nextTick(function () {
          attemptFocus(_this3.$refs.calendar);

          _this3.$emit(EVENT_NAME_SHOWN);
        });
      },
      onHidden: function onHidden() {
        this.isVisible = false;
        this.$emit(EVENT_NAME_HIDDEN);
      },
      // Render helpers
      defaultButtonFn: function defaultButtonFn(_ref) {
        var isHovered = _ref.isHovered,
            hasFocus = _ref.hasFocus;
        return this.$createElement(isHovered || hasFocus ? BIconCalendarFill : BIconCalendar, {
          attrs: {
            'aria-hidden': 'true'
          }
        });
      }
    },
    render: function render(h) {
      var localYMD = this.localYMD,
          disabled = this.disabled,
          readonly = this.readonly,
          dark = this.dark,
          $props = this.$props,
          $scopedSlots = this.$scopedSlots;
      var placeholder = isUndefinedOrNull(this.placeholder) ? this.labelNoDateSelected : this.placeholder; // Optional footer buttons

      var $footer = [];

      if (this.todayButton) {
        var label = this.labelTodayButton;
        $footer.push(h(BButton, {
          props: {
            disabled: disabled || readonly,
            size: 'sm',
            variant: this.todayButtonVariant
          },
          attrs: {
            'aria-label': label || null
          },
          on: {
            click: this.onTodayButton
          }
        }, label));
      }

      if (this.resetButton) {
        var _label = this.labelResetButton;
        $footer.push(h(BButton, {
          props: {
            disabled: disabled || readonly,
            size: 'sm',
            variant: this.resetButtonVariant
          },
          attrs: {
            'aria-label': _label || null
          },
          on: {
            click: this.onResetButton
          }
        }, _label));
      }

      if (this.closeButton) {
        var _label2 = this.labelCloseButton;
        $footer.push(h(BButton, {
          props: {
            disabled: disabled,
            size: 'sm',
            variant: this.closeButtonVariant
          },
          attrs: {
            'aria-label': _label2 || null
          },
          on: {
            click: this.onCloseButton
          }
        }, _label2));
      }

      if ($footer.length > 0) {
        $footer = [h('div', {
          staticClass: 'b-form-date-controls d-flex flex-wrap',
          class: {
            'justify-content-between': $footer.length > 1,
            'justify-content-end': $footer.length < 2
          }
        }, $footer)];
      }

      var $calendar = h(BCalendar, {
        staticClass: 'b-form-date-calendar w-100',
        props: _objectSpread2$3(_objectSpread2$3({}, pluckProps(calendarProps, $props)), {}, {
          hidden: !this.isVisible,
          value: localYMD,
          valueAsDate: false,
          width: this.calendarWidth
        }),
        on: {
          selected: this.onSelected,
          input: this.onInput,
          context: this.onContext
        },
        scopedSlots: pick$1($scopedSlots, ['nav-prev-decade', 'nav-prev-year', 'nav-prev-month', 'nav-this-month', 'nav-next-month', 'nav-next-year', 'nav-next-decade']),
        key: 'calendar',
        ref: 'calendar'
      }, $footer);
      return h(BVFormBtnLabelControl, {
        staticClass: 'b-form-datepicker',
        props: _objectSpread2$3(_objectSpread2$3({}, pluckProps(formBtnLabelControlProps$1, $props)), {}, {
          formattedValue: localYMD ? this.formattedValue : '',
          id: this.safeId(),
          lang: this.computedLang,
          menuClass: [{
            'bg-dark': dark,
            'text-light': dark
          }, this.menuClass],
          placeholder: placeholder,
          rtl: this.isRTL,
          value: localYMD
        }),
        on: {
          show: this.onShow,
          shown: this.onShown,
          hidden: this.onHidden
        },
        scopedSlots: _defineProperty({}, SLOT_NAME_BUTTON_CONTENT, $scopedSlots[SLOT_NAME_BUTTON_CONTENT] || this.defaultButtonFn),
        ref: 'control'
      }, [$calendar]);
    }
  });

  var FormDatepickerPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BFormDatepicker: BFormDatepicker,
      BDatepicker: BFormDatepicker
    }
  });

  var _watch$c;

  var _makeModelMixin$d = makeModelMixin('value', {
    type: [PROP_TYPE_ARRAY, File],
    defaultValue: null,
    validator: function validator(value) {
      /* istanbul ignore next */
      if (value === '') {
        warn(VALUE_EMPTY_DEPRECATED_MSG, NAME_FORM_FILE);
        return true;
      }

      return isUndefinedOrNull(value) || isValidValue(value);
    }
  }),
      modelMixin$c = _makeModelMixin$d.mixin,
      modelProps$c = _makeModelMixin$d.props,
      MODEL_PROP_NAME$c = _makeModelMixin$d.prop,
      MODEL_EVENT_NAME$c = _makeModelMixin$d.event;

  var VALUE_EMPTY_DEPRECATED_MSG = 'Setting "value"/"v-model" to an empty string for reset is deprecated. Set to "null" instead.'; // --- Helper methods ---

  var isValidValue = function isValidValue(value) {
    return isFile(value) || isArray(value) && value.every(function (v) {
      return isValidValue(v);
    });
  }; // Helper method to "safely" get the entry from a data-transfer item

  /* istanbul ignore next: not supported in JSDOM */


  var getDataTransferItemEntry = function getDataTransferItemEntry(item) {
    return isFunction$1(item.getAsEntry) ? item.getAsEntry() : isFunction$1(item.webkitGetAsEntry) ? item.webkitGetAsEntry() : null;
  }; // Drop handler function to get all files

  /* istanbul ignore next: not supported in JSDOM */


  var getAllFileEntries = function getAllFileEntries(dataTransferItemList) {
    var traverseDirectories = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
    return Promise.all(from(dataTransferItemList).filter(function (item) {
      return item.kind === 'file';
    }).map(function (item) {
      var entry = getDataTransferItemEntry(item);

      if (entry) {
        if (entry.isDirectory && traverseDirectories) {
          return getAllFileEntriesInDirectory(entry.createReader(), "".concat(entry.name, "/"));
        } else if (entry.isFile) {
          return new Promise(function (resolve) {
            entry.file(function (file) {
              file.$path = '';
              resolve(file);
            });
          });
        }
      }

      return null;
    }).filter(identity));
  }; // Get all the file entries (recursive) in a directory

  /* istanbul ignore next: not supported in JSDOM */


  var getAllFileEntriesInDirectory = function getAllFileEntriesInDirectory(directoryReader) {
    var path = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
    return new Promise(function (resolve) {
      var entryPromises = [];

      var readDirectoryEntries = function readDirectoryEntries() {
        directoryReader.readEntries(function (entries) {
          if (entries.length === 0) {
            resolve(Promise.all(entryPromises).then(function (entries) {
              return flatten(entries);
            }));
          } else {
            entryPromises.push(Promise.all(entries.map(function (entry) {
              if (entry) {
                if (entry.isDirectory) {
                  return getAllFileEntriesInDirectory(entry.createReader(), "".concat(path).concat(entry.name, "/"));
                } else if (entry.isFile) {
                  return new Promise(function (resolve) {
                    entry.file(function (file) {
                      file.$path = "".concat(path).concat(file.name);
                      resolve(file);
                    });
                  });
                }
              }

              return null;
            }).filter(identity)));
            readDirectoryEntries();
          }
        });
      };

      readDirectoryEntries();
    });
  }; // --- Props ---


  var props$1m = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$25), modelProps$c), props$1x), props$1w), props$1u), props$1v), {}, {
    accept: makeProp(PROP_TYPE_STRING, ''),
    browseText: makeProp(PROP_TYPE_STRING, 'Browse'),
    // Instruct input to capture from camera
    capture: makeProp(PROP_TYPE_BOOLEAN, false),
    directory: makeProp(PROP_TYPE_BOOLEAN, false),
    dropPlaceholder: makeProp(PROP_TYPE_STRING, 'Drop files here'),
    fileNameFormatter: makeProp(PROP_TYPE_FUNCTION),
    multiple: makeProp(PROP_TYPE_BOOLEAN, false),
    noDrop: makeProp(PROP_TYPE_BOOLEAN, false),
    noDropPlaceholder: makeProp(PROP_TYPE_STRING, 'Not allowed'),
    // TODO:
    //   Should we deprecate this and only support flat file structures?
    //   Nested file structures are only supported when files are dropped
    //   A Chromium "bug" prevents `webkitEntries` from being populated
    //   on the file input's `change` event and is marked as "WontFix"
    //   Mozilla implemented the behavior the same way as Chromium
    //   See: https://bugs.chromium.org/p/chromium/issues/detail?id=138987
    //   See: https://bugzilla.mozilla.org/show_bug.cgi?id=1326031
    noTraverse: makeProp(PROP_TYPE_BOOLEAN, false),
    placeholder: makeProp(PROP_TYPE_STRING, 'No file chosen')
  })), NAME_FORM_FILE); // --- Main component ---
  // @vue/component

  var BFormFile = /*#__PURE__*/extend({
    name: NAME_FORM_FILE,
    mixins: [attrsMixin, idMixin, modelMixin$c, normalizeSlotMixin, formControlMixin, formStateMixin, formCustomMixin, normalizeSlotMixin],
    inheritAttrs: false,
    props: props$1m,
    data: function data() {
      return {
        files: [],
        dragging: false,
        // IE 11 doesn't respect setting `event.dataTransfer.dropEffect`,
        // so we handle it ourselves as well
        // https://stackoverflow.com/a/46915971/2744776
        dropAllowed: !this.noDrop,
        hasFocus: false
      };
    },
    computed: {
      // Convert `accept` to an array of `[{ RegExpr, isMime }, ...]`
      computedAccept: function computedAccept() {
        var accept = this.accept;
        accept = (accept || '').trim().split(/[,\s]+/).filter(identity); // Allow any file type/extension

        if (accept.length === 0) {
          return null;
        }

        return accept.map(function (extOrType) {
          var prop = 'name';
          var startMatch = '^';
          var endMatch = '$';

          if (RX_EXTENSION.test(extOrType)) {
            // File extension /\.ext$/
            startMatch = '';
          } else {
            // MIME type /^mime\/.+$/ or /^mime\/type$/
            prop = 'type';

            if (RX_STAR.test(extOrType)) {
              endMatch = '.+$'; // Remove trailing `*`

              extOrType = extOrType.slice(0, -1);
            }
          } // Escape all RegExp special chars


          extOrType = escapeRegExp(extOrType);
          var rx = new RegExp("".concat(startMatch).concat(extOrType).concat(endMatch));
          return {
            rx: rx,
            prop: prop
          };
        });
      },
      computedCapture: function computedCapture() {
        var capture = this.capture;
        return capture === true || capture === '' ? true : capture || null;
      },
      computedAttrs: function computedAttrs() {
        var name = this.name,
            disabled = this.disabled,
            required = this.required,
            form = this.form,
            computedCapture = this.computedCapture,
            accept = this.accept,
            multiple = this.multiple,
            directory = this.directory;
        return _objectSpread2$3(_objectSpread2$3({}, this.bvAttrs), {}, {
          type: 'file',
          id: this.safeId(),
          name: name,
          disabled: disabled,
          required: required,
          form: form || null,
          capture: computedCapture,
          accept: accept || null,
          multiple: multiple,
          directory: directory,
          webkitdirectory: directory,
          'aria-required': required ? 'true' : null
        });
      },
      computedFileNameFormatter: function computedFileNameFormatter() {
        var fileNameFormatter = this.fileNameFormatter;
        return hasPropFunction(fileNameFormatter) ? fileNameFormatter : this.defaultFileNameFormatter;
      },
      clonedFiles: function clonedFiles() {
        return cloneDeep(this.files);
      },
      flattenedFiles: function flattenedFiles() {
        return flattenDeep(this.files);
      },
      fileNames: function fileNames() {
        return this.flattenedFiles.map(function (file) {
          return file.name;
        });
      },
      labelContent: function labelContent() {
        // Draging active

        /* istanbul ignore next: used by drag/drop which can't be tested easily */
        if (this.dragging && !this.noDrop) {
          return (// TODO: Add additional scope with file count, and other not-allowed reasons
            this.normalizeSlot(SLOT_NAME_DROP_PLACEHOLDER, {
              allowed: this.dropAllowed
            }) || (this.dropAllowed ? this.dropPlaceholder : this.$createElement('span', {
              staticClass: 'text-danger'
            }, this.noDropPlaceholder))
          );
        } // No file chosen


        if (this.files.length === 0) {
          return this.normalizeSlot(SLOT_NAME_PLACEHOLDER) || this.placeholder;
        }

        var flattenedFiles = this.flattenedFiles,
            clonedFiles = this.clonedFiles,
            fileNames = this.fileNames,
            computedFileNameFormatter = this.computedFileNameFormatter; // There is a slot for formatting the files/names

        if (this.hasNormalizedSlot(SLOT_NAME_FILE_NAME)) {
          return this.normalizeSlot(SLOT_NAME_FILE_NAME, {
            files: flattenedFiles,
            filesTraversed: clonedFiles,
            names: fileNames
          });
        }

        return computedFileNameFormatter(flattenedFiles, clonedFiles, fileNames);
      }
    },
    watch: (_watch$c = {}, _defineProperty(_watch$c, MODEL_PROP_NAME$c, function (newValue) {
      if (!newValue || isArray(newValue) && newValue.length === 0) {
        this.reset();
      }
    }), _defineProperty(_watch$c, "files", function files(newValue, oldValue) {
      if (!looseEqual(newValue, oldValue)) {
        var multiple = this.multiple,
            noTraverse = this.noTraverse;
        var files = !multiple || noTraverse ? flattenDeep(newValue) : newValue;
        this.$emit(MODEL_EVENT_NAME$c, multiple ? files : files[0] || null);
      }
    }), _watch$c),
    created: function created() {
      // Create private non-reactive props
      this.$_form = null;
    },
    mounted: function mounted() {
      // Listen for form reset events, to reset the file input
      var $form = closest('form', this.$el);

      if ($form) {
        eventOn($form, 'reset', this.reset, EVENT_OPTIONS_PASSIVE);
        this.$_form = $form;
      }
    },
    beforeDestroy: function beforeDestroy() {
      var $form = this.$_form;

      if ($form) {
        eventOff($form, 'reset', this.reset, EVENT_OPTIONS_PASSIVE);
      }
    },
    methods: {
      isFileValid: function isFileValid(file) {
        if (!file) {
          return false;
        }

        var accept = this.computedAccept;
        return accept ? accept.some(function (a) {
          return a.rx.test(file[a.prop]);
        }) : true;
      },
      isFilesArrayValid: function isFilesArrayValid(files) {
        var _this = this;

        return isArray(files) ? files.every(function (file) {
          return _this.isFileValid(file);
        }) : this.isFileValid(files);
      },
      defaultFileNameFormatter: function defaultFileNameFormatter(flattenedFiles, clonedFiles, fileNames) {
        return fileNames.join(', ');
      },
      setFiles: function setFiles(files) {
        // Reset the dragging flags
        this.dropAllowed = !this.noDrop;
        this.dragging = false; // Set the selected files

        this.files = this.multiple ? this.directory ? files : flattenDeep(files) : flattenDeep(files).slice(0, 1);
      },

      /* istanbul ignore next: used by Drag/Drop */
      setInputFiles: function setInputFiles(files) {
        // Try an set the file input files array so that `required`
        // constraint works for dropped files (will fail in IE11 though)
        // To be used only when dropping files
        try {
          // Firefox < 62 workaround exploiting https://bugzilla.mozilla.org/show_bug.cgi?id=1422655
          var dataTransfer = new ClipboardEvent('').clipboardData || new DataTransfer(); // Add flattened files to temp `dataTransfer` object to get a true `FileList` array

          flattenDeep(cloneDeep(files)).forEach(function (file) {
            // Make sure to remove the custom `$path` attribute
            delete file.$path;
            dataTransfer.items.add(file);
          });
          this.$refs.input.files = dataTransfer.files;
        } catch (_unused) {}
      },
      reset: function reset() {
        // IE 11 doesn't support setting `$input.value` to `''` or `null`
        // So we use this little extra hack to reset the value, just in case
        // This also appears to work on modern browsers as well
        // Wrapped in try in case IE 11 or mobile Safari crap out
        try {
          var $input = this.$refs.input;
          $input.value = '';
          $input.type = '';
          $input.type = 'file';
        } catch (_unused2) {}

        this.files = [];
      },
      handleFiles: function handleFiles(files) {
        var isDrop = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;

        if (isDrop) {
          // When dropped, make sure to filter files with the internal `accept` logic
          var filteredFiles = files.filter(this.isFilesArrayValid); // Only update files when we have any after filtering

          if (filteredFiles.length > 0) {
            this.setFiles(filteredFiles); // Try an set the file input's files array so that `required`
            // constraint works for dropped files (will fail in IE 11 though)

            this.setInputFiles(filteredFiles);
          }
        } else {
          // We always update the files from the `change` event
          this.setFiles(files);
        }
      },
      focusHandler: function focusHandler(event) {
        // Bootstrap v4 doesn't have focus styling for custom file input
        // Firefox has a `[type=file]:focus ~ sibling` selector issue,
        // so we add a `focus` class to get around these bugs
        if (this.plain || event.type === 'focusout') {
          this.hasFocus = false;
        } else {
          // Add focus styling for custom file input
          this.hasFocus = true;
        }
      },
      onChange: function onChange(event) {
        var _this2 = this;

        var type = event.type,
            target = event.target,
            _event$dataTransfer = event.dataTransfer,
            dataTransfer = _event$dataTransfer === void 0 ? {} : _event$dataTransfer;
        var isDrop = type === 'drop'; // Always emit original event

        this.$emit(EVENT_NAME_CHANGE, event);
        var items = from(dataTransfer.items || []);

        if (HAS_PROMISE_SUPPORT && items.length > 0 && !isNull(getDataTransferItemEntry(items[0]))) {
          // Drop handling for modern browsers
          // Supports nested directory structures in `directory` mode

          /* istanbul ignore next: not supported in JSDOM */
          getAllFileEntries(items, this.directory).then(function (files) {
            return _this2.handleFiles(files, isDrop);
          });
        } else {
          // Standard file input handling (native file input change event),
          // or fallback drop mode (IE 11 / Opera) which don't support `directory` mode
          var files = from(target.files || dataTransfer.files || []).map(function (file) {
            // Add custom `$path` property to each file (to be consistent with drop mode)
            file.$path = file.webkitRelativePath || '';
            return file;
          });
          this.handleFiles(files, isDrop);
        }
      },
      onDragenter: function onDragenter(event) {
        stopEvent(event);
        this.dragging = true;
        var _event$dataTransfer2 = event.dataTransfer,
            dataTransfer = _event$dataTransfer2 === void 0 ? {} : _event$dataTransfer2; // Early exit when the input or dropping is disabled

        if (this.noDrop || this.disabled || !this.dropAllowed) {
          // Show deny feedback

          /* istanbul ignore next: not supported in JSDOM */
          dataTransfer.dropEffect = 'none';
          this.dropAllowed = false;
          return;
        }
        /* istanbul ignore next: not supported in JSDOM */


        dataTransfer.dropEffect = 'copy';
      },
      // Note this event fires repeatedly while the mouse is over the dropzone at
      // intervals in the milliseconds, so avoid doing much processing in here
      onDragover: function onDragover(event) {
        stopEvent(event);
        this.dragging = true;
        var _event$dataTransfer3 = event.dataTransfer,
            dataTransfer = _event$dataTransfer3 === void 0 ? {} : _event$dataTransfer3; // Early exit when the input or dropping is disabled

        if (this.noDrop || this.disabled || !this.dropAllowed) {
          // Show deny feedback

          /* istanbul ignore next: not supported in JSDOM */
          dataTransfer.dropEffect = 'none';
          this.dropAllowed = false;
          return;
        }
        /* istanbul ignore next: not supported in JSDOM */


        dataTransfer.dropEffect = 'copy';
      },
      onDragleave: function onDragleave(event) {
        var _this3 = this;

        stopEvent(event);
        this.$nextTick(function () {
          _this3.dragging = false; // Reset `dropAllowed` to default

          _this3.dropAllowed = !_this3.noDrop;
        });
      },
      // Triggered by a file drop onto drop target
      onDrop: function onDrop(event) {
        var _this4 = this;

        stopEvent(event);
        this.dragging = false; // Early exit when the input or dropping is disabled

        if (this.noDrop || this.disabled || !this.dropAllowed) {
          this.$nextTick(function () {
            // Reset `dropAllowed` to default
            _this4.dropAllowed = !_this4.noDrop;
          });
          return;
        }

        this.onChange(event);
      }
    },
    render: function render(h) {
      var custom = this.custom,
          plain = this.plain,
          size = this.size,
          dragging = this.dragging,
          stateClass = this.stateClass,
          bvAttrs = this.bvAttrs; // Form Input

      var $input = h('input', {
        class: [{
          'form-control-file': plain,
          'custom-file-input': custom,
          focus: custom && this.hasFocus
        }, stateClass],
        // With IE 11, the input gets in the "way" of the drop events,
        // so we move it out of the way by putting it behind the label
        // Bootstrap v4 has it in front
        style: custom ? {
          zIndex: -5
        } : {},
        attrs: this.computedAttrs,
        on: {
          change: this.onChange,
          focusin: this.focusHandler,
          focusout: this.focusHandler,
          reset: this.reset
        },
        ref: 'input'
      });

      if (plain) {
        return $input;
      } // Overlay label


      var $label = h('label', {
        staticClass: 'custom-file-label',
        class: {
          dragging: dragging
        },
        attrs: {
          for: this.safeId(),
          // This goes away in Bootstrap v5
          'data-browse': this.browseText || null
        }
      }, [h('span', {
        staticClass: 'd-block form-file-text',
        // `pointer-events: none` is used to make sure
        // the drag events fire only on the label
        style: {
          pointerEvents: 'none'
        }
      }, [this.labelContent])]); // Return rendered custom file input

      return h('div', {
        staticClass: 'custom-file b-form-file',
        class: [_defineProperty({}, "b-custom-control-".concat(size), size), stateClass, bvAttrs.class],
        style: bvAttrs.style,
        attrs: {
          id: this.safeId('_BV_file_outer_')
        },
        on: {
          dragenter: this.onDragenter,
          dragover: this.onDragover,
          dragleave: this.onDragleave,
          drop: this.onDrop
        }
      }, [$input, $label]);
    }
  });

  var FormFilePlugin = /*#__PURE__*/pluginFactory({
    components: {
      BFormFile: BFormFile,
      BFile: BFormFile
    }
  });

  var escapeChar = function escapeChar(value) {
    return '\\' + value;
  }; // The `cssEscape()` util is based on this `CSS.escape()` polyfill:
  // https://github.com/mathiasbynens/CSS.escape


  var cssEscape = function cssEscape(value) {
    value = toString(value);
    var length = value.length;
    var firstCharCode = value.charCodeAt(0);
    return value.split('').reduce(function (result, char, index) {
      var charCode = value.charCodeAt(index); // If the character is NULL (U+0000), use (U+FFFD) as replacement

      if (charCode === 0x0000) {
        return result + "\uFFFD";
      } // If the character ...


      if ( // ... is U+007F OR
      charCode === 0x007f || // ... is in the range [\1-\1F] (U+0001 to U+001F) OR ...
      charCode >= 0x0001 && charCode <= 0x001f || // ... is the first character and is in the range [0-9] (U+0030 to U+0039) OR ...
      index === 0 && charCode >= 0x0030 && charCode <= 0x0039 || // ... is the second character and is in the range [0-9] (U+0030 to U+0039)
      // and the first character is a `-` (U+002D) ...
      index === 1 && charCode >= 0x0030 && charCode <= 0x0039 && firstCharCode === 0x002d) {
        // ... https://drafts.csswg.org/cssom/#escape-a-character-as-code-point
        return result + escapeChar("".concat(charCode.toString(16), " "));
      } // If the character ...


      if ( // ... is the first character AND ...
      index === 0 && // ... is a `-` (U+002D) AND ...
      charCode === 0x002d && // ... there is no second character ...
      length === 1) {
        // ... use the escaped character
        return result + escapeChar(char);
      } // If the character ...


      if ( // ... is greater than or equal to U+0080 OR ...
      charCode >= 0x0080 || // ... is `-` (U+002D) OR ...
      charCode === 0x002d || // ... is `_` (U+005F) OR ...
      charCode === 0x005f || // ... is in the range [0-9] (U+0030 to U+0039) OR ...
      charCode >= 0x0030 && charCode <= 0x0039 || // ... is in the range [A-Z] (U+0041 to U+005A) OR ...
      charCode >= 0x0041 && charCode <= 0x005a || // ... is in the range [a-z] (U+0061 to U+007A) ...
      charCode >= 0x0061 && charCode <= 0x007a) {
        // ... use the character itself
        return result + char;
      } // Otherwise use the escaped character
      // See: https://drafts.csswg.org/cssom/#escape-a-character


      return result + escapeChar(char);
    }, '');
  };

  var ALIGN_SELF_VALUES = ['auto', 'start', 'end', 'center', 'baseline', 'stretch']; // --- Helper methods ---
  // Compute a breakpoint class name

  var computeBreakpoint = function computeBreakpoint(type, breakpoint, value) {
    var className = type;

    if (isUndefinedOrNull(value) || value === false) {
      return undefined;
    }

    if (breakpoint) {
      className += "-".concat(breakpoint);
    } // Handling the boolean style prop when accepting `[Boolean, String, Number]`
    // means Vue will not convert `<b-col sm></b-col>` to `sm: true` for us
    // Since the default is `false`, '' indicates the prop's presence


    if (type === 'col' && (value === '' || value === true)) {
      // .col-md
      return lowerCase(className);
    } // .order-md-6


    className += "-".concat(value);
    return lowerCase(className);
  }; // Memoized function for better performance on generating class names


  var computeBreakpointClass = memoize(computeBreakpoint); // Cached copy of the breakpoint prop names

  var breakpointPropMap = create(null); // --- Props ---
  // Prop generator for lazy generation of props

  var generateProps$2 = function generateProps() {
    // Grab the breakpoints from the cached config (exclude the '' (xs) breakpoint)
    var breakpoints = getBreakpointsUpCached().filter(identity); // i.e. 'col-sm', 'col-md-6', 'col-lg-auto', ...

    var breakpointCol = breakpoints.reduce(function (props, breakpoint) {
      props[breakpoint] = makeProp(PROP_TYPE_BOOLEAN_NUMBER_STRING);
      return props;
    }, create(null)); // i.e. 'offset-md-1', 'offset-lg-12', ...

    var breakpointOffset = breakpoints.reduce(function (props, breakpoint) {
      props[suffixPropName(breakpoint, 'offset')] = makeProp(PROP_TYPE_NUMBER_STRING);
      return props;
    }, create(null)); // i.e. 'order-md-1', 'order-lg-12', ...

    var breakpointOrder = breakpoints.reduce(function (props, breakpoint) {
      props[suffixPropName(breakpoint, 'order')] = makeProp(PROP_TYPE_NUMBER_STRING);
      return props;
    }, create(null)); // For loop doesn't need to check `.hasOwnProperty()`
    // when using an object created from `null`

    breakpointPropMap = assign(create(null), {
      col: keys(breakpointCol),
      offset: keys(breakpointOffset),
      order: keys(breakpointOrder)
    }); // Return the generated props

    return makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, breakpointCol), breakpointOffset), breakpointOrder), {}, {
      // Flex alignment
      alignSelf: makeProp(PROP_TYPE_STRING, null, function (value) {
        return arrayIncludes(ALIGN_SELF_VALUES, value);
      }),
      // Generic flexbox 'col' (xs)
      col: makeProp(PROP_TYPE_BOOLEAN, false),
      // i.e. 'col-1', 'col-2', 'col-auto', ...
      cols: makeProp(PROP_TYPE_NUMBER_STRING),
      offset: makeProp(PROP_TYPE_NUMBER_STRING),
      order: makeProp(PROP_TYPE_NUMBER_STRING),
      tag: makeProp(PROP_TYPE_STRING, 'div')
    })), NAME_COL);
  }; // --- Main component ---
  // We do not use extend here as that would evaluate the props
  // immediately, which we do not want to happen
  // @vue/component

  var BCol = {
    name: NAME_COL,
    functional: true,

    get props() {
      // Allow props to be lazy evaled on first access and
      // then they become a non-getter afterwards.
      // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get#Smart_self-overwriting_lazy_getters
      delete this.props; // eslint-disable-next-line no-return-assign

      return this.props = generateProps$2();
    },

    render: function render(h, _ref) {
      var _classList$push;

      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      var cols = props.cols,
          offset = props.offset,
          order = props.order,
          alignSelf = props.alignSelf;
      var classList = []; // Loop through `col`, `offset`, `order` breakpoint props

      for (var type in breakpointPropMap) {
        // Returns colSm, offset, offsetSm, orderMd, etc.
        var _keys = breakpointPropMap[type];

        for (var i = 0; i < _keys.length; i++) {
          // computeBreakpoint(col, colSm => Sm, value=[String, Number, Boolean])
          var c = computeBreakpointClass(type, _keys[i].replace(type, ''), props[_keys[i]]); // If a class is returned, push it onto the array.

          if (c) {
            classList.push(c);
          }
        }
      }

      var hasColClasses = classList.some(function (className) {
        return RX_COL_CLASS.test(className);
      });
      classList.push((_classList$push = {
        // Default to .col if no other col-{bp}-* classes generated nor `cols` specified.
        col: props.col || !hasColClasses && !cols
      }, _defineProperty(_classList$push, "col-".concat(cols), cols), _defineProperty(_classList$push, "offset-".concat(offset), offset), _defineProperty(_classList$push, "order-".concat(order), order), _defineProperty(_classList$push, "align-self-".concat(alignSelf), alignSelf), _classList$push));
      return h(props.tag, a(data, {
        class: classList
      }), children);
    }
  };

  var INPUTS = ['input', 'select', 'textarea']; // Selector for finding first input in the form group

  var INPUT_SELECTOR = INPUTS.map(function (v) {
    return "".concat(v, ":not([disabled])");
  }).join(); // A list of interactive elements (tag names) inside `<b-form-group>`'s legend

  var LEGEND_INTERACTIVE_ELEMENTS = [].concat(INPUTS, ['a', 'button', 'label']); // --- Props ---
  // Prop generator for lazy generation of props

  var generateProps$1 = function generateProps() {
    return makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$25), props$1u), getBreakpointsUpCached().reduce(function (props, breakpoint) {
      // i.e. 'content-cols', 'content-cols-sm', 'content-cols-md', ...
      props[suffixPropName(breakpoint, 'contentCols')] = makeProp(PROP_TYPE_BOOLEAN_NUMBER_STRING); // i.e. 'label-align', 'label-align-sm', 'label-align-md', ...

      props[suffixPropName(breakpoint, 'labelAlign')] = makeProp(PROP_TYPE_STRING); // i.e. 'label-cols', 'label-cols-sm', 'label-cols-md', ...

      props[suffixPropName(breakpoint, 'labelCols')] = makeProp(PROP_TYPE_BOOLEAN_NUMBER_STRING);
      return props;
    }, create(null))), {}, {
      description: makeProp(PROP_TYPE_STRING),
      disabled: makeProp(PROP_TYPE_BOOLEAN, false),
      feedbackAriaLive: makeProp(PROP_TYPE_STRING, 'assertive'),
      invalidFeedback: makeProp(PROP_TYPE_STRING),
      label: makeProp(PROP_TYPE_STRING),
      labelClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
      labelFor: makeProp(PROP_TYPE_STRING),
      labelSize: makeProp(PROP_TYPE_STRING),
      labelSrOnly: makeProp(PROP_TYPE_BOOLEAN, false),
      tooltip: makeProp(PROP_TYPE_BOOLEAN, false),
      validFeedback: makeProp(PROP_TYPE_STRING),
      validated: makeProp(PROP_TYPE_BOOLEAN, false)
    })), NAME_FORM_GROUP);
  }; // --- Main component ---
  // We do not use `extend()` here as that would evaluate the props
  // immediately, which we do not want to happen
  // @vue/component

  var BFormGroup = {
    name: NAME_FORM_GROUP,
    mixins: [idMixin, formStateMixin, normalizeSlotMixin],

    get props() {
      // Allow props to be lazy evaled on first access and
      // then they become a non-getter afterwards
      // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get#Smart_self-overwriting_lazy_getters
      delete this.props; // eslint-disable-next-line no-return-assign

      return this.props = generateProps$1();
    },

    data: function data() {
      return {
        ariaDescribedby: null
      };
    },
    computed: {
      contentColProps: function contentColProps() {
        return this.getColProps(this.$props, 'content');
      },
      labelAlignClasses: function labelAlignClasses() {
        return this.getAlignClasses(this.$props, 'label');
      },
      labelColProps: function labelColProps() {
        return this.getColProps(this.$props, 'label');
      },
      isHorizontal: function isHorizontal() {
        // Determine if the form group will be rendered horizontal
        // based on the existence of 'content-col' or 'label-col' props
        return keys(this.contentColProps).length > 0 || keys(this.labelColProps).length > 0;
      }
    },
    watch: {
      ariaDescribedby: function ariaDescribedby(newValue, oldValue) {
        if (newValue !== oldValue) {
          this.updateAriaDescribedby(newValue, oldValue);
        }
      }
    },
    mounted: function mounted() {
      var _this = this;

      this.$nextTick(function () {
        // Set `aria-describedby` on the input specified by `labelFor`
        // We do this in a `$nextTick()` to ensure the children have finished rendering
        _this.updateAriaDescribedby(_this.ariaDescribedby);
      });
    },
    methods: {
      getAlignClasses: function getAlignClasses(props, prefix) {
        return getBreakpointsUpCached().reduce(function (result, breakpoint) {
          var propValue = props[suffixPropName(breakpoint, "".concat(prefix, "Align"))] || null;

          if (propValue) {
            result.push(['text', breakpoint, propValue].filter(identity).join('-'));
          }

          return result;
        }, []);
      },
      getColProps: function getColProps(props, prefix) {
        return getBreakpointsUpCached().reduce(function (result, breakpoint) {
          var propValue = props[suffixPropName(breakpoint, "".concat(prefix, "Cols"))]; // Handle case where the prop's value is an empty string,
          // which represents `true`

          propValue = propValue === '' ? true : propValue || false;

          if (!isBoolean(propValue) && propValue !== 'auto') {
            // Convert to column size to number
            propValue = toInteger(propValue, 0); // Ensure column size is greater than `0`

            propValue = propValue > 0 ? propValue : false;
          } // Add the prop to the list of props to give to `<b-col>`
          // If breakpoint is '' (`${prefix}Cols` is `true`), then we use
          // the 'col' prop to make equal width at 'xs'


          if (propValue) {
            result[breakpoint || (isBoolean(propValue) ? 'col' : 'cols')] = propValue;
          }

          return result;
        }, {});
      },
      // Sets the `aria-describedby` attribute on the input if `labelFor` is set
      // Optionally accepts a string of IDs to remove as the second parameter
      // Preserves any `aria-describedby` value(s) user may have on input
      updateAriaDescribedby: function updateAriaDescribedby(newValue, oldValue) {
        var labelFor = this.labelFor;

        if (IS_BROWSER && labelFor) {
          // We need to escape `labelFor` since it can be user-provided
          var $input = select("#".concat(cssEscape(labelFor)), this.$refs.content);

          if ($input) {
            var attr = 'aria-describedby';
            var newIds = (newValue || '').split(RX_SPACE_SPLIT);
            var oldIds = (oldValue || '').split(RX_SPACE_SPLIT); // Update ID list, preserving any original IDs
            // and ensuring the ID's are unique

            var ids = (getAttr($input, attr) || '').split(RX_SPACE_SPLIT).filter(function (id) {
              return !arrayIncludes(oldIds, id);
            }).concat(newIds).filter(function (id, index, ids) {
              return ids.indexOf(id) === index;
            }).filter(identity).join(' ').trim();

            if (ids) {
              setAttr($input, attr, ids);
            } else {
              removeAttr($input, attr);
            }
          }
        }
      },
      onLegendClick: function onLegendClick(event) {
        // Don't do anything if `labelFor` is set

        /* istanbul ignore next: clicking a label will focus the input, so no need to test */
        if (this.labelFor) {
          return;
        }

        var target = event.target;
        var tagName = target ? target.tagName : ''; // If clicked an interactive element inside legend,
        // we just let the default happen

        /* istanbul ignore next */

        if (LEGEND_INTERACTIVE_ELEMENTS.indexOf(tagName) !== -1) {
          return;
        } // If only a single input, focus it, emulating label behaviour


        var inputs = selectAll(INPUT_SELECTOR, this.$refs.content).filter(isVisible);

        if (inputs.length === 1) {
          attemptFocus(inputs[0]);
        }
      }
    },
    render: function render(h) {
      var state = this.computedState,
          feedbackAriaLive = this.feedbackAriaLive,
          isHorizontal = this.isHorizontal,
          labelFor = this.labelFor,
          normalizeSlot = this.normalizeSlot,
          safeId = this.safeId,
          tooltip = this.tooltip;
      var id = safeId();
      var isFieldset = !labelFor;
      var $label = h();
      var labelContent = normalizeSlot(SLOT_NAME_LABEL) || this.label;
      var labelId = labelContent ? safeId('_BV_label_') : null;

      if (labelContent || isHorizontal) {
        var labelSize = this.labelSize,
            labelColProps = this.labelColProps;
        var labelTag = isFieldset ? 'legend' : 'label';

        if (this.labelSrOnly) {
          if (labelContent) {
            $label = h(labelTag, {
              class: 'sr-only',
              attrs: {
                id: labelId,
                for: labelFor || null
              }
            }, [labelContent]);
          }

          $label = h(isHorizontal ? BCol : 'div', {
            props: isHorizontal ? labelColProps : {}
          }, [$label]);
        } else {
          $label = h(isHorizontal ? BCol : labelTag, {
            on: isFieldset ? {
              click: this.onLegendClick
            } : {},
            props: isHorizontal ? _objectSpread2$3(_objectSpread2$3({}, labelColProps), {}, {
              tag: labelTag
            }) : {},
            attrs: {
              id: labelId,
              for: labelFor || null,
              // We add a `tabindex` to legend so that screen readers
              // will properly read the `aria-labelledby` in IE
              tabindex: isFieldset ? '-1' : null
            },
            class: [// Hide the focus ring on the legend
            isFieldset ? 'bv-no-focus-ring' : '', // When horizontal or if a legend is rendered, add 'col-form-label' class
            // for correct sizing as Bootstrap has inconsistent font styling for
            // legend in non-horizontal form groups
            // See: https://github.com/twbs/bootstrap/issues/27805
            isHorizontal || isFieldset ? 'col-form-label' : '', // Emulate label padding top of `0` on legend when not horizontal
            !isHorizontal && isFieldset ? 'pt-0' : '', // If not horizontal and not a legend, we add 'd-block' class to label
            // so that label-align works
            !isHorizontal && !isFieldset ? 'd-block' : '', labelSize ? "col-form-label-".concat(labelSize) : '', this.labelAlignClasses, this.labelClass]
          }, [labelContent]);
        }
      }

      var $invalidFeedback = h();
      var invalidFeedbackContent = normalizeSlot(SLOT_NAME_INVALID_FEEDBACK) || this.invalidFeedback;
      var invalidFeedbackId = invalidFeedbackContent ? safeId('_BV_feedback_invalid_') : null;

      if (invalidFeedbackContent) {
        $invalidFeedback = h(BFormInvalidFeedback, {
          props: {
            ariaLive: feedbackAriaLive,
            id: invalidFeedbackId,
            // If state is explicitly `false`, always show the feedback
            state: state,
            tooltip: tooltip
          },
          attrs: {
            tabindex: invalidFeedbackContent ? '-1' : null
          }
        }, [invalidFeedbackContent]);
      }

      var $validFeedback = h();
      var validFeedbackContent = normalizeSlot(SLOT_NAME_VALID_FEEDBACK) || this.validFeedback;
      var validFeedbackId = validFeedbackContent ? safeId('_BV_feedback_valid_') : null;

      if (validFeedbackContent) {
        $validFeedback = h(BFormValidFeedback, {
          props: {
            ariaLive: feedbackAriaLive,
            id: validFeedbackId,
            // If state is explicitly `true`, always show the feedback
            state: state,
            tooltip: tooltip
          },
          attrs: {
            tabindex: validFeedbackContent ? '-1' : null
          }
        }, [validFeedbackContent]);
      }

      var $description = h();
      var descriptionContent = normalizeSlot(SLOT_NAME_DESCRIPTION) || this.description;
      var descriptionId = descriptionContent ? safeId('_BV_description_') : null;

      if (descriptionContent) {
        $description = h(BFormText, {
          attrs: {
            id: descriptionId,
            tabindex: '-1'
          }
        }, [descriptionContent]);
      } // Update `ariaDescribedby`
      // Screen readers will read out any content linked to by `aria-describedby`
      // even if the content is hidden with `display: none;`, hence we only include
      // feedback IDs if the form group's state is explicitly valid or invalid


      var ariaDescribedby = this.ariaDescribedby = [descriptionId, state === false ? invalidFeedbackId : null, state === true ? validFeedbackId : null].filter(identity).join(' ') || null;
      var $content = h(isHorizontal ? BCol : 'div', {
        props: isHorizontal ? this.contentColProps : {},
        ref: 'content'
      }, [normalizeSlot(SLOT_NAME_DEFAULT, {
        ariaDescribedby: ariaDescribedby,
        descriptionId: descriptionId,
        id: id,
        labelId: labelId
      }) || h(), $invalidFeedback, $validFeedback, $description]); // Return it wrapped in a form group
      // Note: Fieldsets do not support adding `row` or `form-row` directly
      // to them due to browser specific render issues, so we move the `form-row`
      // to an inner wrapper div when horizontal and using a fieldset

      return h(isFieldset ? 'fieldset' : isHorizontal ? BFormRow : 'div', {
        staticClass: 'form-group',
        class: [{
          'was-validated': this.validated
        }, this.stateClass],
        attrs: {
          id: id,
          disabled: isFieldset ? this.disabled : null,
          role: isFieldset ? null : 'group',
          'aria-invalid': this.computedAriaInvalid,
          // Only apply `aria-labelledby` if we are a horizontal fieldset
          // as the legend is no longer a direct child of fieldset
          'aria-labelledby': isFieldset && isHorizontal ? labelId : null
        }
      }, isHorizontal && isFieldset ? [h(BFormRow, [$label, $content])] : [$label, $content]);
    }
  };

  var FormGroupPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BFormGroup: BFormGroup,
      BFormFieldset: BFormGroup
    }
  });

  var formSelectionMixin = extend({
    computed: {
      selectionStart: {
        // Expose selectionStart for formatters, etc
        cache: false,

        /* istanbul ignore next */
        get: function get() {
          return this.$refs.input.selectionStart;
        },

        /* istanbul ignore next */
        set: function set(val) {
          this.$refs.input.selectionStart = val;
        }
      },
      selectionEnd: {
        // Expose selectionEnd for formatters, etc
        cache: false,

        /* istanbul ignore next */
        get: function get() {
          return this.$refs.input.selectionEnd;
        },

        /* istanbul ignore next */
        set: function set(val) {
          this.$refs.input.selectionEnd = val;
        }
      },
      selectionDirection: {
        // Expose selectionDirection for formatters, etc
        cache: false,

        /* istanbul ignore next */
        get: function get() {
          return this.$refs.input.selectionDirection;
        },

        /* istanbul ignore next */
        set: function set(val) {
          this.$refs.input.selectionDirection = val;
        }
      }
    },
    methods: {
      /* istanbul ignore next */
      select: function select() {
        var _this$$refs$input;

        // For external handler that may want a select() method
        (_this$$refs$input = this.$refs.input).select.apply(_this$$refs$input, arguments);
      },

      /* istanbul ignore next */
      setSelectionRange: function setSelectionRange() {
        var _this$$refs$input2;

        // For external handler that may want a setSelectionRange(a,b,c) method
        (_this$$refs$input2 = this.$refs.input).setSelectionRange.apply(_this$$refs$input2, arguments);
      },

      /* istanbul ignore next */
      setRangeText: function setRangeText() {
        var _this$$refs$input3;

        // For external handler that may want a setRangeText(a,b,c) method
        (_this$$refs$input3 = this.$refs.input).setRangeText.apply(_this$$refs$input3, arguments);
      }
    }
  });

  var _makeModelMixin$c = makeModelMixin('value', {
    type: PROP_TYPE_NUMBER_STRING,
    defaultValue: '',
    event: EVENT_NAME_UPDATE
  }),
      modelMixin$b = _makeModelMixin$c.mixin,
      modelProps$b = _makeModelMixin$c.props,
      MODEL_PROP_NAME$b = _makeModelMixin$c.prop,
      MODEL_EVENT_NAME$b = _makeModelMixin$c.event;

  var props$1l = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, modelProps$b), {}, {
    ariaInvalid: makeProp(PROP_TYPE_BOOLEAN_STRING, false),
    autocomplete: makeProp(PROP_TYPE_STRING),
    // Debounce timeout (in ms). Not applicable with `lazy` prop
    debounce: makeProp(PROP_TYPE_NUMBER_STRING, 0),
    formatter: makeProp(PROP_TYPE_FUNCTION),
    // Only update the `v-model` on blur/change events
    lazy: makeProp(PROP_TYPE_BOOLEAN, false),
    lazyFormatter: makeProp(PROP_TYPE_BOOLEAN, false),
    number: makeProp(PROP_TYPE_BOOLEAN, false),
    placeholder: makeProp(PROP_TYPE_STRING),
    plaintext: makeProp(PROP_TYPE_BOOLEAN, false),
    readonly: makeProp(PROP_TYPE_BOOLEAN, false),
    trim: makeProp(PROP_TYPE_BOOLEAN, false)
  })), 'formTextControls'); // --- Mixin ---
  // @vue/component

  var formTextMixin = extend({
    mixins: [modelMixin$b],
    props: props$1l,
    data: function data() {
      var value = this[MODEL_PROP_NAME$b];
      return {
        localValue: toString(value),
        vModelValue: this.modifyValue(value)
      };
    },
    computed: {
      computedClass: function computedClass() {
        var plaintext = this.plaintext,
            type = this.type;
        var isRange = type === 'range';
        var isColor = type === 'color';
        return [{
          // Range input needs class `custom-range`
          'custom-range': isRange,
          // `plaintext` not supported by `type="range"` or `type="color"`
          'form-control-plaintext': plaintext && !isRange && !isColor,
          // `form-control` not used by `type="range"` or `plaintext`
          // Always used by `type="color"`
          'form-control': isColor || !plaintext && !isRange
        }, this.sizeFormClass, this.stateClass];
      },
      computedDebounce: function computedDebounce() {
        // Ensure we have a positive number equal to or greater than 0
        return mathMax(toInteger(this.debounce, 0), 0);
      },
      hasFormatter: function hasFormatter() {
        return hasPropFunction(this.formatter);
      }
    },
    watch: _defineProperty({}, MODEL_PROP_NAME$b, function (newValue) {
      var stringifyValue = toString(newValue);
      var modifiedValue = this.modifyValue(newValue);

      if (stringifyValue !== this.localValue || modifiedValue !== this.vModelValue) {
        // Clear any pending debounce timeout, as we are overwriting the user input
        this.clearDebounce(); // Update the local values

        this.localValue = stringifyValue;
        this.vModelValue = modifiedValue;
      }
    }),
    created: function created() {
      // Create private non-reactive props
      this.$_inputDebounceTimer = null;
    },
    beforeDestroy: function beforeDestroy() {
      this.clearDebounce();
    },
    methods: {
      clearDebounce: function clearDebounce() {
        clearTimeout(this.$_inputDebounceTimer);
        this.$_inputDebounceTimer = null;
      },
      formatValue: function formatValue(value, event) {
        var force = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
        value = toString(value);

        if (this.hasFormatter && (!this.lazyFormatter || force)) {
          value = this.formatter(value, event);
        }

        return value;
      },
      modifyValue: function modifyValue(value) {
        value = toString(value); // Emulate `.trim` modifier behaviour

        if (this.trim) {
          value = value.trim();
        } // Emulate `.number` modifier behaviour


        if (this.number) {
          value = toFloat(value, value);
        }

        return value;
      },
      updateValue: function updateValue(value) {
        var _this = this;

        var force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
        var lazy = this.lazy;

        if (lazy && !force) {
          return;
        } // Make sure to always clear the debounce when `updateValue()`
        // is called, even when the v-model hasn't changed


        this.clearDebounce(); // Define the shared update logic in a method to be able to use
        // it for immediate and debounced value changes

        var doUpdate = function doUpdate() {
          value = _this.modifyValue(value);

          if (value !== _this.vModelValue) {
            _this.vModelValue = value;

            _this.$emit(MODEL_EVENT_NAME$b, value);
          } else if (_this.hasFormatter) {
            // When the `vModelValue` hasn't changed but the actual input value
            // is out of sync, make sure to change it to the given one
            // Usually caused by browser autocomplete and how it triggers the
            // change or input event, or depending on the formatter function
            // https://github.com/bootstrap-vue/bootstrap-vue/issues/2657
            // https://github.com/bootstrap-vue/bootstrap-vue/issues/3498

            /* istanbul ignore next: hard to test */
            var $input = _this.$refs.input;
            /* istanbul ignore if: hard to test out of sync value */

            if ($input && value !== $input.value) {
              $input.value = value;
            }
          }
        }; // Only debounce the value update when a value greater than `0`
        // is set and we are not in lazy mode or this is a forced update


        var debounce = this.computedDebounce;

        if (debounce > 0 && !lazy && !force) {
          this.$_inputDebounceTimer = setTimeout(doUpdate, debounce);
        } else {
          // Immediately update the v-model
          doUpdate();
        }
      },
      onInput: function onInput(event) {
        // `event.target.composing` is set by Vue
        // https://github.com/vuejs/vue/blob/dev/src/platforms/web/runtime/directives/model.js
        // TODO: Is this needed now with the latest Vue?

        /* istanbul ignore if: hard to test composition events */
        if (event.target.composing) {
          return;
        }

        var value = event.target.value;
        var formattedValue = this.formatValue(value, event); // Exit when the `formatter` function strictly returned `false`
        // or prevented the input event

        /* istanbul ignore next */

        if (formattedValue === false || event.defaultPrevented) {
          stopEvent(event, {
            propagation: false
          });
          return;
        }

        this.localValue = formattedValue;
        this.updateValue(formattedValue);
        this.$emit(EVENT_NAME_INPUT, formattedValue);
      },
      onChange: function onChange(event) {
        var value = event.target.value;
        var formattedValue = this.formatValue(value, event); // Exit when the `formatter` function strictly returned `false`
        // or prevented the input event

        /* istanbul ignore next */

        if (formattedValue === false || event.defaultPrevented) {
          stopEvent(event, {
            propagation: false
          });
          return;
        }

        this.localValue = formattedValue;
        this.updateValue(formattedValue, true);
        this.$emit(EVENT_NAME_CHANGE, formattedValue);
      },
      onBlur: function onBlur(event) {
        // Apply the `localValue` on blur to prevent cursor jumps
        // on mobile browsers (e.g. caused by autocomplete)
        var value = event.target.value;
        var formattedValue = this.formatValue(value, event, true);

        if (formattedValue !== false) {
          // We need to use the modified value here to apply the
          // `.trim` and `.number` modifiers properly
          this.localValue = toString(this.modifyValue(formattedValue)); // We pass the formatted value here since the `updateValue` method
          // handles the modifiers itself

          this.updateValue(formattedValue, true);
        } // Emit native blur event


        this.$emit(EVENT_NAME_BLUR, event);
      },
      focus: function focus() {
        // For external handler that may want a focus method
        if (!this.disabled) {
          attemptFocus(this.$el);
        }
      },
      blur: function blur() {
        // For external handler that may want a blur method
        if (!this.disabled) {
          attemptBlur(this.$el);
        }
      }
    }
  });

  var formValidityMixin = extend({
    computed: {
      validity: {
        // Expose validity property
        cache: false,

        /* istanbul ignore next */
        get: function get() {
          return this.$refs.input.validity;
        }
      },
      validationMessage: {
        // Expose validationMessage property
        cache: false,

        /* istanbul ignore next */
        get: function get() {
          return this.$refs.input.validationMessage;
        }
      },
      willValidate: {
        // Expose willValidate property
        cache: false,

        /* istanbul ignore next */
        get: function get() {
          return this.$refs.input.willValidate;
        }
      }
    },
    methods: {
      /* istanbul ignore next */
      setCustomValidity: function setCustomValidity() {
        var _this$$refs$input;

        // For external handler that may want a setCustomValidity(...) method
        return (_this$$refs$input = this.$refs.input).setCustomValidity.apply(_this$$refs$input, arguments);
      },

      /* istanbul ignore next */
      checkValidity: function checkValidity() {
        var _this$$refs$input2;

        // For external handler that may want a checkValidity(...) method
        return (_this$$refs$input2 = this.$refs.input).checkValidity.apply(_this$$refs$input2, arguments);
      },

      /* istanbul ignore next */
      reportValidity: function reportValidity() {
        var _this$$refs$input3;

        // For external handler that may want a reportValidity(...) method
        return (_this$$refs$input3 = this.$refs.input).reportValidity.apply(_this$$refs$input3, arguments);
      }
    }
  });

  // Valid supported input types

  var TYPES$1 = ['text', 'password', 'email', 'number', 'url', 'tel', 'search', 'range', 'color', 'date', 'time', 'datetime', 'datetime-local', 'month', 'week']; // --- Props ---

  var props$1k = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$25), props$1x), props$1v), props$1u), props$1l), {}, {
    list: makeProp(PROP_TYPE_STRING),
    max: makeProp(PROP_TYPE_NUMBER_STRING),
    min: makeProp(PROP_TYPE_NUMBER_STRING),
    // Disable mousewheel to prevent wheel from changing values (i.e. number/date)
    noWheel: makeProp(PROP_TYPE_BOOLEAN, false),
    step: makeProp(PROP_TYPE_NUMBER_STRING),
    type: makeProp(PROP_TYPE_STRING, 'text', function (type) {
      return arrayIncludes(TYPES$1, type);
    })
  })), NAME_FORM_INPUT); // --- Main component ---
  // @vue/component

  var BFormInput = /*#__PURE__*/extend({
    name: NAME_FORM_INPUT,
    // Mixin order is important!
    mixins: [listenersMixin, idMixin, formControlMixin, formSizeMixin, formStateMixin, formTextMixin, formSelectionMixin, formValidityMixin],
    props: props$1k,
    computed: {
      localType: function localType() {
        // We only allow certain types
        var type = this.type;
        return arrayIncludes(TYPES$1, type) ? type : 'text';
      },
      computedAttrs: function computedAttrs() {
        var type = this.localType,
            name = this.name,
            form = this.form,
            disabled = this.disabled,
            placeholder = this.placeholder,
            required = this.required,
            min = this.min,
            max = this.max,
            step = this.step;
        return {
          id: this.safeId(),
          name: name,
          form: form,
          type: type,
          disabled: disabled,
          placeholder: placeholder,
          required: required,
          autocomplete: this.autocomplete || null,
          readonly: this.readonly || this.plaintext,
          min: min,
          max: max,
          step: step,
          list: type !== 'password' ? this.list : null,
          'aria-required': required ? 'true' : null,
          'aria-invalid': this.computedAriaInvalid
        };
      },
      computedListeners: function computedListeners() {
        return _objectSpread2$3(_objectSpread2$3({}, this.bvListeners), {}, {
          input: this.onInput,
          change: this.onChange,
          blur: this.onBlur
        });
      }
    },
    watch: {
      noWheel: function noWheel(newValue) {
        this.setWheelStopper(newValue);
      }
    },
    mounted: function mounted() {
      this.setWheelStopper(this.noWheel);
    },

    /* istanbul ignore next */
    deactivated: function deactivated() {
      // Turn off listeners when keep-alive component deactivated

      /* istanbul ignore next */
      this.setWheelStopper(false);
    },

    /* istanbul ignore next */
    activated: function activated() {
      // Turn on listeners (if no-wheel) when keep-alive component activated

      /* istanbul ignore next */
      this.setWheelStopper(this.noWheel);
    },
    beforeDestroy: function beforeDestroy() {
      /* istanbul ignore next */
      this.setWheelStopper(false);
    },
    methods: {
      setWheelStopper: function setWheelStopper(on) {
        var input = this.$el; // We use native events, so that we don't interfere with propagation

        eventOnOff(on, input, 'focus', this.onWheelFocus);
        eventOnOff(on, input, 'blur', this.onWheelBlur);

        if (!on) {
          eventOff(document, 'wheel', this.stopWheel);
        }
      },
      onWheelFocus: function onWheelFocus() {
        eventOn(document, 'wheel', this.stopWheel);
      },
      onWheelBlur: function onWheelBlur() {
        eventOff(document, 'wheel', this.stopWheel);
      },
      stopWheel: function stopWheel(event) {
        stopEvent(event, {
          propagation: false
        });
        attemptBlur(this.$el);
      }
    },
    render: function render(h) {
      return h('input', {
        class: this.computedClass,
        attrs: this.computedAttrs,
        domProps: {
          value: this.localValue
        },
        on: this.computedListeners,
        ref: 'input'
      });
    }
  });

  var FormInputPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BFormInput: BFormInput,
      BInput: BFormInput
    }
  });

  var props$1j = makePropsConfigurable(props$1q, NAME_FORM_RADIO_GROUP); // --- Main component ---
  // @vue/component

  var BFormRadioGroup = /*#__PURE__*/extend({
    name: NAME_FORM_RADIO_GROUP,
    mixins: [formRadioCheckGroupMixin],
    provide: function provide() {
      var _this = this;

      return {
        getBvRadioGroup: function getBvRadioGroup() {
          return _this;
        }
      };
    },
    props: props$1j,
    computed: {
      isRadioGroup: function isRadioGroup() {
        return true;
      }
    }
  });

  var FormRadioPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BFormRadio: BFormRadio,
      BRadio: BFormRadio,
      BFormRadioGroup: BFormRadioGroup,
      BRadioGroup: BFormRadioGroup
    }
  });

  var _watch$b;

  var _makeModelMixin$b = makeModelMixin('value', {
    type: PROP_TYPE_NUMBER_STRING,
    event: EVENT_NAME_CHANGE
  }),
      modelMixin$a = _makeModelMixin$b.mixin,
      modelProps$a = _makeModelMixin$b.props,
      MODEL_PROP_NAME$a = _makeModelMixin$b.prop,
      MODEL_EVENT_NAME$a = _makeModelMixin$b.event;

  var MIN_STARS = 3;
  var DEFAULT_STARS = 5; // --- Helper methods ---

  var computeStars = function computeStars(stars) {
    return mathMax(MIN_STARS, toInteger(stars, DEFAULT_STARS));
  };

  var clampValue = function clampValue(value, min, max) {
    return mathMax(mathMin(value, max), min);
  }; // --- Helper components ---
  // @vue/component


  var BVFormRatingStar = extend({
    name: NAME_FORM_RATING_STAR,
    mixins: [normalizeSlotMixin],
    props: {
      disabled: makeProp(PROP_TYPE_BOOLEAN, false),
      // If parent is focused
      focused: makeProp(PROP_TYPE_BOOLEAN, false),
      hasClear: makeProp(PROP_TYPE_BOOLEAN, false),
      rating: makeProp(PROP_TYPE_NUMBER, 0),
      readonly: makeProp(PROP_TYPE_BOOLEAN, false),
      star: makeProp(PROP_TYPE_NUMBER, 0),
      variant: makeProp(PROP_TYPE_STRING)
    },
    methods: {
      onClick: function onClick(event) {
        if (!this.disabled && !this.readonly) {
          stopEvent(event, {
            propagation: false
          });
          this.$emit(EVENT_NAME_SELECTED, this.star);
        }
      }
    },
    render: function render(h) {
      var rating = this.rating,
          star = this.star,
          focused = this.focused,
          hasClear = this.hasClear,
          variant = this.variant,
          disabled = this.disabled,
          readonly = this.readonly;
      var minStar = hasClear ? 0 : 1;
      var type = rating >= star ? 'full' : rating >= star - 0.5 ? 'half' : 'empty';
      var slotScope = {
        variant: variant,
        disabled: disabled,
        readonly: readonly
      };
      return h('span', {
        staticClass: 'b-rating-star',
        class: {
          // When not hovered, we use this class to focus the current (or first) star
          focused: focused && rating === star || !toInteger(rating) && star === minStar,
          // We add type classes to we can handle RTL styling
          'b-rating-star-empty': type === 'empty',
          'b-rating-star-half': type === 'half',
          'b-rating-star-full': type === 'full'
        },
        attrs: {
          tabindex: !disabled && !readonly ? '-1' : null
        },
        on: {
          click: this.onClick
        }
      }, [h('span', {
        staticClass: 'b-rating-icon'
      }, [this.normalizeSlot(type, slotScope)])]);
    }
  }); // --- Props ---

  var props$1i = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$25), modelProps$a), omit(props$1x, ['required', 'autofocus'])), props$1v), {}, {
    // CSS color string (overrides variant)
    color: makeProp(PROP_TYPE_STRING),
    iconClear: makeProp(PROP_TYPE_STRING, 'x'),
    iconEmpty: makeProp(PROP_TYPE_STRING, 'star'),
    iconFull: makeProp(PROP_TYPE_STRING, 'star-fill'),
    iconHalf: makeProp(PROP_TYPE_STRING, 'star-half'),
    inline: makeProp(PROP_TYPE_BOOLEAN, false),
    // Locale for the formatted value (if shown)
    // Defaults to the browser locale. Falls back to `en`
    locale: makeProp(PROP_TYPE_ARRAY_STRING),
    noBorder: makeProp(PROP_TYPE_BOOLEAN, false),
    precision: makeProp(PROP_TYPE_NUMBER_STRING),
    readonly: makeProp(PROP_TYPE_BOOLEAN, false),
    showClear: makeProp(PROP_TYPE_BOOLEAN, false),
    showValue: makeProp(PROP_TYPE_BOOLEAN, false),
    showValueMax: makeProp(PROP_TYPE_BOOLEAN, false),
    stars: makeProp(PROP_TYPE_NUMBER_STRING, DEFAULT_STARS, function (value) {
      return toInteger(value) >= MIN_STARS;
    }),
    variant: makeProp(PROP_TYPE_STRING)
  })), NAME_FORM_RATING); // --- Main component ---
  // @vue/component

  var BFormRating = /*#__PURE__*/extend({
    name: NAME_FORM_RATING,
    components: {
      BIconStar: BIconStar,
      BIconStarHalf: BIconStarHalf,
      BIconStarFill: BIconStarFill,
      BIconX: BIconX
    },
    mixins: [idMixin, modelMixin$a, formSizeMixin],
    props: props$1i,
    data: function data() {
      var value = toFloat(this[MODEL_PROP_NAME$a], null);
      var stars = computeStars(this.stars);
      return {
        localValue: isNull(value) ? null : clampValue(value, 0, stars),
        hasFocus: false
      };
    },
    computed: {
      computedStars: function computedStars() {
        return computeStars(this.stars);
      },
      computedRating: function computedRating() {
        var value = toFloat(this.localValue, 0);
        var precision = toInteger(this.precision, 3); // We clamp the value between `0` and stars

        return clampValue(toFloat(value.toFixed(precision)), 0, this.computedStars);
      },
      computedLocale: function computedLocale() {
        var locales = concat(this.locale).filter(identity);
        var nf = new Intl.NumberFormat(locales);
        return nf.resolvedOptions().locale;
      },
      isInteractive: function isInteractive() {
        return !this.disabled && !this.readonly;
      },
      isRTL: function isRTL() {
        return isLocaleRTL(this.computedLocale);
      },
      formattedRating: function formattedRating() {
        var precision = toInteger(this.precision);
        var showValueMax = this.showValueMax;
        var locale = this.computedLocale;
        var formatOptions = {
          notation: 'standard',
          minimumFractionDigits: isNaN(precision) ? 0 : precision,
          maximumFractionDigits: isNaN(precision) ? 3 : precision
        };
        var stars = this.computedStars.toLocaleString(locale);
        var value = this.localValue;
        value = isNull(value) ? showValueMax ? '-' : '' : value.toLocaleString(locale, formatOptions);
        return showValueMax ? "".concat(value, "/").concat(stars) : value;
      }
    },
    watch: (_watch$b = {}, _defineProperty(_watch$b, MODEL_PROP_NAME$a, function (newValue, oldValue) {
      if (newValue !== oldValue) {
        var value = toFloat(newValue, null);
        this.localValue = isNull(value) ? null : clampValue(value, 0, this.computedStars);
      }
    }), _defineProperty(_watch$b, "localValue", function localValue(newValue, oldValue) {
      if (newValue !== oldValue && newValue !== (this.value || 0)) {
        this.$emit(MODEL_EVENT_NAME$a, newValue || null);
      }
    }), _defineProperty(_watch$b, "disabled", function disabled(newValue) {
      if (newValue) {
        this.hasFocus = false;
        this.blur();
      }
    }), _watch$b),
    methods: {
      // --- Public methods ---
      focus: function focus() {
        if (!this.disabled) {
          attemptFocus(this.$el);
        }
      },
      blur: function blur() {
        if (!this.disabled) {
          attemptBlur(this.$el);
        }
      },
      // --- Private methods ---
      onKeydown: function onKeydown(event) {
        var keyCode = event.keyCode;

        if (this.isInteractive && arrayIncludes([CODE_LEFT, CODE_DOWN, CODE_RIGHT, CODE_UP], keyCode)) {
          stopEvent(event, {
            propagation: false
          });
          var value = toInteger(this.localValue, 0);
          var min = this.showClear ? 0 : 1;
          var stars = this.computedStars; // In RTL mode, LEFT/RIGHT are swapped

          var amountRtl = this.isRTL ? -1 : 1;

          if (keyCode === CODE_LEFT) {
            this.localValue = clampValue(value - amountRtl, min, stars) || null;
          } else if (keyCode === CODE_RIGHT) {
            this.localValue = clampValue(value + amountRtl, min, stars);
          } else if (keyCode === CODE_DOWN) {
            this.localValue = clampValue(value - 1, min, stars) || null;
          } else if (keyCode === CODE_UP) {
            this.localValue = clampValue(value + 1, min, stars);
          }
        }
      },
      onSelected: function onSelected(value) {
        if (this.isInteractive) {
          this.localValue = value;
        }
      },
      onFocus: function onFocus(event) {
        this.hasFocus = !this.isInteractive ? false : event.type === 'focus';
      },
      // --- Render methods ---
      renderIcon: function renderIcon(icon) {
        return this.$createElement(BIcon, {
          props: {
            icon: icon,
            variant: this.disabled || this.color ? null : this.variant || null
          }
        });
      },
      iconEmptyFn: function iconEmptyFn() {
        return this.renderIcon(this.iconEmpty);
      },
      iconHalfFn: function iconHalfFn() {
        return this.renderIcon(this.iconHalf);
      },
      iconFullFn: function iconFullFn() {
        return this.renderIcon(this.iconFull);
      },
      iconClearFn: function iconClearFn() {
        return this.$createElement(BIcon, {
          props: {
            icon: this.iconClear
          }
        });
      }
    },
    render: function render(h) {
      var _this = this;

      var disabled = this.disabled,
          readonly = this.readonly,
          name = this.name,
          form = this.form,
          inline = this.inline,
          variant = this.variant,
          color = this.color,
          noBorder = this.noBorder,
          hasFocus = this.hasFocus,
          computedRating = this.computedRating,
          computedStars = this.computedStars,
          formattedRating = this.formattedRating,
          showClear = this.showClear,
          isRTL = this.isRTL,
          isInteractive = this.isInteractive,
          $scopedSlots = this.$scopedSlots;
      var $content = [];

      if (showClear && !disabled && !readonly) {
        var $icon = h('span', {
          staticClass: 'b-rating-icon'
        }, [($scopedSlots[SLOT_NAME_ICON_CLEAR] || this.iconClearFn)()]);
        $content.push(h('span', {
          staticClass: 'b-rating-star b-rating-star-clear flex-grow-1',
          class: {
            focused: hasFocus && computedRating === 0
          },
          attrs: {
            tabindex: isInteractive ? '-1' : null
          },
          on: {
            click: function click() {
              return _this.onSelected(null);
            }
          },
          key: 'clear'
        }, [$icon]));
      }

      for (var index = 0; index < computedStars; index++) {
        var value = index + 1;
        $content.push(h(BVFormRatingStar, {
          staticClass: 'flex-grow-1',
          style: color && !disabled ? {
            color: color
          } : {},
          props: {
            rating: computedRating,
            star: value,
            variant: disabled ? null : variant || null,
            disabled: disabled,
            readonly: readonly,
            focused: hasFocus,
            hasClear: showClear
          },
          on: {
            selected: this.onSelected
          },
          scopedSlots: {
            empty: $scopedSlots[SLOT_NAME_ICON_EMPTY] || this.iconEmptyFn,
            half: $scopedSlots[SLOT_NAME_ICON_HALF] || this.iconHalfFn,
            full: $scopedSlots[SLOT_NAME_ICON_FULL] || this.iconFullFn
          },
          key: index
        }));
      }

      if (name) {
        $content.push(h('input', {
          attrs: {
            type: 'hidden',
            value: isNull(this.localValue) ? '' : computedRating,
            name: name,
            form: form || null
          },
          key: 'hidden'
        }));
      }

      if (this.showValue) {
        $content.push(h('b', {
          staticClass: 'b-rating-value flex-grow-1',
          attrs: {
            'aria-hidden': 'true'
          },
          key: 'value'
        }, toString(formattedRating)));
      }

      return h('output', {
        staticClass: 'b-rating form-control align-items-center',
        class: [{
          'd-inline-flex': inline,
          'd-flex': !inline,
          'border-0': noBorder,
          disabled: disabled,
          readonly: !disabled && readonly
        }, this.sizeFormClass],
        attrs: {
          id: this.safeId(),
          dir: isRTL ? 'rtl' : 'ltr',
          tabindex: disabled ? null : '0',
          disabled: disabled,
          role: 'slider',
          'aria-disabled': disabled ? 'true' : null,
          'aria-readonly': !disabled && readonly ? 'true' : null,
          'aria-live': 'off',
          'aria-valuemin': showClear ? '0' : '1',
          'aria-valuemax': toString(computedStars),
          'aria-valuenow': computedRating ? toString(computedRating) : null
        },
        on: {
          keydown: this.onKeydown,
          focus: this.onFocus,
          blur: this.onFocus
        }
      }, $content);
    }
  });

  var FormRatingPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BFormRating: BFormRating,
      BRating: BFormRating
    }
  });

  var _makeModelMixin$a = makeModelMixin('value'),
      mixin = _makeModelMixin$a.mixin,
      props$1h = _makeModelMixin$a.props,
      prop = _makeModelMixin$a.prop,
      event = _makeModelMixin$a.event;

  var props$1g = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, props$1D), {}, {
    labelField: makeProp(PROP_TYPE_STRING, 'label'),
    optionsField: makeProp(PROP_TYPE_STRING, 'options')
  })), 'formOptions'); // --- Mixin ---
  // @vue/component

  var optionsMixin = extend({
    mixins: [formOptionsMixin],
    props: props$1g,
    methods: {
      normalizeOption: function normalizeOption(option) {
        var key = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;

        // When the option is an object, normalize it
        if (isPlainObject(option)) {
          var value = get(option, this.valueField);
          var text = get(option, this.textField);
          var options = get(option, this.optionsField, null); // When it has options, create an `<optgroup>` object

          if (!isNull(options)) {
            return {
              label: String(get(option, this.labelField) || text),
              options: this.normalizeOptions(options)
            };
          } // Otherwise create an `<option>` object


          return {
            value: isUndefined(value) ? key || text : value,
            text: String(isUndefined(text) ? key : text),
            html: get(option, this.htmlField),
            disabled: Boolean(get(option, this.disabledField))
          };
        } // Otherwise create an `<option>` object from the given value


        return {
          value: key || option,
          text: String(option),
          disabled: false
        };
      }
    }
  });

  var props$1f = makePropsConfigurable({
    disabled: makeProp(PROP_TYPE_BOOLEAN, false),
    value: makeProp(PROP_TYPE_ANY, undefined, true) // Required

  }, NAME_FORM_SELECT_OPTION); // --- Main component ---
  // @vue/component

  var BFormSelectOption = /*#__PURE__*/extend({
    name: NAME_FORM_SELECT_OPTION,
    functional: true,
    props: props$1f,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      var value = props.value,
          disabled = props.disabled;
      return h('option', a(data, {
        attrs: {
          disabled: disabled
        },
        domProps: {
          value: value
        }
      }), children);
    }
  });

  var props$1e = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, props$1D), {}, {
    label: makeProp(PROP_TYPE_STRING, undefined, true) // Required

  })), NAME_FORM_SELECT_OPTION_GROUP); // --- Main component ---
  // @vue/component

  var BFormSelectOptionGroup = /*#__PURE__*/extend({
    name: NAME_FORM_SELECT_OPTION_GROUP,
    mixins: [normalizeSlotMixin, formOptionsMixin],
    props: props$1e,
    render: function render(h) {
      var label = this.label;
      var $options = this.formOptions.map(function (option, index) {
        var value = option.value,
            text = option.text,
            html = option.html,
            disabled = option.disabled;
        return h(BFormSelectOption, {
          attrs: {
            value: value,
            disabled: disabled
          },
          domProps: htmlOrText(html, text),
          key: "option_".concat(index)
        });
      });
      return h('optgroup', {
        attrs: {
          label: label
        }
      }, [this.normalizeSlot(SLOT_NAME_FIRST), $options, this.normalizeSlot()]);
    }
  });

  var props$1d = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$25), props$1h), props$1x), props$1w), props$1v), props$1u), {}, {
    ariaInvalid: makeProp(PROP_TYPE_BOOLEAN_STRING, false),
    multiple: makeProp(PROP_TYPE_BOOLEAN, false),
    // Browsers default size to `0`, which shows 4 rows in most browsers in multiple mode
    // Size of `1` can bork out Firefox
    selectSize: makeProp(PROP_TYPE_NUMBER, 0)
  })), NAME_FORM_SELECT); // --- Main component ---
  // @vue/component

  var BFormSelect = /*#__PURE__*/extend({
    name: NAME_FORM_SELECT,
    mixins: [idMixin, mixin, formControlMixin, formSizeMixin, formStateMixin, formCustomMixin, optionsMixin, normalizeSlotMixin],
    props: props$1d,
    data: function data() {
      return {
        localValue: this[prop]
      };
    },
    computed: {
      computedSelectSize: function computedSelectSize() {
        // Custom selects with a size of zero causes the arrows to be hidden,
        // so dont render the size attribute in this case
        return !this.plain && this.selectSize === 0 ? null : this.selectSize;
      },
      inputClass: function inputClass() {
        return [this.plain ? 'form-control' : 'custom-select', this.size && this.plain ? "form-control-".concat(this.size) : null, this.size && !this.plain ? "custom-select-".concat(this.size) : null, this.stateClass];
      }
    },
    watch: {
      value: function value(newValue) {
        this.localValue = newValue;
      },
      localValue: function localValue() {
        this.$emit(event, this.localValue);
      }
    },
    methods: {
      focus: function focus() {
        attemptFocus(this.$refs.input);
      },
      blur: function blur() {
        attemptBlur(this.$refs.input);
      },
      onChange: function onChange(event) {
        var _this = this;

        var target = event.target;
        var selectedValue = from(target.options).filter(function (o) {
          return o.selected;
        }).map(function (o) {
          return '_value' in o ? o._value : o.value;
        });
        this.localValue = target.multiple ? selectedValue : selectedValue[0];
        this.$nextTick(function () {
          _this.$emit(EVENT_NAME_CHANGE, _this.localValue);
        });
      }
    },
    render: function render(h) {
      var name = this.name,
          disabled = this.disabled,
          required = this.required,
          size = this.computedSelectSize,
          value = this.localValue;
      var $options = this.formOptions.map(function (option, index) {
        var value = option.value,
            label = option.label,
            options = option.options,
            disabled = option.disabled;
        var key = "option_".concat(index);
        return isArray(options) ? h(BFormSelectOptionGroup, {
          props: {
            label: label,
            options: options
          },
          key: key
        }) : h(BFormSelectOption, {
          props: {
            value: value,
            disabled: disabled
          },
          domProps: htmlOrText(option.html, option.text),
          key: key
        });
      });
      return h('select', {
        class: this.inputClass,
        attrs: {
          id: this.safeId(),
          name: name,
          form: this.form || null,
          multiple: this.multiple || null,
          size: size,
          disabled: disabled,
          required: required,
          'aria-required': required ? 'true' : null,
          'aria-invalid': this.computedAriaInvalid
        },
        on: {
          change: this.onChange
        },
        directives: [{
          name: 'model',
          value: value
        }],
        ref: 'input'
      }, [this.normalizeSlot(SLOT_NAME_FIRST), $options, this.normalizeSlot()]);
    }
  });

  var FormSelectPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BFormSelect: BFormSelect,
      BFormSelectOption: BFormSelectOption,
      BFormSelectOptionGroup: BFormSelectOptionGroup,
      BSelect: BFormSelect,
      BSelectOption: BFormSelectOption,
      BSelectOptionGroup: BFormSelectOptionGroup
    }
  });

  var _watch$a;

  var _makeModelMixin$9 = makeModelMixin('value', {
    // Should this really be String, to match native number inputs?
    type: PROP_TYPE_BOOLEAN_NUMBER
  }),
      modelMixin$9 = _makeModelMixin$9.mixin,
      modelProps$9 = _makeModelMixin$9.props,
      MODEL_PROP_NAME$9 = _makeModelMixin$9.prop,
      MODEL_EVENT_NAME$9 = _makeModelMixin$9.event; // Default for spin button range and step


  var DEFAULT_MIN = 1;
  var DEFAULT_MAX = 100;
  var DEFAULT_STEP = 1; // Delay before auto-repeat in ms

  var DEFAULT_REPEAT_DELAY = 500; // Repeat interval in ms

  var DEFAULT_REPEAT_INTERVAL = 100; // Repeat rate increased after number of repeats

  var DEFAULT_REPEAT_THRESHOLD = 10; // Repeat speed multiplier (step multiplier, must be an integer)

  var DEFAULT_REPEAT_MULTIPLIER = 4;
  var KEY_CODES = [CODE_UP, CODE_DOWN, CODE_HOME, CODE_END, CODE_PAGEUP, CODE_PAGEDOWN]; // --- Props ---

  var props$1c = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$25), modelProps$9), omit(props$1x, ['required', 'autofocus'])), props$1v), props$1u), {}, {
    ariaControls: makeProp(PROP_TYPE_STRING),
    ariaLabel: makeProp(PROP_TYPE_STRING),
    formatterFn: makeProp(PROP_TYPE_FUNCTION),
    inline: makeProp(PROP_TYPE_BOOLEAN, false),
    labelDecrement: makeProp(PROP_TYPE_STRING, 'Decrement'),
    labelIncrement: makeProp(PROP_TYPE_STRING, 'Increment'),
    locale: makeProp(PROP_TYPE_ARRAY_STRING),
    max: makeProp(PROP_TYPE_NUMBER_STRING, DEFAULT_MAX),
    min: makeProp(PROP_TYPE_NUMBER_STRING, DEFAULT_MIN),
    placeholder: makeProp(PROP_TYPE_STRING),
    readonly: makeProp(PROP_TYPE_BOOLEAN, false),
    repeatDelay: makeProp(PROP_TYPE_NUMBER_STRING, DEFAULT_REPEAT_DELAY),
    repeatInterval: makeProp(PROP_TYPE_NUMBER_STRING, DEFAULT_REPEAT_INTERVAL),
    repeatStepMultiplier: makeProp(PROP_TYPE_NUMBER_STRING, DEFAULT_REPEAT_MULTIPLIER),
    repeatThreshold: makeProp(PROP_TYPE_NUMBER_STRING, DEFAULT_REPEAT_THRESHOLD),
    step: makeProp(PROP_TYPE_NUMBER_STRING, DEFAULT_STEP),
    vertical: makeProp(PROP_TYPE_BOOLEAN, false),
    wrap: makeProp(PROP_TYPE_BOOLEAN, false)
  })), NAME_FORM_SPINBUTTON); // --- Main Component ---
  // @vue/component

  var BFormSpinbutton = /*#__PURE__*/extend({
    name: NAME_FORM_SPINBUTTON,
    // Mixin order is important!
    mixins: [attrsMixin, idMixin, modelMixin$9, formSizeMixin, formStateMixin, normalizeSlotMixin],
    inheritAttrs: false,
    props: props$1c,
    data: function data() {
      return {
        localValue: toFloat(this[MODEL_PROP_NAME$9], null),
        hasFocus: false
      };
    },
    computed: {
      required: function required() {
        return false;
      },
      spinId: function spinId() {
        return this.safeId();
      },
      computedInline: function computedInline() {
        return this.inline && !this.vertical;
      },
      computedReadonly: function computedReadonly() {
        return this.readonly && !this.disabled;
      },
      computedRequired: function computedRequired() {
        return this.required && !this.computedReadonly && !this.disabled;
      },
      computedStep: function computedStep() {
        return toFloat(this.step, DEFAULT_STEP);
      },
      computedMin: function computedMin() {
        return toFloat(this.min, DEFAULT_MIN);
      },
      computedMax: function computedMax() {
        // We round down to the nearest maximum step value
        var max = toFloat(this.max, DEFAULT_MAX);
        var step = this.computedStep;
        var min = this.computedMin;
        return mathFloor((max - min) / step) * step + min;
      },
      computedDelay: function computedDelay() {
        var delay = toInteger(this.repeatDelay, 0);
        return delay > 0 ? delay : DEFAULT_REPEAT_DELAY;
      },
      computedInterval: function computedInterval() {
        var interval = toInteger(this.repeatInterval, 0);
        return interval > 0 ? interval : DEFAULT_REPEAT_INTERVAL;
      },
      computedThreshold: function computedThreshold() {
        return mathMax(toInteger(this.repeatThreshold, DEFAULT_REPEAT_THRESHOLD), 1);
      },
      computedStepMultiplier: function computedStepMultiplier() {
        return mathMax(toInteger(this.repeatStepMultiplier, DEFAULT_REPEAT_MULTIPLIER), 1);
      },
      computedPrecision: function computedPrecision() {
        // Quick and dirty way to get the number of decimals
        var step = this.computedStep;
        return mathFloor(step) === step ? 0 : (step.toString().split('.')[1] || '').length;
      },
      computedMultiplier: function computedMultiplier() {
        return mathPow(10, this.computedPrecision || 0);
      },
      valueAsFixed: function valueAsFixed() {
        var value = this.localValue;
        return isNull(value) ? '' : value.toFixed(this.computedPrecision);
      },
      computedLocale: function computedLocale() {
        var locales = concat(this.locale).filter(identity);
        var nf = new Intl.NumberFormat(locales);
        return nf.resolvedOptions().locale;
      },
      computedRTL: function computedRTL() {
        return isLocaleRTL(this.computedLocale);
      },
      defaultFormatter: function defaultFormatter() {
        // Returns and `Intl.NumberFormat` formatter method reference
        var precision = this.computedPrecision;
        var nf = new Intl.NumberFormat(this.computedLocale, {
          style: 'decimal',
          useGrouping: false,
          minimumIntegerDigits: 1,
          minimumFractionDigits: precision,
          maximumFractionDigits: precision,
          notation: 'standard'
        }); // Return the format method reference

        return nf.format;
      },
      computedFormatter: function computedFormatter() {
        var formatterFn = this.formatterFn;
        return hasPropFunction(formatterFn) ? formatterFn : this.defaultFormatter;
      },
      computedAttrs: function computedAttrs() {
        return _objectSpread2$3(_objectSpread2$3({}, this.bvAttrs), {}, {
          role: 'group',
          lang: this.computedLocale,
          tabindex: this.disabled ? null : '-1',
          title: this.ariaLabel
        });
      },
      computedSpinAttrs: function computedSpinAttrs() {
        var spinId = this.spinId,
            value = this.localValue,
            required = this.computedRequired,
            disabled = this.disabled,
            state = this.state,
            computedFormatter = this.computedFormatter;
        var hasValue = !isNull(value);
        return _objectSpread2$3(_objectSpread2$3({
          dir: this.computedRTL ? 'rtl' : 'ltr'
        }, this.bvAttrs), {}, {
          id: spinId,
          role: 'spinbutton',
          tabindex: disabled ? null : '0',
          'aria-live': 'off',
          'aria-label': this.ariaLabel || null,
          'aria-controls': this.ariaControls || null,
          // TODO: May want to check if the value is in range
          'aria-invalid': state === false || !hasValue && required ? 'true' : null,
          'aria-required': required ? 'true' : null,
          // These attrs are required for role spinbutton
          'aria-valuemin': toString(this.computedMin),
          'aria-valuemax': toString(this.computedMax),
          // These should be `null` if the value is out of range
          // They must also be non-existent attrs if the value is out of range or `null`
          'aria-valuenow': hasValue ? value : null,
          'aria-valuetext': hasValue ? computedFormatter(value) : null
        });
      }
    },
    watch: (_watch$a = {}, _defineProperty(_watch$a, MODEL_PROP_NAME$9, function (value) {
      this.localValue = toFloat(value, null);
    }), _defineProperty(_watch$a, "localValue", function localValue(value) {
      this.$emit(MODEL_EVENT_NAME$9, value);
    }), _defineProperty(_watch$a, "disabled", function disabled(_disabled) {
      if (_disabled) {
        this.clearRepeat();
      }
    }), _defineProperty(_watch$a, "readonly", function readonly(_readonly) {
      if (_readonly) {
        this.clearRepeat();
      }
    }), _watch$a),
    created: function created() {
      // Create non reactive properties
      this.$_autoDelayTimer = null;
      this.$_autoRepeatTimer = null;
      this.$_keyIsDown = false;
    },
    beforeDestroy: function beforeDestroy() {
      this.clearRepeat();
    },

    /* istanbul ignore next */
    deactivated: function deactivated() {
      this.clearRepeat();
    },
    methods: {
      // --- Public methods ---
      focus: function focus() {
        if (!this.disabled) {
          attemptFocus(this.$refs.spinner);
        }
      },
      blur: function blur() {
        if (!this.disabled) {
          attemptBlur(this.$refs.spinner);
        }
      },
      // --- Private methods ---
      emitChange: function emitChange() {
        this.$emit(EVENT_NAME_CHANGE, this.localValue);
      },
      stepValue: function stepValue(direction) {
        // Sets a new incremented or decremented value, supporting optional wrapping
        // Direction is either +1 or -1 (or a multiple thereof)
        var value = this.localValue;

        if (!this.disabled && !isNull(value)) {
          var step = this.computedStep * direction;
          var min = this.computedMin;
          var max = this.computedMax;
          var multiplier = this.computedMultiplier;
          var wrap = this.wrap; // We ensure that the value steps like a native input

          value = mathRound((value - min) / step) * step + min + step; // We ensure that precision is maintained (decimals)

          value = mathRound(value * multiplier) / multiplier; // Handle if wrapping is enabled

          this.localValue = value > max ? wrap ? min : max : value < min ? wrap ? max : min : value;
        }
      },
      onFocusBlur: function onFocusBlur(event) {
        this.hasFocus = this.disabled ? false : event.type === 'focus';
      },
      stepUp: function stepUp() {
        var multiplier = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
        var value = this.localValue;

        if (isNull(value)) {
          this.localValue = this.computedMin;
        } else {
          this.stepValue(+1 * multiplier);
        }
      },
      stepDown: function stepDown() {
        var multiplier = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
        var value = this.localValue;

        if (isNull(value)) {
          this.localValue = this.wrap ? this.computedMax : this.computedMin;
        } else {
          this.stepValue(-1 * multiplier);
        }
      },
      onKeydown: function onKeydown(event) {
        var keyCode = event.keyCode,
            altKey = event.altKey,
            ctrlKey = event.ctrlKey,
            metaKey = event.metaKey;
        /* istanbul ignore if */

        if (this.disabled || this.readonly || altKey || ctrlKey || metaKey) {
          return;
        }

        if (arrayIncludes(KEY_CODES, keyCode)) {
          // https://w3c.github.io/aria-practices/#spinbutton
          stopEvent(event, {
            propagation: false
          });
          /* istanbul ignore if */

          if (this.$_keyIsDown) {
            // Keypress is already in progress
            return;
          }

          this.resetTimers();

          if (arrayIncludes([CODE_UP, CODE_DOWN], keyCode)) {
            // The following use the custom auto-repeat handling
            this.$_keyIsDown = true;

            if (keyCode === CODE_UP) {
              this.handleStepRepeat(event, this.stepUp);
            } else if (keyCode === CODE_DOWN) {
              this.handleStepRepeat(event, this.stepDown);
            }
          } else {
            // These use native OS key repeating
            if (keyCode === CODE_PAGEUP) {
              this.stepUp(this.computedStepMultiplier);
            } else if (keyCode === CODE_PAGEDOWN) {
              this.stepDown(this.computedStepMultiplier);
            } else if (keyCode === CODE_HOME) {
              this.localValue = this.computedMin;
            } else if (keyCode === CODE_END) {
              this.localValue = this.computedMax;
            }
          }
        }
      },
      onKeyup: function onKeyup(event) {
        // Emit a change event when the keyup happens
        var keyCode = event.keyCode,
            altKey = event.altKey,
            ctrlKey = event.ctrlKey,
            metaKey = event.metaKey;
        /* istanbul ignore if */

        if (this.disabled || this.readonly || altKey || ctrlKey || metaKey) {
          return;
        }

        if (arrayIncludes(KEY_CODES, keyCode)) {
          stopEvent(event, {
            propagation: false
          });
          this.resetTimers();
          this.$_keyIsDown = false;
          this.emitChange();
        }
      },
      handleStepRepeat: function handleStepRepeat(event, stepper) {
        var _this = this;

        var _ref = event || {},
            type = _ref.type,
            button = _ref.button;

        if (!this.disabled && !this.readonly) {
          /* istanbul ignore if */
          if (type === 'mousedown' && button) {
            // We only respond to left (main === 0) button clicks
            return;
          }

          this.resetTimers(); // Step the counter initially

          stepper(1);
          var threshold = this.computedThreshold;
          var multiplier = this.computedStepMultiplier;
          var delay = this.computedDelay;
          var interval = this.computedInterval; // Initiate the delay/repeat interval

          this.$_autoDelayTimer = setTimeout(function () {
            var count = 0;
            _this.$_autoRepeatTimer = setInterval(function () {
              // After N initial repeats, we increase the incrementing step amount
              // We do this to minimize screen reader announcements of the value
              // (values are announced every change, which can be chatty for SR users)
              // And to make it easer to select a value when the range is large
              stepper(count < threshold ? 1 : multiplier);
              count++;
            }, interval);
          }, delay);
        }
      },
      onMouseup: function onMouseup(event) {
        // `<body>` listener, only enabled when mousedown starts
        var _ref2 = event || {},
            type = _ref2.type,
            button = _ref2.button;
        /* istanbul ignore if */


        if (type === 'mouseup' && button) {
          // Ignore non left button (main === 0) mouse button click
          return;
        }

        stopEvent(event, {
          propagation: false
        });
        this.resetTimers();
        this.setMouseup(false); // Trigger the change event

        this.emitChange();
      },
      setMouseup: function setMouseup(on) {
        // Enable or disabled the body mouseup/touchend handlers
        // Use try/catch to handle case when called server side
        try {
          eventOnOff(on, document.body, 'mouseup', this.onMouseup, false);
          eventOnOff(on, document.body, 'touchend', this.onMouseup, false);
        } catch (_unused) {}
      },
      resetTimers: function resetTimers() {
        clearTimeout(this.$_autoDelayTimer);
        clearInterval(this.$_autoRepeatTimer);
        this.$_autoDelayTimer = null;
        this.$_autoRepeatTimer = null;
      },
      clearRepeat: function clearRepeat() {
        this.resetTimers();
        this.setMouseup(false);
        this.$_keyIsDown = false;
      }
    },
    render: function render(h) {
      var _this2 = this;

      var spinId = this.spinId,
          value = this.localValue,
          inline = this.computedInline,
          readonly = this.computedReadonly,
          vertical = this.vertical,
          disabled = this.disabled,
          computedFormatter = this.computedFormatter;
      var hasValue = !isNull(value);

      var makeButton = function makeButton(stepper, label, IconCmp, keyRef, shortcut, btnDisabled, slotName) {
        var $icon = h(IconCmp, {
          props: {
            scale: _this2.hasFocus ? 1.5 : 1.25
          },
          attrs: {
            'aria-hidden': 'true'
          }
        });
        var scope = {
          hasFocus: _this2.hasFocus
        };

        var handler = function handler(event) {
          if (!disabled && !readonly) {
            stopEvent(event, {
              propagation: false
            });

            _this2.setMouseup(true); // Since we `preventDefault()`, we must manually focus the button


            attemptFocus(event.currentTarget);

            _this2.handleStepRepeat(event, stepper);
          }
        };

        return h('button', {
          staticClass: 'btn btn-sm border-0 rounded-0',
          class: {
            'py-0': !vertical
          },
          attrs: {
            tabindex: '-1',
            type: 'button',
            disabled: disabled || readonly || btnDisabled,
            'aria-disabled': disabled || readonly || btnDisabled ? 'true' : null,
            'aria-controls': spinId,
            'aria-label': label || null,
            'aria-keyshortcuts': shortcut || null
          },
          on: {
            mousedown: handler,
            touchstart: handler
          },
          key: keyRef || null,
          ref: keyRef
        }, [_this2.normalizeSlot(slotName, scope) || $icon]);
      }; // TODO: Add button disabled state when `wrap` is `false` and at value max/min


      var $increment = makeButton(this.stepUp, this.labelIncrement, BIconPlus, 'inc', 'ArrowUp', false, SLOT_NAME_INCREMENT);
      var $decrement = makeButton(this.stepDown, this.labelDecrement, BIconDash, 'dec', 'ArrowDown', false, SLOT_NAME_DECREMENT);
      var $hidden = h();

      if (this.name && !disabled) {
        $hidden = h('input', {
          attrs: {
            type: 'hidden',
            name: this.name,
            form: this.form || null,
            // TODO: Should this be set to '' if value is out of range?
            value: this.valueAsFixed
          },
          key: 'hidden'
        });
      }

      var $spin = h( // We use 'output' element to make this accept a `<label for="id">` (Except IE)
      'output', {
        staticClass: 'flex-grow-1',
        class: {
          'd-flex': vertical,
          'align-self-center': !vertical,
          'align-items-center': vertical,
          'border-top': vertical,
          'border-bottom': vertical,
          'border-left': !vertical,
          'border-right': !vertical
        },
        attrs: this.computedSpinAttrs,
        key: 'output',
        ref: 'spinner'
      }, [h('bdi', hasValue ? computedFormatter(value) : this.placeholder || '')]);
      return h('div', {
        staticClass: 'b-form-spinbutton form-control',
        class: [{
          disabled: disabled,
          readonly: readonly,
          focus: this.hasFocus,
          'd-inline-flex': inline || vertical,
          'd-flex': !inline && !vertical,
          'align-items-stretch': !vertical,
          'flex-column': vertical
        }, this.sizeFormClass, this.stateClass],
        attrs: this.computedAttrs,
        on: {
          keydown: this.onKeydown,
          keyup: this.onKeyup,
          // We use capture phase (`!` prefix) since focus and blur do not bubble
          '!focus': this.onFocusBlur,
          '!blur': this.onFocusBlur
        }
      }, vertical ? [$increment, $hidden, $spin, $decrement] : [$decrement, $hidden, $spin, $increment]);
    }
  });

  var FormSpinbuttonPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BFormSpinbutton: BFormSpinbutton,
      BSpinbutton: BFormSpinbutton
    }
  });

  var props$1b = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, props$25), {}, {
    disabled: makeProp(PROP_TYPE_BOOLEAN, false),
    noRemove: makeProp(PROP_TYPE_BOOLEAN, false),
    pill: makeProp(PROP_TYPE_BOOLEAN, false),
    removeLabel: makeProp(PROP_TYPE_STRING, 'Remove tag'),
    tag: makeProp(PROP_TYPE_STRING, 'span'),
    title: makeProp(PROP_TYPE_STRING),
    variant: makeProp(PROP_TYPE_STRING, 'secondary')
  })), NAME_FORM_TAG); // --- Main component ---
  // @vue/component

  var BFormTag = /*#__PURE__*/extend({
    name: NAME_FORM_TAG,
    mixins: [idMixin, normalizeSlotMixin],
    props: props$1b,
    methods: {
      onRemove: function onRemove(event) {
        var type = event.type,
            keyCode = event.keyCode;

        if (!this.disabled && (type === 'click' || type === 'keydown' && keyCode === CODE_DELETE)) {
          this.$emit(EVENT_NAME_REMOVE);
        }
      }
    },
    render: function render(h) {
      var title = this.title,
          tag = this.tag,
          variant = this.variant,
          pill = this.pill,
          disabled = this.disabled;
      var tagId = this.safeId();
      var tagLabelId = this.safeId('_taglabel_');
      var $remove = h();

      if (!this.noRemove && !disabled) {
        $remove = h(BButtonClose, {
          staticClass: 'b-form-tag-remove',
          props: {
            ariaLabel: this.removeLabel
          },
          attrs: {
            'aria-controls': tagId,
            'aria-describedby': tagLabelId,
            'aria-keyshortcuts': 'Delete'
          },
          on: {
            click: this.onRemove,
            keydown: this.onRemove
          }
        });
      }

      var $tag = h('span', {
        staticClass: 'b-form-tag-content flex-grow-1 text-truncate',
        attrs: {
          id: tagLabelId
        }
      }, this.normalizeSlot() || title);
      return h(BBadge, {
        staticClass: 'b-form-tag d-inline-flex align-items-baseline mw-100',
        class: {
          disabled: disabled
        },
        props: {
          tag: tag,
          variant: variant,
          pill: pill
        },
        attrs: {
          id: tagId,
          title: title || null,
          'aria-labelledby': tagLabelId
        }
      }, [$tag, $remove]);
    }
  });

  var _watch$9;

  var _makeModelMixin$8 = makeModelMixin('value', {
    type: PROP_TYPE_ARRAY,
    defaultValue: []
  }),
      modelMixin$8 = _makeModelMixin$8.mixin,
      modelProps$8 = _makeModelMixin$8.props,
      MODEL_PROP_NAME$8 = _makeModelMixin$8.prop,
      MODEL_EVENT_NAME$8 = _makeModelMixin$8.event; // Supported input types (for built in input)


  var TYPES = ['text', 'email', 'tel', 'url', 'number']; // Default ignore input focus selector

  var DEFAULT_INPUT_FOCUS_SELECTOR = ['.b-form-tag', 'button', 'input', 'select'].join(' '); // --- Helper methods ---
  // Escape special chars in string and replace
  // contiguous spaces with a whitespace match

  var escapeRegExpChars = function escapeRegExpChars(str) {
    return escapeRegExp(str).replace(RX_SPACES, '\\s');
  }; // Remove leading/trailing spaces from array of tags and remove duplicates


  var cleanTags = function cleanTags(tags) {
    return concat(tags).map(function (tag) {
      return trim(toString(tag));
    }).filter(function (tag, index, arr) {
      return tag.length > 0 && arr.indexOf(tag) === index;
    });
  }; // Processes an input/change event, normalizing string or event argument


  var processEventValue = function processEventValue(event) {
    return isString(event) ? event : isEvent(event) ? event.target.value || '' : '';
  }; // Returns a fresh empty `tagsState` object


  var cleanTagsState = function cleanTagsState() {
    return {
      all: [],
      valid: [],
      invalid: [],
      duplicate: []
    };
  }; // --- Props ---


  var props$1a = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$25), modelProps$8), props$1x), props$1v), props$1u), {}, {
    addButtonText: makeProp(PROP_TYPE_STRING, 'Add'),
    addButtonVariant: makeProp(PROP_TYPE_STRING, 'outline-secondary'),
    // Enable change event triggering tag addition
    // Handy if using <select> as the input
    addOnChange: makeProp(PROP_TYPE_BOOLEAN, false),
    duplicateTagText: makeProp(PROP_TYPE_STRING, 'Duplicate tag(s)'),
    feedbackAriaLive: makeProp(PROP_TYPE_STRING, 'assertive'),
    // Disable the input focus behavior when clicking
    // on element matching the selector (or selectors)
    ignoreInputFocusSelector: makeProp(PROP_TYPE_ARRAY_STRING, DEFAULT_INPUT_FOCUS_SELECTOR),
    // Additional attributes to add to the input element
    inputAttrs: makeProp(PROP_TYPE_OBJECT, {}),
    inputClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    inputId: makeProp(PROP_TYPE_STRING),
    inputType: makeProp(PROP_TYPE_STRING, 'text', function (value) {
      return arrayIncludes(TYPES, value);
    }),
    invalidTagText: makeProp(PROP_TYPE_STRING, 'Invalid tag(s)'),
    limit: makeProp(PROP_TYPE_NUMBER),
    limitTagsText: makeProp(PROP_TYPE_STRING, 'Tag limit reached'),
    // Disable ENTER key from triggering tag addition
    noAddOnEnter: makeProp(PROP_TYPE_BOOLEAN, false),
    // Disable the focus ring on the root element
    noOuterFocus: makeProp(PROP_TYPE_BOOLEAN, false),
    noTagRemove: makeProp(PROP_TYPE_BOOLEAN, false),
    placeholder: makeProp(PROP_TYPE_STRING, 'Add tag...'),
    // Enable deleting last tag in list when CODE_BACKSPACE is
    // pressed and input is empty
    removeOnDelete: makeProp(PROP_TYPE_BOOLEAN, false),
    // Character (or characters) that trigger adding tags
    separator: makeProp(PROP_TYPE_ARRAY_STRING),
    tagClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    tagPills: makeProp(PROP_TYPE_BOOLEAN, false),
    tagRemoveLabel: makeProp(PROP_TYPE_STRING, 'Remove tag'),
    tagRemovedLabel: makeProp(PROP_TYPE_STRING, 'Tag removed'),
    tagValidator: makeProp(PROP_TYPE_FUNCTION),
    tagVariant: makeProp(PROP_TYPE_STRING, 'secondary')
  })), NAME_FORM_TAGS); // --- Main component ---
  // @vue/component

  var BFormTags = /*#__PURE__*/extend({
    name: NAME_FORM_TAGS,
    mixins: [listenersMixin, idMixin, modelMixin$8, formControlMixin, formSizeMixin, formStateMixin, normalizeSlotMixin],
    props: props$1a,
    data: function data() {
      return {
        hasFocus: false,
        newTag: '',
        tags: [],
        // Tags that were removed
        removedTags: [],
        // Populated when tags are parsed
        tagsState: cleanTagsState(),
        focusState: null
      };
    },
    computed: {
      computedInputId: function computedInputId() {
        return this.inputId || this.safeId('__input__');
      },
      computedInputType: function computedInputType() {
        // We only allow certain types
        return arrayIncludes(TYPES, this.inputType) ? this.inputType : 'text';
      },
      computedInputAttrs: function computedInputAttrs() {
        var disabled = this.disabled,
            form = this.form;
        return _objectSpread2$3(_objectSpread2$3({}, this.inputAttrs), {}, {
          // Must have attributes
          id: this.computedInputId,
          value: this.newTag,
          disabled: disabled,
          form: form
        });
      },
      computedInputHandlers: function computedInputHandlers() {
        return _objectSpread2$3(_objectSpread2$3({}, omit(this.bvListeners, [EVENT_NAME_FOCUSIN, EVENT_NAME_FOCUSOUT])), {}, {
          blur: this.onInputBlur,
          change: this.onInputChange,
          focus: this.onInputFocus,
          input: this.onInputInput,
          keydown: this.onInputKeydown,
          reset: this.reset
        });
      },
      computedSeparator: function computedSeparator() {
        // Merge the array into a string
        return concat(this.separator).filter(isString).filter(identity).join('');
      },
      computedSeparatorRegExp: function computedSeparatorRegExp() {
        // We use a computed prop here to precompile the RegExp
        // The RegExp is a character class RE in the form of `/[abc]+/`
        // where a, b, and c are the valid separator characters
        // -> `tags = str.split(/[abc]+/).filter(t => t)`
        var separator = this.computedSeparator;
        return separator ? new RegExp("[".concat(escapeRegExpChars(separator), "]+")) : null;
      },
      computedJoiner: function computedJoiner() {
        // When tag(s) are invalid or duplicate, we leave them
        // in the input so that the user can see them
        // If there are more than one tag in the input, we use the
        // first separator character as the separator in the input
        // We append a space if the first separator is not a space
        var joiner = this.computedSeparator.charAt(0);
        return joiner !== ' ' ? "".concat(joiner, " ") : joiner;
      },
      computeIgnoreInputFocusSelector: function computeIgnoreInputFocusSelector() {
        // Normalize to an single selector with selectors separated by `,`
        return concat(this.ignoreInputFocusSelector).filter(identity).join(',').trim();
      },
      disableAddButton: function disableAddButton() {
        var _this = this;

        // If 'Add' button should be disabled
        // If the input contains at least one tag that can
        // be added, then the 'Add' button should be enabled
        var newTag = trim(this.newTag);
        return newTag === '' || !this.splitTags(newTag).some(function (t) {
          return !arrayIncludes(_this.tags, t) && _this.validateTag(t);
        });
      },
      duplicateTags: function duplicateTags() {
        return this.tagsState.duplicate;
      },
      hasDuplicateTags: function hasDuplicateTags() {
        return this.duplicateTags.length > 0;
      },
      invalidTags: function invalidTags() {
        return this.tagsState.invalid;
      },
      hasInvalidTags: function hasInvalidTags() {
        return this.invalidTags.length > 0;
      },
      isLimitReached: function isLimitReached() {
        var limit = this.limit;
        return isNumber(limit) && limit >= 0 && this.tags.length >= limit;
      }
    },
    watch: (_watch$9 = {}, _defineProperty(_watch$9, MODEL_PROP_NAME$8, function (newValue) {
      this.tags = cleanTags(newValue);
    }), _defineProperty(_watch$9, "tags", function tags(newValue, oldValue) {
      // Update the `v-model` (if it differs from the value prop)
      if (!looseEqual(newValue, this[MODEL_PROP_NAME$8])) {
        this.$emit(MODEL_EVENT_NAME$8, newValue);
      }

      if (!looseEqual(newValue, oldValue)) {
        newValue = concat(newValue).filter(identity);
        oldValue = concat(oldValue).filter(identity);
        this.removedTags = oldValue.filter(function (old) {
          return !arrayIncludes(newValue, old);
        });
      }
    }), _defineProperty(_watch$9, "tagsState", function tagsState(newValue, oldValue) {
      // Emit a tag-state event when the `tagsState` object changes
      if (!looseEqual(newValue, oldValue)) {
        this.$emit(EVENT_NAME_TAG_STATE, newValue.valid, newValue.invalid, newValue.duplicate);
      }
    }), _watch$9),
    created: function created() {
      // We do this in created to make sure an input event emits
      // if the cleaned tags are not equal to the value prop
      this.tags = cleanTags(this[MODEL_PROP_NAME$8]);
    },
    mounted: function mounted() {
      // Listen for form reset events, to reset the tags input
      var $form = closest('form', this.$el);

      if ($form) {
        eventOn($form, 'reset', this.reset, EVENT_OPTIONS_PASSIVE);
      }
    },
    beforeDestroy: function beforeDestroy() {
      var $form = closest('form', this.$el);

      if ($form) {
        eventOff($form, 'reset', this.reset, EVENT_OPTIONS_PASSIVE);
      }
    },
    methods: {
      addTag: function addTag(newTag) {
        newTag = isString(newTag) ? newTag : this.newTag;
        /* istanbul ignore next */

        if (this.disabled || trim(newTag) === '' || this.isLimitReached) {
          // Early exit
          return;
        }

        var parsed = this.parseTags(newTag); // Add any new tags to the `tags` array, or if the
        // array of `allTags` is empty, we clear the input

        if (parsed.valid.length > 0 || parsed.all.length === 0) {
          // Clear the user input element (and leave in any invalid/duplicate tag(s)

          /* istanbul ignore if: full testing to be added later */
          if (matches(this.getInput(), 'select')) {
            // The following is needed to properly
            // work with `<select>` elements
            this.newTag = '';
          } else {
            var invalidAndDuplicates = [].concat(_toConsumableArray$1(parsed.invalid), _toConsumableArray$1(parsed.duplicate));
            this.newTag = parsed.all.filter(function (tag) {
              return arrayIncludes(invalidAndDuplicates, tag);
            }).join(this.computedJoiner).concat(invalidAndDuplicates.length > 0 ? this.computedJoiner.charAt(0) : '');
          }
        }

        if (parsed.valid.length > 0) {
          // We add the new tags in one atomic operation
          // to trigger reactivity once (instead of once per tag)
          // We do this after we update the new tag input value
          // `concat()` can be faster than array spread, when both args are arrays
          this.tags = concat(this.tags, parsed.valid);
        }

        this.tagsState = parsed; // Attempt to re-focus the input (specifically for when using the Add
        // button, as the button disappears after successfully adding a tag

        this.focus();
      },
      removeTag: function removeTag(tag) {
        /* istanbul ignore next */
        if (this.disabled) {
          return;
        } // TODO:
        //   Add `onRemoveTag(tag)` user method, which if returns `false`
        //   will prevent the tag from being removed (i.e. confirmation)
        //   Or emit cancelable `BvEvent`


        this.tags = this.tags.filter(function (t) {
          return t !== tag;
        });
      },
      reset: function reset() {
        var _this2 = this;

        this.newTag = '';
        this.tags = [];
        this.$nextTick(function () {
          _this2.removedTags = [];
          _this2.tagsState = cleanTagsState();
        });
      },
      // --- Input element event handlers ---
      onInputInput: function onInputInput(event) {
        /* istanbul ignore next: hard to test composition events */
        if (this.disabled || isEvent(event) && event.target.composing) {
          // `event.target.composing` is set by Vue (`v-model` directive)
          // https://github.com/vuejs/vue/blob/dev/src/platforms/web/runtime/directives/model.js
          return;
        }

        var newTag = processEventValue(event);
        var separatorRe = this.computedSeparatorRegExp;

        if (this.newTag !== newTag) {
          this.newTag = newTag;
        } // We ignore leading whitespace for the following


        newTag = trimLeft(newTag);

        if (separatorRe && separatorRe.test(newTag.slice(-1))) {
          // A trailing separator character was entered, so add the tag(s)
          // Note: More than one tag on input event is possible via copy/paste
          this.addTag();
        } else {
          // Validate (parse tags) on input event
          this.tagsState = newTag === '' ? cleanTagsState() : this.parseTags(newTag);
        }
      },
      onInputChange: function onInputChange(event) {
        // Change is triggered on `<input>` blur, or `<select>` selected
        // This event is opt-in
        if (!this.disabled && this.addOnChange) {
          var newTag = processEventValue(event);
          /* istanbul ignore next */

          if (this.newTag !== newTag) {
            this.newTag = newTag;
          }

          this.addTag();
        }
      },
      onInputKeydown: function onInputKeydown(event) {
        // Early exit

        /* istanbul ignore next */
        if (this.disabled || !isEvent(event)) {
          return;
        }

        var keyCode = event.keyCode;
        var value = event.target.value || '';
        /* istanbul ignore else: testing to be added later */

        if (!this.noAddOnEnter && keyCode === CODE_ENTER) {
          // Attempt to add the tag when user presses enter
          stopEvent(event, {
            propagation: false
          });
          this.addTag();
        } else if (this.removeOnDelete && (keyCode === CODE_BACKSPACE || keyCode === CODE_DELETE) && value === '') {
          // Remove the last tag if the user pressed backspace/delete and the input is empty
          stopEvent(event, {
            propagation: false
          });
          this.tags = this.tags.slice(0, -1);
        }
      },
      // --- Wrapper event handlers ---
      onClick: function onClick(event) {
        var _this3 = this;

        var ignoreFocusSelector = this.computeIgnoreInputFocusSelector;

        if (!ignoreFocusSelector || !closest(ignoreFocusSelector, event.target, true)) {
          this.$nextTick(function () {
            _this3.focus();
          });
        }
      },
      onInputFocus: function onInputFocus(event) {
        var _this4 = this;

        if (this.focusState !== 'out') {
          this.focusState = 'in';
          this.$nextTick(function () {
            requestAF(function () {
              if (_this4.hasFocus) {
                _this4.$emit(EVENT_NAME_FOCUS, event);

                _this4.focusState = null;
              }
            });
          });
        }
      },
      onInputBlur: function onInputBlur(event) {
        var _this5 = this;

        if (this.focusState !== 'in') {
          this.focusState = 'out';
          this.$nextTick(function () {
            requestAF(function () {
              if (!_this5.hasFocus) {
                _this5.$emit(EVENT_NAME_BLUR, event);

                _this5.focusState = null;
              }
            });
          });
        }
      },
      onFocusin: function onFocusin(event) {
        this.hasFocus = true;
        this.$emit(EVENT_NAME_FOCUSIN, event);
      },
      onFocusout: function onFocusout(event) {
        this.hasFocus = false;
        this.$emit(EVENT_NAME_FOCUSOUT, event);
      },
      handleAutofocus: function handleAutofocus() {
        var _this6 = this;

        this.$nextTick(function () {
          requestAF(function () {
            if (_this6.autofocus) {
              _this6.focus();
            }
          });
        });
      },
      // --- Public methods ---
      focus: function focus() {
        if (!this.disabled) {
          attemptFocus(this.getInput());
        }
      },
      blur: function blur() {
        if (!this.disabled) {
          attemptBlur(this.getInput());
        }
      },
      // --- Private methods ---
      splitTags: function splitTags(newTag) {
        // Split the input into an array of raw tags
        newTag = toString(newTag);
        var separatorRe = this.computedSeparatorRegExp; // Split the tag(s) via the optional separator
        // Normally only a single tag is provided, but copy/paste
        // can enter multiple tags in a single operation

        return (separatorRe ? newTag.split(separatorRe) : [newTag]).map(trim).filter(identity);
      },
      parseTags: function parseTags(newTag) {
        var _this7 = this;

        // Takes `newTag` value and parses it into `validTags`,
        // `invalidTags`, and duplicate tags as an object
        // Split the input into raw tags
        var tags = this.splitTags(newTag); // Base results

        var parsed = {
          all: tags,
          valid: [],
          invalid: [],
          duplicate: []
        }; // Parse the unique tags

        tags.forEach(function (tag) {
          if (arrayIncludes(_this7.tags, tag) || arrayIncludes(parsed.valid, tag)) {
            // Unique duplicate tags
            if (!arrayIncludes(parsed.duplicate, tag)) {
              parsed.duplicate.push(tag);
            }
          } else if (_this7.validateTag(tag)) {
            // We only add unique/valid tags
            parsed.valid.push(tag);
          } else {
            // Unique invalid tags
            if (!arrayIncludes(parsed.invalid, tag)) {
              parsed.invalid.push(tag);
            }
          }
        });
        return parsed;
      },
      validateTag: function validateTag(tag) {
        var tagValidator = this.tagValidator;
        return hasPropFunction(tagValidator) ? tagValidator(tag) : true;
      },
      getInput: function getInput() {
        // Returns the input element reference (or null if not found)
        // We need to escape `computedInputId` since it can be user-provided
        return select("#".concat(cssEscape(this.computedInputId)), this.$el);
      },
      // Default User Interface render
      defaultRender: function defaultRender(_ref) {
        var addButtonText = _ref.addButtonText,
            addButtonVariant = _ref.addButtonVariant,
            addTag = _ref.addTag,
            disableAddButton = _ref.disableAddButton,
            disabled = _ref.disabled,
            duplicateTagText = _ref.duplicateTagText,
            inputAttrs = _ref.inputAttrs,
            inputClass = _ref.inputClass,
            inputHandlers = _ref.inputHandlers,
            inputType = _ref.inputType,
            invalidTagText = _ref.invalidTagText,
            isDuplicate = _ref.isDuplicate,
            isInvalid = _ref.isInvalid,
            isLimitReached = _ref.isLimitReached,
            limitTagsText = _ref.limitTagsText,
            noTagRemove = _ref.noTagRemove,
            placeholder = _ref.placeholder,
            removeTag = _ref.removeTag,
            tagClass = _ref.tagClass,
            tagPills = _ref.tagPills,
            tagRemoveLabel = _ref.tagRemoveLabel,
            tagVariant = _ref.tagVariant,
            tags = _ref.tags;
        var h = this.$createElement; // Make the list of tags

        var $tags = tags.map(function (tag) {
          tag = toString(tag);
          return h(BFormTag, {
            class: tagClass,
            // `BFormTag` will auto generate an ID
            // so we do not need to set the ID prop
            props: {
              disabled: disabled,
              noRemove: noTagRemove,
              pill: tagPills,
              removeLabel: tagRemoveLabel,
              tag: 'li',
              title: tag,
              variant: tagVariant
            },
            on: {
              remove: function remove() {
                return removeTag(tag);
              }
            },
            key: "tags_".concat(tag)
          }, tag);
        }); // Feedback IDs if needed

        var invalidFeedbackId = invalidTagText && isInvalid ? this.safeId('__invalid_feedback__') : null;
        var duplicateFeedbackId = duplicateTagText && isDuplicate ? this.safeId('__duplicate_feedback__') : null;
        var limitFeedbackId = limitTagsText && isLimitReached ? this.safeId('__limit_feedback__') : null; // Compute the `aria-describedby` attribute value

        var ariaDescribedby = [inputAttrs['aria-describedby'], invalidFeedbackId, duplicateFeedbackId, limitFeedbackId].filter(identity).join(' '); // Input

        var $input = h('input', {
          staticClass: 'b-form-tags-input w-100 flex-grow-1 p-0 m-0 bg-transparent border-0',
          class: inputClass,
          style: {
            outline: 0,
            minWidth: '5rem'
          },
          attrs: _objectSpread2$3(_objectSpread2$3({}, inputAttrs), {}, {
            'aria-describedby': ariaDescribedby || null,
            type: inputType,
            placeholder: placeholder || null
          }),
          domProps: {
            value: inputAttrs.value
          },
          on: inputHandlers,
          // Directive needed to get `event.target.composing` set (if needed)
          directives: [{
            name: 'model',
            value: inputAttrs.value
          }],
          ref: 'input'
        }); // Add button

        var $button = h(BButton, {
          staticClass: 'b-form-tags-button py-0',
          class: {
            // Only show the button if the tag can be added
            // We use the `invisible` class instead of not rendering
            // the button, so that we maintain layout to prevent
            // the user input from jumping around
            invisible: disableAddButton
          },
          style: {
            fontSize: '90%'
          },
          props: {
            disabled: disableAddButton || isLimitReached,
            variant: addButtonVariant
          },
          on: {
            click: function click() {
              return addTag();
            }
          },
          ref: 'button'
        }, [this.normalizeSlot(SLOT_NAME_ADD_BUTTON_TEXT) || addButtonText]); // ID of the tags + input `<ul>` list
        // Note we could concatenate `inputAttrs.id` with '__tag_list__'
        // but `inputId` may be `null` until after mount
        // `safeId()` returns `null`, if no user provided ID,
        // until after mount when a unique ID is generated

        var tagListId = this.safeId('__tag_list__');
        var $field = h('li', {
          staticClass: 'b-form-tags-field flex-grow-1',
          attrs: {
            role: 'none',
            'aria-live': 'off',
            'aria-controls': tagListId
          },
          key: 'tags_field'
        }, [h('div', {
          staticClass: 'd-flex',
          attrs: {
            role: 'group'
          }
        }, [$input, $button])]); // Wrap in an unordered list element (we use a list for accessibility)

        var $ul = h('ul', {
          staticClass: 'b-form-tags-list list-unstyled mb-0 d-flex flex-wrap align-items-center',
          attrs: {
            id: tagListId
          },
          key: 'tags_list'
        }, [$tags, $field]); // Assemble the feedback

        var $feedback = h();

        if (invalidTagText || duplicateTagText || limitTagsText) {
          // Add an aria live region for the invalid/duplicate tag
          // messages if the user has not disabled the messages
          var ariaLive = this.feedbackAriaLive,
              joiner = this.computedJoiner; // Invalid tag feedback if needed (error)

          var $invalid = h();

          if (invalidFeedbackId) {
            $invalid = h(BFormInvalidFeedback, {
              props: {
                id: invalidFeedbackId,
                ariaLive: ariaLive,
                forceShow: true
              },
              key: 'tags_invalid_feedback'
            }, [this.invalidTagText, ': ', this.invalidTags.join(joiner)]);
          } // Duplicate tag feedback if needed (warning, not error)


          var $duplicate = h();

          if (duplicateFeedbackId) {
            $duplicate = h(BFormText, {
              props: {
                id: duplicateFeedbackId,
                ariaLive: ariaLive
              },
              key: 'tags_duplicate_feedback'
            }, [this.duplicateTagText, ': ', this.duplicateTags.join(joiner)]);
          } // Limit tags feedback if needed (warning, not error)


          var $limit = h();

          if (limitFeedbackId) {
            $limit = h(BFormText, {
              props: {
                id: limitFeedbackId,
                ariaLive: ariaLive
              },
              key: 'tags_limit_feedback'
            }, [limitTagsText]);
          }

          $feedback = h('div', {
            attrs: {
              'aria-live': 'polite',
              'aria-atomic': 'true'
            },
            key: 'tags_feedback'
          }, [$invalid, $duplicate, $limit]);
        } // Return the content


        return [$ul, $feedback];
      }
    },
    render: function render(h) {
      var name = this.name,
          disabled = this.disabled,
          required = this.required,
          form = this.form,
          tags = this.tags,
          computedInputId = this.computedInputId,
          hasFocus = this.hasFocus,
          noOuterFocus = this.noOuterFocus; // Scoped slot properties

      var scope = _objectSpread2$3({
        // Array of tags (shallow copy to prevent mutations)
        tags: tags.slice(),
        // <input> v-bind:inputAttrs
        inputAttrs: this.computedInputAttrs,
        // We don't include this in the attrs, as users may want to override this
        inputType: this.computedInputType,
        // <input> v-on:inputHandlers
        inputHandlers: this.computedInputHandlers,
        // Methods
        removeTag: this.removeTag,
        addTag: this.addTag,
        reset: this.reset,
        // <input> :id="inputId"
        inputId: computedInputId,
        // Invalid/Duplicate state information
        isInvalid: this.hasInvalidTags,
        invalidTags: this.invalidTags.slice(),
        isDuplicate: this.hasDuplicateTags,
        duplicateTags: this.duplicateTags.slice(),
        isLimitReached: this.isLimitReached,
        // If the 'Add' button should be disabled
        disableAddButton: this.disableAddButton
      }, pick$1(this.$props, ['addButtonText', 'addButtonVariant', 'disabled', 'duplicateTagText', 'form', 'inputClass', 'invalidTagText', 'limit', 'limitTagsText', 'noTagRemove', 'placeholder', 'required', 'separator', 'size', 'state', 'tagClass', 'tagPills', 'tagRemoveLabel', 'tagVariant'])); // Generate the user interface


      var $content = this.normalizeSlot(SLOT_NAME_DEFAULT, scope) || this.defaultRender(scope); // Generate the `aria-live` region for the current value(s)

      var $output = h('output', {
        staticClass: 'sr-only',
        attrs: {
          id: this.safeId('__selected_tags__'),
          role: 'status',
          for: computedInputId,
          'aria-live': hasFocus ? 'polite' : 'off',
          'aria-atomic': 'true',
          'aria-relevant': 'additions text'
        }
      }, this.tags.join(', ')); // Removed tag live region

      var $removed = h('div', {
        staticClass: 'sr-only',
        attrs: {
          id: this.safeId('__removed_tags__'),
          role: 'status',
          'aria-live': hasFocus ? 'assertive' : 'off',
          'aria-atomic': 'true'
        }
      }, this.removedTags.length > 0 ? "(".concat(this.tagRemovedLabel, ") ").concat(this.removedTags.join(', ')) : ''); // Add hidden inputs for form submission

      var $hidden = h();

      if (name && !disabled) {
        // We add hidden inputs for each tag if a name is provided
        // When there are currently no tags, a visually hidden input
        // with empty value is rendered for proper required handling
        var hasTags = tags.length > 0;
        $hidden = (hasTags ? tags : ['']).map(function (tag) {
          return h('input', {
            class: {
              'sr-only': !hasTags
            },
            attrs: {
              type: hasTags ? 'hidden' : 'text',
              value: tag,
              required: required,
              name: name,
              form: form
            },
            key: "tag_input_".concat(tag)
          });
        });
      } // Return the rendered output


      return h('div', {
        staticClass: 'b-form-tags form-control h-auto',
        class: [{
          focus: hasFocus && !noOuterFocus && !disabled,
          disabled: disabled
        }, this.sizeFormClass, this.stateClass],
        attrs: {
          id: this.safeId(),
          role: 'group',
          tabindex: disabled || noOuterFocus ? null : '-1',
          'aria-describedby': this.safeId('__selected_tags__')
        },
        on: {
          click: this.onClick,
          focusin: this.onFocusin,
          focusout: this.onFocusout
        }
      }, [$output, $removed, $content, $hidden]);
    }
  });

  var FormTagsPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BFormTags: BFormTags,
      BTags: BFormTags,
      BFormTag: BFormTag,
      BTag: BFormTag
    }
  });

  var props$19 = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$25), props$1x), props$1v), props$1u), props$1l), {}, {
    maxRows: makeProp(PROP_TYPE_NUMBER_STRING),
    // When in auto resize mode, disable shrinking to content height
    noAutoShrink: makeProp(PROP_TYPE_BOOLEAN, false),
    // Disable the resize handle of textarea
    noResize: makeProp(PROP_TYPE_BOOLEAN, false),
    rows: makeProp(PROP_TYPE_NUMBER_STRING, 2),
    // 'soft', 'hard' or 'off'
    // Browser default is 'soft'
    wrap: makeProp(PROP_TYPE_STRING, 'soft')
  })), NAME_FORM_TEXTAREA); // --- Main component ---
  // @vue/component

  var BFormTextarea = /*#__PURE__*/extend({
    name: NAME_FORM_TEXTAREA,
    directives: {
      'b-visible': VBVisible
    },
    // Mixin order is important!
    mixins: [listenersMixin, idMixin, listenOnRootMixin, formControlMixin, formSizeMixin, formStateMixin, formTextMixin, formSelectionMixin, formValidityMixin],
    props: props$19,
    data: function data() {
      return {
        heightInPx: null
      };
    },
    computed: {
      type: function type() {
        return null;
      },
      computedStyle: function computedStyle() {
        var styles = {
          // Setting `noResize` to true will disable the ability for the user to
          // manually resize the textarea. We also disable when in auto height mode
          resize: !this.computedRows || this.noResize ? 'none' : null
        };

        if (!this.computedRows) {
          // Conditionally set the computed CSS height when auto rows/height is enabled
          // We avoid setting the style to `null`, which can override user manual resize handle
          styles.height = this.heightInPx; // We always add a vertical scrollbar to the textarea when auto-height is
          // enabled so that the computed height calculation returns a stable value

          styles.overflowY = 'scroll';
        }

        return styles;
      },
      computedMinRows: function computedMinRows() {
        // Ensure rows is at least 2 and positive (2 is the native textarea value)
        // A value of 1 can cause issues in some browsers, and most browsers
        // only support 2 as the smallest value
        return mathMax(toInteger(this.rows, 2), 2);
      },
      computedMaxRows: function computedMaxRows() {
        return mathMax(this.computedMinRows, toInteger(this.maxRows, 0));
      },
      computedRows: function computedRows() {
        // This is used to set the attribute 'rows' on the textarea
        // If auto-height is enabled, then we return `null` as we use CSS to control height
        return this.computedMinRows === this.computedMaxRows ? this.computedMinRows : null;
      },
      computedAttrs: function computedAttrs() {
        var disabled = this.disabled,
            required = this.required;
        return {
          id: this.safeId(),
          name: this.name || null,
          form: this.form || null,
          disabled: disabled,
          placeholder: this.placeholder || null,
          required: required,
          autocomplete: this.autocomplete || null,
          readonly: this.readonly || this.plaintext,
          rows: this.computedRows,
          wrap: this.wrap || null,
          'aria-required': this.required ? 'true' : null,
          'aria-invalid': this.computedAriaInvalid
        };
      },
      computedListeners: function computedListeners() {
        return _objectSpread2$3(_objectSpread2$3({}, this.bvListeners), {}, {
          input: this.onInput,
          change: this.onChange,
          blur: this.onBlur
        });
      }
    },
    watch: {
      localValue: function localValue() {
        this.setHeight();
      }
    },
    mounted: function mounted() {
      this.setHeight();
    },
    methods: {
      // Called by intersection observer directive

      /* istanbul ignore next */
      visibleCallback: function visibleCallback(visible) {
        if (visible) {
          // We use a `$nextTick()` here just to make sure any
          // transitions or portalling have completed
          this.$nextTick(this.setHeight);
        }
      },
      setHeight: function setHeight() {
        var _this = this;

        this.$nextTick(function () {
          requestAF(function () {
            _this.heightInPx = _this.computeHeight();
          });
        });
      },

      /* istanbul ignore next: can't test getComputedStyle in JSDOM */
      computeHeight: function computeHeight() {
        if (this.$isServer || !isNull(this.computedRows)) {
          return null;
        }

        var el = this.$el; // Element must be visible (not hidden) and in document
        // Must be checked after above checks

        if (!isVisible(el)) {
          return null;
        } // Get current computed styles


        var computedStyle = getCS(el); // Height of one line of text in px

        var lineHeight = toFloat(computedStyle.lineHeight, 1); // Calculate height of border and padding

        var border = toFloat(computedStyle.borderTopWidth, 0) + toFloat(computedStyle.borderBottomWidth, 0);
        var padding = toFloat(computedStyle.paddingTop, 0) + toFloat(computedStyle.paddingBottom, 0); // Calculate offset

        var offset = border + padding; // Minimum height for min rows (which must be 2 rows or greater for cross-browser support)

        var minHeight = lineHeight * this.computedMinRows + offset; // Get the current style height (with `px` units)

        var oldHeight = getStyle(el, 'height') || computedStyle.height; // Probe scrollHeight by temporarily changing the height to `auto`

        setStyle(el, 'height', 'auto');
        var scrollHeight = el.scrollHeight; // Place the original old height back on the element, just in case `computedProp`
        // returns the same value as before

        setStyle(el, 'height', oldHeight); // Calculate content height in 'rows' (scrollHeight includes padding but not border)

        var contentRows = mathMax((scrollHeight - padding) / lineHeight, 2); // Calculate number of rows to display (limited within min/max rows)

        var rows = mathMin(mathMax(contentRows, this.computedMinRows), this.computedMaxRows); // Calculate the required height of the textarea including border and padding (in pixels)

        var height = mathMax(mathCeil(rows * lineHeight + offset), minHeight); // Computed height remains the larger of `oldHeight` and new `height`,
        // when height is in `sticky` mode (prop `no-auto-shrink` is true)

        if (this.noAutoShrink && toFloat(oldHeight, 0) > height) {
          return oldHeight;
        } // Return the new computed CSS height in px units


        return "".concat(height, "px");
      }
    },
    render: function render(h) {
      return h('textarea', {
        class: this.computedClass,
        style: this.computedStyle,
        directives: [{
          name: 'b-visible',
          value: this.visibleCallback,
          // If textarea is within 640px of viewport, consider it visible
          modifiers: {
            '640': true
          }
        }],
        attrs: this.computedAttrs,
        domProps: {
          value: this.localValue
        },
        on: this.computedListeners,
        ref: 'input'
      });
    }
  });

  var FormTextareaPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BFormTextarea: BFormTextarea,
      BTextarea: BFormTextarea
    }
  });

  var _watch$8;

  var _makeModelMixin$7 = makeModelMixin('value', {
    type: PROP_TYPE_STRING,
    defaultValue: ''
  }),
      modelMixin$7 = _makeModelMixin$7.mixin,
      modelProps$7 = _makeModelMixin$7.props,
      MODEL_PROP_NAME$7 = _makeModelMixin$7.prop,
      MODEL_EVENT_NAME$7 = _makeModelMixin$7.event;

  var NUMERIC = 'numeric'; // --- Helper methods ---

  var padLeftZeros = function padLeftZeros(value) {
    return "00".concat(value || '').slice(-2);
  };

  var parseHMS = function parseHMS(value) {
    value = toString(value);
    var hh = null,
        mm = null,
        ss = null;

    if (RX_TIME.test(value)) {

      var _value$split$map = value.split(':').map(function (v) {
        return toInteger(v, null);
      });

      var _value$split$map2 = _slicedToArray(_value$split$map, 3);

      hh = _value$split$map2[0];
      mm = _value$split$map2[1];
      ss = _value$split$map2[2];
    }

    return {
      hours: isUndefinedOrNull(hh) ? null : hh,
      minutes: isUndefinedOrNull(mm) ? null : mm,
      seconds: isUndefinedOrNull(ss) ? null : ss,
      ampm: isUndefinedOrNull(hh) || hh < 12 ? 0 : 1
    };
  };

  var formatHMS = function formatHMS(_ref) {
    var hours = _ref.hours,
        minutes = _ref.minutes,
        seconds = _ref.seconds;
    var requireSeconds = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;

    if (isNull(hours) || isNull(minutes) || requireSeconds && isNull(seconds)) {
      return '';
    }

    var hms = [hours, minutes, requireSeconds ? seconds : 0];
    return hms.map(padLeftZeros).join(':');
  }; // --- Props ---


  var props$18 = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$25), modelProps$7), pick$1(props$1c, ['labelIncrement', 'labelDecrement'])), {}, {
    // ID of label element
    ariaLabelledby: makeProp(PROP_TYPE_STRING),
    disabled: makeProp(PROP_TYPE_BOOLEAN, false),
    footerTag: makeProp(PROP_TYPE_STRING, 'footer'),
    headerTag: makeProp(PROP_TYPE_STRING, 'header'),
    hidden: makeProp(PROP_TYPE_BOOLEAN, false),
    hideHeader: makeProp(PROP_TYPE_BOOLEAN, false),
    // Explicitly force 12 or 24 hour time
    // Default is to use resolved locale for 12/24 hour display
    // Tri-state: `true` = 12, `false` = 24, `null` = auto
    hour12: makeProp(PROP_TYPE_BOOLEAN, null),
    labelAm: makeProp(PROP_TYPE_STRING, 'AM'),
    labelAmpm: makeProp(PROP_TYPE_STRING, 'AM/PM'),
    labelHours: makeProp(PROP_TYPE_STRING, 'Hours'),
    labelMinutes: makeProp(PROP_TYPE_STRING, 'Minutes'),
    labelNoTimeSelected: makeProp(PROP_TYPE_STRING, 'No time selected'),
    labelPm: makeProp(PROP_TYPE_STRING, 'PM'),
    labelSeconds: makeProp(PROP_TYPE_STRING, 'Seconds'),
    labelSelected: makeProp(PROP_TYPE_STRING, 'Selected time'),
    locale: makeProp(PROP_TYPE_ARRAY_STRING),
    minutesStep: makeProp(PROP_TYPE_NUMBER_STRING, 1),
    readonly: makeProp(PROP_TYPE_BOOLEAN, false),
    secondsStep: makeProp(PROP_TYPE_NUMBER_STRING, 1),
    // If `true`, show the second spinbutton
    showSeconds: makeProp(PROP_TYPE_BOOLEAN, false)
  })), NAME_TIME); // --- Main component ---
  // @vue/component

  var BTime = /*#__PURE__*/extend({
    name: NAME_TIME,
    mixins: [idMixin, modelMixin$7, normalizeSlotMixin],
    props: props$18,
    data: function data() {
      var parsed = parseHMS(this[MODEL_PROP_NAME$7] || '');
      return {
        // Spin button models
        modelHours: parsed.hours,
        modelMinutes: parsed.minutes,
        modelSeconds: parsed.seconds,
        modelAmpm: parsed.ampm,
        // Internal flag to enable aria-live regions
        isLive: false
      };
    },
    computed: {
      computedHMS: function computedHMS() {
        var hours = this.modelHours;
        var minutes = this.modelMinutes;
        var seconds = this.modelSeconds;
        return formatHMS({
          hours: hours,
          minutes: minutes,
          seconds: seconds
        }, this.showSeconds);
      },
      resolvedOptions: function resolvedOptions() {
        // Resolved locale options
        var locale = concat(this.locale).filter(identity);
        var options = {
          hour: NUMERIC,
          minute: NUMERIC,
          second: NUMERIC
        };

        if (!isUndefinedOrNull(this.hour12)) {
          // Force 12 or 24 hour clock
          options.hour12 = !!this.hour12;
        }

        var dtf = new Intl.DateTimeFormat(locale, options);
        var resolved = dtf.resolvedOptions();
        var hour12 = resolved.hour12 || false; // IE 11 doesn't resolve the hourCycle, so we make
        // an assumption and fall back to common values

        var hourCycle = resolved.hourCycle || (hour12 ? 'h12' : 'h23');
        return {
          locale: resolved.locale,
          hour12: hour12,
          hourCycle: hourCycle
        };
      },
      computedLocale: function computedLocale() {
        return this.resolvedOptions.locale;
      },
      computedLang: function computedLang() {
        return (this.computedLocale || '').replace(/-u-.*$/, '');
      },
      computedRTL: function computedRTL() {
        return isLocaleRTL(this.computedLang);
      },
      computedHourCycle: function computedHourCycle() {
        // h11, h12, h23, or h24
        // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Locale/hourCycle
        // h12 - Hour system using 1–12. Corresponds to 'h' in patterns. The 12 hour clock, with midnight starting at 12:00 am
        // h23 - Hour system using 0–23. Corresponds to 'H' in patterns. The 24 hour clock, with midnight starting at 0:00
        // h11 - Hour system using 0–11. Corresponds to 'K' in patterns. The 12 hour clock, with midnight starting at 0:00 am
        // h24 - Hour system using 1–24. Corresponds to 'k' in pattern. The 24 hour clock, with midnight starting at 24:00
        // For h12 or h24, we visually format 00 hours as 12
        return this.resolvedOptions.hourCycle;
      },
      is12Hour: function is12Hour() {
        return !!this.resolvedOptions.hour12;
      },
      context: function context() {
        return {
          locale: this.computedLocale,
          isRTL: this.computedRTL,
          hourCycle: this.computedHourCycle,
          hour12: this.is12Hour,
          hours: this.modelHours,
          minutes: this.modelMinutes,
          seconds: this.showSeconds ? this.modelSeconds : 0,
          value: this.computedHMS,
          formatted: this.formattedTimeString
        };
      },
      valueId: function valueId() {
        return this.safeId() || null;
      },
      computedAriaLabelledby: function computedAriaLabelledby() {
        return [this.ariaLabelledby, this.valueId].filter(identity).join(' ') || null;
      },
      timeFormatter: function timeFormatter() {
        // Returns a formatter function reference
        // The formatter converts the time to a localized string
        var options = {
          hour12: this.is12Hour,
          hourCycle: this.computedHourCycle,
          hour: NUMERIC,
          minute: NUMERIC,
          timeZone: 'UTC'
        };

        if (this.showSeconds) {
          options.second = NUMERIC;
        } // Formats the time as a localized string


        return createDateFormatter(this.computedLocale, options);
      },
      numberFormatter: function numberFormatter() {
        // Returns a formatter function reference
        // The formatter always formats as 2 digits and is localized
        var nf = new Intl.NumberFormat(this.computedLocale, {
          style: 'decimal',
          minimumIntegerDigits: 2,
          minimumFractionDigits: 0,
          maximumFractionDigits: 0,
          notation: 'standard'
        });
        return nf.format;
      },
      formattedTimeString: function formattedTimeString() {
        var hours = this.modelHours;
        var minutes = this.modelMinutes;
        var seconds = this.showSeconds ? this.modelSeconds || 0 : 0;

        if (this.computedHMS) {
          return this.timeFormatter(createDate(Date.UTC(0, 0, 1, hours, minutes, seconds)));
        }

        return this.labelNoTimeSelected || ' ';
      },
      spinScopedSlots: function spinScopedSlots() {
        var h = this.$createElement;
        return {
          increment: function increment(_ref2) {
            var hasFocus = _ref2.hasFocus;
            return h(BIconChevronUp, {
              props: {
                scale: hasFocus ? 1.5 : 1.25
              },
              attrs: {
                'aria-hidden': 'true'
              }
            });
          },
          decrement: function decrement(_ref3) {
            var hasFocus = _ref3.hasFocus;
            return h(BIconChevronUp, {
              props: {
                flipV: true,
                scale: hasFocus ? 1.5 : 1.25
              },
              attrs: {
                'aria-hidden': 'true'
              }
            });
          }
        };
      }
    },
    watch: (_watch$8 = {}, _defineProperty(_watch$8, MODEL_PROP_NAME$7, function (newValue, oldValue) {
      if (newValue !== oldValue && !looseEqual(parseHMS(newValue), parseHMS(this.computedHMS))) {
        var _parseHMS = parseHMS(newValue),
            hours = _parseHMS.hours,
            minutes = _parseHMS.minutes,
            seconds = _parseHMS.seconds,
            ampm = _parseHMS.ampm;

        this.modelHours = hours;
        this.modelMinutes = minutes;
        this.modelSeconds = seconds;
        this.modelAmpm = ampm;
      }
    }), _defineProperty(_watch$8, "computedHMS", function computedHMS(newValue, oldValue) {
      if (newValue !== oldValue) {
        this.$emit(MODEL_EVENT_NAME$7, newValue);
      }
    }), _defineProperty(_watch$8, "context", function context(newValue, oldValue) {
      if (!looseEqual(newValue, oldValue)) {
        this.$emit(EVENT_NAME_CONTEXT, newValue);
      }
    }), _defineProperty(_watch$8, "modelAmpm", function modelAmpm(newValue, oldValue) {
      var _this = this;

      if (newValue !== oldValue) {
        var hours = isNull(this.modelHours) ? 0 : this.modelHours;
        this.$nextTick(function () {
          if (newValue === 0 && hours > 11) {
            // Switched to AM
            _this.modelHours = hours - 12;
          } else if (newValue === 1 && hours < 12) {
            // Switched to PM
            _this.modelHours = hours + 12;
          }
        });
      }
    }), _defineProperty(_watch$8, "modelHours", function modelHours(newHours, oldHours) {
      if (newHours !== oldHours) {
        this.modelAmpm = newHours > 11 ? 1 : 0;
      }
    }), _watch$8),
    created: function created() {
      var _this2 = this;

      this.$nextTick(function () {
        _this2.$emit(EVENT_NAME_CONTEXT, _this2.context);
      });
    },
    mounted: function mounted() {
      this.setLive(true);
    },

    /* istanbul ignore next */
    activated: function activated() {
      this.setLive(true);
    },

    /* istanbul ignore next */
    deactivated: function deactivated() {
      this.setLive(false);
    },
    beforeDestroy: function beforeDestroy() {
      this.setLive(false);
    },
    methods: {
      // Public methods
      focus: function focus() {
        if (!this.disabled) {
          // We focus the first spin button
          attemptFocus(this.$refs.spinners[0]);
        }
      },
      blur: function blur() {
        if (!this.disabled) {
          var activeElement = getActiveElement();

          if (contains(this.$el, activeElement)) {
            attemptBlur(activeElement);
          }
        }
      },
      // Formatters for the spin buttons
      formatHours: function formatHours(hh) {
        var hourCycle = this.computedHourCycle; // We always store 0-23, but format based on h11/h12/h23/h24 formats

        hh = this.is12Hour && hh > 12 ? hh - 12 : hh; // Determine how 00:00 and 12:00 are shown

        hh = hh === 0 && hourCycle === 'h12' ? 12 : hh === 0 && hourCycle === 'h24' ?
        /* istanbul ignore next */
        24 : hh === 12 && hourCycle === 'h11' ?
        /* istanbul ignore next */
        0 : hh;
        return this.numberFormatter(hh);
      },
      formatMinutes: function formatMinutes(mm) {
        return this.numberFormatter(mm);
      },
      formatSeconds: function formatSeconds(ss) {
        return this.numberFormatter(ss);
      },
      formatAmpm: function formatAmpm(ampm) {
        // These should come from label props???
        // `ampm` should always be a value of `0` or `1`
        return ampm === 0 ? this.labelAm : ampm === 1 ? this.labelPm : '';
      },
      // Spinbutton on change handlers
      setHours: function setHours(value) {
        this.modelHours = value;
      },
      setMinutes: function setMinutes(value) {
        this.modelMinutes = value;
      },
      setSeconds: function setSeconds(value) {
        this.modelSeconds = value;
      },
      setAmpm: function setAmpm(value) {
        this.modelAmpm = value;
      },
      onSpinLeftRight: function onSpinLeftRight() {
        var event = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
        var type = event.type,
            keyCode = event.keyCode;

        if (!this.disabled && type === 'keydown' && (keyCode === CODE_LEFT || keyCode === CODE_RIGHT)) {
          stopEvent(event);
          var spinners = this.$refs.spinners || [];
          var index = spinners.map(function (cmp) {
            return !!cmp.hasFocus;
          }).indexOf(true);
          index = index + (keyCode === CODE_LEFT ? -1 : 1);
          index = index >= spinners.length ? 0 : index < 0 ? spinners.length - 1 : index;
          attemptFocus(spinners[index]);
        }
      },
      setLive: function setLive(on) {
        var _this3 = this;

        if (on) {
          this.$nextTick(function () {
            requestAF(function () {
              _this3.isLive = true;
            });
          });
        } else {
          this.isLive = false;
        }
      }
    },
    render: function render(h) {
      var _this4 = this;

      // If hidden, we just render a placeholder comment

      /* istanbul ignore if */
      if (this.hidden) {
        return h();
      }

      var disabled = this.disabled,
          readonly = this.readonly,
          locale = this.computedLocale,
          ariaLabelledby = this.computedAriaLabelledby,
          labelIncrement = this.labelIncrement,
          labelDecrement = this.labelDecrement,
          valueId = this.valueId,
          focusHandler = this.focus;
      var spinIds = []; // Helper method to render a spinbutton

      var makeSpinbutton = function makeSpinbutton(handler, key, classes) {
        var spinbuttonProps = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
        var id = _this4.safeId("_spinbutton_".concat(key, "_")) || null;
        spinIds.push(id);
        return h(BFormSpinbutton, _defineProperty({
          class: classes,
          props: _objectSpread2$3({
            id: id,
            placeholder: '--',
            vertical: true,
            required: true,
            disabled: disabled,
            readonly: readonly,
            locale: locale,
            labelIncrement: labelIncrement,
            labelDecrement: labelDecrement,
            wrap: true,
            ariaControls: valueId,
            min: 0
          }, spinbuttonProps),
          scopedSlots: _this4.spinScopedSlots,
          on: {
            // We use `change` event to minimize SR verbosity
            // As the spinbutton will announce each value change
            // and we don't want the formatted time to be announced
            // on each value input if repeat is happening
            change: handler
          },
          key: key,
          ref: 'spinners'
        }, REF_FOR_KEY, true));
      }; // Helper method to return a "colon" separator


      var makeColon = function makeColon() {
        return h('div', {
          staticClass: 'd-flex flex-column',
          class: {
            'text-muted': disabled || readonly
          },
          attrs: {
            'aria-hidden': 'true'
          }
        }, [h(BIconCircleFill, {
          props: {
            shiftV: 4,
            scale: 0.5
          }
        }), h(BIconCircleFill, {
          props: {
            shiftV: -4,
            scale: 0.5
          }
        })]);
      };

      var $spinners = []; // Hours

      $spinners.push(makeSpinbutton(this.setHours, 'hours', 'b-time-hours', {
        value: this.modelHours,
        max: 23,
        step: 1,
        formatterFn: this.formatHours,
        ariaLabel: this.labelHours
      })); // Spacer

      $spinners.push(makeColon()); // Minutes

      $spinners.push(makeSpinbutton(this.setMinutes, 'minutes', 'b-time-minutes', {
        value: this.modelMinutes,
        max: 59,
        step: this.minutesStep || 1,
        formatterFn: this.formatMinutes,
        ariaLabel: this.labelMinutes
      }));

      if (this.showSeconds) {
        // Spacer
        $spinners.push(makeColon()); // Seconds

        $spinners.push(makeSpinbutton(this.setSeconds, 'seconds', 'b-time-seconds', {
          value: this.modelSeconds,
          max: 59,
          step: this.secondsStep || 1,
          formatterFn: this.formatSeconds,
          ariaLabel: this.labelSeconds
        }));
      } // AM/PM ?
      // depends on client settings, shouldn't be rendered on server


      if (this.isLive && this.is12Hour) {
        // TODO:
        //   If locale is RTL, unshift this instead of push?
        //   And switch class `ml-2` to `mr-2`
        //   Note some LTR locales (i.e. zh) also place AM/PM to the left
        $spinners.push(makeSpinbutton(this.setAmpm, 'ampm', 'b-time-ampm', {
          value: this.modelAmpm,
          max: 1,
          formatterFn: this.formatAmpm,
          ariaLabel: this.labelAmpm,
          // We set `required` as `false`, since this always has a value
          required: false
        }));
      } // Assemble spinners


      $spinners = h('div', {
        staticClass: 'd-flex align-items-center justify-content-center mx-auto',
        attrs: {
          role: 'group',
          tabindex: disabled || readonly ? null : '-1',
          'aria-labelledby': ariaLabelledby
        },
        on: {
          keydown: this.onSpinLeftRight,
          click:
          /* istanbul ignore next */
          function click(event) {
            if (event.target === event.currentTarget) {
              focusHandler();
            }
          }
        }
      }, $spinners); // Selected type display

      var $value = h('output', {
        staticClass: 'form-control form-control-sm text-center',
        class: {
          disabled: disabled || readonly
        },
        attrs: {
          id: valueId,
          role: 'status',
          for: spinIds.filter(identity).join(' ') || null,
          tabindex: disabled ? null : '-1',
          'aria-live': this.isLive ? 'polite' : 'off',
          'aria-atomic': 'true'
        },
        on: {
          // Transfer focus/click to focus hours spinner
          click: focusHandler,
          focus: focusHandler
        }
      }, [h('bdi', this.formattedTimeString), this.computedHMS ? h('span', {
        staticClass: 'sr-only'
      }, " (".concat(this.labelSelected, ") ")) : '']);
      var $header = h(this.headerTag, {
        staticClass: 'b-time-header',
        class: {
          'sr-only': this.hideHeader
        }
      }, [$value]);
      var $content = this.normalizeSlot();
      var $footer = $content ? h(this.footerTag, {
        staticClass: 'b-time-footer'
      }, $content) : h();
      return h('div', {
        staticClass: 'b-time d-inline-flex flex-column text-center',
        attrs: {
          role: 'group',
          lang: this.computedLang || null,
          'aria-labelledby': ariaLabelledby || null,
          'aria-disabled': disabled ? 'true' : null,
          'aria-readonly': readonly && !disabled ? 'true' : null
        }
      }, [$header, $spinners, $footer]);
    }
  });

  var _watch$7;

  var _makeModelMixin$6 = makeModelMixin('value', {
    type: PROP_TYPE_STRING,
    defaultValue: ''
  }),
      modelMixin$6 = _makeModelMixin$6.mixin,
      modelProps$6 = _makeModelMixin$6.props,
      MODEL_PROP_NAME$6 = _makeModelMixin$6.prop,
      MODEL_EVENT_NAME$6 = _makeModelMixin$6.event; // --- Props ---


  var timeProps = omit(props$18, ['hidden', 'id', 'value']);
  var formBtnLabelControlProps = omit(props$1o, ['formattedValue', 'id', 'lang', 'rtl', 'value']);
  var props$17 = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$25), modelProps$6), timeProps), formBtnLabelControlProps), {}, {
    closeButtonVariant: makeProp(PROP_TYPE_STRING, 'outline-secondary'),
    labelCloseButton: makeProp(PROP_TYPE_STRING, 'Close'),
    labelNowButton: makeProp(PROP_TYPE_STRING, 'Select now'),
    labelResetButton: makeProp(PROP_TYPE_STRING, 'Reset'),
    noCloseButton: makeProp(PROP_TYPE_BOOLEAN, false),
    nowButton: makeProp(PROP_TYPE_BOOLEAN, false),
    nowButtonVariant: makeProp(PROP_TYPE_STRING, 'outline-primary'),
    resetButton: makeProp(PROP_TYPE_BOOLEAN, false),
    resetButtonVariant: makeProp(PROP_TYPE_STRING, 'outline-danger'),
    resetValue: makeProp(PROP_TYPE_DATE_STRING)
  })), NAME_FORM_TIMEPICKER); // --- Main component ---
  // @vue/component

  var BFormTimepicker = /*#__PURE__*/extend({
    name: NAME_FORM_TIMEPICKER,
    mixins: [idMixin, modelMixin$6],
    props: props$17,
    data: function data() {
      return {
        // We always use `HH:mm:ss` value internally
        localHMS: this[MODEL_PROP_NAME$6] || '',
        // Context data from BTime
        localLocale: null,
        isRTL: false,
        formattedValue: '',
        // If the menu is opened
        isVisible: false
      };
    },
    computed: {
      computedLang: function computedLang() {
        return (this.localLocale || '').replace(/-u-.*$/i, '') || null;
      }
    },
    watch: (_watch$7 = {}, _defineProperty(_watch$7, MODEL_PROP_NAME$6, function (newValue) {
      this.localHMS = newValue || '';
    }), _defineProperty(_watch$7, "localHMS", function localHMS(newValue) {
      // We only update the v-model value when the timepicker
      // is open, to prevent cursor jumps when bound to a
      // text input in button only mode
      if (this.isVisible) {
        this.$emit(MODEL_EVENT_NAME$6, newValue || '');
      }
    }), _watch$7),
    methods: {
      // Public methods
      focus: function focus() {
        if (!this.disabled) {
          attemptFocus(this.$refs.control);
        }
      },
      blur: function blur() {
        if (!this.disabled) {
          attemptBlur(this.$refs.control);
        }
      },
      // Private methods
      setAndClose: function setAndClose(value) {
        var _this = this;

        this.localHMS = value;
        this.$nextTick(function () {
          _this.$refs.control.hide(true);
        });
      },
      onInput: function onInput(hms) {
        if (this.localHMS !== hms) {
          this.localHMS = hms;
        }
      },
      onContext: function onContext(ctx) {
        var isRTL = ctx.isRTL,
            locale = ctx.locale,
            value = ctx.value,
            formatted = ctx.formatted;
        this.isRTL = isRTL;
        this.localLocale = locale;
        this.formattedValue = formatted;
        this.localHMS = value || ''; // Re-emit the context event

        this.$emit(EVENT_NAME_CONTEXT, ctx);
      },
      onNowButton: function onNowButton() {
        var now = new Date();
        var hours = now.getHours();
        var minutes = now.getMinutes();
        var seconds = this.showSeconds ? now.getSeconds() : 0;
        var value = [hours, minutes, seconds].map(function (v) {
          return "00".concat(v || '').slice(-2);
        }).join(':');
        this.setAndClose(value);
      },
      onResetButton: function onResetButton() {
        this.setAndClose(this.resetValue);
      },
      onCloseButton: function onCloseButton() {
        this.$refs.control.hide(true);
      },
      onShow: function onShow() {
        this.isVisible = true;
      },
      onShown: function onShown() {
        var _this2 = this;

        this.$nextTick(function () {
          attemptFocus(_this2.$refs.time);

          _this2.$emit(EVENT_NAME_SHOWN);
        });
      },
      onHidden: function onHidden() {
        this.isVisible = false;
        this.$emit(EVENT_NAME_HIDDEN);
      },
      // Render function helpers
      defaultButtonFn: function defaultButtonFn(_ref) {
        var isHovered = _ref.isHovered,
            hasFocus = _ref.hasFocus;
        return this.$createElement(isHovered || hasFocus ? BIconClockFill : BIconClock, {
          attrs: {
            'aria-hidden': 'true'
          }
        });
      }
    },
    render: function render(h) {
      var localHMS = this.localHMS,
          disabled = this.disabled,
          readonly = this.readonly,
          $props = this.$props;
      var placeholder = isUndefinedOrNull(this.placeholder) ? this.labelNoTimeSelected : this.placeholder; // Footer buttons

      var $footer = [];

      if (this.nowButton) {
        var label = this.labelNowButton;
        $footer.push(h(BButton, {
          props: {
            size: 'sm',
            disabled: disabled || readonly,
            variant: this.nowButtonVariant
          },
          attrs: {
            'aria-label': label || null
          },
          on: {
            click: this.onNowButton
          },
          key: 'now-btn'
        }, label));
      }

      if (this.resetButton) {
        if ($footer.length > 0) {
          // Add a "spacer" between buttons ('&nbsp;')
          $footer.push(h('span', "\xA0"));
        }

        var _label = this.labelResetButton;
        $footer.push(h(BButton, {
          props: {
            size: 'sm',
            disabled: disabled || readonly,
            variant: this.resetButtonVariant
          },
          attrs: {
            'aria-label': _label || null
          },
          on: {
            click: this.onResetButton
          },
          key: 'reset-btn'
        }, _label));
      }

      if (!this.noCloseButton) {
        // Add a "spacer" between buttons ('&nbsp;')
        if ($footer.length > 0) {
          $footer.push(h('span', "\xA0"));
        }

        var _label2 = this.labelCloseButton;
        $footer.push(h(BButton, {
          props: {
            size: 'sm',
            disabled: disabled,
            variant: this.closeButtonVariant
          },
          attrs: {
            'aria-label': _label2 || null
          },
          on: {
            click: this.onCloseButton
          },
          key: 'close-btn'
        }, _label2));
      }

      if ($footer.length > 0) {
        $footer = [h('div', {
          staticClass: 'b-form-date-controls d-flex flex-wrap',
          class: {
            'justify-content-between': $footer.length > 1,
            'justify-content-end': $footer.length < 2
          }
        }, $footer)];
      }

      var $time = h(BTime, {
        staticClass: 'b-form-time-control',
        props: _objectSpread2$3(_objectSpread2$3({}, pluckProps(timeProps, $props)), {}, {
          value: localHMS,
          hidden: !this.isVisible
        }),
        on: {
          input: this.onInput,
          context: this.onContext
        },
        ref: 'time'
      }, $footer);
      return h(BVFormBtnLabelControl, {
        staticClass: 'b-form-timepicker',
        props: _objectSpread2$3(_objectSpread2$3({}, pluckProps(formBtnLabelControlProps, $props)), {}, {
          id: this.safeId(),
          value: localHMS,
          formattedValue: localHMS ? this.formattedValue : '',
          placeholder: placeholder,
          rtl: this.isRTL,
          lang: this.computedLang
        }),
        on: {
          show: this.onShow,
          shown: this.onShown,
          hidden: this.onHidden
        },
        scopedSlots: _defineProperty({}, SLOT_NAME_BUTTON_CONTENT, this.$scopedSlots[SLOT_NAME_BUTTON_CONTENT] || this.defaultButtonFn),
        ref: 'control'
      }, [$time]);
    }
  });

  var FormTimepickerPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BFormTimepicker: BFormTimepicker,
      BTimepicker: BFormTimepicker
    }
  });

  var ImagePlugin = /*#__PURE__*/pluginFactory({
    components: {
      BImg: BImg,
      BImgLazy: BImgLazy
    }
  });

  var props$16 = makePropsConfigurable({
    tag: makeProp(PROP_TYPE_STRING, 'div')
  }, NAME_INPUT_GROUP_TEXT); // --- Main component ---
  // @vue/component

  var BInputGroupText = /*#__PURE__*/extend({
    name: NAME_INPUT_GROUP_TEXT,
    functional: true,
    props: props$16,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      return h(props.tag, a(data, {
        staticClass: 'input-group-text'
      }), children);
    }
  });

  var props$15 = makePropsConfigurable({
    append: makeProp(PROP_TYPE_BOOLEAN, false),
    id: makeProp(PROP_TYPE_STRING),
    isText: makeProp(PROP_TYPE_BOOLEAN, false),
    tag: makeProp(PROP_TYPE_STRING, 'div')
  }, NAME_INPUT_GROUP_ADDON); // --- Main component ---
  // @vue/component

  var BInputGroupAddon = /*#__PURE__*/extend({
    name: NAME_INPUT_GROUP_ADDON,
    functional: true,
    props: props$15,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      var append = props.append;
      return h(props.tag, a(data, {
        class: {
          'input-group-append': append,
          'input-group-prepend': !append
        },
        attrs: {
          id: props.id
        }
      }), props.isText ? [h(BInputGroupText, children)] : children);
    }
  });

  var props$14 = makePropsConfigurable(omit(props$15, ['append']), NAME_INPUT_GROUP_APPEND); // --- Main component ---
  // @vue/component

  var BInputGroupAppend = /*#__PURE__*/extend({
    name: NAME_INPUT_GROUP_APPEND,
    functional: true,
    props: props$14,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      // Pass all our data down to child, and set `append` to `true`
      return h(BInputGroupAddon, a(data, {
        props: _objectSpread2$3(_objectSpread2$3({}, props), {}, {
          append: true
        })
      }), children);
    }
  });

  var props$13 = makePropsConfigurable(omit(props$15, ['append']), NAME_INPUT_GROUP_PREPEND); // --- Main component ---
  // @vue/component

  var BInputGroupPrepend = /*#__PURE__*/extend({
    name: NAME_INPUT_GROUP_PREPEND,
    functional: true,
    props: props$13,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      // Pass all our data down to child, and set `append` to `true`
      return h(BInputGroupAddon, a(data, {
        props: _objectSpread2$3(_objectSpread2$3({}, props), {}, {
          append: false
        })
      }), children);
    }
  });

  var props$12 = makePropsConfigurable({
    append: makeProp(PROP_TYPE_STRING),
    appendHtml: makeProp(PROP_TYPE_STRING),
    id: makeProp(PROP_TYPE_STRING),
    prepend: makeProp(PROP_TYPE_STRING),
    prependHtml: makeProp(PROP_TYPE_STRING),
    size: makeProp(PROP_TYPE_STRING),
    tag: makeProp(PROP_TYPE_STRING, 'div')
  }, NAME_INPUT_GROUP); // --- Main component ---
  // @vue/component

  var BInputGroup = /*#__PURE__*/extend({
    name: NAME_INPUT_GROUP,
    functional: true,
    props: props$12,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          slots = _ref.slots,
          scopedSlots = _ref.scopedSlots;
      var prepend = props.prepend,
          prependHtml = props.prependHtml,
          append = props.append,
          appendHtml = props.appendHtml,
          size = props.size;
      var $scopedSlots = scopedSlots || {};
      var $slots = slots();
      var slotScope = {};
      var $prepend = h();
      var hasPrependSlot = hasNormalizedSlot(SLOT_NAME_PREPEND, $scopedSlots, $slots);

      if (hasPrependSlot || prepend || prependHtml) {
        $prepend = h(BInputGroupPrepend, [hasPrependSlot ? normalizeSlot(SLOT_NAME_PREPEND, slotScope, $scopedSlots, $slots) : h(BInputGroupText, {
          domProps: htmlOrText(prependHtml, prepend)
        })]);
      }

      var $append = h();
      var hasAppendSlot = hasNormalizedSlot(SLOT_NAME_APPEND, $scopedSlots, $slots);

      if (hasAppendSlot || append || appendHtml) {
        $append = h(BInputGroupAppend, [hasAppendSlot ? normalizeSlot(SLOT_NAME_APPEND, slotScope, $scopedSlots, $slots) : h(BInputGroupText, {
          domProps: htmlOrText(appendHtml, append)
        })]);
      }

      return h(props.tag, a(data, {
        staticClass: 'input-group',
        class: _defineProperty({}, "input-group-".concat(size), size),
        attrs: {
          id: props.id || null,
          role: 'group'
        }
      }), [$prepend, normalizeSlot(SLOT_NAME_DEFAULT, slotScope, $scopedSlots, $slots), $append]);
    }
  });

  var InputGroupPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BInputGroup: BInputGroup,
      BInputGroupAddon: BInputGroupAddon,
      BInputGroupPrepend: BInputGroupPrepend,
      BInputGroupAppend: BInputGroupAppend,
      BInputGroupText: BInputGroupText
    }
  });

  var props$11 = makePropsConfigurable({
    // String breakpoint name new in Bootstrap v4.4.x
    fluid: makeProp(PROP_TYPE_BOOLEAN_STRING, false),
    tag: makeProp(PROP_TYPE_STRING, 'div')
  }, NAME_CONTAINER); // --- Main component ---
  // @vue/component

  var BContainer = /*#__PURE__*/extend({
    name: NAME_CONTAINER,
    functional: true,
    props: props$11,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      var fluid = props.fluid;
      return h(props.tag, a(data, {
        class: _defineProperty({
          container: !(fluid || fluid === ''),
          'container-fluid': fluid === true || fluid === ''
        }, "container-".concat(fluid), fluid && fluid !== true)
      }), children);
    }
  });

  var props$10 = makePropsConfigurable({
    bgVariant: makeProp(PROP_TYPE_STRING),
    borderVariant: makeProp(PROP_TYPE_STRING),
    containerFluid: makeProp(PROP_TYPE_BOOLEAN_STRING, false),
    fluid: makeProp(PROP_TYPE_BOOLEAN, false),
    header: makeProp(PROP_TYPE_STRING),
    headerHtml: makeProp(PROP_TYPE_STRING),
    headerLevel: makeProp(PROP_TYPE_NUMBER_STRING, 3),
    headerTag: makeProp(PROP_TYPE_STRING, 'h1'),
    lead: makeProp(PROP_TYPE_STRING),
    leadHtml: makeProp(PROP_TYPE_STRING),
    leadTag: makeProp(PROP_TYPE_STRING, 'p'),
    tag: makeProp(PROP_TYPE_STRING, 'div'),
    textVariant: makeProp(PROP_TYPE_STRING)
  }, NAME_JUMBOTRON); // --- Main component ---
  // @vue/component

  var BJumbotron = /*#__PURE__*/extend({
    name: NAME_JUMBOTRON,
    functional: true,
    props: props$10,
    render: function render(h, _ref) {
      var _class2;

      var props = _ref.props,
          data = _ref.data,
          slots = _ref.slots,
          scopedSlots = _ref.scopedSlots;
      var header = props.header,
          headerHtml = props.headerHtml,
          lead = props.lead,
          leadHtml = props.leadHtml,
          textVariant = props.textVariant,
          bgVariant = props.bgVariant,
          borderVariant = props.borderVariant;
      var $scopedSlots = scopedSlots || {};
      var $slots = slots();
      var slotScope = {};
      var $header = h();
      var hasHeaderSlot = hasNormalizedSlot(SLOT_NAME_HEADER, $scopedSlots, $slots);

      if (hasHeaderSlot || header || headerHtml) {
        var headerLevel = props.headerLevel;
        $header = h(props.headerTag, {
          class: _defineProperty({}, "display-".concat(headerLevel), headerLevel),
          domProps: hasHeaderSlot ? {} : htmlOrText(headerHtml, header)
        }, normalizeSlot(SLOT_NAME_HEADER, slotScope, $scopedSlots, $slots));
      }

      var $lead = h();
      var hasLeadSlot = hasNormalizedSlot(SLOT_NAME_LEAD, $scopedSlots, $slots);

      if (hasLeadSlot || lead || leadHtml) {
        $lead = h(props.leadTag, {
          staticClass: 'lead',
          domProps: hasLeadSlot ? {} : htmlOrText(leadHtml, lead)
        }, normalizeSlot(SLOT_NAME_LEAD, slotScope, $scopedSlots, $slots));
      }

      var $children = [$header, $lead, normalizeSlot(SLOT_NAME_DEFAULT, slotScope, $scopedSlots, $slots)]; // If fluid, wrap content in a container

      if (props.fluid) {
        $children = [h(BContainer, {
          props: {
            fluid: props.containerFluid
          }
        }, $children)];
      }

      return h(props.tag, a(data, {
        staticClass: 'jumbotron',
        class: (_class2 = {
          'jumbotron-fluid': props.fluid
        }, _defineProperty(_class2, "text-".concat(textVariant), textVariant), _defineProperty(_class2, "bg-".concat(bgVariant), bgVariant), _defineProperty(_class2, "border-".concat(borderVariant), borderVariant), _defineProperty(_class2, "border", borderVariant), _class2)
      }), $children);
    }
  });

  var JumbotronPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BJumbotron: BJumbotron
    }
  });

  var COMMON_ALIGNMENT = ['start', 'end', 'center']; // --- Helper methods ---
  // Compute a `row-cols-{breakpoint}-{cols}` class name
  // Memoized function for better performance on generating class names

  var computeRowColsClass = memoize(function (breakpoint, cols) {
    cols = trim(toString(cols));
    return cols ? lowerCase(['row-cols', breakpoint, cols].filter(identity).join('-')) : null;
  }); // Get the breakpoint name from the `rowCols` prop name
  // Memoized function for better performance on extracting breakpoint names

  var computeRowColsBreakpoint = memoize(function (prop) {
    return lowerCase(prop.replace('cols', ''));
  }); // Cached copy of the `row-cols` breakpoint prop names
  // Will be populated when the props are generated

  var rowColsPropList = []; // --- Props ---
  // Prop generator for lazy generation of props

  var generateProps = function generateProps() {
    // i.e. 'row-cols-2', 'row-cols-md-4', 'row-cols-xl-6', ...
    var rowColsProps = getBreakpointsUpCached().reduce(function (props, breakpoint) {
      props[suffixPropName(breakpoint, 'cols')] = makeProp(PROP_TYPE_NUMBER_STRING);
      return props;
    }, create(null)); // Cache the row-cols prop names

    rowColsPropList = keys(rowColsProps); // Return the generated props

    return makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, rowColsProps), {}, {
      alignContent: makeProp(PROP_TYPE_STRING, null, function (value) {
        return arrayIncludes(concat(COMMON_ALIGNMENT, 'between', 'around', 'stretch'), value);
      }),
      alignH: makeProp(PROP_TYPE_STRING, null, function (value) {
        return arrayIncludes(concat(COMMON_ALIGNMENT, 'between', 'around'), value);
      }),
      alignV: makeProp(PROP_TYPE_STRING, null, function (value) {
        return arrayIncludes(concat(COMMON_ALIGNMENT, 'baseline', 'stretch'), value);
      }),
      noGutters: makeProp(PROP_TYPE_BOOLEAN, false),
      tag: makeProp(PROP_TYPE_STRING, 'div')
    })), NAME_ROW);
  }; // --- Main component ---
  // We do not use `extend()` here as that would evaluate the props
  // immediately, which we do not want to happen
  // @vue/component

  var BRow = {
    name: NAME_ROW,
    functional: true,

    get props() {
      // Allow props to be lazy evaled on first access and
      // then they become a non-getter afterwards
      // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get#Smart_self-overwriting_lazy_getters
      delete this.props;
      this.props = generateProps();
      return this.props;
    },

    render: function render(h, _ref) {
      var _classList$push;

      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      var alignV = props.alignV,
          alignH = props.alignH,
          alignContent = props.alignContent; // Loop through row-cols breakpoint props and generate the classes

      var classList = [];
      rowColsPropList.forEach(function (prop) {
        var c = computeRowColsClass(computeRowColsBreakpoint(prop), props[prop]); // If a class is returned, push it onto the array

        if (c) {
          classList.push(c);
        }
      });
      classList.push((_classList$push = {
        'no-gutters': props.noGutters
      }, _defineProperty(_classList$push, "align-items-".concat(alignV), alignV), _defineProperty(_classList$push, "justify-content-".concat(alignH), alignH), _defineProperty(_classList$push, "align-content-".concat(alignContent), alignContent), _classList$push));
      return h(props.tag, a(data, {
        staticClass: 'row',
        class: classList
      }), children);
    }
  };

  var LayoutPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BContainer: BContainer,
      BRow: BRow,
      BCol: BCol,
      BFormRow: BFormRow
    }
  });

  var LinkPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BLink: BLink
    }
  });

  var props$$ = makePropsConfigurable({
    flush: makeProp(PROP_TYPE_BOOLEAN, false),
    horizontal: makeProp(PROP_TYPE_BOOLEAN_STRING, false),
    tag: makeProp(PROP_TYPE_STRING, 'div')
  }, NAME_LIST_GROUP); // --- Main component ---
  // @vue/component

  var BListGroup = /*#__PURE__*/extend({
    name: NAME_LIST_GROUP,
    functional: true,
    props: props$$,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      var horizontal = props.horizontal === '' ? true : props.horizontal;
      horizontal = props.flush ? false : horizontal;
      var componentData = {
        staticClass: 'list-group',
        class: _defineProperty({
          'list-group-flush': props.flush,
          'list-group-horizontal': horizontal === true
        }, "list-group-horizontal-".concat(horizontal), isString(horizontal))
      };
      return h(props.tag, a(data, componentData), children);
    }
  });

  var actionTags = ['a', 'router-link', 'button', 'b-link']; // --- Props ---

  var linkProps$3 = omit(props$2f, ['event', 'routerTag']);
  delete linkProps$3.href.default;
  delete linkProps$3.to.default;
  var props$_ = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, linkProps$3), {}, {
    action: makeProp(PROP_TYPE_BOOLEAN, false),
    button: makeProp(PROP_TYPE_BOOLEAN, false),
    tag: makeProp(PROP_TYPE_STRING, 'div'),
    variant: makeProp(PROP_TYPE_STRING)
  })), NAME_LIST_GROUP_ITEM); // --- Main component ---
  // @vue/component

  var BListGroupItem = /*#__PURE__*/extend({
    name: NAME_LIST_GROUP_ITEM,
    functional: true,
    props: props$_,
    render: function render(h, _ref) {
      var _class;

      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      var button = props.button,
          variant = props.variant,
          active = props.active,
          disabled = props.disabled;
      var link = isLink$1(props);
      var tag = button ? 'button' : !link ? props.tag : BLink;
      var action = !!(props.action || link || button || arrayIncludes(actionTags, props.tag));
      var attrs = {};
      var itemProps = {};

      if (isTag(tag, 'button')) {
        if (!data.attrs || !data.attrs.type) {
          // Add a type for button is one not provided in passed attributes
          attrs.type = 'button';
        }

        if (props.disabled) {
          // Set disabled attribute if button and disabled
          attrs.disabled = true;
        }
      } else {
        itemProps = pluckProps(linkProps$3, props);
      }

      return h(tag, a(data, {
        attrs: attrs,
        props: itemProps,
        staticClass: 'list-group-item',
        class: (_class = {}, _defineProperty(_class, "list-group-item-".concat(variant), variant), _defineProperty(_class, 'list-group-item-action', action), _defineProperty(_class, "active", active), _defineProperty(_class, "disabled", disabled), _class)
      }), children);
    }
  });

  var ListGroupPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BListGroup: BListGroup,
      BListGroupItem: BListGroupItem
    }
  });

  var props$Z = makePropsConfigurable({
    right: makeProp(PROP_TYPE_BOOLEAN, false),
    tag: makeProp(PROP_TYPE_STRING, 'div'),
    verticalAlign: makeProp(PROP_TYPE_STRING, 'top')
  }, NAME_MEDIA_ASIDE); // --- Main component ---
  // @vue/component

  var BMediaAside = /*#__PURE__*/extend({
    name: NAME_MEDIA_ASIDE,
    functional: true,
    props: props$Z,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      var verticalAlign = props.verticalAlign;
      var align = verticalAlign === 'top' ? 'start' : verticalAlign === 'bottom' ? 'end' :
      /* istanbul ignore next */
      verticalAlign;
      return h(props.tag, a(data, {
        staticClass: 'media-aside',
        class: _defineProperty({
          'media-aside-right': props.right
        }, "align-self-".concat(align), align)
      }), children);
    }
  });

  var props$Y = makePropsConfigurable({
    tag: makeProp(PROP_TYPE_STRING, 'div')
  }, NAME_MEDIA_BODY); // --- Main component ---
  // @vue/component

  var BMediaBody = /*#__PURE__*/extend({
    name: NAME_MEDIA_BODY,
    functional: true,
    props: props$Y,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      return h(props.tag, a(data, {
        staticClass: 'media-body'
      }), children);
    }
  });

  var props$X = makePropsConfigurable({
    noBody: makeProp(PROP_TYPE_BOOLEAN, false),
    rightAlign: makeProp(PROP_TYPE_BOOLEAN, false),
    tag: makeProp(PROP_TYPE_STRING, 'div'),
    verticalAlign: makeProp(PROP_TYPE_STRING, 'top')
  }, NAME_MEDIA); // --- Main component ---
  // @vue/component

  var BMedia = /*#__PURE__*/extend({
    name: NAME_MEDIA,
    functional: true,
    props: props$X,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          slots = _ref.slots,
          scopedSlots = _ref.scopedSlots,
          children = _ref.children;
      var noBody = props.noBody,
          rightAlign = props.rightAlign,
          verticalAlign = props.verticalAlign;
      var $children = noBody ? children : [];

      if (!noBody) {
        var slotScope = {};
        var $slots = slots();
        var $scopedSlots = scopedSlots || {};
        $children.push(h(BMediaBody, normalizeSlot(SLOT_NAME_DEFAULT, slotScope, $scopedSlots, $slots)));
        var $aside = normalizeSlot(SLOT_NAME_ASIDE, slotScope, $scopedSlots, $slots);

        if ($aside) {
          $children[rightAlign ? 'push' : 'unshift'](h(BMediaAside, {
            props: {
              right: rightAlign,
              verticalAlign: verticalAlign
            }
          }, $aside));
        }
      }

      return h(props.tag, a(data, {
        staticClass: 'media'
      }), $children);
    }
  });

  var MediaPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BMedia: BMedia,
      BMediaAside: BMediaAside,
      BMediaBody: BMediaBody
    }
  });

  var PROP$1 = '$_documentListeners'; // --- Mixin ---
  // @vue/component

  var listenOnDocumentMixin = extend({
    created: function created() {
      // Define non-reactive property
      // Object of arrays, keyed by event name,
      // where value is an array of callbacks
      this[PROP$1] = {};
    },
    beforeDestroy: function beforeDestroy() {
      var _this = this;

      // Unregister all registered listeners
      keys(this[PROP$1] || {}).forEach(function (event) {
        _this[PROP$1][event].forEach(function (callback) {
          _this.listenOffDocument(event, callback);
        });
      });
      this[PROP$1] = null;
    },
    methods: {
      registerDocumentListener: function registerDocumentListener(event, callback) {
        if (this[PROP$1]) {
          this[PROP$1][event] = this[PROP$1][event] || [];

          if (!arrayIncludes(this[PROP$1][event], callback)) {
            this[PROP$1][event].push(callback);
          }
        }
      },
      unregisterDocumentListener: function unregisterDocumentListener(event, callback) {
        if (this[PROP$1] && this[PROP$1][event]) {
          this[PROP$1][event] = this[PROP$1][event].filter(function (cb) {
            return cb !== callback;
          });
        }
      },
      listenDocument: function listenDocument(on, event, callback) {
        on ? this.listenOnDocument(event, callback) : this.listenOffDocument(event, callback);
      },
      listenOnDocument: function listenOnDocument(event, callback) {
        if (IS_BROWSER) {
          eventOn(document, event, callback, EVENT_OPTIONS_NO_CAPTURE);
          this.registerDocumentListener(event, callback);
        }
      },
      listenOffDocument: function listenOffDocument(event, callback) {
        if (IS_BROWSER) {
          eventOff(document, event, callback, EVENT_OPTIONS_NO_CAPTURE);
        }

        this.unregisterDocumentListener(event, callback);
      }
    }
  });

  var PROP = '$_windowListeners'; // --- Mixin ---
  // @vue/component

  var listenOnWindowMixin = extend({
    created: function created() {
      // Define non-reactive property
      // Object of arrays, keyed by event name,
      // where value is an array of callbacks
      this[PROP] = {};
    },
    beforeDestroy: function beforeDestroy() {
      var _this = this;

      // Unregister all registered listeners
      keys(this[PROP] || {}).forEach(function (event) {
        _this[PROP][event].forEach(function (callback) {
          _this.listenOffWindow(event, callback);
        });
      });
      this[PROP] = null;
    },
    methods: {
      registerWindowListener: function registerWindowListener(event, callback) {
        if (this[PROP]) {
          this[PROP][event] = this[PROP][event] || [];

          if (!arrayIncludes(this[PROP][event], callback)) {
            this[PROP][event].push(callback);
          }
        }
      },
      unregisterWindowListener: function unregisterWindowListener(event, callback) {
        if (this[PROP] && this[PROP][event]) {
          this[PROP][event] = this[PROP][event].filter(function (cb) {
            return cb !== callback;
          });
        }
      },
      listenWindow: function listenWindow(on, event, callback) {
        on ? this.listenOnWindow(event, callback) : this.listenOffWindow(event, callback);
      },
      listenOnWindow: function listenOnWindow(event, callback) {
        if (IS_BROWSER) {
          eventOn(window, event, callback, EVENT_OPTIONS_NO_CAPTURE);
          this.registerWindowListener(event, callback);
        }
      },
      listenOffWindow: function listenOffWindow(event, callback) {
        if (IS_BROWSER) {
          eventOff(window, event, callback, EVENT_OPTIONS_NO_CAPTURE);
        }

        this.unregisterWindowListener(event, callback);
      }
    }
  });

  // @vue/component

  var useParentMixin = extend({
    computed: {
      bvParent: function bvParent() {
        return this.$parent || this.$root === this && this.$options.bvParent;
      }
    }
  });

  // This method returns a component's scoped style attribute name: `data-v-xxxxxxx`
  // The `_scopeId` options property is added by vue-loader when using scoped styles
  // and will be `undefined` if no scoped styles are in use
  var getScopeId = function getScopeId(vm) {
    var defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
    return vm ? vm.$options._scopeId || defaultValue : defaultValue;
  };

  var scopedStyleMixin = extend({
    mixins: [useParentMixin],
    computed: {
      scopedStyleAttrs: function scopedStyleAttrs() {
        var scopeId = getScopeId(this.bvParent);
        return scopeId ? _defineProperty({}, scopeId, '') : {};
      }
    }
  });

  var createNewChildComponent = function createNewChildComponent(parent, Component) {
    var config = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
    var bvEventRoot = parent.$root ? parent.$root.$options.bvEventRoot || parent.$root : null;
    return new Component(_objectSpread2$3(_objectSpread2$3({}, config), {}, {
      parent: parent,
      bvParent: parent,
      bvEventRoot: bvEventRoot
    }));
  };

  // BVTransporter/BVTransporterTarget:
  //
  // Single root node portaling of content, which retains parent/child hierarchy
  // Unlike Portal-Vue where portaled content is no longer a descendent of its
  // intended parent components
  //
  // Private components for use by Tooltips, Popovers and Modals
  //
  // Based on vue-simple-portal
  // https://github.com/LinusBorg/vue-simple-portal
  // Transporter target used by BVTransporter
  // Supports only a single root element
  // @vue/component

  var BVTransporterTarget = /*#__PURE__*/extend({
    // As an abstract component, it doesn't appear in the $parent chain of
    // components, which means the next parent of any component rendered inside
    // of this one will be the parent from which is was portal'd
    abstract: true,
    name: NAME_TRANSPORTER_TARGET,
    props: {
      // Even though we only support a single root element,
      // VNodes are always passed as an array
      nodes: makeProp(PROP_TYPE_ARRAY_FUNCTION)
    },
    data: function data(vm) {
      return {
        updatedNodes: vm.nodes
      };
    },
    destroyed: function destroyed() {
      removeNode(this.$el);
    },
    render: function render(h) {
      var updatedNodes = this.updatedNodes;
      var $nodes = isFunction$1(updatedNodes) ? updatedNodes({}) : updatedNodes;
      $nodes = concat($nodes).filter(identity);

      if ($nodes && $nodes.length > 0 && !$nodes[0].text) {
        return $nodes[0];
      }
      /* istanbul ignore next */


      return h();
    }
  }); // --- Props ---

  var props$W = {
    // String: CSS selector,
    // HTMLElement: Element reference
    // Mainly needed for tooltips/popovers inside modals
    container: makeProp([HTMLElement, PROP_TYPE_STRING], 'body'),
    disabled: makeProp(PROP_TYPE_BOOLEAN, false),
    // This should be set to match the root element type
    tag: makeProp(PROP_TYPE_STRING, 'div')
  }; // --- Main component ---
  // @vue/component

  var BVTransporterVue2 = /*#__PURE__*/extend({
    name: NAME_TRANSPORTER,
    mixins: [normalizeSlotMixin],
    props: props$W,
    watch: {
      disabled: {
        immediate: true,
        handler: function handler(disabled) {
          disabled ? this.unmountTarget() : this.$nextTick(this.mountTarget);
        }
      }
    },
    created: function created() {
      // Create private non-reactive props
      this.$_defaultFn = null;
      this.$_target = null;
    },
    beforeMount: function beforeMount() {
      this.mountTarget();
    },
    updated: function updated() {
      // We need to make sure that all children have completed updating
      // before rendering in the target
      // `vue-simple-portal` has the this in a `$nextTick()`,
      // while `portal-vue` doesn't
      // Just trying to see if the `$nextTick()` delay is required or not
      // Since all slots in Vue 2.6.x are always functions
      this.updateTarget();
    },
    beforeDestroy: function beforeDestroy() {
      this.unmountTarget();
      this.$_defaultFn = null;
    },
    methods: {
      // Get the element which the target should be appended to
      getContainer: function getContainer() {
        /* istanbul ignore else */
        if (IS_BROWSER) {
          var container = this.container;
          return isString(container) ? select(container) : container;
        } else {
          return null;
        }
      },
      // Mount the target
      mountTarget: function mountTarget() {
        if (!this.$_target) {
          var $container = this.getContainer();

          if ($container) {
            var $el = document.createElement('div');
            $container.appendChild($el);
            this.$_target = createNewChildComponent(this, BVTransporterTarget, {
              el: $el,
              propsData: {
                // Initial nodes to be rendered
                nodes: concat(this.normalizeSlot())
              }
            });
          }
        }
      },
      // Update the content of the target
      updateTarget: function updateTarget() {
        if (IS_BROWSER && this.$_target) {
          var defaultFn = this.$scopedSlots.default;

          if (!this.disabled) {
            /* istanbul ignore else: only applicable in Vue 2.5.x */
            if (defaultFn && this.$_defaultFn !== defaultFn) {
              // We only update the target component if the scoped slot
              // function is a fresh one. The new slot syntax (since Vue 2.6)
              // can cache unchanged slot functions and we want to respect that here
              this.$_target.updatedNodes = defaultFn;
            } else if (!defaultFn) {
              // We also need to be back compatible with non-scoped default slot (i.e. 2.5.x)
              this.$_target.updatedNodes = this.$slots.default;
            }
          } // Update the scoped slot function cache


          this.$_defaultFn = defaultFn;
        }
      },
      // Unmount the target
      unmountTarget: function unmountTarget() {
        this.$_target && this.$_target.$destroy();
        this.$_target = null;
      }
    },
    render: function render(h) {
      // This component has no root element, so only a single VNode is allowed
      if (this.disabled) {
        var $nodes = concat(this.normalizeSlot()).filter(identity);

        if ($nodes.length > 0 && !$nodes[0].text) {
          return $nodes[0];
        }
      }

      return h();
    }
  });
  var BVTransporterVue3 = /*#__PURE__*/extend({
    name: NAME_TRANSPORTER,
    mixins: [normalizeSlotMixin],
    props: props$W,
    render: function render(h) {
      if (this.disabled) {
        var $nodes = concat(this.normalizeSlot()).filter(identity);

        if ($nodes.length > 0) {
          return $nodes[0];
        }
      }

      return h(Vue__default['default'].Teleport, {
        to: this.container
      }, this.normalizeSlot());
    }
  });
  var BVTransporter = isVue3 ? BVTransporterVue3 : BVTransporterVue2;

  var BvModalEvent = /*#__PURE__*/function (_BvEvent) {
    _inherits(BvModalEvent, _BvEvent);

    var _super = _createSuper(BvModalEvent);

    function BvModalEvent(type) {
      var _this;

      var eventInit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

      _classCallCheck(this, BvModalEvent);

      _this = _super.call(this, type, eventInit); // Freeze our new props as readonly, but leave them enumerable

      defineProperties(_assertThisInitialized(_this), {
        trigger: readonlyDescriptor()
      });
      return _this;
    }

    _createClass(BvModalEvent, null, [{
      key: "Defaults",
      get: function get() {
        return _objectSpread2$3(_objectSpread2$3({}, _get(_getPrototypeOf(BvModalEvent), "Defaults", this)), {}, {
          trigger: null
        });
      }
    }]);

    return BvModalEvent;
  }(BvEvent); // Named exports

  /**
   * Private ModalManager helper
   * Handles controlling modal stacking zIndexes and body adjustments/classes
   */
  // Default modal backdrop z-index

  var DEFAULT_ZINDEX = 1040; // Selectors for padding/margin adjustments

  var SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top';
  var SELECTOR_STICKY_CONTENT = '.sticky-top';
  var SELECTOR_NAVBAR_TOGGLER = '.navbar-toggler'; // --- Main component ---
  // @vue/component

  var ModalManager = /*#__PURE__*/extend({
    data: function data() {
      return {
        modals: [],
        baseZIndex: null,
        scrollbarWidth: null,
        isBodyOverflowing: false
      };
    },
    computed: {
      modalCount: function modalCount() {
        return this.modals.length;
      },
      modalsAreOpen: function modalsAreOpen() {
        return this.modalCount > 0;
      }
    },
    watch: {
      modalCount: function modalCount(newCount, oldCount) {
        if (IS_BROWSER) {
          this.getScrollbarWidth();

          if (newCount > 0 && oldCount === 0) {
            // Transitioning to modal(s) open
            this.checkScrollbar();
            this.setScrollbar();
            addClass(document.body, 'modal-open');
          } else if (newCount === 0 && oldCount > 0) {
            // Transitioning to modal(s) closed
            this.resetScrollbar();
            removeClass(document.body, 'modal-open');
          }

          setAttr(document.body, 'data-modal-open-count', String(newCount));
        }
      },
      modals: function modals(newValue) {
        var _this = this;

        this.checkScrollbar();
        requestAF(function () {
          _this.updateModals(newValue || []);
        });
      }
    },
    methods: {
      // Public methods
      registerModal: function registerModal(modal) {
        // Register the modal if not already registered
        if (modal && this.modals.indexOf(modal) === -1) {
          this.modals.push(modal);
        }
      },
      unregisterModal: function unregisterModal(modal) {
        var index = this.modals.indexOf(modal);

        if (index > -1) {
          // Remove modal from modals array
          this.modals.splice(index, 1); // Reset the modal's data

          if (!modal._isBeingDestroyed && !modal._isDestroyed) {
            this.resetModal(modal);
          }
        }
      },
      getBaseZIndex: function getBaseZIndex() {
        if (IS_BROWSER && isNull(this.baseZIndex)) {
          // Create a temporary `div.modal-backdrop` to get computed z-index
          var div = document.createElement('div');
          addClass(div, 'modal-backdrop');
          addClass(div, 'd-none');
          setStyle(div, 'display', 'none');
          document.body.appendChild(div);
          this.baseZIndex = toInteger(getCS(div).zIndex, DEFAULT_ZINDEX);
          document.body.removeChild(div);
        }

        return this.baseZIndex || DEFAULT_ZINDEX;
      },
      getScrollbarWidth: function getScrollbarWidth() {
        if (IS_BROWSER && isNull(this.scrollbarWidth)) {
          // Create a temporary `div.measure-scrollbar` to get computed z-index
          var div = document.createElement('div');
          addClass(div, 'modal-scrollbar-measure');
          document.body.appendChild(div);
          this.scrollbarWidth = getBCR(div).width - div.clientWidth;
          document.body.removeChild(div);
        }

        return this.scrollbarWidth || 0;
      },
      // Private methods
      updateModals: function updateModals(modals) {
        var _this2 = this;

        var baseZIndex = this.getBaseZIndex();
        var scrollbarWidth = this.getScrollbarWidth();
        modals.forEach(function (modal, index) {
          // We update data values on each modal
          modal.zIndex = baseZIndex + index;
          modal.scrollbarWidth = scrollbarWidth;
          modal.isTop = index === _this2.modals.length - 1;
          modal.isBodyOverflowing = _this2.isBodyOverflowing;
        });
      },
      resetModal: function resetModal(modal) {
        if (modal) {
          modal.zIndex = this.getBaseZIndex();
          modal.isTop = true;
          modal.isBodyOverflowing = false;
        }
      },
      checkScrollbar: function checkScrollbar() {
        // Determine if the body element is overflowing
        var _getBCR = getBCR(document.body),
            left = _getBCR.left,
            right = _getBCR.right;

        this.isBodyOverflowing = left + right < window.innerWidth;
      },
      setScrollbar: function setScrollbar() {
        var body = document.body; // Storage place to cache changes to margins and padding
        // Note: This assumes the following element types are not added to the
        // document after the modal has opened.

        body._paddingChangedForModal = body._paddingChangedForModal || [];
        body._marginChangedForModal = body._marginChangedForModal || [];

        if (this.isBodyOverflowing) {
          var scrollbarWidth = this.scrollbarWidth; // Adjust fixed content padding

          /* istanbul ignore next: difficult to test in JSDOM */

          selectAll(SELECTOR_FIXED_CONTENT).forEach(function (el) {
            var actualPadding = getStyle(el, 'paddingRight') || '';
            setAttr(el, 'data-padding-right', actualPadding);
            setStyle(el, 'paddingRight', "".concat(toFloat(getCS(el).paddingRight, 0) + scrollbarWidth, "px"));

            body._paddingChangedForModal.push(el);
          }); // Adjust sticky content margin

          /* istanbul ignore next: difficult to test in JSDOM */

          selectAll(SELECTOR_STICKY_CONTENT).forEach(function (el)
          /* istanbul ignore next */
          {
            var actualMargin = getStyle(el, 'marginRight') || '';
            setAttr(el, 'data-margin-right', actualMargin);
            setStyle(el, 'marginRight', "".concat(toFloat(getCS(el).marginRight, 0) - scrollbarWidth, "px"));

            body._marginChangedForModal.push(el);
          }); // Adjust <b-navbar-toggler> margin

          /* istanbul ignore next: difficult to test in JSDOM */

          selectAll(SELECTOR_NAVBAR_TOGGLER).forEach(function (el)
          /* istanbul ignore next */
          {
            var actualMargin = getStyle(el, 'marginRight') || '';
            setAttr(el, 'data-margin-right', actualMargin);
            setStyle(el, 'marginRight', "".concat(toFloat(getCS(el).marginRight, 0) + scrollbarWidth, "px"));

            body._marginChangedForModal.push(el);
          }); // Adjust body padding

          var actualPadding = getStyle(body, 'paddingRight') || '';
          setAttr(body, 'data-padding-right', actualPadding);
          setStyle(body, 'paddingRight', "".concat(toFloat(getCS(body).paddingRight, 0) + scrollbarWidth, "px"));
        }
      },
      resetScrollbar: function resetScrollbar() {
        var body = document.body;

        if (body._paddingChangedForModal) {
          // Restore fixed content padding
          body._paddingChangedForModal.forEach(function (el) {
            /* istanbul ignore next: difficult to test in JSDOM */
            if (hasAttr(el, 'data-padding-right')) {
              setStyle(el, 'paddingRight', getAttr(el, 'data-padding-right') || '');
              removeAttr(el, 'data-padding-right');
            }
          });
        }

        if (body._marginChangedForModal) {
          // Restore sticky content and navbar-toggler margin
          body._marginChangedForModal.forEach(function (el) {
            /* istanbul ignore next: difficult to test in JSDOM */
            if (hasAttr(el, 'data-margin-right')) {
              setStyle(el, 'marginRight', getAttr(el, 'data-margin-right') || '');
              removeAttr(el, 'data-margin-right');
            }
          });
        }

        body._paddingChangedForModal = null;
        body._marginChangedForModal = null; // Restore body padding

        if (hasAttr(body, 'data-padding-right')) {
          setStyle(body, 'paddingRight', getAttr(body, 'data-padding-right') || '');
          removeAttr(body, 'data-padding-right');
        }
      }
    }
  }); // Create and export our modal manager instance

  var modalManager = new ModalManager();

  var _makeModelMixin$5 = makeModelMixin('visible', {
    type: PROP_TYPE_BOOLEAN,
    defaultValue: false,
    event: EVENT_NAME_CHANGE
  }),
      modelMixin$5 = _makeModelMixin$5.mixin,
      modelProps$5 = _makeModelMixin$5.props,
      MODEL_PROP_NAME$5 = _makeModelMixin$5.prop,
      MODEL_EVENT_NAME$5 = _makeModelMixin$5.event;

  var TRIGGER_BACKDROP = 'backdrop';
  var TRIGGER_ESC = 'esc';
  var TRIGGER_FORCE = 'FORCE';
  var TRIGGER_TOGGLE = 'toggle';
  var BUTTON_CANCEL = 'cancel'; // TODO: This should be renamed to 'close'

  var BUTTON_CLOSE = 'headerclose';
  var BUTTON_OK = 'ok';
  var BUTTONS = [BUTTON_CANCEL, BUTTON_CLOSE, BUTTON_OK]; // `ObserveDom` config to detect changes in modal content
  // so that we can adjust the modal padding if needed

  var OBSERVER_CONFIG = {
    subtree: true,
    childList: true,
    characterData: true,
    attributes: true,
    attributeFilter: ['style', 'class']
  }; // --- Props ---

  var props$V = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$25), modelProps$5), {}, {
    ariaLabel: makeProp(PROP_TYPE_STRING),
    autoFocusButton: makeProp(PROP_TYPE_STRING, null,
    /* istanbul ignore next */
    function (value) {
      return isUndefinedOrNull(value) || arrayIncludes(BUTTONS, value);
    }),
    bodyBgVariant: makeProp(PROP_TYPE_STRING),
    bodyClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    bodyTextVariant: makeProp(PROP_TYPE_STRING),
    busy: makeProp(PROP_TYPE_BOOLEAN, false),
    buttonSize: makeProp(PROP_TYPE_STRING),
    cancelDisabled: makeProp(PROP_TYPE_BOOLEAN, false),
    cancelTitle: makeProp(PROP_TYPE_STRING, 'Cancel'),
    cancelTitleHtml: makeProp(PROP_TYPE_STRING),
    cancelVariant: makeProp(PROP_TYPE_STRING, 'secondary'),
    centered: makeProp(PROP_TYPE_BOOLEAN, false),
    contentClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    dialogClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    footerBgVariant: makeProp(PROP_TYPE_STRING),
    footerBorderVariant: makeProp(PROP_TYPE_STRING),
    footerClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    footerTag: makeProp(PROP_TYPE_STRING, 'footer'),
    footerTextVariant: makeProp(PROP_TYPE_STRING),
    headerBgVariant: makeProp(PROP_TYPE_STRING),
    headerBorderVariant: makeProp(PROP_TYPE_STRING),
    headerClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    headerCloseContent: makeProp(PROP_TYPE_STRING, '&times;'),
    headerCloseLabel: makeProp(PROP_TYPE_STRING, 'Close'),
    headerCloseVariant: makeProp(PROP_TYPE_STRING),
    headerTag: makeProp(PROP_TYPE_STRING, 'header'),
    headerTextVariant: makeProp(PROP_TYPE_STRING),
    // TODO: Rename to `noBackdrop` and deprecate `hideBackdrop`
    hideBackdrop: makeProp(PROP_TYPE_BOOLEAN, false),
    // TODO: Rename to `noFooter` and deprecate `hideFooter`
    hideFooter: makeProp(PROP_TYPE_BOOLEAN, false),
    // TODO: Rename to `noHeader` and deprecate `hideHeader`
    hideHeader: makeProp(PROP_TYPE_BOOLEAN, false),
    // TODO: Rename to `noHeaderClose` and deprecate `hideHeaderClose`
    hideHeaderClose: makeProp(PROP_TYPE_BOOLEAN, false),
    ignoreEnforceFocusSelector: makeProp(PROP_TYPE_ARRAY_STRING),
    lazy: makeProp(PROP_TYPE_BOOLEAN, false),
    modalClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    noCloseOnBackdrop: makeProp(PROP_TYPE_BOOLEAN, false),
    noCloseOnEsc: makeProp(PROP_TYPE_BOOLEAN, false),
    noEnforceFocus: makeProp(PROP_TYPE_BOOLEAN, false),
    noFade: makeProp(PROP_TYPE_BOOLEAN, false),
    noStacking: makeProp(PROP_TYPE_BOOLEAN, false),
    okDisabled: makeProp(PROP_TYPE_BOOLEAN, false),
    okOnly: makeProp(PROP_TYPE_BOOLEAN, false),
    okTitle: makeProp(PROP_TYPE_STRING, 'OK'),
    okTitleHtml: makeProp(PROP_TYPE_STRING),
    okVariant: makeProp(PROP_TYPE_STRING, 'primary'),
    // HTML Element, CSS selector string or Vue component instance
    returnFocus: makeProp([HTMLElement, PROP_TYPE_OBJECT, PROP_TYPE_STRING]),
    scrollable: makeProp(PROP_TYPE_BOOLEAN, false),
    size: makeProp(PROP_TYPE_STRING, 'md'),
    static: makeProp(PROP_TYPE_BOOLEAN, false),
    title: makeProp(PROP_TYPE_STRING),
    titleClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    titleHtml: makeProp(PROP_TYPE_STRING),
    titleSrOnly: makeProp(PROP_TYPE_BOOLEAN, false),
    titleTag: makeProp(PROP_TYPE_STRING, 'h5')
  })), NAME_MODAL); // --- Main component ---
  // @vue/component

  var BModal = /*#__PURE__*/extend({
    name: NAME_MODAL,
    mixins: [attrsMixin, idMixin, modelMixin$5, listenOnDocumentMixin, listenOnRootMixin, listenOnWindowMixin, normalizeSlotMixin, scopedStyleMixin],
    inheritAttrs: false,
    props: props$V,
    data: function data() {
      return {
        isHidden: true,
        // If modal should not be in document
        isVisible: false,
        // Controls modal visible state
        isTransitioning: false,
        // Used for style control
        isShow: false,
        // Used for style control
        isBlock: false,
        // Used for style control
        isOpening: false,
        // To signal that the modal is in the process of opening
        isClosing: false,
        // To signal that the modal is in the process of closing
        ignoreBackdropClick: false,
        // Used to signify if click out listener should ignore the click
        isModalOverflowing: false,
        // The following items are controlled by the modalManager instance
        scrollbarWidth: 0,
        zIndex: modalManager.getBaseZIndex(),
        isTop: true,
        isBodyOverflowing: false
      };
    },
    computed: {
      modalId: function modalId() {
        return this.safeId();
      },
      modalOuterId: function modalOuterId() {
        return this.safeId('__BV_modal_outer_');
      },
      modalHeaderId: function modalHeaderId() {
        return this.safeId('__BV_modal_header_');
      },
      modalBodyId: function modalBodyId() {
        return this.safeId('__BV_modal_body_');
      },
      modalTitleId: function modalTitleId() {
        return this.safeId('__BV_modal_title_');
      },
      modalContentId: function modalContentId() {
        return this.safeId('__BV_modal_content_');
      },
      modalFooterId: function modalFooterId() {
        return this.safeId('__BV_modal_footer_');
      },
      modalBackdropId: function modalBackdropId() {
        return this.safeId('__BV_modal_backdrop_');
      },
      modalClasses: function modalClasses() {
        return [{
          fade: !this.noFade,
          show: this.isShow
        }, this.modalClass];
      },
      modalStyles: function modalStyles() {
        var sbWidth = "".concat(this.scrollbarWidth, "px");
        return {
          paddingLeft: !this.isBodyOverflowing && this.isModalOverflowing ? sbWidth : '',
          paddingRight: this.isBodyOverflowing && !this.isModalOverflowing ? sbWidth : '',
          // Needed to fix issue https://github.com/bootstrap-vue/bootstrap-vue/issues/3457
          // Even though we are using v-show, we must ensure 'none' is restored in the styles
          display: this.isBlock ? 'block' : 'none'
        };
      },
      dialogClasses: function dialogClasses() {
        var _ref;

        return [(_ref = {}, _defineProperty(_ref, "modal-".concat(this.size), this.size), _defineProperty(_ref, 'modal-dialog-centered', this.centered), _defineProperty(_ref, 'modal-dialog-scrollable', this.scrollable), _ref), this.dialogClass];
      },
      headerClasses: function headerClasses() {
        var _ref2;

        return [(_ref2 = {}, _defineProperty(_ref2, "bg-".concat(this.headerBgVariant), this.headerBgVariant), _defineProperty(_ref2, "text-".concat(this.headerTextVariant), this.headerTextVariant), _defineProperty(_ref2, "border-".concat(this.headerBorderVariant), this.headerBorderVariant), _ref2), this.headerClass];
      },
      titleClasses: function titleClasses() {
        return [{
          'sr-only': this.titleSrOnly
        }, this.titleClass];
      },
      bodyClasses: function bodyClasses() {
        var _ref3;

        return [(_ref3 = {}, _defineProperty(_ref3, "bg-".concat(this.bodyBgVariant), this.bodyBgVariant), _defineProperty(_ref3, "text-".concat(this.bodyTextVariant), this.bodyTextVariant), _ref3), this.bodyClass];
      },
      footerClasses: function footerClasses() {
        var _ref4;

        return [(_ref4 = {}, _defineProperty(_ref4, "bg-".concat(this.footerBgVariant), this.footerBgVariant), _defineProperty(_ref4, "text-".concat(this.footerTextVariant), this.footerTextVariant), _defineProperty(_ref4, "border-".concat(this.footerBorderVariant), this.footerBorderVariant), _ref4), this.footerClass];
      },
      modalOuterStyle: function modalOuterStyle() {
        // Styles needed for proper stacking of modals
        return {
          position: 'absolute',
          zIndex: this.zIndex
        };
      },
      slotScope: function slotScope() {
        return {
          cancel: this.onCancel,
          close: this.onClose,
          hide: this.hide,
          ok: this.onOk,
          visible: this.isVisible
        };
      },
      computeIgnoreEnforceFocusSelector: function computeIgnoreEnforceFocusSelector() {
        // Normalize to an single selector with selectors separated by `,`
        return concat(this.ignoreEnforceFocusSelector).filter(identity).join(',').trim();
      },
      computedAttrs: function computedAttrs() {
        // If the parent has a scoped style attribute, and the modal
        // is portalled, add the scoped attribute to the modal wrapper
        var scopedStyleAttrs = !this.static ? this.scopedStyleAttrs : {};
        return _objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, scopedStyleAttrs), this.bvAttrs), {}, {
          id: this.modalOuterId
        });
      },
      computedModalAttrs: function computedModalAttrs() {
        var isVisible = this.isVisible,
            ariaLabel = this.ariaLabel;
        return {
          id: this.modalId,
          role: 'dialog',
          'aria-hidden': isVisible ? null : 'true',
          'aria-modal': isVisible ? 'true' : null,
          'aria-label': ariaLabel,
          'aria-labelledby': this.hideHeader || ariaLabel || // TODO: Rename slot to `title` and deprecate `modal-title`
          !(this.hasNormalizedSlot(SLOT_NAME_MODAL_TITLE) || this.titleHtml || this.title) ? null : this.modalTitleId,
          'aria-describedby': this.modalBodyId
        };
      }
    },
    watch: _defineProperty({}, MODEL_PROP_NAME$5, function (newValue, oldValue) {
      if (newValue !== oldValue) {
        this[newValue ? 'show' : 'hide']();
      }
    }),
    created: function created() {
      // Define non-reactive properties
      this.$_observer = null;
      this.$_returnFocus = this.returnFocus || null;
    },
    mounted: function mounted() {
      // Set initial z-index as queried from the DOM
      this.zIndex = modalManager.getBaseZIndex(); // Listen for events from others to either open or close ourselves
      // and listen to all modals to enable/disable enforce focus

      this.listenOnRoot(getRootActionEventName(NAME_MODAL, EVENT_NAME_SHOW), this.showHandler);
      this.listenOnRoot(getRootActionEventName(NAME_MODAL, EVENT_NAME_HIDE), this.hideHandler);
      this.listenOnRoot(getRootActionEventName(NAME_MODAL, EVENT_NAME_TOGGLE), this.toggleHandler); // Listen for `bv:modal::show events`, and close ourselves if the
      // opening modal not us

      this.listenOnRoot(getRootEventName(NAME_MODAL, EVENT_NAME_SHOW), this.modalListener); // Initially show modal?

      if (this[MODEL_PROP_NAME$5] === true) {
        this.$nextTick(this.show);
      }
    },
    beforeDestroy: function beforeDestroy() {
      // Ensure everything is back to normal
      modalManager.unregisterModal(this);
      this.setObserver(false);

      if (this.isVisible) {
        this.isVisible = false;
        this.isShow = false;
        this.isTransitioning = false;
      }
    },
    methods: {
      setObserver: function setObserver() {
        var on = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
        this.$_observer && this.$_observer.disconnect();
        this.$_observer = null;

        if (on) {
          this.$_observer = observeDom(this.$refs.content, this.checkModalOverflow.bind(this), OBSERVER_CONFIG);
        }
      },
      // Private method to update the v-model
      updateModel: function updateModel(value) {
        if (value !== this[MODEL_PROP_NAME$5]) {
          this.$emit(MODEL_EVENT_NAME$5, value);
        }
      },
      // Private method to create a BvModalEvent object
      buildEvent: function buildEvent(type) {
        var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
        return new BvModalEvent(type, _objectSpread2$3(_objectSpread2$3({
          // Default options
          cancelable: false,
          target: this.$refs.modal || this.$el || null,
          relatedTarget: null,
          trigger: null
        }, options), {}, {
          // Options that can't be overridden
          vueTarget: this,
          componentId: this.modalId
        }));
      },
      // Public method to show modal
      show: function show() {
        if (this.isVisible || this.isOpening) {
          // If already open, or in the process of opening, do nothing

          /* istanbul ignore next */
          return;
        }
        /* istanbul ignore next */


        if (this.isClosing) {
          // If we are in the process of closing, wait until hidden before re-opening

          /* istanbul ignore next */
          this.$once(EVENT_NAME_HIDDEN, this.show);
          /* istanbul ignore next */

          return;
        }

        this.isOpening = true; // Set the element to return focus to when closed

        this.$_returnFocus = this.$_returnFocus || this.getActiveElement();
        var showEvent = this.buildEvent(EVENT_NAME_SHOW, {
          cancelable: true
        });
        this.emitEvent(showEvent); // Don't show if canceled

        if (showEvent.defaultPrevented || this.isVisible) {
          this.isOpening = false; // Ensure the v-model reflects the current state

          this.updateModel(false);
          return;
        } // Show the modal


        this.doShow();
      },
      // Public method to hide modal
      hide: function hide() {
        var trigger = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';

        if (!this.isVisible || this.isClosing) {
          /* istanbul ignore next */
          return;
        }

        this.isClosing = true;
        var hideEvent = this.buildEvent(EVENT_NAME_HIDE, {
          cancelable: trigger !== TRIGGER_FORCE,
          trigger: trigger || null
        }); // We emit specific event for one of the three built-in buttons

        if (trigger === BUTTON_OK) {
          this.$emit(EVENT_NAME_OK, hideEvent);
        } else if (trigger === BUTTON_CANCEL) {
          this.$emit(EVENT_NAME_CANCEL, hideEvent);
        } else if (trigger === BUTTON_CLOSE) {
          this.$emit(EVENT_NAME_CLOSE, hideEvent);
        }

        this.emitEvent(hideEvent); // Hide if not canceled

        if (hideEvent.defaultPrevented || !this.isVisible) {
          this.isClosing = false; // Ensure v-model reflects current state

          this.updateModel(true);
          return;
        } // Stop observing for content changes


        this.setObserver(false); // Trigger the hide transition

        this.isVisible = false; // Update the v-model

        this.updateModel(false);
      },
      // Public method to toggle modal visibility
      toggle: function toggle(triggerEl) {
        if (triggerEl) {
          this.$_returnFocus = triggerEl;
        }

        if (this.isVisible) {
          this.hide(TRIGGER_TOGGLE);
        } else {
          this.show();
        }
      },
      // Private method to get the current document active element
      getActiveElement: function getActiveElement$1() {
        // Returning focus to `document.body` may cause unwanted scrolls,
        // so we exclude setting focus on body
        var activeElement = getActiveElement(IS_BROWSER ? [document.body] : []); // Preset the fallback return focus value if it is not set
        // `document.activeElement` should be the trigger element that was clicked or
        // in the case of using the v-model, which ever element has current focus
        // Will be overridden by some commands such as toggle, etc.
        // Note: On IE 11, `document.activeElement` may be `null`
        // So we test it for truthiness first
        // https://github.com/bootstrap-vue/bootstrap-vue/issues/3206


        return activeElement && activeElement.focus ? activeElement : null;
      },
      // Private method to finish showing modal
      doShow: function doShow() {
        var _this = this;

        /* istanbul ignore next: commenting out for now until we can test stacking */
        if (modalManager.modalsAreOpen && this.noStacking) {
          // If another modal(s) is already open, wait for it(them) to close
          this.listenOnRootOnce(getRootEventName(NAME_MODAL, EVENT_NAME_HIDDEN), this.doShow);
          return;
        }

        modalManager.registerModal(this); // Place modal in DOM

        this.isHidden = false;
        this.$nextTick(function () {
          // We do this in `$nextTick()` to ensure the modal is in DOM first
          // before we show it
          _this.isVisible = true;
          _this.isOpening = false; // Update the v-model

          _this.updateModel(true);

          _this.$nextTick(function () {
            // Observe changes in modal content and adjust if necessary
            // In a `$nextTick()` in case modal content is lazy
            _this.setObserver(true);
          });
        });
      },
      // Transition handlers
      onBeforeEnter: function onBeforeEnter() {
        this.isTransitioning = true;
        this.setResizeEvent(true);
      },
      onEnter: function onEnter() {
        var _this2 = this;

        this.isBlock = true; // We add the `show` class 1 frame later
        // `requestAF()` runs the callback before the next repaint, so we need
        // two calls to guarantee the next frame has been rendered

        requestAF(function () {
          requestAF(function () {
            _this2.isShow = true;
          });
        });
      },
      onAfterEnter: function onAfterEnter() {
        var _this3 = this;

        this.checkModalOverflow();
        this.isTransitioning = false; // We use `requestAF()` to allow transition hooks to complete
        // before passing control over to the other handlers
        // This will allow users to not have to use `$nextTick()` or `requestAF()`
        // when trying to pre-focus an element

        requestAF(function () {
          _this3.emitEvent(_this3.buildEvent(EVENT_NAME_SHOWN));

          _this3.setEnforceFocus(true);

          _this3.$nextTick(function () {
            // Delayed in a `$nextTick()` to allow users time to pre-focus
            // an element if the wish
            _this3.focusFirst();
          });
        });
      },
      onBeforeLeave: function onBeforeLeave() {
        this.isTransitioning = true;
        this.setResizeEvent(false);
        this.setEnforceFocus(false);
      },
      onLeave: function onLeave() {
        // Remove the 'show' class
        this.isShow = false;
      },
      onAfterLeave: function onAfterLeave() {
        var _this4 = this;

        this.isBlock = false;
        this.isTransitioning = false;
        this.isModalOverflowing = false;
        this.isHidden = true;
        this.$nextTick(function () {
          _this4.isClosing = false;
          modalManager.unregisterModal(_this4);

          _this4.returnFocusTo(); // TODO: Need to find a way to pass the `trigger` property
          //       to the `hidden` event, not just only the `hide` event


          _this4.emitEvent(_this4.buildEvent(EVENT_NAME_HIDDEN));
        });
      },
      emitEvent: function emitEvent(bvEvent) {
        var type = bvEvent.type; // We emit on `$root` first in case a global listener wants to cancel
        // the event first before the instance emits its event

        this.emitOnRoot(getRootEventName(NAME_MODAL, type), bvEvent, bvEvent.componentId);
        this.$emit(type, bvEvent);
      },
      // UI event handlers
      onDialogMousedown: function onDialogMousedown() {
        var _this5 = this;

        // Watch to see if the matching mouseup event occurs outside the dialog
        // And if it does, cancel the clickOut handler
        var modal = this.$refs.modal;

        var onceModalMouseup = function onceModalMouseup(event) {
          eventOff(modal, 'mouseup', onceModalMouseup, EVENT_OPTIONS_NO_CAPTURE);

          if (event.target === modal) {
            _this5.ignoreBackdropClick = true;
          }
        };

        eventOn(modal, 'mouseup', onceModalMouseup, EVENT_OPTIONS_NO_CAPTURE);
      },
      onClickOut: function onClickOut(event) {
        if (this.ignoreBackdropClick) {
          // Click was initiated inside the modal content, but finished outside.
          // Set by the above onDialogMousedown handler
          this.ignoreBackdropClick = false;
          return;
        } // Do nothing if not visible, backdrop click disabled, or element
        // that generated click event is no longer in document body


        if (!this.isVisible || this.noCloseOnBackdrop || !contains(document.body, event.target)) {
          return;
        } // If backdrop clicked, hide modal


        if (!contains(this.$refs.content, event.target)) {
          this.hide(TRIGGER_BACKDROP);
        }
      },
      onOk: function onOk() {
        this.hide(BUTTON_OK);
      },
      onCancel: function onCancel() {
        this.hide(BUTTON_CANCEL);
      },
      onClose: function onClose() {
        this.hide(BUTTON_CLOSE);
      },
      onEsc: function onEsc(event) {
        // If ESC pressed, hide modal
        if (event.keyCode === CODE_ESC && this.isVisible && !this.noCloseOnEsc) {
          this.hide(TRIGGER_ESC);
        }
      },
      // Document focusin listener
      focusHandler: function focusHandler(event) {
        // If focus leaves modal content, bring it back
        var content = this.$refs.content;
        var target = event.target;

        if (this.noEnforceFocus || !this.isTop || !this.isVisible || !content || document === target || contains(content, target) || this.computeIgnoreEnforceFocusSelector && closest(this.computeIgnoreEnforceFocusSelector, target, true)) {
          return;
        }

        var tabables = getTabables(this.$refs.content);
        var bottomTrap = this.$refs['bottom-trap'];
        var topTrap = this.$refs['top-trap'];

        if (bottomTrap && target === bottomTrap) {
          // If user pressed TAB out of modal into our bottom trab trap element
          // Find the first tabable element in the modal content and focus it
          if (attemptFocus(tabables[0])) {
            // Focus was successful
            return;
          }
        } else if (topTrap && target === topTrap) {
          // If user pressed CTRL-TAB out of modal and into our top tab trap element
          // Find the last tabable element in the modal content and focus it
          if (attemptFocus(tabables[tabables.length - 1])) {
            // Focus was successful
            return;
          }
        } // Otherwise focus the modal content container


        attemptFocus(content, {
          preventScroll: true
        });
      },
      // Turn on/off focusin listener
      setEnforceFocus: function setEnforceFocus(on) {
        this.listenDocument(on, 'focusin', this.focusHandler);
      },
      // Resize listener
      setResizeEvent: function setResizeEvent(on) {
        this.listenWindow(on, 'resize', this.checkModalOverflow);
        this.listenWindow(on, 'orientationchange', this.checkModalOverflow);
      },
      // Root listener handlers
      showHandler: function showHandler(id, triggerEl) {
        if (id === this.modalId) {
          this.$_returnFocus = triggerEl || this.getActiveElement();
          this.show();
        }
      },
      hideHandler: function hideHandler(id) {
        if (id === this.modalId) {
          this.hide('event');
        }
      },
      toggleHandler: function toggleHandler(id, triggerEl) {
        if (id === this.modalId) {
          this.toggle(triggerEl);
        }
      },
      modalListener: function modalListener(bvEvent) {
        // If another modal opens, close this one if stacking not permitted
        if (this.noStacking && bvEvent.vueTarget !== this) {
          this.hide();
        }
      },
      // Focus control handlers
      focusFirst: function focusFirst() {
        var _this6 = this;

        // Don't try and focus if we are SSR
        if (IS_BROWSER) {
          requestAF(function () {
            var modal = _this6.$refs.modal;
            var content = _this6.$refs.content;

            var activeElement = _this6.getActiveElement(); // If the modal contains the activeElement, we don't do anything


            if (modal && content && !(activeElement && contains(content, activeElement))) {
              var ok = _this6.$refs['ok-button'];
              var cancel = _this6.$refs['cancel-button'];
              var close = _this6.$refs['close-button']; // Focus the appropriate button or modal content wrapper

              var autoFocus = _this6.autoFocusButton;
              /* istanbul ignore next */

              var el = autoFocus === BUTTON_OK && ok ? ok.$el || ok : autoFocus === BUTTON_CANCEL && cancel ? cancel.$el || cancel : autoFocus === BUTTON_CLOSE && close ? close.$el || close : content; // Focus the element

              attemptFocus(el);

              if (el === content) {
                // Make sure top of modal is showing (if longer than the viewport)
                _this6.$nextTick(function () {
                  modal.scrollTop = 0;
                });
              }
            }
          });
        }
      },
      returnFocusTo: function returnFocusTo() {
        // Prefer `returnFocus` prop over event specified
        // `return_focus` value
        var el = this.returnFocus || this.$_returnFocus || null;
        this.$_returnFocus = null;
        this.$nextTick(function () {
          // Is el a string CSS selector?
          el = isString(el) ? select(el) : el;

          if (el) {
            // Possibly could be a component reference
            el = el.$el || el;
            attemptFocus(el);
          }
        });
      },
      checkModalOverflow: function checkModalOverflow() {
        if (this.isVisible) {
          var modal = this.$refs.modal;
          this.isModalOverflowing = modal.scrollHeight > document.documentElement.clientHeight;
        }
      },
      makeModal: function makeModal(h) {
        // Modal header
        var $header = h();

        if (!this.hideHeader) {
          // TODO: Rename slot to `header` and deprecate `modal-header`
          var $modalHeader = this.normalizeSlot(SLOT_NAME_MODAL_HEADER, this.slotScope);

          if (!$modalHeader) {
            var $closeButton = h();

            if (!this.hideHeaderClose) {
              $closeButton = h(BButtonClose, {
                props: {
                  content: this.headerCloseContent,
                  disabled: this.isTransitioning,
                  ariaLabel: this.headerCloseLabel,
                  textVariant: this.headerCloseVariant || this.headerTextVariant
                },
                on: {
                  click: this.onClose
                },
                ref: 'close-button'
              }, // TODO: Rename slot to `header-close` and deprecate `modal-header-close`
              [this.normalizeSlot(SLOT_NAME_MODAL_HEADER_CLOSE)]);
            }

            $modalHeader = [h(this.titleTag, {
              staticClass: 'modal-title',
              class: this.titleClasses,
              attrs: {
                id: this.modalTitleId
              },
              // TODO: Rename slot to `title` and deprecate `modal-title`
              domProps: this.hasNormalizedSlot(SLOT_NAME_MODAL_TITLE) ? {} : htmlOrText(this.titleHtml, this.title)
            }, // TODO: Rename slot to `title` and deprecate `modal-title`
            this.normalizeSlot(SLOT_NAME_MODAL_TITLE, this.slotScope)), $closeButton];
          }

          $header = h(this.headerTag, {
            staticClass: 'modal-header',
            class: this.headerClasses,
            attrs: {
              id: this.modalHeaderId
            },
            ref: 'header'
          }, [$modalHeader]);
        } // Modal body


        var $body = h('div', {
          staticClass: 'modal-body',
          class: this.bodyClasses,
          attrs: {
            id: this.modalBodyId
          },
          ref: 'body'
        }, this.normalizeSlot(SLOT_NAME_DEFAULT, this.slotScope)); // Modal footer

        var $footer = h();

        if (!this.hideFooter) {
          // TODO: Rename slot to `footer` and deprecate `modal-footer`
          var $modalFooter = this.normalizeSlot(SLOT_NAME_MODAL_FOOTER, this.slotScope);

          if (!$modalFooter) {
            var $cancelButton = h();

            if (!this.okOnly) {
              $cancelButton = h(BButton, {
                props: {
                  variant: this.cancelVariant,
                  size: this.buttonSize,
                  disabled: this.cancelDisabled || this.busy || this.isTransitioning
                },
                // TODO: Rename slot to `cancel-button` and deprecate `modal-cancel`
                domProps: this.hasNormalizedSlot(SLOT_NAME_MODAL_CANCEL) ? {} : htmlOrText(this.cancelTitleHtml, this.cancelTitle),
                on: {
                  click: this.onCancel
                },
                ref: 'cancel-button'
              }, // TODO: Rename slot to `cancel-button` and deprecate `modal-cancel`
              this.normalizeSlot(SLOT_NAME_MODAL_CANCEL));
            }

            var $okButton = h(BButton, {
              props: {
                variant: this.okVariant,
                size: this.buttonSize,
                disabled: this.okDisabled || this.busy || this.isTransitioning
              },
              // TODO: Rename slot to `ok-button` and deprecate `modal-ok`
              domProps: this.hasNormalizedSlot(SLOT_NAME_MODAL_OK) ? {} : htmlOrText(this.okTitleHtml, this.okTitle),
              on: {
                click: this.onOk
              },
              ref: 'ok-button'
            }, // TODO: Rename slot to `ok-button` and deprecate `modal-ok`
            this.normalizeSlot(SLOT_NAME_MODAL_OK));
            $modalFooter = [$cancelButton, $okButton];
          }

          $footer = h(this.footerTag, {
            staticClass: 'modal-footer',
            class: this.footerClasses,
            attrs: {
              id: this.modalFooterId
            },
            ref: 'footer'
          }, [$modalFooter]);
        } // Assemble modal content


        var $modalContent = h('div', {
          staticClass: 'modal-content',
          class: this.contentClass,
          attrs: {
            id: this.modalContentId,
            tabindex: '-1'
          },
          ref: 'content'
        }, [$header, $body, $footer]); // Tab traps to prevent page from scrolling to next element in
        // tab index during enforce-focus tab cycle

        var $tabTrapTop = h();
        var $tabTrapBottom = h();

        if (this.isVisible && !this.noEnforceFocus) {
          $tabTrapTop = h('span', {
            attrs: {
              tabindex: '0'
            },
            ref: 'top-trap'
          });
          $tabTrapBottom = h('span', {
            attrs: {
              tabindex: '0'
            },
            ref: 'bottom-trap'
          });
        } // Modal dialog wrapper


        var $modalDialog = h('div', {
          staticClass: 'modal-dialog',
          class: this.dialogClasses,
          on: {
            mousedown: this.onDialogMousedown
          },
          ref: 'dialog'
        }, [$tabTrapTop, $modalContent, $tabTrapBottom]); // Modal

        var $modal = h('div', {
          staticClass: 'modal',
          class: this.modalClasses,
          style: this.modalStyles,
          attrs: this.computedModalAttrs,
          on: {
            keydown: this.onEsc,
            click: this.onClickOut
          },
          directives: [{
            name: 'show',
            value: this.isVisible
          }],
          ref: 'modal'
        }, [$modalDialog]); // Wrap modal in transition
        // Sadly, we can't use `BVTransition` here due to the differences in
        // transition durations for `.modal` and `.modal-dialog`
        // At least until https://github.com/vuejs/vue/issues/9986 is resolved

        $modal = h('transition', {
          props: {
            enterClass: '',
            enterToClass: '',
            enterActiveClass: '',
            leaveClass: '',
            leaveActiveClass: '',
            leaveToClass: ''
          },
          on: {
            beforeEnter: this.onBeforeEnter,
            enter: this.onEnter,
            afterEnter: this.onAfterEnter,
            beforeLeave: this.onBeforeLeave,
            leave: this.onLeave,
            afterLeave: this.onAfterLeave
          }
        }, [$modal]); // Modal backdrop

        var $backdrop = h();

        if (!this.hideBackdrop && this.isVisible) {
          $backdrop = h('div', {
            staticClass: 'modal-backdrop',
            attrs: {
              id: this.modalBackdropId
            }
          }, // TODO: Rename slot to `backdrop` and deprecate `modal-backdrop`
          this.normalizeSlot(SLOT_NAME_MODAL_BACKDROP));
        }

        $backdrop = h(BVTransition, {
          props: {
            noFade: this.noFade
          }
        }, [$backdrop]); // Assemble modal and backdrop in an outer <div>

        return h('div', {
          style: this.modalOuterStyle,
          attrs: this.computedAttrs,
          key: "modal-outer-".concat(this[COMPONENT_UID_KEY])
        }, [$modal, $backdrop]);
      }
    },
    render: function render(h) {
      if (this.static) {
        return this.lazy && this.isHidden ? h() : this.makeModal(h);
      } else {
        return this.isHidden ? h() : h(BVTransporter, [this.makeModal(h)]);
      }
    }
  });

  var ROOT_ACTION_EVENT_NAME_SHOW = getRootActionEventName(NAME_MODAL, EVENT_NAME_SHOW); // Prop name we use to store info on root element

  var PROPERTY = '__bv_modal_directive__';

  var getTarget = function getTarget(_ref) {
    var _ref$modifiers = _ref.modifiers,
        modifiers = _ref$modifiers === void 0 ? {} : _ref$modifiers,
        arg = _ref.arg,
        value = _ref.value;
    // Try value, then arg, otherwise pick last modifier
    return isString(value) ? value : isString(arg) ? arg : keys(modifiers).reverse()[0];
  };

  var getTriggerElement = function getTriggerElement(el) {
    // If root element is a dropdown-item or nav-item, we
    // need to target the inner link or button instead
    return el && matches(el, '.dropdown-menu > li, li.nav-item') ? select('a, button', el) || el : el;
  };

  var setRole = function setRole(trigger) {
    // Ensure accessibility on non button elements
    if (trigger && trigger.tagName !== 'BUTTON') {
      // Only set a role if the trigger element doesn't have one
      if (!hasAttr(trigger, 'role')) {
        setAttr(trigger, 'role', 'button');
      } // Add a tabindex is not a button or link, and tabindex is not provided


      if (trigger.tagName !== 'A' && !hasAttr(trigger, 'tabindex')) {
        setAttr(trigger, 'tabindex', '0');
      }
    }
  };

  var bind = function bind(el, binding, vnode) {
    var target = getTarget(binding);
    var trigger = getTriggerElement(el);

    if (target && trigger) {
      var handler = function handler(event) {
        // `currentTarget` is the element with the listener on it
        var currentTarget = event.currentTarget;

        if (!isDisabled(currentTarget)) {
          var type = event.type;
          var key = event.keyCode; // Open modal only if trigger is not disabled

          if (type === 'click' || type === 'keydown' && (key === CODE_ENTER || key === CODE_SPACE)) {
            getEventRoot(getInstanceFromDirective(vnode, binding)).$emit(ROOT_ACTION_EVENT_NAME_SHOW, target, currentTarget);
          }
        }
      };

      el[PROPERTY] = {
        handler: handler,
        target: target,
        trigger: trigger
      }; // If element is not a button, we add `role="button"` for accessibility

      setRole(trigger); // Listen for click events

      eventOn(trigger, 'click', handler, EVENT_OPTIONS_PASSIVE);

      if (trigger.tagName !== 'BUTTON' && getAttr(trigger, 'role') === 'button') {
        // If trigger isn't a button but has role button,
        // we also listen for `keydown.space` && `keydown.enter`
        eventOn(trigger, 'keydown', handler, EVENT_OPTIONS_PASSIVE);
      }
    }
  };

  var unbind = function unbind(el) {
    var oldProp = el[PROPERTY] || {};
    var trigger = oldProp.trigger;
    var handler = oldProp.handler;

    if (trigger && handler) {
      eventOff(trigger, 'click', handler, EVENT_OPTIONS_PASSIVE);
      eventOff(trigger, 'keydown', handler, EVENT_OPTIONS_PASSIVE);
      eventOff(el, 'click', handler, EVENT_OPTIONS_PASSIVE);
      eventOff(el, 'keydown', handler, EVENT_OPTIONS_PASSIVE);
    }

    delete el[PROPERTY];
  };

  var componentUpdated = function componentUpdated(el, binding, vnode) {
    var oldProp = el[PROPERTY] || {};
    var target = getTarget(binding);
    var trigger = getTriggerElement(el);

    if (target !== oldProp.target || trigger !== oldProp.trigger) {
      // We bind and rebind if the target or trigger changes
      unbind(el);
      bind(el, binding, vnode);
    } // If trigger element is not a button, ensure `role="button"`
    // is still set for accessibility


    setRole(trigger);
  };

  var updated = function updated() {};
  /*
   * Export our directive
   */


  var VBModal = {
    inserted: componentUpdated,
    updated: updated,
    componentUpdated: componentUpdated,
    unbind: unbind
  };

  var PROP_NAME$1 = '$bvModal';
  var PROP_NAME_PRIV$1 = '_bv__modal'; // Base modal props that are allowed
  // Some may be ignored or overridden on some message boxes
  // Prop ID is allowed, but really only should be used for testing
  // We need to add it in explicitly as it comes from the `idMixin`

  var BASE_PROPS$1 = ['id'].concat(_toConsumableArray$1(keys(omit(props$V, ['busy', 'lazy', 'noStacking', 'static', 'visible'])))); // Fallback event resolver (returns undefined)

  var defaultResolver = function defaultResolver() {}; // Map prop names to modal slot names


  var propsToSlots$1 = {
    msgBoxContent: 'default',
    title: 'modal-title',
    okTitle: 'modal-ok',
    cancelTitle: 'modal-cancel'
  }; // --- Helper methods ---
  // Method to filter only recognized props that are not undefined

  var filterOptions$1 = function filterOptions(options) {
    return BASE_PROPS$1.reduce(function (memo, key) {
      if (!isUndefined(options[key])) {
        memo[key] = options[key];
      }

      return memo;
    }, {});
  }; // Method to install `$bvModal` VM injection


  var plugin$1 = function plugin(Vue) {
    // Create a private sub-component that extends BModal
    // which self-destructs after hidden
    // @vue/component
    var BMsgBox = Vue.extend({
      name: NAME_MSG_BOX,
      extends: BModal,
      mixins: [useParentMixin],
      destroyed: function destroyed() {
        // Make sure we not in document any more
        if (this.$el && this.$el.parentNode) {
          this.$el.parentNode.removeChild(this.$el);
        }
      },
      mounted: function mounted() {
        var _this = this;

        // Self destruct handler
        var handleDestroy = function handleDestroy() {
          _this.$nextTick(function () {
            // In a `requestAF()` to release control back to application
            requestAF(function () {
              _this.$destroy();
            });
          });
        }; // Self destruct if parent destroyed


        this.bvParent.$once(HOOK_EVENT_NAME_DESTROYED, handleDestroy); // Self destruct after hidden

        this.$once(EVENT_NAME_HIDDEN, handleDestroy); // Self destruct on route change

        /* istanbul ignore if */

        if (this.$router && this.$route) {
          // Destroy ourselves if route changes

          /* istanbul ignore next */
          this.$once(HOOK_EVENT_NAME_BEFORE_DESTROY, this.$watch('$router', handleDestroy));
        } // Show the `BMsgBox`


        this.show();
      }
    }); // Method to generate the on-demand modal message box
    // Returns a promise that resolves to a value returned by the resolve

    var asyncMsgBox = function asyncMsgBox(parent, props) {
      var resolver = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : defaultResolver;

      if (warnNotClient(PROP_NAME$1) || warnNoPromiseSupport(PROP_NAME$1)) {
        /* istanbul ignore next */
        return;
      } // Create an instance of `BMsgBox` component
      // We set parent as the local VM so these modals can emit events on
      // the app `$root`, as needed by things like tooltips and popovers
      // And it helps to ensure `BMsgBox` is destroyed when parent is destroyed


      var msgBox = createNewChildComponent(parent, BMsgBox, {
        // Preset the prop values
        propsData: _objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, filterOptions$1(getComponentConfig(NAME_MODAL))), {}, {
          // Defaults that user can override
          hideHeaderClose: true,
          hideHeader: !(props.title || props.titleHtml)
        }, omit(props, keys(propsToSlots$1))), {}, {
          // Props that can't be overridden
          lazy: false,
          busy: false,
          visible: false,
          noStacking: false,
          noEnforceFocus: false
        })
      }); // Convert certain props to scoped slots

      keys(propsToSlots$1).forEach(function (prop) {
        if (!isUndefined(props[prop])) {
          // Can be a string, or array of VNodes.
          // Alternatively, user can use HTML version of prop to pass an HTML string.
          msgBox.$slots[propsToSlots$1[prop]] = concat(props[prop]);
        }
      }); // Return a promise that resolves when hidden, or rejects on destroyed

      return new Promise(function (resolve, reject) {
        var resolved = false;
        msgBox.$once(HOOK_EVENT_NAME_DESTROYED, function () {
          if (!resolved) {
            /* istanbul ignore next */
            reject(new Error('BootstrapVue MsgBox destroyed before resolve'));
          }
        });
        msgBox.$on(EVENT_NAME_HIDE, function (bvModalEvent) {
          if (!bvModalEvent.defaultPrevented) {
            var result = resolver(bvModalEvent); // If resolver didn't cancel hide, we resolve

            if (!bvModalEvent.defaultPrevented) {
              resolved = true;
              resolve(result);
            }
          }
        }); // Create a mount point (a DIV) and mount the msgBo which will trigger it to show

        var div = document.createElement('div');
        document.body.appendChild(div);
        msgBox.$mount(div);
      });
    }; // Private utility method to open a user defined message box and returns a promise.
    // Not to be used directly by consumers, as this method may change calling syntax


    var makeMsgBox = function makeMsgBox(parent, content) {
      var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
      var resolver = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;

      if (!content || warnNoPromiseSupport(PROP_NAME$1) || warnNotClient(PROP_NAME$1) || !isFunction$1(resolver)) {
        /* istanbul ignore next */
        return;
      }

      return asyncMsgBox(parent, _objectSpread2$3(_objectSpread2$3({}, filterOptions$1(options)), {}, {
        msgBoxContent: content
      }), resolver);
    }; // BvModal instance class


    var BvModal = /*#__PURE__*/function () {
      function BvModal(vm) {
        _classCallCheck(this, BvModal);

        // Assign the new properties to this instance
        assign(this, {
          _vm: vm,
          _root: getEventRoot(vm)
        }); // Set these properties as read-only and non-enumerable

        defineProperties(this, {
          _vm: readonlyDescriptor(),
          _root: readonlyDescriptor()
        });
      } // --- Instance methods ---
      // Show modal with the specified ID args are for future use


      _createClass(BvModal, [{
        key: "show",
        value: function show(id) {
          if (id && this._root) {
            var _this$_root;

            for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
              args[_key - 1] = arguments[_key];
            }

            (_this$_root = this._root).$emit.apply(_this$_root, [getRootActionEventName(NAME_MODAL, 'show'), id].concat(args));
          }
        } // Hide modal with the specified ID args are for future use

      }, {
        key: "hide",
        value: function hide(id) {
          if (id && this._root) {
            var _this$_root2;

            for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
              args[_key2 - 1] = arguments[_key2];
            }

            (_this$_root2 = this._root).$emit.apply(_this$_root2, [getRootActionEventName(NAME_MODAL, 'hide'), id].concat(args));
          }
        } // The following methods require Promise support!
        // IE 11 and others do not support Promise natively, so users
        // should have a Polyfill loaded (which they need anyways for IE 11 support)
        // Open a message box with OK button only and returns a promise

      }, {
        key: "msgBoxOk",
        value: function msgBoxOk(message) {
          var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

          // Pick the modal props we support from options
          var props = _objectSpread2$3(_objectSpread2$3({}, options), {}, {
            // Add in overrides and our content prop
            okOnly: true,
            okDisabled: false,
            hideFooter: false,
            msgBoxContent: message
          });

          return makeMsgBox(this._vm, message, props, function () {
            // Always resolve to true for OK
            return true;
          });
        } // Open a message box modal with OK and CANCEL buttons
        // and returns a promise

      }, {
        key: "msgBoxConfirm",
        value: function msgBoxConfirm(message) {
          var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

          // Set the modal props we support from options
          var props = _objectSpread2$3(_objectSpread2$3({}, options), {}, {
            // Add in overrides and our content prop
            okOnly: false,
            okDisabled: false,
            cancelDisabled: false,
            hideFooter: false
          });

          return makeMsgBox(this._vm, message, props, function (bvModalEvent) {
            var trigger = bvModalEvent.trigger;
            return trigger === 'ok' ? true : trigger === 'cancel' ? false : null;
          });
        }
      }]);

      return BvModal;
    }(); // Add our instance mixin


    Vue.mixin({
      beforeCreate: function beforeCreate() {
        // Because we need access to `$root` for `$emits`, and VM for parenting,
        // we have to create a fresh instance of `BvModal` for each VM
        this[PROP_NAME_PRIV$1] = new BvModal(this);
      }
    }); // Define our read-only `$bvModal` instance property
    // Placed in an if just in case in HMR mode

    if (!hasOwnProperty(Vue.prototype, PROP_NAME$1)) {
      defineProperty$1(Vue.prototype, PROP_NAME$1, {
        get: function get() {
          /* istanbul ignore next */
          if (!this || !this[PROP_NAME_PRIV$1]) {
            warn("\"".concat(PROP_NAME$1, "\" must be accessed from a Vue instance \"this\" context."), NAME_MODAL);
          }

          return this[PROP_NAME_PRIV$1];
        }
      });
    }
  };

  var BVModalPlugin = /*#__PURE__*/pluginFactory({
    plugins: {
      plugin: plugin$1
    }
  });

  var ModalPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BModal: BModal
    },
    directives: {
      VBModal: VBModal
    },
    // $bvModal injection
    plugins: {
      BVModalPlugin: BVModalPlugin
    }
  });

  var computeJustifyContent$1 = function computeJustifyContent(value) {
    value = value === 'left' ? 'start' : value === 'right' ? 'end' : value;
    return "justify-content-".concat(value);
  }; // --- Props ---


  var props$U = makePropsConfigurable({
    align: makeProp(PROP_TYPE_STRING),
    // Set to `true` if placing in a card header
    cardHeader: makeProp(PROP_TYPE_BOOLEAN, false),
    fill: makeProp(PROP_TYPE_BOOLEAN, false),
    justified: makeProp(PROP_TYPE_BOOLEAN, false),
    pills: makeProp(PROP_TYPE_BOOLEAN, false),
    small: makeProp(PROP_TYPE_BOOLEAN, false),
    tabs: makeProp(PROP_TYPE_BOOLEAN, false),
    tag: makeProp(PROP_TYPE_STRING, 'ul'),
    vertical: makeProp(PROP_TYPE_BOOLEAN, false)
  }, NAME_NAV); // --- Main component ---
  // @vue/component

  var BNav = /*#__PURE__*/extend({
    name: NAME_NAV,
    functional: true,
    props: props$U,
    render: function render(h, _ref) {
      var _class;

      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      var tabs = props.tabs,
          pills = props.pills,
          vertical = props.vertical,
          align = props.align,
          cardHeader = props.cardHeader;
      return h(props.tag, a(data, {
        staticClass: 'nav',
        class: (_class = {
          'nav-tabs': tabs,
          'nav-pills': pills && !tabs,
          'card-header-tabs': !vertical && cardHeader && tabs,
          'card-header-pills': !vertical && cardHeader && pills && !tabs,
          'flex-column': vertical,
          'nav-fill': !vertical && props.fill,
          'nav-justified': !vertical && props.justified
        }, _defineProperty(_class, computeJustifyContent$1(align), !vertical && align), _defineProperty(_class, "small", props.small), _class)
      }), children);
    }
  });

  var linkProps$2 = omit(props$2f, ['event', 'routerTag']);
  var props$T = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, linkProps$2), {}, {
    linkAttrs: makeProp(PROP_TYPE_OBJECT, {}),
    linkClasses: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING)
  })), NAME_NAV_ITEM); // --- Main component ---
  // @vue/component

  var BNavItem = /*#__PURE__*/extend({
    name: NAME_NAV_ITEM,
    functional: true,
    props: props$T,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          listeners = _ref.listeners,
          children = _ref.children;
      return h('li', a(omit(data, ['on']), {
        staticClass: 'nav-item'
      }), [h(BLink, {
        staticClass: 'nav-link',
        class: props.linkClasses,
        attrs: props.linkAttrs,
        props: pluckProps(linkProps$2, props),
        on: listeners
      }, children)]);
    }
  });

  var props$S = {}; // --- Main component ---
  // @vue/component

  var BNavText = /*#__PURE__*/extend({
    name: NAME_NAV_TEXT,
    functional: true,
    props: props$S,
    render: function render(h, _ref) {
      var data = _ref.data,
          children = _ref.children;
      return h('li', a(data, {
        staticClass: 'navbar-text'
      }), children);
    }
  });

  var formProps = omit(props$1I, ['inline']);
  var props$R = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, formProps), {}, {
    formClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING)
  })), NAME_NAV_FORM); // --- Main component ---
  // @vue/component

  var BNavForm = /*#__PURE__*/extend({
    name: NAME_NAV_FORM,
    functional: true,
    props: props$R,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          children = _ref.children,
          listeners = _ref.listeners;
      var $form = h(BForm, {
        class: props.formClass,
        props: _objectSpread2$3(_objectSpread2$3({}, pluckProps(formProps, props)), {}, {
          inline: true
        }),
        attrs: data.attrs,
        on: listeners
      }, children);
      return h('li', a(omit(data, ['attrs', 'on']), {
        staticClass: 'form-inline'
      }), [$form]);
    }
  });

  var props$Q = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, props$25), pick$1(props$1N, [].concat(_toConsumableArray$1(keys(props$1O)), ['html', 'lazy', 'menuClass', 'noCaret', 'role', 'text', 'toggleClass'])))), NAME_NAV_ITEM_DROPDOWN); // --- Main component ---
  // @vue/component

  var BNavItemDropdown = /*#__PURE__*/extend({
    name: NAME_NAV_ITEM_DROPDOWN,
    mixins: [idMixin, dropdownMixin, normalizeSlotMixin],
    props: props$Q,
    computed: {
      toggleId: function toggleId() {
        return this.safeId('_BV_toggle_');
      },
      menuId: function menuId() {
        return this.safeId('_BV_toggle_menu_');
      },
      dropdownClasses: function dropdownClasses() {
        return [this.directionClass, this.boundaryClass, {
          show: this.visible
        }];
      },
      menuClasses: function menuClasses() {
        return [this.menuClass, {
          'dropdown-menu-right': this.right,
          show: this.visible
        }];
      },
      toggleClasses: function toggleClasses() {
        return [this.toggleClass, {
          'dropdown-toggle-no-caret': this.noCaret
        }];
      }
    },
    render: function render(h) {
      var toggleId = this.toggleId,
          menuId = this.menuId,
          visible = this.visible,
          hide = this.hide;
      var $toggle = h(BLink, {
        staticClass: 'nav-link dropdown-toggle',
        class: this.toggleClasses,
        props: {
          href: "#".concat(this.id || ''),
          disabled: this.disabled
        },
        attrs: {
          id: toggleId,
          role: 'button',
          'aria-haspopup': 'true',
          'aria-expanded': visible ? 'true' : 'false',
          'aria-controls': menuId
        },
        on: {
          mousedown: this.onMousedown,
          click: this.toggle,
          keydown: this.toggle // Handle ENTER, SPACE and DOWN

        },
        ref: 'toggle'
      }, [// TODO: The `text` slot is deprecated in favor of the `button-content` slot
      this.normalizeSlot([SLOT_NAME_BUTTON_CONTENT, SLOT_NAME_TEXT]) || h('span', {
        domProps: htmlOrText(this.html, this.text)
      })]);
      var $menu = h('ul', {
        staticClass: 'dropdown-menu',
        class: this.menuClasses,
        attrs: {
          tabindex: '-1',
          'aria-labelledby': toggleId,
          id: menuId
        },
        on: {
          keydown: this.onKeydown // Handle UP, DOWN and ESC

        },
        ref: 'menu'
      }, !this.lazy || visible ? this.normalizeSlot(SLOT_NAME_DEFAULT, {
        hide: hide
      }) : [h()]);
      return h('li', {
        staticClass: 'nav-item b-nav-dropdown dropdown',
        class: this.dropdownClasses,
        attrs: {
          id: this.safeId()
        }
      }, [$toggle, $menu]);
    }
  });

  var NavPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BNav: BNav,
      BNavItem: BNavItem,
      BNavText: BNavText,
      BNavForm: BNavForm,
      BNavItemDropdown: BNavItemDropdown,
      BNavItemDd: BNavItemDropdown,
      BNavDropdown: BNavItemDropdown,
      BNavDd: BNavItemDropdown
    },
    plugins: {
      DropdownPlugin: DropdownPlugin
    }
  });

  var props$P = makePropsConfigurable({
    fixed: makeProp(PROP_TYPE_STRING),
    print: makeProp(PROP_TYPE_BOOLEAN, false),
    sticky: makeProp(PROP_TYPE_BOOLEAN, false),
    tag: makeProp(PROP_TYPE_STRING, 'nav'),
    toggleable: makeProp(PROP_TYPE_BOOLEAN_STRING, false),
    type: makeProp(PROP_TYPE_STRING, 'light'),
    variant: makeProp(PROP_TYPE_STRING)
  }, NAME_NAVBAR); // --- Main component ---
  // @vue/component

  var BNavbar = /*#__PURE__*/extend({
    name: NAME_NAVBAR,
    mixins: [normalizeSlotMixin],
    provide: function provide() {
      var _this = this;

      return {
        getBvNavbar: function getBvNavbar() {
          return _this;
        }
      };
    },
    props: props$P,
    computed: {
      breakpointClass: function breakpointClass() {
        var toggleable = this.toggleable;
        var xs = getBreakpoints()[0];
        var breakpoint = null;

        if (toggleable && isString(toggleable) && toggleable !== xs) {
          breakpoint = "navbar-expand-".concat(toggleable);
        } else if (toggleable === false) {
          breakpoint = 'navbar-expand';
        }

        return breakpoint;
      }
    },
    render: function render(h) {
      var _ref;

      var tag = this.tag,
          type = this.type,
          variant = this.variant,
          fixed = this.fixed;
      return h(tag, {
        staticClass: 'navbar',
        class: [(_ref = {
          'd-print': this.print,
          'sticky-top': this.sticky
        }, _defineProperty(_ref, "navbar-".concat(type), type), _defineProperty(_ref, "bg-".concat(variant), variant), _defineProperty(_ref, "fixed-".concat(fixed), fixed), _ref), this.breakpointClass],
        attrs: {
          role: isTag(tag, 'nav') ? null : 'navigation'
        }
      }, [this.normalizeSlot()]);
    }
  });

  var computeJustifyContent = function computeJustifyContent(value) {
    value = value === 'left' ? 'start' : value === 'right' ? 'end' : value;
    return "justify-content-".concat(value);
  }; // --- Props ---


  var props$O = makePropsConfigurable(pick$1(props$U, ['tag', 'fill', 'justified', 'align', 'small']), NAME_NAVBAR_NAV); // --- Main component ---
  // @vue/component

  var BNavbarNav = /*#__PURE__*/extend({
    name: NAME_NAVBAR_NAV,
    functional: true,
    props: props$O,
    render: function render(h, _ref) {
      var _class;

      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      var align = props.align;
      return h(props.tag, a(data, {
        staticClass: 'navbar-nav',
        class: (_class = {
          'nav-fill': props.fill,
          'nav-justified': props.justified
        }, _defineProperty(_class, computeJustifyContent(align), align), _defineProperty(_class, "small", props.small), _class)
      }), children);
    }
  });

  var linkProps$1 = omit(props$2f, ['event', 'routerTag']);
  linkProps$1.href.default = undefined;
  linkProps$1.to.default = undefined;
  var props$N = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, linkProps$1), {}, {
    tag: makeProp(PROP_TYPE_STRING, 'div')
  })), NAME_NAVBAR_BRAND); // --- Main component ---
  // @vue/component

  var BNavbarBrand = /*#__PURE__*/extend({
    name: NAME_NAVBAR_BRAND,
    functional: true,
    props: props$N,
    render: function render(h, _ref) {
      var props = _ref.props,
          data = _ref.data,
          children = _ref.children;
      var isLink = props.to || props.href;
      var tag = isLink ? BLink : props.tag;
      return h(tag, a(data, {
        staticClass: 'navbar-brand',
        props: isLink ? pluckProps(linkProps$1, props) : {}
      }), children);
    }
  });

  var CLASS_NAME$1 = 'navbar-toggler';
  var ROOT_EVENT_NAME_STATE$1 = getRootEventName(NAME_COLLAPSE, 'state');
  var ROOT_EVENT_NAME_SYNC_STATE$1 = getRootEventName(NAME_COLLAPSE, 'sync-state'); // --- Props ---

  var props$M = makePropsConfigurable({
    disabled: makeProp(PROP_TYPE_BOOLEAN, false),
    label: makeProp(PROP_TYPE_STRING, 'Toggle navigation'),
    target: makeProp(PROP_TYPE_ARRAY_STRING, undefined, true) // Required

  }, NAME_NAVBAR_TOGGLE); // --- Main component ---
  // @vue/component

  var BNavbarToggle = /*#__PURE__*/extend({
    name: NAME_NAVBAR_TOGGLE,
    directives: {
      VBToggle: VBToggle
    },
    mixins: [listenOnRootMixin, normalizeSlotMixin],
    props: props$M,
    data: function data() {
      return {
        toggleState: false
      };
    },
    created: function created() {
      this.listenOnRoot(ROOT_EVENT_NAME_STATE$1, this.handleStateEvent);
      this.listenOnRoot(ROOT_EVENT_NAME_SYNC_STATE$1, this.handleStateEvent);
    },
    methods: {
      onClick: function onClick(event) {
        if (!this.disabled) {
          // Emit courtesy `click` event
          this.$emit(EVENT_NAME_CLICK, event);
        }
      },
      handleStateEvent: function handleStateEvent(id, state) {
        // We listen for state events so that we can pass the
        // boolean expanded state to the default scoped slot
        if (id === this.target) {
          this.toggleState = state;
        }
      }
    },
    render: function render(h) {
      var disabled = this.disabled;
      return h('button', {
        staticClass: CLASS_NAME$1,
        class: {
          disabled: disabled
        },
        directives: [{
          name: 'VBToggle',
          value: this.target
        }],
        attrs: {
          type: 'button',
          disabled: disabled,
          'aria-label': this.label
        },
        on: {
          click: this.onClick
        }
      }, [this.normalizeSlot(SLOT_NAME_DEFAULT, {
        expanded: this.toggleState
      }) || h('span', {
        staticClass: "".concat(CLASS_NAME$1, "-icon")
      })]);
    }
  });

  var NavbarPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BNavbar: BNavbar,
      BNavbarNav: BNavbarNav,
      BNavbarBrand: BNavbarBrand,
      BNavbarToggle: BNavbarToggle,
      BNavToggle: BNavbarToggle
    },
    plugins: {
      NavPlugin: NavPlugin,
      CollapsePlugin: CollapsePlugin,
      DropdownPlugin: DropdownPlugin
    }
  });

  var props$L = makePropsConfigurable({
    label: makeProp(PROP_TYPE_STRING),
    role: makeProp(PROP_TYPE_STRING, 'status'),
    small: makeProp(PROP_TYPE_BOOLEAN, false),
    tag: makeProp(PROP_TYPE_STRING, 'span'),
    type: makeProp(PROP_TYPE_STRING, 'border'),
    variant: makeProp(PROP_TYPE_STRING)
  }, NAME_SPINNER); // --- Main component ---
  // @vue/component

  var BSpinner = /*#__PURE__*/extend({
    name: NAME_SPINNER,
    functional: true,
    props: props$L,
    render: function render(h, _ref) {
      var _class;

      var props = _ref.props,
          data = _ref.data,
          slots = _ref.slots,
          scopedSlots = _ref.scopedSlots;
      var $slots = slots();
      var $scopedSlots = scopedSlots || {};
      var $label = normalizeSlot(SLOT_NAME_LABEL, {}, $scopedSlots, $slots) || props.label;

      if ($label) {
        $label = h('span', {
          staticClass: 'sr-only'
        }, $label);
      }

      return h(props.tag, a(data, {
        attrs: {
          role: $label ? props.role || 'status' : null,
          'aria-hidden': $label ? null : 'true'
        },
        class: (_class = {}, _defineProperty(_class, "spinner-".concat(props.type), props.type), _defineProperty(_class, "spinner-".concat(props.type, "-sm"), props.small), _defineProperty(_class, "text-".concat(props.variant), props.variant), _class)
      }), [$label || h()]);
    }
  });

  var POSITION_COVER = {
    top: 0,
    left: 0,
    bottom: 0,
    right: 0
  }; // --- Props ---

  var props$K = makePropsConfigurable({
    // Alternative to variant, allowing a specific
    // CSS color to be applied to the overlay
    bgColor: makeProp(PROP_TYPE_STRING),
    blur: makeProp(PROP_TYPE_STRING, '2px'),
    fixed: makeProp(PROP_TYPE_BOOLEAN, false),
    noCenter: makeProp(PROP_TYPE_BOOLEAN, false),
    noFade: makeProp(PROP_TYPE_BOOLEAN, false),
    // If `true, does not render the default slot
    // and switches to absolute positioning
    noWrap: makeProp(PROP_TYPE_BOOLEAN, false),
    opacity: makeProp(PROP_TYPE_NUMBER_STRING, 0.85, function (value) {
      var number = toFloat(value, 0);
      return number >= 0 && number <= 1;
    }),
    overlayTag: makeProp(PROP_TYPE_STRING, 'div'),
    rounded: makeProp(PROP_TYPE_BOOLEAN_STRING, false),
    show: makeProp(PROP_TYPE_BOOLEAN, false),
    spinnerSmall: makeProp(PROP_TYPE_BOOLEAN, false),
    spinnerType: makeProp(PROP_TYPE_STRING, 'border'),
    spinnerVariant: makeProp(PROP_TYPE_STRING),
    variant: makeProp(PROP_TYPE_STRING, 'light'),
    wrapTag: makeProp(PROP_TYPE_STRING, 'div'),
    zIndex: makeProp(PROP_TYPE_NUMBER_STRING, 10)
  }, NAME_OVERLAY); // --- Main component ---
  // @vue/component

  var BOverlay = /*#__PURE__*/extend({
    name: NAME_OVERLAY,
    mixins: [normalizeSlotMixin],
    props: props$K,
    computed: {
      computedRounded: function computedRounded() {
        var rounded = this.rounded;
        return rounded === true || rounded === '' ? 'rounded' : !rounded ? '' : "rounded-".concat(rounded);
      },
      computedVariant: function computedVariant() {
        var variant = this.variant;
        return variant && !this.bgColor ? "bg-".concat(variant) : '';
      },
      slotScope: function slotScope() {
        return {
          spinnerType: this.spinnerType || null,
          spinnerVariant: this.spinnerVariant || null,
          spinnerSmall: this.spinnerSmall
        };
      }
    },
    methods: {
      defaultOverlayFn: function defaultOverlayFn(_ref) {
        var spinnerType = _ref.spinnerType,
            spinnerVariant = _ref.spinnerVariant,
            spinnerSmall = _ref.spinnerSmall;
        return this.$createElement(BSpinner, {
          props: {
            type: spinnerType,
            variant: spinnerVariant,
            small: spinnerSmall
          }
        });
      }
    },
    render: function render(h) {
      var _this = this;

      var show = this.show,
          fixed = this.fixed,
          noFade = this.noFade,
          noWrap = this.noWrap,
          slotScope = this.slotScope;
      var $overlay = h();

      if (show) {
        var $background = h('div', {
          staticClass: 'position-absolute',
          class: [this.computedVariant, this.computedRounded],
          style: _objectSpread2$3(_objectSpread2$3({}, POSITION_COVER), {}, {
            opacity: this.opacity,
            backgroundColor: this.bgColor || null,
            backdropFilter: this.blur ? "blur(".concat(this.blur, ")") : null
          })
        });
        var $content = h('div', {
          staticClass: 'position-absolute',
          style: this.noCenter ?
          /* istanbul ignore next */
          _objectSpread2$3({}, POSITION_COVER) : {
            top: '50%',
            left: '50%',
            transform: 'translateX(-50%) translateY(-50%)'
          }
        }, [this.normalizeSlot(SLOT_NAME_OVERLAY, slotScope) || this.defaultOverlayFn(slotScope)]);
        $overlay = h(this.overlayTag, {
          staticClass: 'b-overlay',
          class: {
            'position-absolute': !noWrap || noWrap && !fixed,
            'position-fixed': noWrap && fixed
          },
          style: _objectSpread2$3(_objectSpread2$3({}, POSITION_COVER), {}, {
            zIndex: this.zIndex || 10
          }),
          on: {
            click: function click(event) {
              return _this.$emit(EVENT_NAME_CLICK, event);
            }
          },
          key: 'overlay'
        }, [$background, $content]);
      } // Wrap in a fade transition


      $overlay = h(BVTransition, {
        props: {
          noFade: noFade,
          appear: true
        },
        on: {
          'after-enter': function afterEnter() {
            return _this.$emit(EVENT_NAME_SHOWN);
          },
          'after-leave': function afterLeave() {
            return _this.$emit(EVENT_NAME_HIDDEN);
          }
        }
      }, [$overlay]);

      if (noWrap) {
        return $overlay;
      }

      return h(this.wrapTag, {
        staticClass: 'b-overlay-wrap position-relative',
        attrs: {
          'aria-busy': show ? 'true' : null
        }
      }, noWrap ? [$overlay] : [this.normalizeSlot(), $overlay]);
    }
  });

  var OverlayPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BOverlay: BOverlay
    }
  });

  var _watch$6;
  // for `<b-pagination>` and `<b-pagination-nav>`
  // --- Constants ---

  var _makeModelMixin$4 = makeModelMixin('value', {
    type: PROP_TYPE_BOOLEAN_NUMBER_STRING,
    defaultValue: null,

    /* istanbul ignore next */
    validator: function validator(value) {
      if (!isNull(value) && toInteger(value, 0) < 1) {
        warn('"v-model" value must be a number greater than "0"', NAME_PAGINATION);
        return false;
      }

      return true;
    }
  }),
      modelMixin$4 = _makeModelMixin$4.mixin,
      modelProps$4 = _makeModelMixin$4.props,
      MODEL_PROP_NAME$4 = _makeModelMixin$4.prop,
      MODEL_EVENT_NAME$4 = _makeModelMixin$4.event;

  var ELLIPSIS_THRESHOLD = 3; // Default # of buttons limit

  var DEFAULT_LIMIT = 5; // --- Helper methods ---
  // Make an array of N to N+X

  var makePageArray = function makePageArray(startNumber, numberOfPages) {
    return createArray(numberOfPages, function (_, i) {
      return {
        number: startNumber + i,
        classes: null
      };
    });
  }; // Sanitize the provided limit value (converting to a number)


  var sanitizeLimit = function sanitizeLimit(value) {
    var limit = toInteger(value) || 1;
    return limit < 1 ? DEFAULT_LIMIT : limit;
  }; // Sanitize the provided current page number (converting to a number)


  var sanitizeCurrentPage = function sanitizeCurrentPage(val, numberOfPages) {
    var page = toInteger(val) || 1;
    return page > numberOfPages ? numberOfPages : page < 1 ? 1 : page;
  }; // Links don't normally respond to SPACE, so we add that
  // functionality via this handler


  var onSpaceKey = function onSpaceKey(event) {
    if (event.keyCode === CODE_SPACE) {
      // Stop page from scrolling
      stopEvent(event, {
        immediatePropagation: true
      }); // Trigger the click event on the link

      event.currentTarget.click();
      return false;
    }
  }; // --- Props ---


  var props$J = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, modelProps$4), {}, {
    align: makeProp(PROP_TYPE_STRING, 'left'),
    ariaLabel: makeProp(PROP_TYPE_STRING, 'Pagination'),
    disabled: makeProp(PROP_TYPE_BOOLEAN, false),
    ellipsisClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    ellipsisText: makeProp(PROP_TYPE_STRING, "\u2026"),
    // '…'
    firstClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    firstNumber: makeProp(PROP_TYPE_BOOLEAN, false),
    firstText: makeProp(PROP_TYPE_STRING, "\xAB"),
    // '«'
    hideEllipsis: makeProp(PROP_TYPE_BOOLEAN, false),
    hideGotoEndButtons: makeProp(PROP_TYPE_BOOLEAN, false),
    labelFirstPage: makeProp(PROP_TYPE_STRING, 'Go to first page'),
    labelLastPage: makeProp(PROP_TYPE_STRING, 'Go to last page'),
    labelNextPage: makeProp(PROP_TYPE_STRING, 'Go to next page'),
    labelPage: makeProp(PROP_TYPE_FUNCTION_STRING, 'Go to page'),
    labelPrevPage: makeProp(PROP_TYPE_STRING, 'Go to previous page'),
    lastClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    lastNumber: makeProp(PROP_TYPE_BOOLEAN, false),
    lastText: makeProp(PROP_TYPE_STRING, "\xBB"),
    // '»'
    limit: makeProp(PROP_TYPE_NUMBER_STRING, DEFAULT_LIMIT,
    /* istanbul ignore next */
    function (value) {
      if (toInteger(value, 0) < 1) {
        warn('Prop "limit" must be a number greater than "0"', NAME_PAGINATION);
        return false;
      }

      return true;
    }),
    nextClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    nextText: makeProp(PROP_TYPE_STRING, "\u203A"),
    // '›'
    pageClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    pills: makeProp(PROP_TYPE_BOOLEAN, false),
    prevClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    prevText: makeProp(PROP_TYPE_STRING, "\u2039"),
    // '‹'
    size: makeProp(PROP_TYPE_STRING)
  })), 'pagination'); // --- Mixin ---
  // @vue/component

  var paginationMixin$1 = extend({
    mixins: [modelMixin$4, normalizeSlotMixin],
    props: props$J,
    data: function data() {
      // `-1` signifies no page initially selected
      var currentPage = toInteger(this[MODEL_PROP_NAME$4], 0);
      currentPage = currentPage > 0 ? currentPage : -1;
      return {
        currentPage: currentPage,
        localNumberOfPages: 1,
        localLimit: DEFAULT_LIMIT
      };
    },
    computed: {
      btnSize: function btnSize() {
        var size = this.size;
        return size ? "pagination-".concat(size) : '';
      },
      alignment: function alignment() {
        var align = this.align;

        if (align === 'center') {
          return 'justify-content-center';
        } else if (align === 'end' || align === 'right') {
          return 'justify-content-end';
        } else if (align === 'fill') {
          // The page-items will also have 'flex-fill' added
          // We add text centering to make the button appearance better in fill mode
          return 'text-center';
        }

        return '';
      },
      styleClass: function styleClass() {
        return this.pills ? 'b-pagination-pills' : '';
      },
      computedCurrentPage: function computedCurrentPage() {
        return sanitizeCurrentPage(this.currentPage, this.localNumberOfPages);
      },
      paginationParams: function paginationParams() {
        // Determine if we should show the the ellipsis
        var limit = this.localLimit,
            numberOfPages = this.localNumberOfPages,
            currentPage = this.computedCurrentPage,
            hideEllipsis = this.hideEllipsis,
            firstNumber = this.firstNumber,
            lastNumber = this.lastNumber;
        var showFirstDots = false;
        var showLastDots = false;
        var numberOfLinks = limit;
        var startNumber = 1;

        if (numberOfPages <= limit) {
          // Special case: Less pages available than the limit of displayed pages
          numberOfLinks = numberOfPages;
        } else if (currentPage < limit - 1 && limit > ELLIPSIS_THRESHOLD) {
          if (!hideEllipsis || lastNumber) {
            showLastDots = true;
            numberOfLinks = limit - (firstNumber ? 0 : 1);
          }

          numberOfLinks = mathMin(numberOfLinks, limit);
        } else if (numberOfPages - currentPage + 2 < limit && limit > ELLIPSIS_THRESHOLD) {
          if (!hideEllipsis || firstNumber) {
            showFirstDots = true;
            numberOfLinks = limit - (lastNumber ? 0 : 1);
          }

          startNumber = numberOfPages - numberOfLinks + 1;
        } else {
          // We are somewhere in the middle of the page list
          if (limit > ELLIPSIS_THRESHOLD) {
            numberOfLinks = limit - (hideEllipsis ? 0 : 2);
            showFirstDots = !!(!hideEllipsis || firstNumber);
            showLastDots = !!(!hideEllipsis || lastNumber);
          }

          startNumber = currentPage - mathFloor(numberOfLinks / 2);
        } // Sanity checks

        /* istanbul ignore if */


        if (startNumber < 1) {
          startNumber = 1;
          showFirstDots = false;
        } else if (startNumber > numberOfPages - numberOfLinks) {
          startNumber = numberOfPages - numberOfLinks + 1;
          showLastDots = false;
        }

        if (showFirstDots && firstNumber && startNumber < 4) {
          numberOfLinks = numberOfLinks + 2;
          startNumber = 1;
          showFirstDots = false;
        }

        var lastPageNumber = startNumber + numberOfLinks - 1;

        if (showLastDots && lastNumber && lastPageNumber > numberOfPages - 3) {
          numberOfLinks = numberOfLinks + (lastPageNumber === numberOfPages - 2 ? 2 : 3);
          showLastDots = false;
        } // Special handling for lower limits (where ellipsis are never shown)


        if (limit <= ELLIPSIS_THRESHOLD) {
          if (firstNumber && startNumber === 1) {
            numberOfLinks = mathMin(numberOfLinks + 1, numberOfPages, limit + 1);
          } else if (lastNumber && numberOfPages === startNumber + numberOfLinks - 1) {
            startNumber = mathMax(startNumber - 1, 1);
            numberOfLinks = mathMin(numberOfPages - startNumber + 1, numberOfPages, limit + 1);
          }
        }

        numberOfLinks = mathMin(numberOfLinks, numberOfPages - startNumber + 1);
        return {
          showFirstDots: showFirstDots,
          showLastDots: showLastDots,
          numberOfLinks: numberOfLinks,
          startNumber: startNumber
        };
      },
      pageList: function pageList() {
        // Generates the pageList array
        var _this$paginationParam = this.paginationParams,
            numberOfLinks = _this$paginationParam.numberOfLinks,
            startNumber = _this$paginationParam.startNumber;
        var currentPage = this.computedCurrentPage; // Generate list of page numbers

        var pages = makePageArray(startNumber, numberOfLinks); // We limit to a total of 3 page buttons on XS screens
        // So add classes to page links to hide them for XS breakpoint
        // Note: Ellipsis will also be hidden on XS screens
        // TODO: Make this visual limit configurable based on breakpoint(s)

        if (pages.length > 3) {
          var idx = currentPage - startNumber; // THe following is a bootstrap-vue custom utility class

          var classes = 'bv-d-xs-down-none';

          if (idx === 0) {
            // Keep leftmost 3 buttons visible when current page is first page
            for (var i = 3; i < pages.length; i++) {
              pages[i].classes = classes;
            }
          } else if (idx === pages.length - 1) {
            // Keep rightmost 3 buttons visible when current page is last page
            for (var _i = 0; _i < pages.length - 3; _i++) {
              pages[_i].classes = classes;
            }
          } else {
            // Hide all except current page, current page - 1 and current page + 1
            for (var _i2 = 0; _i2 < idx - 1; _i2++) {
              // hide some left button(s)
              pages[_i2].classes = classes;
            }

            for (var _i3 = pages.length - 1; _i3 > idx + 1; _i3--) {
              // hide some right button(s)
              pages[_i3].classes = classes;
            }
          }
        }

        return pages;
      }
    },
    watch: (_watch$6 = {}, _defineProperty(_watch$6, MODEL_PROP_NAME$4, function (newValue, oldValue) {
      if (newValue !== oldValue) {
        this.currentPage = sanitizeCurrentPage(newValue, this.localNumberOfPages);
      }
    }), _defineProperty(_watch$6, "currentPage", function currentPage(newValue, oldValue) {
      if (newValue !== oldValue) {
        // Emit `null` if no page selected
        this.$emit(MODEL_EVENT_NAME$4, newValue > 0 ? newValue : null);
      }
    }), _defineProperty(_watch$6, "limit", function limit(newValue, oldValue) {
      if (newValue !== oldValue) {
        this.localLimit = sanitizeLimit(newValue);
      }
    }), _watch$6),
    created: function created() {
      var _this = this;

      // Set our default values in data
      this.localLimit = sanitizeLimit(this.limit);
      this.$nextTick(function () {
        // Sanity check
        _this.currentPage = _this.currentPage > _this.localNumberOfPages ? _this.localNumberOfPages : _this.currentPage;
      });
    },
    methods: {
      handleKeyNav: function handleKeyNav(event) {
        var keyCode = event.keyCode,
            shiftKey = event.shiftKey;
        /* istanbul ignore if */

        if (this.isNav) {
          // We disable left/right keyboard navigation in `<b-pagination-nav>`
          return;
        }

        if (keyCode === CODE_LEFT || keyCode === CODE_UP) {
          stopEvent(event, {
            propagation: false
          });
          shiftKey ? this.focusFirst() : this.focusPrev();
        } else if (keyCode === CODE_RIGHT || keyCode === CODE_DOWN) {
          stopEvent(event, {
            propagation: false
          });
          shiftKey ? this.focusLast() : this.focusNext();
        }
      },
      getButtons: function getButtons() {
        // Return only buttons that are visible
        return selectAll('button.page-link, a.page-link', this.$el).filter(function (btn) {
          return isVisible(btn);
        });
      },
      focusCurrent: function focusCurrent() {
        var _this2 = this;

        // We do this in `$nextTick()` to ensure buttons have finished rendering
        this.$nextTick(function () {
          var btn = _this2.getButtons().find(function (el) {
            return toInteger(getAttr(el, 'aria-posinset'), 0) === _this2.computedCurrentPage;
          });

          if (!attemptFocus(btn)) {
            // Fallback if current page is not in button list
            _this2.focusFirst();
          }
        });
      },
      focusFirst: function focusFirst() {
        var _this3 = this;

        // We do this in `$nextTick()` to ensure buttons have finished rendering
        this.$nextTick(function () {
          var btn = _this3.getButtons().find(function (el) {
            return !isDisabled(el);
          });

          attemptFocus(btn);
        });
      },
      focusLast: function focusLast() {
        var _this4 = this;

        // We do this in `$nextTick()` to ensure buttons have finished rendering
        this.$nextTick(function () {
          var btn = _this4.getButtons().reverse().find(function (el) {
            return !isDisabled(el);
          });

          attemptFocus(btn);
        });
      },
      focusPrev: function focusPrev() {
        var _this5 = this;

        // We do this in `$nextTick()` to ensure buttons have finished rendering
        this.$nextTick(function () {
          var buttons = _this5.getButtons();

          var index = buttons.indexOf(getActiveElement());

          if (index > 0 && !isDisabled(buttons[index - 1])) {
            attemptFocus(buttons[index - 1]);
          }
        });
      },
      focusNext: function focusNext() {
        var _this6 = this;

        // We do this in `$nextTick()` to ensure buttons have finished rendering
        this.$nextTick(function () {
          var buttons = _this6.getButtons();

          var index = buttons.indexOf(getActiveElement());

          if (index < buttons.length - 1 && !isDisabled(buttons[index + 1])) {
            attemptFocus(buttons[index + 1]);
          }
        });
      }
    },
    render: function render(h) {
      var _this7 = this;

      var _safeVueInstance = safeVueInstance(this),
          disabled = _safeVueInstance.disabled,
          labelPage = _safeVueInstance.labelPage,
          ariaLabel = _safeVueInstance.ariaLabel,
          isNav = _safeVueInstance.isNav,
          numberOfPages = _safeVueInstance.localNumberOfPages,
          currentPage = _safeVueInstance.computedCurrentPage;

      var pageNumbers = this.pageList.map(function (p) {
        return p.number;
      });
      var _this$paginationParam2 = this.paginationParams,
          showFirstDots = _this$paginationParam2.showFirstDots,
          showLastDots = _this$paginationParam2.showLastDots;
      var fill = this.align === 'fill';
      var $buttons = []; // Helper function and flag

      var isActivePage = function isActivePage(pageNumber) {
        return pageNumber === currentPage;
      };

      var noCurrentPage = this.currentPage < 1; // Factory function for prev/next/first/last buttons

      var makeEndBtn = function makeEndBtn(linkTo, ariaLabel, btnSlot, btnText, btnClass, pageTest, key) {
        var isDisabled = disabled || isActivePage(pageTest) || noCurrentPage || linkTo < 1 || linkTo > numberOfPages;
        var pageNumber = linkTo < 1 ? 1 : linkTo > numberOfPages ? numberOfPages : linkTo;
        var scope = {
          disabled: isDisabled,
          page: pageNumber,
          index: pageNumber - 1
        };
        var $btnContent = _this7.normalizeSlot(btnSlot, scope) || toString(btnText) || h();
        var $inner = h(isDisabled ? 'span' : isNav ? BLink : 'button', {
          staticClass: 'page-link',
          class: {
            'flex-grow-1': !isNav && !isDisabled && fill
          },
          props: isDisabled || !isNav ? {} : _this7.linkProps(linkTo),
          attrs: {
            role: isNav ? null : 'menuitem',
            type: isNav || isDisabled ? null : 'button',
            tabindex: isDisabled || isNav ? null : '-1',
            'aria-label': ariaLabel,
            'aria-controls': safeVueInstance(_this7).ariaControls || null,
            'aria-disabled': isDisabled ? 'true' : null
          },
          on: isDisabled ? {} : {
            '!click': function click(event) {
              _this7.onClick(event, linkTo);
            },
            keydown: onSpaceKey
          }
        }, [$btnContent]);
        return h('li', {
          key: key,
          staticClass: 'page-item',
          class: [{
            disabled: isDisabled,
            'flex-fill': fill,
            'd-flex': fill && !isNav && !isDisabled
          }, btnClass],
          attrs: {
            role: isNav ? null : 'presentation',
            'aria-hidden': isDisabled ? 'true' : null
          }
        }, [$inner]);
      }; // Ellipsis factory


      var makeEllipsis = function makeEllipsis(isLast) {
        return h('li', {
          staticClass: 'page-item',
          class: ['disabled', 'bv-d-xs-down-none', fill ? 'flex-fill' : '', _this7.ellipsisClass],
          attrs: {
            role: 'separator'
          },
          key: "ellipsis-".concat(isLast ? 'last' : 'first')
        }, [h('span', {
          staticClass: 'page-link'
        }, [_this7.normalizeSlot(SLOT_NAME_ELLIPSIS_TEXT) || toString(_this7.ellipsisText) || h()])]);
      }; // Page button factory


      var makePageButton = function makePageButton(page, idx) {
        var pageNumber = page.number;
        var active = isActivePage(pageNumber) && !noCurrentPage; // Active page will have tabindex of 0, or if no current page and first page button

        var tabIndex = disabled ? null : active || noCurrentPage && idx === 0 ? '0' : '-1';
        var attrs = {
          role: isNav ? null : 'menuitemradio',
          type: isNav || disabled ? null : 'button',
          'aria-disabled': disabled ? 'true' : null,
          'aria-controls': safeVueInstance(_this7).ariaControls || null,
          'aria-label': hasPropFunction(labelPage) ?
          /* istanbul ignore next */
          labelPage(pageNumber) : "".concat(isFunction$1(labelPage) ? labelPage() : labelPage, " ").concat(pageNumber),
          'aria-checked': isNav ? null : active ? 'true' : 'false',
          'aria-current': isNav && active ? 'page' : null,
          'aria-posinset': isNav ? null : pageNumber,
          'aria-setsize': isNav ? null : numberOfPages,
          // ARIA "roving tabindex" method (except in `isNav` mode)
          tabindex: isNav ? null : tabIndex
        };
        var btnContent = toString(_this7.makePage(pageNumber));
        var scope = {
          page: pageNumber,
          index: pageNumber - 1,
          content: btnContent,
          active: active,
          disabled: disabled
        };
        var $inner = h(disabled ? 'span' : isNav ? BLink : 'button', {
          props: disabled || !isNav ? {} : _this7.linkProps(pageNumber),
          staticClass: 'page-link',
          class: {
            'flex-grow-1': !isNav && !disabled && fill
          },
          attrs: attrs,
          on: disabled ? {} : {
            '!click': function click(event) {
              _this7.onClick(event, pageNumber);
            },
            keydown: onSpaceKey
          }
        }, [_this7.normalizeSlot(SLOT_NAME_PAGE, scope) || btnContent]);
        return h('li', {
          staticClass: 'page-item',
          class: [{
            disabled: disabled,
            active: active,
            'flex-fill': fill,
            'd-flex': fill && !isNav && !disabled
          }, page.classes, _this7.pageClass],
          attrs: {
            role: isNav ? null : 'presentation'
          },
          key: "page-".concat(pageNumber)
        }, [$inner]);
      }; // Goto first page button
      // Don't render button when `hideGotoEndButtons` or `firstNumber` is set


      var $firstPageBtn = h();

      if (!this.firstNumber && !this.hideGotoEndButtons) {
        $firstPageBtn = makeEndBtn(1, this.labelFirstPage, SLOT_NAME_FIRST_TEXT, this.firstText, this.firstClass, 1, 'pagination-goto-first');
      }

      $buttons.push($firstPageBtn); // Goto previous page button

      $buttons.push(makeEndBtn(currentPage - 1, this.labelPrevPage, SLOT_NAME_PREV_TEXT, this.prevText, this.prevClass, 1, 'pagination-goto-prev')); // Show first (1) button?

      $buttons.push(this.firstNumber && pageNumbers[0] !== 1 ? makePageButton({
        number: 1
      }, 0) : h()); // First ellipsis

      $buttons.push(showFirstDots ? makeEllipsis(false) : h()); // Individual page links

      this.pageList.forEach(function (page, idx) {
        var offset = showFirstDots && _this7.firstNumber && pageNumbers[0] !== 1 ? 1 : 0;
        $buttons.push(makePageButton(page, idx + offset));
      }); // Last ellipsis

      $buttons.push(showLastDots ? makeEllipsis(true) : h()); // Show last page button?

      $buttons.push(this.lastNumber && pageNumbers[pageNumbers.length - 1] !== numberOfPages ? makePageButton({
        number: numberOfPages
      }, -1) : h()); // Goto next page button

      $buttons.push(makeEndBtn(currentPage + 1, this.labelNextPage, SLOT_NAME_NEXT_TEXT, this.nextText, this.nextClass, numberOfPages, 'pagination-goto-next')); // Goto last page button
      // Don't render button when `hideGotoEndButtons` or `lastNumber` is set

      var $lastPageBtn = h();

      if (!this.lastNumber && !this.hideGotoEndButtons) {
        $lastPageBtn = makeEndBtn(numberOfPages, this.labelLastPage, SLOT_NAME_LAST_TEXT, this.lastText, this.lastClass, numberOfPages, 'pagination-goto-last');
      }

      $buttons.push($lastPageBtn); // Assemble the pagination buttons

      var $pagination = h('ul', {
        staticClass: 'pagination',
        class: ['b-pagination', this.btnSize, this.alignment, this.styleClass],
        attrs: {
          role: isNav ? null : 'menubar',
          'aria-disabled': disabled ? 'true' : 'false',
          'aria-label': isNav ? null : ariaLabel || null
        },
        // We disable keyboard left/right nav when `<b-pagination-nav>`
        on: isNav ? {} : {
          keydown: this.handleKeyNav
        },
        ref: 'ul'
      }, $buttons); // If we are `<b-pagination-nav>`, wrap in `<nav>` wrapper

      if (isNav) {
        return h('nav', {
          attrs: {
            'aria-disabled': disabled ? 'true' : null,
            'aria-hidden': disabled ? 'true' : 'false',
            'aria-label': isNav ? ariaLabel || null : null
          }
        }, [$pagination]);
      }

      return $pagination;
    }
  });

  var DEFAULT_PER_PAGE = 20;
  var DEFAULT_TOTAL_ROWS = 0; // --- Helper methods ---
  // Sanitize the provided per page number (converting to a number)

  var sanitizePerPage = function sanitizePerPage(value) {
    return mathMax(toInteger(value) || DEFAULT_PER_PAGE, 1);
  }; // Sanitize the provided total rows number (converting to a number)


  var sanitizeTotalRows = function sanitizeTotalRows(value) {
    return mathMax(toInteger(value) || DEFAULT_TOTAL_ROWS, 0);
  }; // --- Props ---


  var props$I = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, props$J), {}, {
    ariaControls: makeProp(PROP_TYPE_STRING),
    perPage: makeProp(PROP_TYPE_NUMBER_STRING, DEFAULT_PER_PAGE),
    totalRows: makeProp(PROP_TYPE_NUMBER_STRING, DEFAULT_TOTAL_ROWS)
  })), NAME_PAGINATION); // --- Main component ---
  // @vue/component

  var BPagination = /*#__PURE__*/extend({
    name: NAME_PAGINATION,
    // The render function is brought in via the `paginationMixin`
    mixins: [paginationMixin$1],
    props: props$I,
    computed: {
      numberOfPages: function numberOfPages() {
        var result = mathCeil(sanitizeTotalRows(this.totalRows) / sanitizePerPage(this.perPage));
        return result < 1 ? 1 : result;
      },
      // Used for watching changes to `perPage` and `numberOfPages`
      pageSizeNumberOfPages: function pageSizeNumberOfPages() {
        return {
          perPage: sanitizePerPage(this.perPage),
          totalRows: sanitizeTotalRows(this.totalRows),
          numberOfPages: this.numberOfPages
        };
      }
    },
    watch: {
      pageSizeNumberOfPages: function pageSizeNumberOfPages(newValue, oldValue) {
        if (!isUndefinedOrNull(oldValue)) {
          if (newValue.perPage !== oldValue.perPage && newValue.totalRows === oldValue.totalRows) {
            // If the page size changes, reset to page 1
            this.currentPage = 1;
          } else if (newValue.numberOfPages !== oldValue.numberOfPages && this.currentPage > newValue.numberOfPages) {
            // If `numberOfPages` changes and is less than
            // the `currentPage` number, reset to page 1
            this.currentPage = 1;
          }
        }

        this.localNumberOfPages = newValue.numberOfPages;
      }
    },
    created: function created() {
      var _this = this;

      // Set the initial page count
      this.localNumberOfPages = this.numberOfPages; // Set the initial page value

      var currentPage = toInteger(this[MODEL_PROP_NAME$4], 0);

      if (currentPage > 0) {
        this.currentPage = currentPage;
      } else {
        this.$nextTick(function () {
          // If this value parses to `NaN` or a value less than `1`
          // trigger an initial emit of `null` if no page specified
          _this.currentPage = 0;
        });
      }
    },
    methods: {
      // These methods are used by the render function
      onClick: function onClick(event, pageNumber) {
        var _this2 = this;

        // Dont do anything if clicking the current active page
        if (pageNumber === this.currentPage) {
          return;
        }

        var target = event.target; // Emit a user-cancelable `page-click` event

        var clickEvent = new BvEvent(EVENT_NAME_PAGE_CLICK, {
          cancelable: true,
          vueTarget: this,
          target: target
        });
        this.$emit(clickEvent.type, clickEvent, pageNumber);

        if (clickEvent.defaultPrevented) {
          return;
        } // Update the `v-model`


        this.currentPage = pageNumber; // Emit event triggered by user interaction

        this.$emit(EVENT_NAME_CHANGE, this.currentPage); // Keep the current button focused if possible

        this.$nextTick(function () {
          if (isVisible(target) && _this2.$el.contains(target)) {
            attemptFocus(target);
          } else {
            _this2.focusCurrent();
          }
        });
      },
      makePage: function makePage(pageNum) {
        return pageNum;
      },

      /* istanbul ignore next */
      linkProps: function linkProps() {
        // No props, since we render a plain button
        return {};
      }
    }
  });

  var PaginationPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BPagination: BPagination
    }
  });

  // Sanitize the provided number of pages (converting to a number)

  var sanitizeNumberOfPages = function sanitizeNumberOfPages(value) {
    return mathMax(toInteger(value, 0), 1);
  }; // --- Props ---

  var _linkProps = omit(props$2f, ['event', 'routerTag']);

  var props$H = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$J), _linkProps), {}, {
    baseUrl: makeProp(PROP_TYPE_STRING, '/'),
    linkGen: makeProp(PROP_TYPE_FUNCTION),
    // Disable auto page number detection if `true`
    noPageDetect: makeProp(PROP_TYPE_BOOLEAN, false),
    numberOfPages: makeProp(PROP_TYPE_NUMBER_STRING, 1,
    /* istanbul ignore next */
    function (value) {
      var number = toInteger(value, 0);

      if (number < 1) {
        warn('Prop "number-of-pages" must be a number greater than "0"', NAME_PAGINATION_NAV);
        return false;
      }

      return true;
    }),
    pageGen: makeProp(PROP_TYPE_FUNCTION),
    // Optional array of page links
    pages: makeProp(PROP_TYPE_ARRAY),
    useRouter: makeProp(PROP_TYPE_BOOLEAN, false)
  })), NAME_PAGINATION_NAV); // --- Main component ---
  // @vue/component

  var BPaginationNav = /*#__PURE__*/extend({
    name: NAME_PAGINATION_NAV,
    // The render function is brought in via the pagination mixin
    mixins: [paginationMixin$1],
    props: props$H,
    computed: {
      // Used by render function to trigger wrapping in '<nav>' element
      isNav: function isNav() {
        return true;
      },
      computedValue: function computedValue() {
        // Returns the value prop as a number or `null` if undefined or < 1
        var value = toInteger(this.value, 0);
        return value < 1 ? null : value;
      }
    },
    watch: {
      numberOfPages: function numberOfPages() {
        var _this = this;

        this.$nextTick(function () {
          _this.setNumberOfPages();
        });
      },
      pages: function pages() {
        var _this2 = this;

        this.$nextTick(function () {
          _this2.setNumberOfPages();
        });
      }
    },
    created: function created() {
      this.setNumberOfPages();
    },
    mounted: function mounted() {
      var _this3 = this;

      if (this.$router) {
        // We only add the watcher if vue router is detected
        this.$watch('$route', function () {
          _this3.$nextTick(function () {
            requestAF(function () {
              _this3.guessCurrentPage();
            });
          });
        });
      }
    },
    methods: {
      setNumberOfPages: function setNumberOfPages() {
        var _this4 = this;

        if (isArray(this.pages) && this.pages.length > 0) {
          this.localNumberOfPages = this.pages.length;
        } else {
          this.localNumberOfPages = sanitizeNumberOfPages(this.numberOfPages);
        }

        this.$nextTick(function () {
          _this4.guessCurrentPage();
        });
      },
      onClick: function onClick(event, pageNumber) {
        var _this5 = this;

        // Dont do anything if clicking the current active page
        if (pageNumber === this.currentPage) {
          return;
        }

        var target = event.currentTarget || event.target; // Emit a user-cancelable `page-click` event

        var clickEvent = new BvEvent(EVENT_NAME_PAGE_CLICK, {
          cancelable: true,
          vueTarget: this,
          target: target
        });
        this.$emit(clickEvent.type, clickEvent, pageNumber);

        if (clickEvent.defaultPrevented) {
          return;
        } // Update the `v-model`
        // Done in in requestAF() to allow browser to complete the
        // native browser click handling of a link


        requestAF(function () {
          _this5.currentPage = pageNumber;

          _this5.$emit(EVENT_NAME_CHANGE, pageNumber);
        }); // Emulate native link click page reloading behaviour by blurring the
        // paginator and returning focus to the document
        // Done in a `nextTick()` to ensure rendering complete

        this.$nextTick(function () {
          attemptBlur(target);
        });
      },
      getPageInfo: function getPageInfo(pageNumber) {
        if (!isArray(this.pages) || this.pages.length === 0 || isUndefined(this.pages[pageNumber - 1])) {
          var link = "".concat(this.baseUrl).concat(pageNumber);
          return {
            link: this.useRouter ? {
              path: link
            } : link,
            text: toString(pageNumber)
          };
        }

        var info = this.pages[pageNumber - 1];

        if (isObject(info)) {
          var _link = info.link;
          return {
            // Normalize link for router use
            link: isObject(_link) ? _link : this.useRouter ? {
              path: _link
            } : _link,
            // Make sure text has a value
            text: toString(info.text || pageNumber)
          };
        } else {
          return {
            link: toString(info),
            text: toString(pageNumber)
          };
        }
      },
      makePage: function makePage(pageNumber) {
        var pageGen = this.pageGen;
        var info = this.getPageInfo(pageNumber);

        if (hasPropFunction(pageGen)) {
          return pageGen(pageNumber, info);
        }

        return info.text;
      },
      makeLink: function makeLink(pageNumber) {
        var linkGen = this.linkGen;
        var info = this.getPageInfo(pageNumber);

        if (hasPropFunction(linkGen)) {
          return linkGen(pageNumber, info);
        }

        return info.link;
      },
      linkProps: function linkProps(pageNumber) {
        var props = pluckProps(_linkProps, this);
        var link = this.makeLink(pageNumber);

        if (this.useRouter || isObject(link)) {
          props.to = link;
        } else {
          props.href = link;
        }

        return props;
      },
      resolveLink: function resolveLink() {
        var to = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
        // Given a to (or href string), convert to normalized route-like structure
        // Works only client side!
        var link;

        try {
          // Convert the `to` to a HREF via a temporary `a` tag
          link = document.createElement('a');
          link.href = computeHref({
            to: to
          }, 'a', '/', '/'); // We need to add the anchor to the document to make sure the
          // `pathname` is correctly detected in any browser (i.e. IE)

          document.body.appendChild(link); // Once href is assigned, the link will be normalized to the full URL bits

          var _link2 = link,
              pathname = _link2.pathname,
              hash = _link2.hash,
              search = _link2.search; // Remove link from document

          document.body.removeChild(link); // Return the location in a route-like object

          return {
            path: pathname,
            hash: hash,
            query: parseQuery(search)
          };
        } catch (e) {
          /* istanbul ignore next */
          try {
            link && link.parentNode && link.parentNode.removeChild(link);
          } catch (_unused) {}
          /* istanbul ignore next */


          return {};
        }
      },
      resolveRoute: function resolveRoute() {
        var to = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';

        // Given a to (or href string), convert to normalized route location structure
        // Works only when router available!
        try {
          var route = this.$router.resolve(to, this.$route).route;
          return {
            path: route.path,
            hash: route.hash,
            query: route.query
          };
        } catch (e) {
          /* istanbul ignore next */
          return {};
        }
      },
      guessCurrentPage: function guessCurrentPage() {
        var $router = this.$router,
            $route = this.$route;
        var guess = this.computedValue; // This section only occurs if we are client side, or server-side with `$router`

        if (!this.noPageDetect && !guess && (IS_BROWSER || !IS_BROWSER && $router)) {
          // Current route (if router available)
          var currentRoute = $router && $route ? {
            path: $route.path,
            hash: $route.hash,
            query: $route.query
          } : {}; // Current page full HREF (if client side)
          // Can't be done as a computed prop!

          var loc = IS_BROWSER ? window.location || document.location : null;
          var currentLink = loc ? {
            path: loc.pathname,
            hash: loc.hash,
            query: parseQuery(loc.search)
          } :
          /* istanbul ignore next */
          {}; // Loop through the possible pages looking for a match until found

          for (var pageNumber = 1; !guess && pageNumber <= this.localNumberOfPages; pageNumber++) {
            var to = this.makeLink(pageNumber);

            if ($router && (isObject(to) || this.useRouter)) {
              // Resolve the page via the `$router`
              guess = looseEqual(this.resolveRoute(to), currentRoute) ? pageNumber : null;
            } else if (IS_BROWSER) {
              // If no `$router` available (or `!this.useRouter` when `to` is a string)
              // we compare using parsed URIs
              guess = looseEqual(this.resolveLink(to), currentLink) ? pageNumber : null;
            } else {
              // Probably SSR, but no `$router` so we can't guess,
              // so lets break out of the loop early

              /* istanbul ignore next */
              guess = -1;
            }
          }
        } // We set `currentPage` to `0` to trigger an `$emit('input', null)`
        // As the default for `currentPage` is `-1` when no value is specified
        // Valid page numbers are greater than `0`


        this.currentPage = guess > 0 ? guess : 0;
      }
    }
  });

  var PaginationNavPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BPaginationNav: BPaginationNav
    }
  });

  // Base on-demand component for tooltip / popover templates

  var AttachmentMap = {
    AUTO: 'auto',
    TOP: 'top',
    RIGHT: 'right',
    BOTTOM: 'bottom',
    LEFT: 'left',
    TOPLEFT: 'top',
    TOPRIGHT: 'top',
    RIGHTTOP: 'right',
    RIGHTBOTTOM: 'right',
    BOTTOMLEFT: 'bottom',
    BOTTOMRIGHT: 'bottom',
    LEFTTOP: 'left',
    LEFTBOTTOM: 'left'
  };
  var OffsetMap = {
    AUTO: 0,
    TOPLEFT: -1,
    TOP: 0,
    TOPRIGHT: +1,
    RIGHTTOP: -1,
    RIGHT: 0,
    RIGHTBOTTOM: +1,
    BOTTOMLEFT: -1,
    BOTTOM: 0,
    BOTTOMRIGHT: +1,
    LEFTTOP: -1,
    LEFT: 0,
    LEFTBOTTOM: +1
  }; // --- Props ---

  var props$G = {
    // The minimum distance (in `px`) from the edge of the
    // tooltip/popover that the arrow can be positioned
    arrowPadding: makeProp(PROP_TYPE_NUMBER_STRING, 6),
    // 'scrollParent', 'viewport', 'window', or `Element`
    boundary: makeProp([HTMLElement, PROP_TYPE_STRING], 'scrollParent'),
    // Tooltip/popover will try and stay away from
    // boundary edge by this many pixels
    boundaryPadding: makeProp(PROP_TYPE_NUMBER_STRING, 5),
    fallbackPlacement: makeProp(PROP_TYPE_ARRAY_STRING, 'flip'),
    offset: makeProp(PROP_TYPE_NUMBER_STRING, 0),
    placement: makeProp(PROP_TYPE_STRING, 'top'),
    // Element that the tooltip/popover is positioned relative to
    target: makeProp([HTMLElement, SVGElement])
  }; // --- Main component ---
  // @vue/component

  var BVPopper = /*#__PURE__*/extend({
    name: NAME_POPPER,
    mixins: [useParentMixin],
    props: props$G,
    data: function data() {
      return {
        // reactive props set by parent
        noFade: false,
        // State related data
        localShow: true,
        attachment: this.getAttachment(this.placement)
      };
    },
    computed: {
      /* istanbul ignore next */
      templateType: function templateType() {
        // Overridden by template component
        return 'unknown';
      },
      popperConfig: function popperConfig() {
        var _this = this;

        var placement = this.placement;
        return {
          placement: this.getAttachment(placement),
          modifiers: {
            offset: {
              offset: this.getOffset(placement)
            },
            flip: {
              behavior: this.fallbackPlacement
            },
            // `arrow.element` can also be a reference to an HTML Element
            // maybe we should make this a `$ref` in the templates?
            arrow: {
              element: '.arrow'
            },
            preventOverflow: {
              padding: this.boundaryPadding,
              boundariesElement: this.boundary
            }
          },
          onCreate: function onCreate(data) {
            // Handle flipping arrow classes
            if (data.originalPlacement !== data.placement) {
              /* istanbul ignore next: can't test in JSDOM */
              _this.popperPlacementChange(data);
            }
          },
          onUpdate: function onUpdate(data) {
            // Handle flipping arrow classes
            _this.popperPlacementChange(data);
          }
        };
      }
    },
    created: function created() {
      var _this2 = this;

      // Note: We are created on-demand, and should be guaranteed that
      // DOM is rendered/ready by the time the created hook runs
      this.$_popper = null; // Ensure we show as we mount

      this.localShow = true; // Create popper instance before shown

      this.$on(EVENT_NAME_SHOW, function (el) {
        _this2.popperCreate(el);
      }); // Self destruct handler

      var handleDestroy = function handleDestroy() {
        _this2.$nextTick(function () {
          // In a `requestAF()` to release control back to application
          requestAF(function () {
            _this2.$destroy();
          });
        });
      }; // Self destruct if parent destroyed


      this.bvParent.$once(HOOK_EVENT_NAME_DESTROYED, handleDestroy); // Self destruct after hidden

      this.$once(EVENT_NAME_HIDDEN, handleDestroy);
    },
    beforeMount: function beforeMount() {
      // Ensure that the attachment position is correct before mounting
      // as our propsData is added after `new Template({...})`
      this.attachment = this.getAttachment(this.placement);
    },
    updated: function updated() {
      // Update popper if needed
      // TODO: Should this be a watcher on `this.popperConfig` instead?
      this.updatePopper();
    },
    beforeDestroy: function beforeDestroy() {
      this.destroyPopper();
    },
    destroyed: function destroyed() {
      // Make sure template is removed from DOM
      var el = this.$el;
      el && el.parentNode && el.parentNode.removeChild(el);
    },
    methods: {
      // "Public" method to trigger hide template
      hide: function hide() {
        this.localShow = false;
      },
      // Private
      getAttachment: function getAttachment(placement) {
        return AttachmentMap[String(placement).toUpperCase()] || 'auto';
      },
      getOffset: function getOffset(placement) {
        if (!this.offset) {
          // Could set a ref for the arrow element
          var arrow = this.$refs.arrow || select('.arrow', this.$el);
          var arrowOffset = toFloat(getCS(arrow).width, 0) + toFloat(this.arrowPadding, 0);

          switch (OffsetMap[String(placement).toUpperCase()] || 0) {
            /* istanbul ignore next: can't test in JSDOM */
            case +1:
              /* istanbul ignore next: can't test in JSDOM */
              return "+50%p - ".concat(arrowOffset, "px");

            /* istanbul ignore next: can't test in JSDOM */

            case -1:
              /* istanbul ignore next: can't test in JSDOM */
              return "-50%p + ".concat(arrowOffset, "px");

            default:
              return 0;
          }
        }
        /* istanbul ignore next */


        return this.offset;
      },
      popperCreate: function popperCreate(el) {
        this.destroyPopper(); // We use `el` rather than `this.$el` just in case the original
        // mountpoint root element type was changed by the template

        this.$_popper = new Popper(this.target, el, this.popperConfig);
      },
      destroyPopper: function destroyPopper() {
        this.$_popper && this.$_popper.destroy();
        this.$_popper = null;
      },
      updatePopper: function updatePopper() {
        this.$_popper && this.$_popper.scheduleUpdate();
      },
      popperPlacementChange: function popperPlacementChange(data) {
        // Callback used by popper to adjust the arrow placement
        this.attachment = this.getAttachment(data.placement);
      },

      /* istanbul ignore next */
      renderTemplate: function renderTemplate(h) {
        // Will be overridden by templates
        return h('div');
      }
    },
    render: function render(h) {
      var _this3 = this;

      var noFade = this.noFade; // Note: 'show' and 'fade' classes are only appled during transition

      return h(BVTransition, {
        // Transitions as soon as mounted
        props: {
          appear: true,
          noFade: noFade
        },
        on: {
          // Events used by parent component/instance
          beforeEnter: function beforeEnter(el) {
            return _this3.$emit(EVENT_NAME_SHOW, el);
          },
          afterEnter: function afterEnter(el) {
            return _this3.$emit(EVENT_NAME_SHOWN, el);
          },
          beforeLeave: function beforeLeave(el) {
            return _this3.$emit(EVENT_NAME_HIDE, el);
          },
          afterLeave: function afterLeave(el) {
            return _this3.$emit(EVENT_NAME_HIDDEN, el);
          }
        }
      }, [this.localShow ? this.renderTemplate(h) : h()]);
    }
  });

  var props$F = {
    // Used only by the directive versions
    html: makeProp(PROP_TYPE_BOOLEAN, false),
    // Other non-reactive (while open) props are pulled in from BVPopper
    id: makeProp(PROP_TYPE_STRING)
  }; // --- Main component ---
  // @vue/component

  var BVTooltipTemplate = /*#__PURE__*/extend({
    name: NAME_TOOLTIP_TEMPLATE,
    extends: BVPopper,
    mixins: [scopedStyleMixin],
    props: props$F,
    data: function data() {
      // We use data, rather than props to ensure reactivity
      // Parent component will directly set this data
      return {
        title: '',
        content: '',
        variant: null,
        customClass: null,
        interactive: true
      };
    },
    computed: {
      templateType: function templateType() {
        return 'tooltip';
      },
      templateClasses: function templateClasses() {
        var _ref;

        var variant = this.variant,
            attachment = this.attachment,
            templateType = this.templateType;
        return [(_ref = {
          // Disables pointer events to hide the tooltip when the user
          // hovers over its content
          noninteractive: !this.interactive
        }, _defineProperty(_ref, "b-".concat(templateType, "-").concat(variant), variant), _defineProperty(_ref, "bs-".concat(templateType, "-").concat(attachment), attachment), _ref), this.customClass];
      },
      templateAttributes: function templateAttributes() {
        var id = this.id;
        return _objectSpread2$3(_objectSpread2$3({}, this.bvParent.bvParent.$attrs), {}, {
          id: id,
          role: 'tooltip',
          tabindex: '-1'
        }, this.scopedStyleAttrs);
      },
      templateListeners: function templateListeners() {
        var _this = this;

        // Used for hover/focus trigger listeners
        return {
          mouseenter:
          /* istanbul ignore next */
          function mouseenter(event) {
            _this.$emit(EVENT_NAME_MOUSEENTER, event);
          },
          mouseleave:
          /* istanbul ignore next */
          function mouseleave(event) {
            _this.$emit(EVENT_NAME_MOUSELEAVE, event);
          },
          focusin:
          /* istanbul ignore next */
          function focusin(event) {
            _this.$emit(EVENT_NAME_FOCUSIN, event);
          },
          focusout:
          /* istanbul ignore next */
          function focusout(event) {
            _this.$emit(EVENT_NAME_FOCUSOUT, event);
          }
        };
      }
    },
    methods: {
      renderTemplate: function renderTemplate(h) {
        var title = this.title; // Title can be a scoped slot function

        var $title = isFunction$1(title) ? title({}) : title; // Directive versions only

        var domProps = this.html && !isFunction$1(title) ? {
          innerHTML: title
        } : {};
        return h('div', {
          staticClass: 'tooltip b-tooltip',
          class: this.templateClasses,
          attrs: this.templateAttributes,
          on: this.templateListeners
        }, [h('div', {
          staticClass: 'arrow',
          ref: 'arrow'
        }), h('div', {
          staticClass: 'tooltip-inner',
          domProps: domProps
        }, [$title])]);
      }
    }
  });

  // Modal container selector for appending tooltip/popover

  var MODAL_SELECTOR = '.modal-content'; // Modal `$root` hidden event

  var ROOT_EVENT_NAME_MODAL_HIDDEN = getRootEventName(NAME_MODAL, EVENT_NAME_HIDDEN); // Sidebar container selector for appending tooltip/popover

  var SIDEBAR_SELECTOR = '.b-sidebar'; // For finding the container to append to

  var CONTAINER_SELECTOR = [MODAL_SELECTOR, SIDEBAR_SELECTOR].join(', '); // For dropdown sniffing

  var DROPDOWN_CLASS = 'dropdown';
  var DROPDOWN_OPEN_SELECTOR = '.dropdown-menu.show'; // Data attribute to temporary store the `title` attribute's value

  var DATA_TITLE_ATTR = 'data-original-title'; // Data specific to popper and template
  // We don't use props, as we need reactivity (we can't pass reactive props)

  var templateData = {
    // Text string or Scoped slot function
    title: '',
    // Text string or Scoped slot function
    content: '',
    // String
    variant: null,
    // String, Array, Object
    customClass: null,
    // String or array of Strings (overwritten by BVPopper)
    triggers: '',
    // String (overwritten by BVPopper)
    placement: 'auto',
    // String or array of strings
    fallbackPlacement: 'flip',
    // Element or Component reference (or function that returns element) of
    // the element that will have the trigger events bound, and is also
    // default element for positioning
    target: null,
    // HTML ID, Element or Component reference
    container: null,
    // 'body'
    // Boolean
    noFade: false,
    // 'scrollParent', 'viewport', 'window', Element, or Component reference
    boundary: 'scrollParent',
    // Tooltip/popover will try and stay away from
    // boundary edge by this many pixels (Number)
    boundaryPadding: 5,
    // Arrow offset (Number)
    offset: 0,
    // Hover/focus delay (Number or Object)
    delay: 0,
    // Arrow of Tooltip/popover will try and stay away from
    // the edge of tooltip/popover edge by this many pixels
    arrowPadding: 6,
    // Interactive state (Boolean)
    interactive: true,
    // Disabled state (Boolean)
    disabled: false,
    // ID to use for tooltip/popover
    id: null,
    // Flag used by directives only, for HTML content
    html: false
  }; // --- Main component ---
  // @vue/component

  var BVTooltip = /*#__PURE__*/extend({
    name: NAME_TOOLTIP_HELPER,
    mixins: [listenOnRootMixin, useParentMixin],
    data: function data() {
      return _objectSpread2$3(_objectSpread2$3({}, templateData), {}, {
        // State management data
        activeTrigger: {
          // manual: false,
          hover: false,
          click: false,
          focus: false
        },
        localShow: false
      });
    },
    computed: {
      templateType: function templateType() {
        // Overwritten by BVPopover
        return 'tooltip';
      },
      computedId: function computedId() {
        return this.id || "__bv_".concat(this.templateType, "_").concat(this[COMPONENT_UID_KEY], "__");
      },
      computedDelay: function computedDelay() {
        // Normalizes delay into object form
        var delay = {
          show: 0,
          hide: 0
        };

        if (isPlainObject(this.delay)) {
          delay.show = mathMax(toInteger(this.delay.show, 0), 0);
          delay.hide = mathMax(toInteger(this.delay.hide, 0), 0);
        } else if (isNumber(this.delay) || isString(this.delay)) {
          delay.show = delay.hide = mathMax(toInteger(this.delay, 0), 0);
        }

        return delay;
      },
      computedTriggers: function computedTriggers() {
        // Returns the triggers in sorted array form
        // TODO: Switch this to object form for easier lookup
        return concat(this.triggers).filter(identity).join(' ').trim().toLowerCase().split(/\s+/).sort();
      },
      isWithActiveTrigger: function isWithActiveTrigger() {
        for (var trigger in this.activeTrigger) {
          if (this.activeTrigger[trigger]) {
            return true;
          }
        }

        return false;
      },
      computedTemplateData: function computedTemplateData() {
        var title = this.title,
            content = this.content,
            variant = this.variant,
            customClass = this.customClass,
            noFade = this.noFade,
            interactive = this.interactive;
        return {
          title: title,
          content: content,
          variant: variant,
          customClass: customClass,
          noFade: noFade,
          interactive: interactive
        };
      }
    },
    watch: {
      computedTriggers: function computedTriggers(newTriggers, oldTriggers) {
        var _this = this;

        // Triggers have changed, so re-register them

        /* istanbul ignore next */
        if (!looseEqual(newTriggers, oldTriggers)) {
          this.$nextTick(function () {
            // Disable trigger listeners
            _this.unListen(); // Clear any active triggers that are no longer in the list of triggers


            oldTriggers.forEach(function (trigger) {
              if (!arrayIncludes(newTriggers, trigger)) {
                if (_this.activeTrigger[trigger]) {
                  _this.activeTrigger[trigger] = false;
                }
              }
            }); // Re-enable the trigger listeners

            _this.listen();
          });
        }
      },
      computedTemplateData: function computedTemplateData() {
        // If any of the while open reactive "props" change,
        // ensure that the template updates accordingly
        this.handleTemplateUpdate();
      },
      title: function title(newValue, oldValue) {
        // Make sure to hide the tooltip when the title is set empty
        if (newValue !== oldValue && !newValue) {
          this.hide();
        }
      },
      disabled: function disabled(newValue) {
        if (newValue) {
          this.disable();
        } else {
          this.enable();
        }
      }
    },
    created: function created() {
      var _this2 = this;

      // Create non-reactive properties
      this.$_tip = null;
      this.$_hoverTimeout = null;
      this.$_hoverState = '';
      this.$_visibleInterval = null;
      this.$_enabled = !this.disabled;
      this.$_noop = noop.bind(this); // Destroy ourselves when the parent is destroyed

      if (this.bvParent) {
        this.bvParent.$once(HOOK_EVENT_NAME_BEFORE_DESTROY, function () {
          _this2.$nextTick(function () {
            // In a `requestAF()` to release control back to application
            requestAF(function () {
              _this2.$destroy();
            });
          });
        });
      }

      this.$nextTick(function () {
        var target = _this2.getTarget();

        if (target && contains(document.body, target)) {
          // Copy the parent's scoped style attribute
          _this2.scopeId = getScopeId(_this2.bvParent); // Set up all trigger handlers and listeners

          _this2.listen();
        } else {
          /* istanbul ignore next */
          warn(isString(_this2.target) ? "Unable to find target element by ID \"#".concat(_this2.target, "\" in document.") : 'The provided target is no valid HTML element.', _this2.templateType);
        }
      });
    },

    /* istanbul ignore next */
    updated: function updated() {
      // Usually called when the slots/data changes
      this.$nextTick(this.handleTemplateUpdate);
    },

    /* istanbul ignore next */
    deactivated: function deactivated() {
      // In a keepalive that has been deactivated, so hide
      // the tooltip/popover if it is showing
      this.forceHide();
    },
    beforeDestroy: function beforeDestroy() {
      // Remove all handler/listeners
      this.unListen();
      this.setWhileOpenListeners(false); // Clear any timeouts/intervals

      this.clearHoverTimeout();
      this.clearVisibilityInterval(); // Destroy the template

      this.destroyTemplate(); // Remove any other private properties created during create

      this.$_noop = null;
    },
    methods: {
      // --- Methods for creating and destroying the template ---
      getTemplate: function getTemplate() {
        // Overridden by BVPopover
        return BVTooltipTemplate;
      },
      updateData: function updateData() {
        var _this3 = this;

        var data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
        // Method for updating popper/template data
        // We only update data if it exists, and has not changed
        var titleUpdated = false;
        keys(templateData).forEach(function (prop) {
          if (!isUndefined(data[prop]) && _this3[prop] !== data[prop]) {
            _this3[prop] = data[prop];

            if (prop === 'title') {
              titleUpdated = true;
            }
          }
        }); // If the title has updated, we may need to handle the `title`
        // attribute on the trigger target
        // We only do this while the template is open

        if (titleUpdated && this.localShow) {
          this.fixTitle();
        }
      },
      createTemplateAndShow: function createTemplateAndShow() {
        // Creates the template instance and show it
        var container = this.getContainer();
        var Template = this.getTemplate();
        var $tip = this.$_tip = createNewChildComponent(this, Template, {
          // The following is not reactive to changes in the props data
          propsData: {
            // These values cannot be changed while template is showing
            id: this.computedId,
            html: this.html,
            placement: this.placement,
            fallbackPlacement: this.fallbackPlacement,
            target: this.getPlacementTarget(),
            boundary: this.getBoundary(),
            // Ensure the following are integers
            offset: toInteger(this.offset, 0),
            arrowPadding: toInteger(this.arrowPadding, 0),
            boundaryPadding: toInteger(this.boundaryPadding, 0)
          }
        }); // We set the initial reactive data (values that can be changed while open)

        this.handleTemplateUpdate(); // Template transition phase events (handled once only)
        // When the template has mounted, but not visibly shown yet

        $tip.$once(EVENT_NAME_SHOW, this.onTemplateShow); // When the template has completed showing

        $tip.$once(EVENT_NAME_SHOWN, this.onTemplateShown); // When the template has started to hide

        $tip.$once(EVENT_NAME_HIDE, this.onTemplateHide); // When the template has completed hiding

        $tip.$once(EVENT_NAME_HIDDEN, this.onTemplateHidden); // When the template gets destroyed for any reason

        $tip.$once(HOOK_EVENT_NAME_DESTROYED, this.destroyTemplate); // Convenience events from template
        // To save us from manually adding/removing DOM
        // listeners to tip element when it is open

        $tip.$on(EVENT_NAME_FOCUSIN, this.handleEvent);
        $tip.$on(EVENT_NAME_FOCUSOUT, this.handleEvent);
        $tip.$on(EVENT_NAME_MOUSEENTER, this.handleEvent);
        $tip.$on(EVENT_NAME_MOUSELEAVE, this.handleEvent); // Mount (which triggers the `show`)

        $tip.$mount(container.appendChild(document.createElement('div'))); // Template will automatically remove its markup from DOM when hidden
      },
      hideTemplate: function hideTemplate() {
        // Trigger the template to start hiding
        // The template will emit the `hide` event after this and
        // then emit the `hidden` event once it is fully hidden
        // The `hook:destroyed` will also be called (safety measure)
        this.$_tip && this.$_tip.hide(); // Clear out any stragging active triggers

        this.clearActiveTriggers(); // Reset the hover state

        this.$_hoverState = '';
      },
      // Destroy the template instance and reset state
      destroyTemplate: function destroyTemplate() {
        this.setWhileOpenListeners(false);
        this.clearHoverTimeout();
        this.$_hoverState = '';
        this.clearActiveTriggers();
        this.localPlacementTarget = null;

        try {
          this.$_tip.$destroy();
        } catch (_unused) {}

        this.$_tip = null;
        this.removeAriaDescribedby();
        this.restoreTitle();
        this.localShow = false;
      },
      getTemplateElement: function getTemplateElement() {
        return this.$_tip ? this.$_tip.$el : null;
      },
      handleTemplateUpdate: function handleTemplateUpdate() {
        var _this4 = this;

        // Update our template title/content "props"
        // So that the template updates accordingly
        var $tip = this.$_tip;

        if ($tip) {
          var props = ['title', 'content', 'variant', 'customClass', 'noFade', 'interactive']; // Only update the values if they have changed

          props.forEach(function (prop) {
            if ($tip[prop] !== _this4[prop]) {
              $tip[prop] = _this4[prop];
            }
          });
        }
      },
      // --- Show/Hide handlers ---
      // Show the tooltip
      show: function show() {
        var target = this.getTarget();

        if (!target || !contains(document.body, target) || !isVisible(target) || this.dropdownOpen() || (isUndefinedOrNull(this.title) || this.title === '') && (isUndefinedOrNull(this.content) || this.content === '')) {
          // If trigger element isn't in the DOM or is not visible, or
          // is on an open dropdown toggle, or has no content, then
          // we exit without showing
          return;
        } // If tip already exists, exit early


        if (this.$_tip || this.localShow) {
          /* istanbul ignore next */
          return;
        } // In the process of showing


        this.localShow = true; // Create a cancelable BvEvent

        var showEvent = this.buildEvent(EVENT_NAME_SHOW, {
          cancelable: true
        });
        this.emitEvent(showEvent); // Don't show if event cancelled

        /* istanbul ignore if */

        if (showEvent.defaultPrevented) {
          // Destroy the template (if for some reason it was created)
          this.destroyTemplate();
          return;
        } // Fix the title attribute on target


        this.fixTitle(); // Set aria-describedby on target

        this.addAriaDescribedby(); // Create and show the tooltip

        this.createTemplateAndShow();
      },
      hide: function hide() {
        var force = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
        // Hide the tooltip
        var tip = this.getTemplateElement();
        /* istanbul ignore if */

        if (!tip || !this.localShow) {
          this.restoreTitle();
          return;
        } // Emit cancelable BvEvent 'hide'
        // We disable cancelling if `force` is true


        var hideEvent = this.buildEvent(EVENT_NAME_HIDE, {
          cancelable: !force
        });
        this.emitEvent(hideEvent);
        /* istanbul ignore if: ignore for now */

        if (hideEvent.defaultPrevented) {
          // Don't hide if event cancelled
          return;
        } // Tell the template to hide


        this.hideTemplate();
      },
      forceHide: function forceHide() {
        // Forcefully hides/destroys the template, regardless of any active triggers
        var tip = this.getTemplateElement();

        if (!tip || !this.localShow) {
          /* istanbul ignore next */
          return;
        } // Disable while open listeners/watchers
        // This is also done in the template `hide` event handler


        this.setWhileOpenListeners(false); // Clear any hover enter/leave event

        this.clearHoverTimeout();
        this.$_hoverState = '';
        this.clearActiveTriggers(); // Disable the fade animation on the template

        if (this.$_tip) {
          this.$_tip.noFade = true;
        } // Hide the tip (with force = true)


        this.hide(true);
      },
      enable: function enable() {
        this.$_enabled = true; // Create a non-cancelable BvEvent

        this.emitEvent(this.buildEvent(EVENT_NAME_ENABLED));
      },
      disable: function disable() {
        this.$_enabled = false; // Create a non-cancelable BvEvent

        this.emitEvent(this.buildEvent(EVENT_NAME_DISABLED));
      },
      // --- Handlers for template events ---
      // When template is inserted into DOM, but not yet shown
      onTemplateShow: function onTemplateShow() {
        // Enable while open listeners/watchers
        this.setWhileOpenListeners(true);
      },
      // When template show transition completes
      onTemplateShown: function onTemplateShown() {
        var prevHoverState = this.$_hoverState;
        this.$_hoverState = '';
        /* istanbul ignore next: occasional Node 10 coverage error */

        if (prevHoverState === 'out') {
          this.leave(null);
        } // Emit a non-cancelable BvEvent 'shown'


        this.emitEvent(this.buildEvent(EVENT_NAME_SHOWN));
      },
      // When template is starting to hide
      onTemplateHide: function onTemplateHide() {
        // Disable while open listeners/watchers
        this.setWhileOpenListeners(false);
      },
      // When template has completed closing (just before it self destructs)
      onTemplateHidden: function onTemplateHidden() {
        // Destroy the template
        this.destroyTemplate(); // Emit a non-cancelable BvEvent 'shown'

        this.emitEvent(this.buildEvent(EVENT_NAME_HIDDEN));
      },
      // --- Helper methods ---
      getTarget: function getTarget() {
        var target = this.target;

        if (isString(target)) {
          target = getById(target.replace(/^#/, ''));
        } else if (isFunction$1(target)) {
          target = target();
        } else if (target) {
          target = target.$el || target;
        }

        return isElement(target) ? target : null;
      },
      getPlacementTarget: function getPlacementTarget() {
        // This is the target that the tooltip will be placed on, which may not
        // necessarily be the same element that has the trigger event listeners
        // For now, this is the same as target
        // TODO:
        //   Add in child selector support
        //   Add in visibility checks for this element
        //   Fallback to target if not found
        return this.getTarget();
      },
      getTargetId: function getTargetId() {
        // Returns the ID of the trigger element
        var target = this.getTarget();
        return target && target.id ? target.id : null;
      },
      getContainer: function getContainer() {
        // Handle case where container may be a component ref
        var container = this.container ? this.container.$el || this.container : false;
        var body = document.body;
        var target = this.getTarget(); // If we are in a modal, we append to the modal, If we
        // are in a sidebar, we append to the sidebar, else append
        // to body, unless a container is specified
        // TODO:
        //   Template should periodically check to see if it is in dom
        //   And if not, self destruct (if container got v-if'ed out of DOM)
        //   Or this could possibly be part of the visibility check

        return container === false ? closest(CONTAINER_SELECTOR, target) || body :
        /*istanbul ignore next */
        isString(container) ?
        /*istanbul ignore next */
        getById(container.replace(/^#/, '')) || body :
        /*istanbul ignore next */
        body;
      },
      getBoundary: function getBoundary() {
        return this.boundary ? this.boundary.$el || this.boundary : 'scrollParent';
      },
      isInModal: function isInModal() {
        var target = this.getTarget();
        return target && closest(MODAL_SELECTOR, target);
      },
      isDropdown: function isDropdown() {
        // Returns true if trigger is a dropdown
        var target = this.getTarget();
        return target && hasClass(target, DROPDOWN_CLASS);
      },
      dropdownOpen: function dropdownOpen() {
        // Returns true if trigger is a dropdown and the dropdown menu is open
        var target = this.getTarget();
        return this.isDropdown() && target && select(DROPDOWN_OPEN_SELECTOR, target);
      },
      clearHoverTimeout: function clearHoverTimeout() {
        clearTimeout(this.$_hoverTimeout);
        this.$_hoverTimeout = null;
      },
      clearVisibilityInterval: function clearVisibilityInterval() {
        clearInterval(this.$_visibleInterval);
        this.$_visibleInterval = null;
      },
      clearActiveTriggers: function clearActiveTriggers() {
        for (var trigger in this.activeTrigger) {
          this.activeTrigger[trigger] = false;
        }
      },
      addAriaDescribedby: function addAriaDescribedby() {
        // Add aria-describedby on trigger element, without removing any other IDs
        var target = this.getTarget();
        var desc = getAttr(target, 'aria-describedby') || '';
        desc = desc.split(/\s+/).concat(this.computedId).join(' ').trim(); // Update/add aria-described by

        setAttr(target, 'aria-describedby', desc);
      },
      removeAriaDescribedby: function removeAriaDescribedby() {
        var _this5 = this;

        // Remove aria-describedby on trigger element, without removing any other IDs
        var target = this.getTarget();
        var desc = getAttr(target, 'aria-describedby') || '';
        desc = desc.split(/\s+/).filter(function (d) {
          return d !== _this5.computedId;
        }).join(' ').trim(); // Update or remove aria-describedby

        if (desc) {
          /* istanbul ignore next */
          setAttr(target, 'aria-describedby', desc);
        } else {
          removeAttr(target, 'aria-describedby');
        }
      },
      fixTitle: function fixTitle() {
        // If the target has a `title` attribute,
        // remove it and store it on a data attribute
        var target = this.getTarget();

        if (hasAttr(target, 'title')) {
          // Get `title` attribute value and remove it from target
          var title = getAttr(target, 'title');
          setAttr(target, 'title', ''); // Only set the data attribute when the value is truthy

          if (title) {
            setAttr(target, DATA_TITLE_ATTR, title);
          }
        }
      },
      restoreTitle: function restoreTitle() {
        // If the target had a `title` attribute,
        // restore it and remove the data attribute
        var target = this.getTarget();

        if (hasAttr(target, DATA_TITLE_ATTR)) {
          // Get data attribute value and remove it from target
          var title = getAttr(target, DATA_TITLE_ATTR);
          removeAttr(target, DATA_TITLE_ATTR); // Only restore the `title` attribute when the value is truthy

          if (title) {
            setAttr(target, 'title', title);
          }
        }
      },
      // --- BvEvent helpers ---
      buildEvent: function buildEvent(type) {
        var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
        // Defaults to a non-cancellable event
        return new BvEvent(type, _objectSpread2$3({
          cancelable: false,
          target: this.getTarget(),
          relatedTarget: this.getTemplateElement() || null,
          componentId: this.computedId,
          vueTarget: this
        }, options));
      },
      emitEvent: function emitEvent(bvEvent) {
        var type = bvEvent.type;
        this.emitOnRoot(getRootEventName(this.templateType, type), bvEvent);
        this.$emit(type, bvEvent);
      },
      // --- Event handler setup methods ---
      listen: function listen() {
        var _this6 = this;

        // Enable trigger event handlers
        var el = this.getTarget();

        if (!el) {
          /* istanbul ignore next */
          return;
        } // Listen for global show/hide events


        this.setRootListener(true); // Set up our listeners on the target trigger element

        this.computedTriggers.forEach(function (trigger) {
          if (trigger === 'click') {
            eventOn(el, 'click', _this6.handleEvent, EVENT_OPTIONS_NO_CAPTURE);
          } else if (trigger === 'focus') {
            eventOn(el, 'focusin', _this6.handleEvent, EVENT_OPTIONS_NO_CAPTURE);
            eventOn(el, 'focusout', _this6.handleEvent, EVENT_OPTIONS_NO_CAPTURE);
          } else if (trigger === 'blur') {
            // Used to close $tip when element loses focus

            /* istanbul ignore next */
            eventOn(el, 'focusout', _this6.handleEvent, EVENT_OPTIONS_NO_CAPTURE);
          } else if (trigger === 'hover') {
            eventOn(el, 'mouseenter', _this6.handleEvent, EVENT_OPTIONS_NO_CAPTURE);
            eventOn(el, 'mouseleave', _this6.handleEvent, EVENT_OPTIONS_NO_CAPTURE);
          }
        }, this);
      },

      /* istanbul ignore next */
      unListen: function unListen() {
        var _this7 = this;

        // Remove trigger event handlers
        var events = ['click', 'focusin', 'focusout', 'mouseenter', 'mouseleave'];
        var target = this.getTarget(); // Stop listening for global show/hide/enable/disable events

        this.setRootListener(false); // Clear out any active target listeners

        events.forEach(function (event) {
          target && eventOff(target, event, _this7.handleEvent, EVENT_OPTIONS_NO_CAPTURE);
        }, this);
      },
      setRootListener: function setRootListener(on) {
        // Listen for global `bv::{hide|show}::{tooltip|popover}` hide request event
        var method = on ? 'listenOnRoot' : 'listenOffRoot';
        var type = this.templateType;
        this[method](getRootActionEventName(type, EVENT_NAME_HIDE), this.doHide);
        this[method](getRootActionEventName(type, EVENT_NAME_SHOW), this.doShow);
        this[method](getRootActionEventName(type, EVENT_NAME_DISABLE), this.doDisable);
        this[method](getRootActionEventName(type, EVENT_NAME_ENABLE), this.doEnable);
      },
      setWhileOpenListeners: function setWhileOpenListeners(on) {
        // Events that are only registered when the template is showing
        // Modal close events
        this.setModalListener(on); // Dropdown open events (if we are attached to a dropdown)

        this.setDropdownListener(on); // Periodic $element visibility check
        // For handling when tip target is in <keepalive>, tabs, carousel, etc

        this.visibleCheck(on); // On-touch start listeners

        this.setOnTouchStartListener(on);
      },
      // Handler for periodic visibility check
      visibleCheck: function visibleCheck(on) {
        var _this8 = this;

        this.clearVisibilityInterval();
        var target = this.getTarget();

        if (on) {
          this.$_visibleInterval = setInterval(function () {
            var tip = _this8.getTemplateElement();

            if (tip && _this8.localShow && (!target.parentNode || !isVisible(target))) {
              // Target element is no longer visible or not in DOM, so force-hide the tooltip
              _this8.forceHide();
            }
          }, 100);
        }
      },
      setModalListener: function setModalListener(on) {
        // Handle case where tooltip/target is in a modal
        if (this.isInModal()) {
          // We can listen for modal hidden events on `$root`
          this[on ? 'listenOnRoot' : 'listenOffRoot'](ROOT_EVENT_NAME_MODAL_HIDDEN, this.forceHide);
        }
      },

      /* istanbul ignore next: JSDOM doesn't support `ontouchstart` */
      setOnTouchStartListener: function setOnTouchStartListener(on) {
        var _this9 = this;

        // If this is a touch-enabled device we add extra empty
        // `mouseover` listeners to the body's immediate children
        // Only needed because of broken event delegation on iOS
        // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
        if ('ontouchstart' in document.documentElement) {
          from(document.body.children).forEach(function (el) {
            eventOnOff(on, el, 'mouseover', _this9.$_noop);
          });
        }
      },
      setDropdownListener: function setDropdownListener(on) {
        var target = this.getTarget();

        if (!target || !this.bvEventRoot || !this.isDropdown) {
          return;
        } // We can listen for dropdown shown events on its instance
        // TODO:
        //   We could grab the ID from the dropdown, and listen for
        //   $root events for that particular dropdown id
        //   Dropdown shown and hidden events will need to emit
        //   Note: Dropdown auto-ID happens in a `$nextTick()` after mount
        //         So the ID lookup would need to be done in a `$nextTick()`


        var instance = getInstanceFromElement(target);

        if (instance) {
          instance[on ? '$on' : '$off'](EVENT_NAME_SHOWN, this.forceHide);
        }
      },
      // --- Event handlers ---
      handleEvent: function handleEvent(event) {
        // General trigger event handler
        // target is the trigger element
        var target = this.getTarget();

        if (!target || isDisabled(target) || !this.$_enabled || this.dropdownOpen()) {
          // If disabled or not enabled, or if a dropdown that is open, don't do anything
          // If tip is shown before element gets disabled, then tip will not
          // close until no longer disabled or forcefully closed
          return;
        }

        var type = event.type;
        var triggers = this.computedTriggers;

        if (type === 'click' && arrayIncludes(triggers, 'click')) {
          this.click(event);
        } else if (type === 'mouseenter' && arrayIncludes(triggers, 'hover')) {
          // `mouseenter` is a non-bubbling event
          this.enter(event);
        } else if (type === 'focusin' && arrayIncludes(triggers, 'focus')) {
          // `focusin` is a bubbling event
          // `event` includes `relatedTarget` (element losing focus)
          this.enter(event);
        } else if (type === 'focusout' && (arrayIncludes(triggers, 'focus') || arrayIncludes(triggers, 'blur')) || type === 'mouseleave' && arrayIncludes(triggers, 'hover')) {
          // `focusout` is a bubbling event
          // `mouseleave` is a non-bubbling event
          // `tip` is the template (will be null if not open)
          var tip = this.getTemplateElement(); // `eventTarget` is the element which is losing focus/hover and

          var eventTarget = event.target; // `relatedTarget` is the element gaining focus/hover

          var relatedTarget = event.relatedTarget;
          /* istanbul ignore next */

          if ( // From tip to target
          tip && contains(tip, eventTarget) && contains(target, relatedTarget) || // From target to tip
          tip && contains(target, eventTarget) && contains(tip, relatedTarget) || // Within tip
          tip && contains(tip, eventTarget) && contains(tip, relatedTarget) || // Within target
          contains(target, eventTarget) && contains(target, relatedTarget)) {
            // If focus/hover moves within `tip` and `target`, don't trigger a leave
            return;
          } // Otherwise trigger a leave


          this.leave(event);
        }
      },
      doHide: function doHide(id) {
        // Programmatically hide tooltip or popover
        if (!id || this.getTargetId() === id || this.computedId === id) {
          // Close all tooltips or popovers, or this specific tip (with ID)
          this.forceHide();
        }
      },
      doShow: function doShow(id) {
        // Programmatically show tooltip or popover
        if (!id || this.getTargetId() === id || this.computedId === id) {
          // Open all tooltips or popovers, or this specific tip (with ID)
          this.show();
        }
      },

      /*istanbul ignore next: ignore for now */
      doDisable: function doDisable(id)
      /*istanbul ignore next: ignore for now */
      {
        // Programmatically disable tooltip or popover
        if (!id || this.getTargetId() === id || this.computedId === id) {
          // Disable all tooltips or popovers (no ID), or this specific tip (with ID)
          this.disable();
        }
      },

      /*istanbul ignore next: ignore for now */
      doEnable: function doEnable(id)
      /*istanbul ignore next: ignore for now */
      {
        // Programmatically enable tooltip or popover
        if (!id || this.getTargetId() === id || this.computedId === id) {
          // Enable all tooltips or popovers (no ID), or this specific tip (with ID)
          this.enable();
        }
      },
      click: function click(event) {
        if (!this.$_enabled || this.dropdownOpen()) {
          /* istanbul ignore next */
          return;
        } // Get around a WebKit bug where `click` does not trigger focus events
        // On most browsers, `click` triggers a `focusin`/`focus` event first
        // Needed so that trigger 'click blur' works on iOS
        // https://github.com/bootstrap-vue/bootstrap-vue/issues/5099
        // We use `currentTarget` rather than `target` to trigger on the
        // element, not the inner content


        attemptFocus(event.currentTarget);
        this.activeTrigger.click = !this.activeTrigger.click;

        if (this.isWithActiveTrigger) {
          this.enter(null);
        } else {
          /* istanbul ignore next */
          this.leave(null);
        }
      },

      /* istanbul ignore next */
      toggle: function toggle() {
        // Manual toggle handler
        if (!this.$_enabled || this.dropdownOpen()) {
          /* istanbul ignore next */
          return;
        } // Should we register as an active trigger?
        // this.activeTrigger.manual = !this.activeTrigger.manual


        if (this.localShow) {
          this.leave(null);
        } else {
          this.enter(null);
        }
      },
      enter: function enter() {
        var _this10 = this;

        var event = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;

        // Opening trigger handler
        // Note: Click events are sent with event === null
        if (event) {
          this.activeTrigger[event.type === 'focusin' ? 'focus' : 'hover'] = true;
        }
        /* istanbul ignore next */


        if (this.localShow || this.$_hoverState === 'in') {
          this.$_hoverState = 'in';
          return;
        }

        this.clearHoverTimeout();
        this.$_hoverState = 'in';

        if (!this.computedDelay.show) {
          this.show();
        } else {
          // Hide any title attribute while enter delay is active
          this.fixTitle();
          this.$_hoverTimeout = setTimeout(function () {
            /* istanbul ignore else */
            if (_this10.$_hoverState === 'in') {
              _this10.show();
            } else if (!_this10.localShow) {
              _this10.restoreTitle();
            }
          }, this.computedDelay.show);
        }
      },
      leave: function leave() {
        var _this11 = this;

        var event = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;

        // Closing trigger handler
        // Note: Click events are sent with event === null
        if (event) {
          this.activeTrigger[event.type === 'focusout' ? 'focus' : 'hover'] = false;
          /* istanbul ignore next */

          if (event.type === 'focusout' && arrayIncludes(this.computedTriggers, 'blur')) {
            // Special case for `blur`: we clear out the other triggers
            this.activeTrigger.click = false;
            this.activeTrigger.hover = false;
          }
        }
        /* istanbul ignore next: ignore for now */


        if (this.isWithActiveTrigger) {
          return;
        }

        this.clearHoverTimeout();
        this.$_hoverState = 'out';

        if (!this.computedDelay.hide) {
          this.hide();
        } else {
          this.$_hoverTimeout = setTimeout(function () {
            if (_this11.$_hoverState === 'out') {
              _this11.hide();
            }
          }, this.computedDelay.hide);
        }
      }
    }
  });

  var _makePropsConfigurabl, _watch$5;

  var MODEL_PROP_NAME_ENABLED = 'disabled';
  var MODEL_EVENT_NAME_ENABLED = MODEL_EVENT_NAME_PREFIX + MODEL_PROP_NAME_ENABLED;
  var MODEL_PROP_NAME_SHOW = 'show';
  var MODEL_EVENT_NAME_SHOW = MODEL_EVENT_NAME_PREFIX + MODEL_PROP_NAME_SHOW; // --- Props ---

  var props$E = makePropsConfigurable((_makePropsConfigurabl = {
    // String: scrollParent, window, or viewport
    // Element: element reference
    // Object: Vue component
    boundary: makeProp([HTMLElement, PROP_TYPE_OBJECT, PROP_TYPE_STRING], 'scrollParent'),
    boundaryPadding: makeProp(PROP_TYPE_NUMBER_STRING, 50),
    // String: HTML ID of container, if null body is used (default)
    // HTMLElement: element reference reference
    // Object: Vue Component
    container: makeProp([HTMLElement, PROP_TYPE_OBJECT, PROP_TYPE_STRING]),
    customClass: makeProp(PROP_TYPE_STRING),
    delay: makeProp(PROP_TYPE_NUMBER_OBJECT_STRING, 50)
  }, _defineProperty(_makePropsConfigurabl, MODEL_PROP_NAME_ENABLED, makeProp(PROP_TYPE_BOOLEAN, false)), _defineProperty(_makePropsConfigurabl, "fallbackPlacement", makeProp(PROP_TYPE_ARRAY_STRING, 'flip')), _defineProperty(_makePropsConfigurabl, "id", makeProp(PROP_TYPE_STRING)), _defineProperty(_makePropsConfigurabl, "noFade", makeProp(PROP_TYPE_BOOLEAN, false)), _defineProperty(_makePropsConfigurabl, "noninteractive", makeProp(PROP_TYPE_BOOLEAN, false)), _defineProperty(_makePropsConfigurabl, "offset", makeProp(PROP_TYPE_NUMBER_STRING, 0)), _defineProperty(_makePropsConfigurabl, "placement", makeProp(PROP_TYPE_STRING, 'top')), _defineProperty(_makePropsConfigurabl, MODEL_PROP_NAME_SHOW, makeProp(PROP_TYPE_BOOLEAN, false)), _defineProperty(_makePropsConfigurabl, "target", makeProp([HTMLElement, SVGElement, PROP_TYPE_FUNCTION, PROP_TYPE_OBJECT, PROP_TYPE_STRING], undefined, true)), _defineProperty(_makePropsConfigurabl, "title", makeProp(PROP_TYPE_STRING)), _defineProperty(_makePropsConfigurabl, "triggers", makeProp(PROP_TYPE_ARRAY_STRING, 'hover focus')), _defineProperty(_makePropsConfigurabl, "variant", makeProp(PROP_TYPE_STRING)), _makePropsConfigurabl), NAME_TOOLTIP); // --- Main component ---
  // @vue/component

  var BTooltip = /*#__PURE__*/extend({
    name: NAME_TOOLTIP,
    mixins: [normalizeSlotMixin, useParentMixin],
    inheritAttrs: false,
    props: props$E,
    data: function data() {
      return {
        localShow: this[MODEL_PROP_NAME_SHOW],
        localTitle: '',
        localContent: ''
      };
    },
    computed: {
      // Data that will be passed to the template and popper
      templateData: function templateData() {
        return _objectSpread2$3({
          title: this.localTitle,
          content: this.localContent,
          interactive: !this.noninteractive
        }, pick$1(this.$props, ['boundary', 'boundaryPadding', 'container', 'customClass', 'delay', 'fallbackPlacement', 'id', 'noFade', 'offset', 'placement', 'target', 'target', 'triggers', 'variant', MODEL_PROP_NAME_ENABLED]));
      },
      // Used to watch for changes to the title and content props
      templateTitleContent: function templateTitleContent() {
        var title = this.title,
            content = this.content;
        return {
          title: title,
          content: content
        };
      }
    },
    watch: (_watch$5 = {}, _defineProperty(_watch$5, MODEL_PROP_NAME_SHOW, function (newValue, oldValue) {
      if (newValue !== oldValue && newValue !== this.localShow && this.$_toolpop) {
        if (newValue) {
          this.$_toolpop.show();
        } else {
          // We use `forceHide()` to override any active triggers
          this.$_toolpop.forceHide();
        }
      }
    }), _defineProperty(_watch$5, MODEL_PROP_NAME_ENABLED, function (newValue) {
      if (newValue) {
        this.doDisable();
      } else {
        this.doEnable();
      }
    }), _defineProperty(_watch$5, "localShow", function localShow(newValue) {
      // TODO: May need to be done in a `$nextTick()`
      this.$emit(MODEL_EVENT_NAME_SHOW, newValue);
    }), _defineProperty(_watch$5, "templateData", function templateData() {
      var _this = this;

      this.$nextTick(function () {
        if (_this.$_toolpop) {
          _this.$_toolpop.updateData(_this.templateData);
        }
      });
    }), _defineProperty(_watch$5, "templateTitleContent", function templateTitleContent() {
      this.$nextTick(this.updateContent);
    }), _watch$5),
    created: function created() {
      // Create private non-reactive props
      this.$_toolpop = null;
    },
    updated: function updated() {
      // Update the `propData` object
      // Done in a `$nextTick()` to ensure slot(s) have updated
      this.$nextTick(this.updateContent);
    },
    beforeDestroy: function beforeDestroy() {
      // Shutdown our local event listeners
      this.$off(EVENT_NAME_OPEN, this.doOpen);
      this.$off(EVENT_NAME_CLOSE, this.doClose);
      this.$off(EVENT_NAME_DISABLE, this.doDisable);
      this.$off(EVENT_NAME_ENABLE, this.doEnable); // Destroy the tip instance

      if (this.$_toolpop) {
        this.$_toolpop.$destroy();
        this.$_toolpop = null;
      }
    },
    mounted: function mounted() {
      var _this2 = this;

      // Instantiate a new BVTooltip instance
      // Done in a `$nextTick()` to ensure DOM has completed rendering
      // so that target can be found
      this.$nextTick(function () {
        // Load the on demand child instance
        var Component = _this2.getComponent(); // Ensure we have initial content


        _this2.updateContent(); // Pass down the scoped style attribute if available


        var scopeId = getScopeId(_this2) || getScopeId(_this2.bvParent); // Create the instance

        var $toolpop = _this2.$_toolpop = createNewChildComponent(_this2, Component, {
          // Pass down the scoped style ID
          _scopeId: scopeId || undefined
        }); // Set the initial data

        $toolpop.updateData(_this2.templateData); // Set listeners

        $toolpop.$on(EVENT_NAME_SHOW, _this2.onShow);
        $toolpop.$on(EVENT_NAME_SHOWN, _this2.onShown);
        $toolpop.$on(EVENT_NAME_HIDE, _this2.onHide);
        $toolpop.$on(EVENT_NAME_HIDDEN, _this2.onHidden);
        $toolpop.$on(EVENT_NAME_DISABLED, _this2.onDisabled);
        $toolpop.$on(EVENT_NAME_ENABLED, _this2.onEnabled); // Initially disabled?

        if (_this2[MODEL_PROP_NAME_ENABLED]) {
          // Initially disabled
          _this2.doDisable();
        } // Listen to open signals from others


        _this2.$on(EVENT_NAME_OPEN, _this2.doOpen); // Listen to close signals from others


        _this2.$on(EVENT_NAME_CLOSE, _this2.doClose); // Listen to disable signals from others


        _this2.$on(EVENT_NAME_DISABLE, _this2.doDisable); // Listen to enable signals from others


        _this2.$on(EVENT_NAME_ENABLE, _this2.doEnable); // Initially show tooltip?


        if (_this2.localShow) {
          $toolpop.show();
        }
      });
    },
    methods: {
      getComponent: function getComponent() {
        // Overridden by BPopover
        return BVTooltip;
      },
      updateContent: function updateContent() {
        // Overridden by BPopover
        // Tooltip: Default slot is `title`
        // Popover: Default slot is `content`, `title` slot is title
        // We pass a scoped slot function reference by default (Vue v2.6x)
        // And pass the title prop as a fallback
        this.setTitle(this.normalizeSlot() || this.title);
      },
      // Helper methods for `updateContent()`
      setTitle: function setTitle(value) {
        value = isUndefinedOrNull(value) ? '' : value; // We only update the value if it has changed

        if (this.localTitle !== value) {
          this.localTitle = value;
        }
      },
      setContent: function setContent(value) {
        value = isUndefinedOrNull(value) ? '' : value; // We only update the value if it has changed

        if (this.localContent !== value) {
          this.localContent = value;
        }
      },
      // --- Template event handlers ---
      onShow: function onShow(bvEvent) {
        // Placeholder
        this.$emit(EVENT_NAME_SHOW, bvEvent);

        if (bvEvent) {
          this.localShow = !bvEvent.defaultPrevented;
        }
      },
      onShown: function onShown(bvEvent) {
        // Tip is now showing
        this.localShow = true;
        this.$emit(EVENT_NAME_SHOWN, bvEvent);
      },
      onHide: function onHide(bvEvent) {
        this.$emit(EVENT_NAME_HIDE, bvEvent);
      },
      onHidden: function onHidden(bvEvent) {
        // Tip is no longer showing
        this.$emit(EVENT_NAME_HIDDEN, bvEvent);
        this.localShow = false;
      },
      onDisabled: function onDisabled(bvEvent) {
        // Prevent possible endless loop if user mistakenly
        // fires `disabled` instead of `disable`
        if (bvEvent && bvEvent.type === EVENT_NAME_DISABLED) {
          this.$emit(MODEL_EVENT_NAME_ENABLED, true);
          this.$emit(EVENT_NAME_DISABLED, bvEvent);
        }
      },
      onEnabled: function onEnabled(bvEvent) {
        // Prevent possible endless loop if user mistakenly
        // fires `enabled` instead of `enable`
        if (bvEvent && bvEvent.type === EVENT_NAME_ENABLED) {
          this.$emit(MODEL_EVENT_NAME_ENABLED, false);
          this.$emit(EVENT_NAME_ENABLED, bvEvent);
        }
      },
      // --- Local event listeners ---
      doOpen: function doOpen() {
        !this.localShow && this.$_toolpop && this.$_toolpop.show();
      },
      doClose: function doClose() {
        this.localShow && this.$_toolpop && this.$_toolpop.hide();
      },
      doDisable: function doDisable() {
        this.$_toolpop && this.$_toolpop.disable();
      },
      doEnable: function doEnable() {
        this.$_toolpop && this.$_toolpop.enable();
      }
    },
    render: function render(h) {
      // Always renders a comment node
      // TODO:
      //   Future: Possibly render a target slot (single root element)
      //   which we can apply the listeners to (pass `this.$el` to BVTooltip)
      return h();
    }
  });

  var BVPopoverTemplate = /*#__PURE__*/extend({
    name: NAME_POPOVER_TEMPLATE,
    extends: BVTooltipTemplate,
    computed: {
      templateType: function templateType() {
        return 'popover';
      }
    },
    methods: {
      renderTemplate: function renderTemplate(h) {
        var title = this.title,
            content = this.content; // Title and content could be a scoped slot function

        var $title = isFunction$1(title) ? title({}) : title;
        var $content = isFunction$1(content) ? content({}) : content; // Directive usage only

        var titleDomProps = this.html && !isFunction$1(title) ? {
          innerHTML: title
        } : {};
        var contentDomProps = this.html && !isFunction$1(content) ? {
          innerHTML: content
        } : {};
        return h('div', {
          staticClass: 'popover b-popover',
          class: this.templateClasses,
          attrs: this.templateAttributes,
          on: this.templateListeners
        }, [h('div', {
          staticClass: 'arrow',
          ref: 'arrow'
        }), isUndefinedOrNull($title) || $title === '' ?
        /* istanbul ignore next */
        h() : h('h3', {
          staticClass: 'popover-header',
          domProps: titleDomProps
        }, [$title]), isUndefinedOrNull($content) || $content === '' ?
        /* istanbul ignore next */
        h() : h('div', {
          staticClass: 'popover-body',
          domProps: contentDomProps
        }, [$content])]);
      }
    }
  });

  // Popover "Class" (Built as a renderless Vue instance)

  var BVPopover = /*#__PURE__*/extend({
    name: NAME_POPOVER_HELPER,
    extends: BVTooltip,
    computed: {
      // Overwrites BVTooltip
      templateType: function templateType() {
        return 'popover';
      }
    },
    methods: {
      getTemplate: function getTemplate() {
        // Overwrites BVTooltip
        return BVPopoverTemplate;
      }
    }
  });

  var props$D = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, props$E), {}, {
    content: makeProp(PROP_TYPE_STRING),
    placement: makeProp(PROP_TYPE_STRING, 'right'),
    triggers: makeProp(PROP_TYPE_ARRAY_STRING, EVENT_NAME_CLICK)
  })), NAME_POPOVER); // --- Main component ---
  // @vue/component

  var BPopover = /*#__PURE__*/extend({
    name: NAME_POPOVER,
    extends: BTooltip,
    inheritAttrs: false,
    props: props$D,
    methods: {
      getComponent: function getComponent() {
        // Overridden by BPopover
        return BVPopover;
      },
      updateContent: function updateContent() {
        // Tooltip: Default slot is `title`
        // Popover: Default slot is `content`, `title` slot is title
        // We pass a scoped slot function references by default (Vue v2.6x)
        // And pass the title prop as a fallback
        this.setContent(this.normalizeSlot() || this.content);
        this.setTitle(this.normalizeSlot(SLOT_NAME_TITLE) || this.title);
      }
    } // Render function provided by BTooltip

  });

  var BV_POPOVER = '__BV_Popover__'; // Default trigger

  var DefaultTrigger$1 = 'click'; // Valid event triggers

  var validTriggers$1 = {
    focus: true,
    hover: true,
    click: true,
    blur: true,
    manual: true
  }; // Directive modifier test regular expressions. Pre-compile for performance

  var htmlRE$1 = /^html$/i;
  var noFadeRE$1 = /^nofade$/i;
  var placementRE$1 = /^(auto|top(left|right)?|bottom(left|right)?|left(top|bottom)?|right(top|bottom)?)$/i;
  var boundaryRE$1 = /^(window|viewport|scrollParent)$/i;
  var delayRE$1 = /^d\d+$/i;
  var delayShowRE$1 = /^ds\d+$/i;
  var delayHideRE$1 = /^dh\d+$/i;
  var offsetRE$2 = /^o-?\d+$/i;
  var variantRE$1 = /^v-.+$/i;
  var spacesRE$1 = /\s+/; // Build a Popover config based on bindings (if any)
  // Arguments and modifiers take precedence over passed value config object

  var parseBindings$2 = function parseBindings(bindings, vnode)
  /* istanbul ignore next: not easy to test */
  {
    // We start out with a basic config
    var config = {
      title: undefined,
      content: undefined,
      trigger: '',
      // Default set below if needed
      placement: 'right',
      fallbackPlacement: 'flip',
      container: false,
      // Default of body
      animation: true,
      offset: 0,
      disabled: false,
      id: null,
      html: false,
      delay: getComponentConfig(NAME_POPOVER, 'delay', 50),
      boundary: String(getComponentConfig(NAME_POPOVER, 'boundary', 'scrollParent')),
      boundaryPadding: toInteger(getComponentConfig(NAME_POPOVER, 'boundaryPadding', 5), 0),
      variant: getComponentConfig(NAME_POPOVER, 'variant'),
      customClass: getComponentConfig(NAME_POPOVER, 'customClass')
    }; // Process `bindings.value`

    if (isString(bindings.value) || isNumber(bindings.value)) {
      // Value is popover content (html optionally supported)
      config.content = bindings.value;
    } else if (isFunction$1(bindings.value)) {
      // Content generator function
      config.content = bindings.value;
    } else if (isPlainObject(bindings.value)) {
      // Value is config object, so merge
      config = _objectSpread2$3(_objectSpread2$3({}, config), bindings.value);
    } // If argument, assume element ID of container element


    if (bindings.arg) {
      // Element ID specified as arg
      // We must prepend '#' to become a CSS selector
      config.container = "#".concat(bindings.arg);
    } // If title is not provided, try title attribute


    if (isUndefined(config.title)) {
      // Try attribute
      var data = vnode.data || {};
      config.title = data.attrs && !isUndefinedOrNull(data.attrs.title) ? data.attrs.title : undefined;
    } // Normalize delay


    if (!isPlainObject(config.delay)) {
      config.delay = {
        show: toInteger(config.delay, 0),
        hide: toInteger(config.delay, 0)
      };
    } // Process modifiers


    keys(bindings.modifiers).forEach(function (mod) {
      if (htmlRE$1.test(mod)) {
        // Title/content allows HTML
        config.html = true;
      } else if (noFadeRE$1.test(mod)) {
        // No animation
        config.animation = false;
      } else if (placementRE$1.test(mod)) {
        // Placement of popover
        config.placement = mod;
      } else if (boundaryRE$1.test(mod)) {
        // Boundary of popover
        mod = mod === 'scrollparent' ? 'scrollParent' : mod;
        config.boundary = mod;
      } else if (delayRE$1.test(mod)) {
        // Delay value
        var delay = toInteger(mod.slice(1), 0);
        config.delay.show = delay;
        config.delay.hide = delay;
      } else if (delayShowRE$1.test(mod)) {
        // Delay show value
        config.delay.show = toInteger(mod.slice(2), 0);
      } else if (delayHideRE$1.test(mod)) {
        // Delay hide value
        config.delay.hide = toInteger(mod.slice(2), 0);
      } else if (offsetRE$2.test(mod)) {
        // Offset value, negative allowed
        config.offset = toInteger(mod.slice(1), 0);
      } else if (variantRE$1.test(mod)) {
        // Variant
        config.variant = mod.slice(2) || null;
      }
    }); // Special handling of event trigger modifiers trigger is
    // a space separated list

    var selectedTriggers = {}; // Parse current config object trigger

    concat(config.trigger || '').filter(identity).join(' ').trim().toLowerCase().split(spacesRE$1).forEach(function (trigger) {
      if (validTriggers$1[trigger]) {
        selectedTriggers[trigger] = true;
      }
    }); // Parse modifiers for triggers

    keys(bindings.modifiers).forEach(function (mod) {
      mod = mod.toLowerCase();

      if (validTriggers$1[mod]) {
        // If modifier is a valid trigger
        selectedTriggers[mod] = true;
      }
    }); // Sanitize triggers

    config.trigger = keys(selectedTriggers).join(' ');

    if (config.trigger === 'blur') {
      // Blur by itself is useless, so convert it to 'focus'
      config.trigger = 'focus';
    }

    if (!config.trigger) {
      // Use default trigger
      config.trigger = DefaultTrigger$1;
    }

    return config;
  }; // Add or update Popover on our element


  var applyPopover = function applyPopover(el, bindings, vnode) {
    if (!IS_BROWSER) {
      /* istanbul ignore next */
      return;
    }

    var config = parseBindings$2(bindings, vnode);

    if (!el[BV_POPOVER]) {
      var parent = getInstanceFromDirective(vnode, bindings);
      el[BV_POPOVER] = createNewChildComponent(parent, BVPopover, {
        // Add the parent's scoped style attribute data
        _scopeId: getScopeId(parent, undefined)
      });
      el[BV_POPOVER].__bv_prev_data__ = {};
      el[BV_POPOVER].$on(EVENT_NAME_SHOW, function ()
      /* istanbul ignore next: for now */
      {
        // Before showing the popover, we update the title
        // and content if they are functions
        var data = {};

        if (isFunction$1(config.title)) {
          data.title = config.title(el);
        }

        if (isFunction$1(config.content)) {
          data.content = config.content(el);
        }

        if (keys(data).length > 0) {
          el[BV_POPOVER].updateData(data);
        }
      });
    }

    var data = {
      title: config.title,
      content: config.content,
      triggers: config.trigger,
      placement: config.placement,
      fallbackPlacement: config.fallbackPlacement,
      variant: config.variant,
      customClass: config.customClass,
      container: config.container,
      boundary: config.boundary,
      delay: config.delay,
      offset: config.offset,
      noFade: !config.animation,
      id: config.id,
      disabled: config.disabled,
      html: config.html
    };
    var oldData = el[BV_POPOVER].__bv_prev_data__;
    el[BV_POPOVER].__bv_prev_data__ = data;

    if (!looseEqual(data, oldData)) {
      // We only update the instance if data has changed
      var newData = {
        target: el
      };
      keys(data).forEach(function (prop) {
        // We only pass data properties that have changed
        if (data[prop] !== oldData[prop]) {
          // If title/content is a function, we execute it here
          newData[prop] = (prop === 'title' || prop === 'content') && isFunction$1(data[prop]) ?
          /* istanbul ignore next */
          data[prop](el) : data[prop];
        }
      });
      el[BV_POPOVER].updateData(newData);
    }
  }; // Remove Popover from our element


  var removePopover = function removePopover(el) {
    if (el[BV_POPOVER]) {
      el[BV_POPOVER].$destroy();
      el[BV_POPOVER] = null;
    }

    delete el[BV_POPOVER];
  }; // Export our directive


  var VBPopover = {
    bind: function bind(el, bindings, vnode) {
      applyPopover(el, bindings, vnode);
    },
    // We use `componentUpdated` here instead of `update`, as the former
    // waits until the containing component and children have finished updating
    componentUpdated: function componentUpdated(el, bindings, vnode) {
      // Performed in a `$nextTick()` to prevent endless render/update loops
      nextTick(function () {
        applyPopover(el, bindings, vnode);
      });
    },
    unbind: function unbind(el) {
      removePopover(el);
    }
  };

  var VBPopoverPlugin = /*#__PURE__*/pluginFactory({
    directives: {
      VBPopover: VBPopover
    }
  });

  var PopoverPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BPopover: BPopover
    },
    plugins: {
      VBPopoverPlugin: VBPopoverPlugin
    }
  });

  var props$C = makePropsConfigurable({
    animated: makeProp(PROP_TYPE_BOOLEAN, null),
    label: makeProp(PROP_TYPE_STRING),
    labelHtml: makeProp(PROP_TYPE_STRING),
    max: makeProp(PROP_TYPE_NUMBER_STRING, null),
    precision: makeProp(PROP_TYPE_NUMBER_STRING, null),
    showProgress: makeProp(PROP_TYPE_BOOLEAN, null),
    showValue: makeProp(PROP_TYPE_BOOLEAN, null),
    striped: makeProp(PROP_TYPE_BOOLEAN, null),
    value: makeProp(PROP_TYPE_NUMBER_STRING, 0),
    variant: makeProp(PROP_TYPE_STRING)
  }, NAME_PROGRESS_BAR); // --- Main component ---
  // @vue/component

  var BProgressBar = /*#__PURE__*/extend({
    name: NAME_PROGRESS_BAR,
    mixins: [normalizeSlotMixin],
    inject: {
      getBvProgress: {
        default:
        /* istanbul ignore next */
        function _default() {
          return function () {
            return {};
          };
        }
      }
    },
    props: props$C,
    computed: {
      bvProgress: function bvProgress() {
        return this.getBvProgress();
      },
      progressBarClasses: function progressBarClasses() {
        var computedAnimated = this.computedAnimated,
            computedVariant = this.computedVariant;
        return [computedVariant ? "bg-".concat(computedVariant) : '', this.computedStriped || computedAnimated ? 'progress-bar-striped' : '', computedAnimated ? 'progress-bar-animated' : ''];
      },
      progressBarStyles: function progressBarStyles() {
        return {
          width: 100 * (this.computedValue / this.computedMax) + '%'
        };
      },
      computedValue: function computedValue() {
        return toFloat(this.value, 0);
      },
      computedMax: function computedMax() {
        // Prefer our max over parent setting
        // Default to `100` for invalid values (`-x`, `0`, `NaN`)
        var max = toFloat(this.max) || toFloat(this.bvProgress.max, 0);
        return max > 0 ? max : 100;
      },
      computedPrecision: function computedPrecision() {
        // Prefer our precision over parent setting
        // Default to `0` for invalid values (`-x`, `NaN`)
        return mathMax(toInteger(this.precision, toInteger(this.bvProgress.precision, 0)), 0);
      },
      computedProgress: function computedProgress() {
        var precision = this.computedPrecision;
        var p = mathPow(10, precision);
        return toFixed(100 * p * this.computedValue / this.computedMax / p, precision);
      },
      computedVariant: function computedVariant() {
        // Prefer our variant over parent setting
        return this.variant || this.bvProgress.variant;
      },
      computedStriped: function computedStriped() {
        // Prefer our striped over parent setting
        return isBoolean(this.striped) ? this.striped : this.bvProgress.striped || false;
      },
      computedAnimated: function computedAnimated() {
        // Prefer our animated over parent setting
        return isBoolean(this.animated) ? this.animated : this.bvProgress.animated || false;
      },
      computedShowProgress: function computedShowProgress() {
        // Prefer our showProgress over parent setting
        return isBoolean(this.showProgress) ? this.showProgress : this.bvProgress.showProgress || false;
      },
      computedShowValue: function computedShowValue() {
        // Prefer our showValue over parent setting
        return isBoolean(this.showValue) ? this.showValue : this.bvProgress.showValue || false;
      }
    },
    render: function render(h) {
      var label = this.label,
          labelHtml = this.labelHtml,
          computedValue = this.computedValue,
          computedPrecision = this.computedPrecision;
      var $children;
      var domProps = {};

      if (this.hasNormalizedSlot()) {
        $children = this.normalizeSlot();
      } else if (label || labelHtml) {
        domProps = htmlOrText(labelHtml, label);
      } else if (this.computedShowProgress) {
        $children = this.computedProgress;
      } else if (this.computedShowValue) {
        $children = toFixed(computedValue, computedPrecision);
      }

      return h('div', {
        staticClass: 'progress-bar',
        class: this.progressBarClasses,
        style: this.progressBarStyles,
        attrs: {
          role: 'progressbar',
          'aria-valuemin': '0',
          'aria-valuemax': toString(this.computedMax),
          'aria-valuenow': toFixed(computedValue, computedPrecision)
        },
        domProps: domProps
      }, $children);
    }
  });

  var progressBarProps = omit(props$C, ['label', 'labelHtml']);
  var props$B = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, progressBarProps), {}, {
    animated: makeProp(PROP_TYPE_BOOLEAN, false),
    height: makeProp(PROP_TYPE_STRING),
    max: makeProp(PROP_TYPE_NUMBER_STRING, 100),
    precision: makeProp(PROP_TYPE_NUMBER_STRING, 0),
    showProgress: makeProp(PROP_TYPE_BOOLEAN, false),
    showValue: makeProp(PROP_TYPE_BOOLEAN, false),
    striped: makeProp(PROP_TYPE_BOOLEAN, false)
  })), NAME_PROGRESS); // --- Main component ---
  // @vue/component

  var BProgress = /*#__PURE__*/extend({
    name: NAME_PROGRESS,
    mixins: [normalizeSlotMixin],
    provide: function provide() {
      var _this = this;

      return {
        getBvProgress: function getBvProgress() {
          return _this;
        }
      };
    },
    props: props$B,
    computed: {
      progressHeight: function progressHeight() {
        return {
          height: this.height || null
        };
      }
    },
    render: function render(h) {
      var $childNodes = this.normalizeSlot();

      if (!$childNodes) {
        $childNodes = h(BProgressBar, {
          props: pluckProps(progressBarProps, this.$props)
        });
      }

      return h('div', {
        staticClass: 'progress',
        style: this.progressHeight
      }, [$childNodes]);
    }
  });

  var ProgressPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BProgress: BProgress,
      BProgressBar: BProgressBar
    }
  });

  var _watch$4;

  var CLASS_NAME = 'b-sidebar';
  var ROOT_ACTION_EVENT_NAME_REQUEST_STATE = getRootActionEventName(NAME_COLLAPSE, 'request-state');
  var ROOT_ACTION_EVENT_NAME_TOGGLE = getRootActionEventName(NAME_COLLAPSE, 'toggle');
  var ROOT_EVENT_NAME_STATE = getRootEventName(NAME_COLLAPSE, 'state');
  var ROOT_EVENT_NAME_SYNC_STATE = getRootEventName(NAME_COLLAPSE, 'sync-state');

  var _makeModelMixin$3 = makeModelMixin('visible', {
    type: PROP_TYPE_BOOLEAN,
    defaultValue: false,
    event: EVENT_NAME_CHANGE
  }),
      modelMixin$3 = _makeModelMixin$3.mixin,
      modelProps$3 = _makeModelMixin$3.props,
      MODEL_PROP_NAME$3 = _makeModelMixin$3.prop,
      MODEL_EVENT_NAME$3 = _makeModelMixin$3.event; // --- Props ---


  var props$A = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$25), modelProps$3), {}, {
    ariaLabel: makeProp(PROP_TYPE_STRING),
    ariaLabelledby: makeProp(PROP_TYPE_STRING),
    // If `true`, shows a basic backdrop
    backdrop: makeProp(PROP_TYPE_BOOLEAN, false),
    backdropVariant: makeProp(PROP_TYPE_STRING, 'dark'),
    bgVariant: makeProp(PROP_TYPE_STRING, 'light'),
    bodyClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    // `aria-label` for close button
    closeLabel: makeProp(PROP_TYPE_STRING),
    footerClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    footerTag: makeProp(PROP_TYPE_STRING, 'footer'),
    headerClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    headerTag: makeProp(PROP_TYPE_STRING, 'header'),
    lazy: makeProp(PROP_TYPE_BOOLEAN, false),
    noCloseOnBackdrop: makeProp(PROP_TYPE_BOOLEAN, false),
    noCloseOnEsc: makeProp(PROP_TYPE_BOOLEAN, false),
    noCloseOnRouteChange: makeProp(PROP_TYPE_BOOLEAN, false),
    noEnforceFocus: makeProp(PROP_TYPE_BOOLEAN, false),
    noHeader: makeProp(PROP_TYPE_BOOLEAN, false),
    noHeaderClose: makeProp(PROP_TYPE_BOOLEAN, false),
    noSlide: makeProp(PROP_TYPE_BOOLEAN, false),
    right: makeProp(PROP_TYPE_BOOLEAN, false),
    shadow: makeProp(PROP_TYPE_BOOLEAN_STRING, false),
    sidebarClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    tag: makeProp(PROP_TYPE_STRING, 'div'),
    textVariant: makeProp(PROP_TYPE_STRING, 'dark'),
    title: makeProp(PROP_TYPE_STRING),
    width: makeProp(PROP_TYPE_STRING),
    zIndex: makeProp(PROP_TYPE_NUMBER_STRING)
  })), NAME_SIDEBAR); // --- Render methods ---

  var renderHeaderTitle = function renderHeaderTitle(h, ctx) {
    // Render a empty `<span>` when to title was provided
    var title = ctx.normalizeSlot(SLOT_NAME_TITLE, ctx.slotScope) || ctx.title;

    if (!title) {
      return h('span');
    }

    return h('strong', {
      attrs: {
        id: ctx.safeId('__title__')
      }
    }, [title]);
  };

  var renderHeaderClose = function renderHeaderClose(h, ctx) {
    if (ctx.noHeaderClose) {
      return h();
    }

    var closeLabel = ctx.closeLabel,
        textVariant = ctx.textVariant,
        hide = ctx.hide;
    return h(BButtonClose, {
      props: {
        ariaLabel: closeLabel,
        textVariant: textVariant
      },
      on: {
        click: hide
      },
      ref: 'close-button'
    }, [ctx.normalizeSlot(SLOT_NAME_HEADER_CLOSE) || h(BIconX)]);
  };

  var renderHeader = function renderHeader(h, ctx) {
    if (ctx.noHeader) {
      return h();
    }

    var $content = ctx.normalizeSlot(SLOT_NAME_HEADER, ctx.slotScope);

    if (!$content) {
      var $title = renderHeaderTitle(h, ctx);
      var $close = renderHeaderClose(h, ctx);
      $content = ctx.right ? [$close, $title] : [$title, $close];
    }

    return h(ctx.headerTag, {
      staticClass: "".concat(CLASS_NAME, "-header"),
      class: ctx.headerClass,
      key: 'header'
    }, $content);
  };

  var renderBody = function renderBody(h, ctx) {
    return h('div', {
      staticClass: "".concat(CLASS_NAME, "-body"),
      class: ctx.bodyClass,
      key: 'body'
    }, [ctx.normalizeSlot(SLOT_NAME_DEFAULT, ctx.slotScope)]);
  };

  var renderFooter = function renderFooter(h, ctx) {
    var $footer = ctx.normalizeSlot(SLOT_NAME_FOOTER, ctx.slotScope);

    if (!$footer) {
      return h();
    }

    return h(ctx.footerTag, {
      staticClass: "".concat(CLASS_NAME, "-footer"),
      class: ctx.footerClass,
      key: 'footer'
    }, [$footer]);
  };

  var renderContent = function renderContent(h, ctx) {
    // We render the header even if `lazy` is enabled as it
    // acts as the accessible label for the sidebar
    var $header = renderHeader(h, ctx);

    if (ctx.lazy && !ctx.isOpen) {
      return $header;
    }

    return [$header, renderBody(h, ctx), renderFooter(h, ctx)];
  };

  var renderBackdrop = function renderBackdrop(h, ctx) {
    if (!ctx.backdrop) {
      return h();
    }

    var backdropVariant = ctx.backdropVariant;
    return h('div', {
      directives: [{
        name: 'show',
        value: ctx.localShow
      }],
      staticClass: 'b-sidebar-backdrop',
      class: _defineProperty({}, "bg-".concat(backdropVariant), backdropVariant),
      on: {
        click: ctx.onBackdropClick
      }
    });
  }; // --- Main component ---
  // @vue/component


  var BSidebar = /*#__PURE__*/extend({
    name: NAME_SIDEBAR,
    mixins: [attrsMixin, idMixin, modelMixin$3, listenOnRootMixin, normalizeSlotMixin],
    inheritAttrs: false,
    props: props$A,
    data: function data() {
      var visible = !!this[MODEL_PROP_NAME$3];
      return {
        // Internal `v-model` state
        localShow: visible,
        // For lazy render triggering
        isOpen: visible
      };
    },
    computed: {
      transitionProps: function transitionProps() {
        return this.noSlide ?
        /* istanbul ignore next */
        {
          css: true
        } : {
          css: true,
          enterClass: '',
          enterActiveClass: 'slide',
          enterToClass: 'show',
          leaveClass: 'show',
          leaveActiveClass: 'slide',
          leaveToClass: ''
        };
      },
      slotScope: function slotScope() {
        var hide = this.hide,
            right = this.right,
            visible = this.localShow;
        return {
          hide: hide,
          right: right,
          visible: visible
        };
      },
      hasTitle: function hasTitle() {
        var $scopedSlots = this.$scopedSlots,
            $slots = this.$slots;
        return !this.noHeader && !this.hasNormalizedSlot(SLOT_NAME_HEADER) && !!(this.normalizeSlot(SLOT_NAME_TITLE, this.slotScope, $scopedSlots, $slots) || this.title);
      },
      titleId: function titleId() {
        return this.hasTitle ? this.safeId('__title__') : null;
      },
      computedAttrs: function computedAttrs() {
        return _objectSpread2$3(_objectSpread2$3({}, this.bvAttrs), {}, {
          id: this.safeId(),
          tabindex: '-1',
          role: 'dialog',
          'aria-modal': this.backdrop ? 'true' : 'false',
          'aria-hidden': this.localShow ? null : 'true',
          'aria-label': this.ariaLabel || null,
          'aria-labelledby': this.ariaLabelledby || this.titleId || null
        });
      }
    },
    watch: (_watch$4 = {}, _defineProperty(_watch$4, MODEL_PROP_NAME$3, function (newValue, oldValue) {
      if (newValue !== oldValue) {
        this.localShow = newValue;
      }
    }), _defineProperty(_watch$4, "localShow", function localShow(newValue, oldValue) {
      if (newValue !== oldValue) {
        this.emitState(newValue);
        this.$emit(MODEL_EVENT_NAME$3, newValue);
      }
    }), _defineProperty(_watch$4, "$route", function $route() {
      var newValue = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
      var oldValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

      if (!this.noCloseOnRouteChange && newValue.fullPath !== oldValue.fullPath) {
        this.hide();
      }
    }), _watch$4),
    created: function created() {
      // Define non-reactive properties
      this.$_returnFocusEl = null;
    },
    mounted: function mounted() {
      var _this = this;

      // Add `$root` listeners
      this.listenOnRoot(ROOT_ACTION_EVENT_NAME_TOGGLE, this.handleToggle);
      this.listenOnRoot(ROOT_ACTION_EVENT_NAME_REQUEST_STATE, this.handleSync); // Send out a gratuitous state event to ensure toggle button is synced

      this.$nextTick(function () {
        _this.emitState(_this.localShow);
      });
    },

    /* istanbul ignore next */
    activated: function activated() {
      this.emitSync();
    },
    beforeDestroy: function beforeDestroy() {
      this.localShow = false;
      this.$_returnFocusEl = null;
    },
    methods: {
      hide: function hide() {
        this.localShow = false;
      },
      emitState: function emitState() {
        var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.localShow;
        this.emitOnRoot(ROOT_EVENT_NAME_STATE, this.safeId(), state);
      },
      emitSync: function emitSync() {
        var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.localShow;
        this.emitOnRoot(ROOT_EVENT_NAME_SYNC_STATE, this.safeId(), state);
      },
      handleToggle: function handleToggle(id) {
        // Note `safeId()` can be null until after mount
        if (id && id === this.safeId()) {
          this.localShow = !this.localShow;
        }
      },
      handleSync: function handleSync(id) {
        var _this2 = this;

        // Note `safeId()` can be null until after mount
        if (id && id === this.safeId()) {
          this.$nextTick(function () {
            _this2.emitSync(_this2.localShow);
          });
        }
      },
      onKeydown: function onKeydown(event) {
        var keyCode = event.keyCode;

        if (!this.noCloseOnEsc && keyCode === CODE_ESC && this.localShow) {
          this.hide();
        }
      },
      onBackdropClick: function onBackdropClick() {
        if (this.localShow && !this.noCloseOnBackdrop) {
          this.hide();
        }
      },

      /* istanbul ignore next */
      onTopTrapFocus: function onTopTrapFocus() {
        var tabables = getTabables(this.$refs.content);
        this.enforceFocus(tabables.reverse()[0]);
      },

      /* istanbul ignore next */
      onBottomTrapFocus: function onBottomTrapFocus() {
        var tabables = getTabables(this.$refs.content);
        this.enforceFocus(tabables[0]);
      },
      onBeforeEnter: function onBeforeEnter() {
        // Returning focus to `document.body` may cause unwanted scrolls,
        // so we exclude setting focus on body
        this.$_returnFocusEl = getActiveElement(IS_BROWSER ? [document.body] : []); // Trigger lazy render

        this.isOpen = true;
      },
      onAfterEnter: function onAfterEnter(el) {
        if (!contains(el, getActiveElement())) {
          this.enforceFocus(el);
        }

        this.$emit(EVENT_NAME_SHOWN);
      },
      onAfterLeave: function onAfterLeave() {
        this.enforceFocus(this.$_returnFocusEl);
        this.$_returnFocusEl = null; // Trigger lazy render

        this.isOpen = false;
        this.$emit(EVENT_NAME_HIDDEN);
      },
      enforceFocus: function enforceFocus(el) {
        if (!this.noEnforceFocus) {
          attemptFocus(el);
        }
      }
    },
    render: function render(h) {
      var _ref;

      var bgVariant = this.bgVariant,
          width = this.width,
          textVariant = this.textVariant,
          localShow = this.localShow;
      var shadow = this.shadow === '' ? true : this.shadow;
      var $sidebar = h(this.tag, {
        staticClass: CLASS_NAME,
        class: [(_ref = {
          shadow: shadow === true
        }, _defineProperty(_ref, "shadow-".concat(shadow), shadow && shadow !== true), _defineProperty(_ref, "".concat(CLASS_NAME, "-right"), this.right), _defineProperty(_ref, "bg-".concat(bgVariant), bgVariant), _defineProperty(_ref, "text-".concat(textVariant), textVariant), _ref), this.sidebarClass],
        style: {
          width: width
        },
        attrs: this.computedAttrs,
        directives: [{
          name: 'show',
          value: localShow
        }],
        ref: 'content'
      }, [renderContent(h, this)]);
      $sidebar = h('transition', {
        props: this.transitionProps,
        on: {
          beforeEnter: this.onBeforeEnter,
          afterEnter: this.onAfterEnter,
          afterLeave: this.onAfterLeave
        }
      }, [$sidebar]);
      var $backdrop = h(BVTransition, {
        props: {
          noFade: this.noSlide
        }
      }, [renderBackdrop(h, this)]);
      var $tabTrapTop = h();
      var $tabTrapBottom = h();

      if (this.backdrop && localShow) {
        $tabTrapTop = h('div', {
          attrs: {
            tabindex: '0'
          },
          on: {
            focus: this.onTopTrapFocus
          }
        });
        $tabTrapBottom = h('div', {
          attrs: {
            tabindex: '0'
          },
          on: {
            focus: this.onBottomTrapFocus
          }
        });
      }

      return h('div', {
        staticClass: 'b-sidebar-outer',
        style: {
          zIndex: this.zIndex
        },
        attrs: {
          tabindex: '-1'
        },
        on: {
          keydown: this.onKeydown
        }
      }, [$tabTrapTop, $sidebar, $tabTrapBottom, $backdrop]);
    }
  });

  var SidebarPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BSidebar: BSidebar
    },
    plugins: {
      VBTogglePlugin: VBTogglePlugin
    }
  });

  var props$z = makePropsConfigurable({
    animation: makeProp(PROP_TYPE_STRING, 'wave'),
    height: makeProp(PROP_TYPE_STRING),
    size: makeProp(PROP_TYPE_STRING),
    type: makeProp(PROP_TYPE_STRING, 'text'),
    variant: makeProp(PROP_TYPE_STRING),
    width: makeProp(PROP_TYPE_STRING)
  }, NAME_SKELETON); // --- Main component ---
  // @vue/component

  var BSkeleton = /*#__PURE__*/extend({
    name: NAME_SKELETON,
    functional: true,
    props: props$z,
    render: function render(h, _ref) {
      var _class;

      var data = _ref.data,
          props = _ref.props;
      var size = props.size,
          animation = props.animation,
          variant = props.variant;
      return h('div', a(data, {
        staticClass: 'b-skeleton',
        style: {
          width: size || props.width,
          height: size || props.height
        },
        class: (_class = {}, _defineProperty(_class, "b-skeleton-".concat(props.type), true), _defineProperty(_class, "b-skeleton-animate-".concat(animation), animation), _defineProperty(_class, "bg-".concat(variant), variant), _class)
      }));
    }
  });

  makePropsConfigurable(omit(props$2h, ['content', 'stacked']), NAME_ICONSTACK); // --- Main component ---

  var props$y = makePropsConfigurable({
    animation: makeProp(PROP_TYPE_STRING, 'wave'),
    icon: makeProp(PROP_TYPE_STRING),
    iconProps: makeProp(PROP_TYPE_OBJECT, {})
  }, NAME_SKELETON_ICON); // --- Main component ---
  // @vue/component

  var BSkeletonIcon = /*#__PURE__*/extend({
    name: NAME_SKELETON_ICON,
    functional: true,
    props: props$y,
    render: function render(h, _ref) {
      var data = _ref.data,
          props = _ref.props;
      var icon = props.icon,
          animation = props.animation;
      var $icon = h(BIcon, {
        staticClass: 'b-skeleton-icon',
        props: _objectSpread2$3(_objectSpread2$3({}, props.iconProps), {}, {
          icon: icon
        })
      });
      return h('div', a(data, {
        staticClass: 'b-skeleton-icon-wrapper position-relative d-inline-block overflow-hidden',
        class: _defineProperty({}, "b-skeleton-animate-".concat(animation), animation)
      }), [$icon]);
    }
  });

  var props$x = makePropsConfigurable({
    animation: makeProp(PROP_TYPE_STRING),
    aspect: makeProp(PROP_TYPE_STRING, '16:9'),
    cardImg: makeProp(PROP_TYPE_STRING),
    height: makeProp(PROP_TYPE_STRING),
    noAspect: makeProp(PROP_TYPE_BOOLEAN, false),
    variant: makeProp(PROP_TYPE_STRING),
    width: makeProp(PROP_TYPE_STRING)
  }, NAME_SKELETON_IMG); // --- Main component ---
  // @vue/component

  var BSkeletonImg = /*#__PURE__*/extend({
    name: NAME_SKELETON_IMG,
    functional: true,
    props: props$x,
    render: function render(h, _ref) {
      var data = _ref.data,
          props = _ref.props;
      var aspect = props.aspect,
          width = props.width,
          height = props.height,
          animation = props.animation,
          variant = props.variant,
          cardImg = props.cardImg;
      var $img = h(BSkeleton, a(data, {
        props: {
          type: 'img',
          width: width,
          height: height,
          animation: animation,
          variant: variant
        },
        class: _defineProperty({}, "card-img-".concat(cardImg), cardImg)
      }));
      return props.noAspect ? $img : h(BAspect, {
        props: {
          aspect: aspect
        }
      }, [$img]);
    }
  });

  // Mixin to determine if an event listener has been registered

  var hasListenerMixin = extend({
    methods: {
      hasListener: function hasListener(name) {
        if (isVue3) {
          return true;
        } // Only includes listeners registered via `v-on:name`


        var $listeners = this.$listeners || {}; // Includes `v-on:name` and `this.$on('name')` registered listeners
        // Note this property is not part of the public Vue API, but it is
        // the only way to determine if a listener was added via `vm.$on`

        var $events = this._events || {}; // Registered listeners in `this._events` are always an array,
        // but might be zero length

        return !isUndefined($listeners[name]) || isArray($events[name]) && $events[name].length > 0;
      }
    }
  });

  var LIGHT = 'light';
  var DARK = 'dark'; // --- Props ---

  var props$w = makePropsConfigurable({
    variant: makeProp(PROP_TYPE_STRING)
  }, NAME_TR); // --- Main component ---
  // TODO:
  //   In Bootstrap v5, we won't need "sniffing" as table element variants properly inherit
  //   to the child elements, so this can be converted to a functional component
  // @vue/component

  var BTr = /*#__PURE__*/extend({
    name: NAME_TR,
    mixins: [attrsMixin, listenersMixin, normalizeSlotMixin],
    provide: function provide() {
      var _this = this;

      return {
        getBvTableTr: function getBvTableTr() {
          return _this;
        }
      };
    },
    inject: {
      getBvTableRowGroup: {
        default:
        /* istanbul ignore next */
        function _default() {
          return function () {
            return {};
          };
        }
      }
    },
    inheritAttrs: false,
    props: props$w,
    computed: {
      bvTableRowGroup: function bvTableRowGroup() {
        return this.getBvTableRowGroup();
      },
      // Sniffed by `<b-td>` / `<b-th>`
      inTbody: function inTbody() {
        return this.bvTableRowGroup.isTbody;
      },
      // Sniffed by `<b-td>` / `<b-th>`
      inThead: function inThead() {
        return this.bvTableRowGroup.isThead;
      },
      // Sniffed by `<b-td>` / `<b-th>`
      inTfoot: function inTfoot() {
        return this.bvTableRowGroup.isTfoot;
      },
      // Sniffed by `<b-td>` / `<b-th>`
      isDark: function isDark() {
        return this.bvTableRowGroup.isDark;
      },
      // Sniffed by `<b-td>` / `<b-th>`
      isStacked: function isStacked() {
        return this.bvTableRowGroup.isStacked;
      },
      // Sniffed by `<b-td>` / `<b-th>`
      isResponsive: function isResponsive() {
        return this.bvTableRowGroup.isResponsive;
      },
      // Sniffed by `<b-td>` / `<b-th>`
      // Sticky headers are only supported in thead
      isStickyHeader: function isStickyHeader() {
        return this.bvTableRowGroup.isStickyHeader;
      },
      // Sniffed by <b-tr> / `<b-td>` / `<b-th>`
      // Needed to handle header background classes, due to lack of
      // background color inheritance with Bootstrap v4 table CSS
      hasStickyHeader: function hasStickyHeader() {
        return !this.isStacked && this.bvTableRowGroup.hasStickyHeader;
      },
      // Sniffed by `<b-td>` / `<b-th>`
      tableVariant: function tableVariant() {
        return this.bvTableRowGroup.tableVariant;
      },
      // Sniffed by `<b-td>` / `<b-th>`
      headVariant: function headVariant() {
        return this.inThead ? this.bvTableRowGroup.headVariant : null;
      },
      // Sniffed by `<b-td>` / `<b-th>`
      footVariant: function footVariant() {
        return this.inTfoot ? this.bvTableRowGroup.footVariant : null;
      },
      isRowDark: function isRowDark() {
        return this.headVariant === LIGHT || this.footVariant === LIGHT ?
        /* istanbul ignore next */
        false : this.headVariant === DARK || this.footVariant === DARK ?
        /* istanbul ignore next */
        true : this.isDark;
      },
      trClasses: function trClasses() {
        var variant = this.variant;
        return [variant ? "".concat(this.isRowDark ? 'bg' : 'table', "-").concat(variant) : null];
      },
      trAttrs: function trAttrs() {
        return _objectSpread2$3({
          role: 'row'
        }, this.bvAttrs);
      }
    },
    render: function render(h) {
      return h('tr', {
        class: this.trClasses,
        attrs: this.trAttrs,
        // Pass native listeners to child
        on: this.bvListeners
      }, this.normalizeSlot());
    }
  });

  var props$v = {}; // --- Mixin ---
  // @vue/component

  var bottomRowMixin = extend({
    props: props$v,
    methods: {
      renderBottomRow: function renderBottomRow() {
        var fields = this.computedFields,
            stacked = this.stacked,
            tbodyTrClass = this.tbodyTrClass,
            tbodyTrAttr = this.tbodyTrAttr;
        var h = this.$createElement; // Static bottom row slot (hidden in visibly stacked mode as we can't control the data-label)
        // If in *always* stacked mode, we don't bother rendering the row

        if (!this.hasNormalizedSlot(SLOT_NAME_BOTTOM_ROW) || stacked === true || stacked === '') {
          return h();
        }

        return h(BTr, {
          staticClass: 'b-table-bottom-row',
          class: [isFunction$1(tbodyTrClass) ?
          /* istanbul ignore next */
          tbodyTrClass(null, 'row-bottom') : tbodyTrClass],
          attrs: isFunction$1(tbodyTrAttr) ?
          /* istanbul ignore next */
          tbodyTrAttr(null, 'row-bottom') : tbodyTrAttr,
          key: 'b-bottom-row'
        }, this.normalizeSlot(SLOT_NAME_BOTTOM_ROW, {
          columns: fields.length,
          fields: fields
        }));
      }
    }
  });

  // Parse a rowspan or colspan into a digit (or `null` if < `1` )

  var parseSpan = function parseSpan(value) {
    value = toInteger(value, 0);
    return value > 0 ? value : null;
  };
  /* istanbul ignore next */


  var spanValidator = function spanValidator(value) {
    return isUndefinedOrNull(value) || parseSpan(value) > 0;
  }; // --- Props ---


  var props$u = makePropsConfigurable({
    colspan: makeProp(PROP_TYPE_NUMBER_STRING, null, spanValidator),
    rowspan: makeProp(PROP_TYPE_NUMBER_STRING, null, spanValidator),
    stackedHeading: makeProp(PROP_TYPE_STRING),
    stickyColumn: makeProp(PROP_TYPE_BOOLEAN, false),
    variant: makeProp(PROP_TYPE_STRING)
  }, NAME_TABLE_CELL); // --- Main component ---
  // TODO:
  //   In Bootstrap v5, we won't need "sniffing" as table element variants properly inherit
  //   to the child elements, so this can be converted to a functional component
  // @vue/component

  var BTd = /*#__PURE__*/extend({
    name: NAME_TABLE_CELL,
    // Mixin order is important!
    mixins: [attrsMixin, listenersMixin, normalizeSlotMixin],
    inject: {
      getBvTableTr: {
        default:
        /* istanbul ignore next */
        function _default() {
          return function () {
            return {};
          };
        }
      }
    },
    inheritAttrs: false,
    props: props$u,
    computed: {
      bvTableTr: function bvTableTr() {
        return this.getBvTableTr();
      },
      // Overridden by `<b-th>`
      tag: function tag() {
        return 'td';
      },
      inTbody: function inTbody() {
        return this.bvTableTr.inTbody;
      },
      inThead: function inThead() {
        return this.bvTableTr.inThead;
      },
      inTfoot: function inTfoot() {
        return this.bvTableTr.inTfoot;
      },
      isDark: function isDark() {
        return this.bvTableTr.isDark;
      },
      isStacked: function isStacked() {
        return this.bvTableTr.isStacked;
      },
      // We only support stacked-heading in tbody in stacked mode
      isStackedCell: function isStackedCell() {
        return this.inTbody && this.isStacked;
      },
      isResponsive: function isResponsive() {
        return this.bvTableTr.isResponsive;
      },
      // Needed to handle header background classes, due to lack of
      // background color inheritance with Bootstrap v4 table CSS
      // Sticky headers only apply to cells in table `thead`
      isStickyHeader: function isStickyHeader() {
        return this.bvTableTr.isStickyHeader;
      },
      // Needed to handle header background classes, due to lack of
      // background color inheritance with Bootstrap v4 table CSS
      hasStickyHeader: function hasStickyHeader() {
        return this.bvTableTr.hasStickyHeader;
      },
      // Needed to handle background classes, due to lack of
      // background color inheritance with Bootstrap v4 table CSS
      // Sticky column cells are only available in responsive
      // mode (horizontal scrolling) or when sticky header mode
      // Applies to cells in `thead`, `tbody` and `tfoot`
      isStickyColumn: function isStickyColumn() {
        return !this.isStacked && (this.isResponsive || this.hasStickyHeader) && this.stickyColumn;
      },
      rowVariant: function rowVariant() {
        return this.bvTableTr.variant;
      },
      headVariant: function headVariant() {
        return this.bvTableTr.headVariant;
      },
      footVariant: function footVariant() {
        return this.bvTableTr.footVariant;
      },
      tableVariant: function tableVariant() {
        return this.bvTableTr.tableVariant;
      },
      computedColspan: function computedColspan() {
        return parseSpan(this.colspan);
      },
      computedRowspan: function computedRowspan() {
        return parseSpan(this.rowspan);
      },
      // We use computed props here for improved performance by caching
      // the results of the string interpolation
      cellClasses: function cellClasses() {
        var variant = this.variant,
            headVariant = this.headVariant,
            isStickyColumn = this.isStickyColumn;

        if (!variant && this.isStickyHeader && !headVariant || !variant && isStickyColumn && this.inTfoot && !this.footVariant || !variant && isStickyColumn && this.inThead && !headVariant || !variant && isStickyColumn && this.inTbody) {
          // Needed for sticky-header mode as Bootstrap v4 table cells do
          // not inherit parent's `background-color`
          variant = this.rowVariant || this.tableVariant || 'b-table-default';
        }

        return [variant ? "".concat(this.isDark ? 'bg' : 'table', "-").concat(variant) : null, isStickyColumn ? 'b-table-sticky-column' : null];
      },
      cellAttrs: function cellAttrs() {
        var stackedHeading = this.stackedHeading; // We use computed props here for improved performance by caching
        // the results of the object spread (Object.assign)

        var headOrFoot = this.inThead || this.inTfoot; // Make sure col/rowspan's are > 0 or null

        var colspan = this.computedColspan;
        var rowspan = this.computedRowspan; // Default role and scope

        var role = 'cell';
        var scope = null; // Compute role and scope
        // We only add scopes with an explicit span of 1 or greater

        if (headOrFoot) {
          // Header or footer cells
          role = 'columnheader';
          scope = colspan > 0 ? 'colspan' : 'col';
        } else if (isTag(this.tag, 'th')) {
          // th's in tbody
          role = 'rowheader';
          scope = rowspan > 0 ? 'rowgroup' : 'row';
        }

        return _objectSpread2$3(_objectSpread2$3({
          colspan: colspan,
          rowspan: rowspan,
          role: role,
          scope: scope
        }, this.bvAttrs), {}, {
          // Add in the stacked cell label data-attribute if in
          // stacked mode (if a stacked heading label is provided)
          'data-label': this.isStackedCell && !isUndefinedOrNull(stackedHeading) ?
          /* istanbul ignore next */
          toString(stackedHeading) : null
        });
      }
    },
    render: function render(h) {
      var $content = [this.normalizeSlot()];
      return h(this.tag, {
        class: this.cellClasses,
        attrs: this.cellAttrs,
        // Transfer any native listeners
        on: this.bvListeners
      }, [this.isStackedCell ? h('div', [$content]) : $content]);
    }
  });

  var MODEL_PROP_NAME_BUSY = 'busy';
  var MODEL_EVENT_NAME_BUSY = MODEL_EVENT_NAME_PREFIX + MODEL_PROP_NAME_BUSY; // --- Props ---

  var props$t = _defineProperty({}, MODEL_PROP_NAME_BUSY, makeProp(PROP_TYPE_BOOLEAN, false)); // --- Mixin ---
  // @vue/component

  var busyMixin = extend({
    props: props$t,
    data: function data() {
      return {
        localBusy: false
      };
    },
    computed: {
      computedBusy: function computedBusy() {
        return this[MODEL_PROP_NAME_BUSY] || this.localBusy;
      }
    },
    watch: {
      localBusy: function localBusy(newValue, oldValue) {
        if (newValue !== oldValue) {
          this.$emit(MODEL_EVENT_NAME_BUSY, newValue);
        }
      }
    },
    methods: {
      // Event handler helper
      stopIfBusy: function stopIfBusy(event) {
        // If table is busy (via provider) then don't propagate
        if (this.computedBusy) {
          stopEvent(event);
          return true;
        }

        return false;
      },
      // Render the busy indicator or return `null` if not busy
      renderBusy: function renderBusy() {
        var tbodyTrClass = this.tbodyTrClass,
            tbodyTrAttr = this.tbodyTrAttr;
        var h = this.$createElement; // Return a busy indicator row, or `null` if not busy

        if (this.computedBusy && this.hasNormalizedSlot(SLOT_NAME_TABLE_BUSY)) {
          return h(BTr, {
            staticClass: 'b-table-busy-slot',
            class: [isFunction$1(tbodyTrClass) ?
            /* istanbul ignore next */
            tbodyTrClass(null, SLOT_NAME_TABLE_BUSY) : tbodyTrClass],
            attrs: isFunction$1(tbodyTrAttr) ?
            /* istanbul ignore next */
            tbodyTrAttr(null, SLOT_NAME_TABLE_BUSY) : tbodyTrAttr,
            key: 'table-busy-slot'
          }, [h(BTd, {
            props: {
              colspan: this.computedFields.length || null
            }
          }, [this.normalizeSlot(SLOT_NAME_TABLE_BUSY)])]);
        } // We return `null` here so that we can determine if we need to
        // render the table items rows or not


        return null;
      }
    }
  });

  var props$s = {
    caption: makeProp(PROP_TYPE_STRING),
    captionHtml: makeProp(PROP_TYPE_STRING) // `caption-top` is part of table-render mixin (styling)
    // captionTop: makeProp(PROP_TYPE_BOOLEAN, false)

  }; // --- Mixin ---
  // @vue/component

  var captionMixin = extend({
    props: props$s,
    computed: {
      captionId: function captionId() {
        return this.isStacked ? this.safeId('_caption_') : null;
      }
    },
    methods: {
      renderCaption: function renderCaption() {
        var caption = this.caption,
            captionHtml = this.captionHtml;
        var h = this.$createElement;
        var $caption = h();
        var hasCaptionSlot = this.hasNormalizedSlot(SLOT_NAME_TABLE_CAPTION);

        if (hasCaptionSlot || caption || captionHtml) {
          $caption = h('caption', {
            attrs: {
              id: this.captionId
            },
            domProps: hasCaptionSlot ? {} : htmlOrText(captionHtml, caption),
            key: 'caption',
            ref: 'caption'
          }, this.normalizeSlot(SLOT_NAME_TABLE_CAPTION));
        }

        return $caption;
      }
    }
  });

  var props$r = {}; // --- Mixin ---
  // @vue/component

  var colgroupMixin = extend({
    methods: {
      renderColgroup: function renderColgroup() {
        var fields = this.computedFields;
        var h = this.$createElement;
        var $colgroup = h();

        if (this.hasNormalizedSlot(SLOT_NAME_TABLE_COLGROUP)) {
          $colgroup = h('colgroup', {
            key: 'colgroup'
          }, [this.normalizeSlot(SLOT_NAME_TABLE_COLGROUP, {
            columns: fields.length,
            fields: fields
          })]);
        }

        return $colgroup;
      }
    }
  });

  var props$q = {
    emptyFilteredHtml: makeProp(PROP_TYPE_STRING),
    emptyFilteredText: makeProp(PROP_TYPE_STRING, 'There are no records matching your request'),
    emptyHtml: makeProp(PROP_TYPE_STRING),
    emptyText: makeProp(PROP_TYPE_STRING, 'There are no records to show'),
    showEmpty: makeProp(PROP_TYPE_BOOLEAN, false)
  }; // --- Mixin ---
  // @vue/component

  var emptyMixin = extend({
    props: props$q,
    methods: {
      renderEmpty: function renderEmpty() {
        var _safeVueInstance = safeVueInstance(this),
            items = _safeVueInstance.computedItems,
            computedBusy = _safeVueInstance.computedBusy;

        var h = this.$createElement;
        var $empty = h();

        if (this.showEmpty && (!items || items.length === 0) && !(computedBusy && this.hasNormalizedSlot(SLOT_NAME_TABLE_BUSY))) {
          var fields = this.computedFields,
              isFiltered = this.isFiltered,
              emptyText = this.emptyText,
              emptyHtml = this.emptyHtml,
              emptyFilteredText = this.emptyFilteredText,
              emptyFilteredHtml = this.emptyFilteredHtml,
              tbodyTrClass = this.tbodyTrClass,
              tbodyTrAttr = this.tbodyTrAttr;
          $empty = this.normalizeSlot(isFiltered ? SLOT_NAME_EMPTYFILTERED : SLOT_NAME_EMPTY, {
            emptyFilteredHtml: emptyFilteredHtml,
            emptyFilteredText: emptyFilteredText,
            emptyHtml: emptyHtml,
            emptyText: emptyText,
            fields: fields,
            // Not sure why this is included, as it will always be an empty array
            items: items
          });

          if (!$empty) {
            $empty = h('div', {
              class: ['text-center', 'my-2'],
              domProps: isFiltered ? htmlOrText(emptyFilteredHtml, emptyFilteredText) : htmlOrText(emptyHtml, emptyText)
            });
          }

          $empty = h(BTd, {
            props: {
              colspan: fields.length || null
            }
          }, [h('div', {
            attrs: {
              role: 'alert',
              'aria-live': 'polite'
            }
          }, [$empty])]);
          $empty = h(BTr, {
            staticClass: 'b-table-empty-row',
            class: [isFunction$1(tbodyTrClass) ?
            /* istanbul ignore next */
            tbodyTrClass(null, 'row-empty') : tbodyTrClass],
            attrs: isFunction$1(tbodyTrAttr) ?
            /* istanbul ignore next */
            tbodyTrAttr(null, 'row-empty') : tbodyTrAttr,
            key: isFiltered ? 'b-empty-filtered-row' : 'b-empty-row'
          }, [$empty]);
        }

        return $empty;
      }
    }
  });

  // SSR safe deterministic way (keys are sorted before stringification)
  //
  //   ex:
  //     { b: 3, c: { z: 'zzz', d: null, e: 2 }, d: [10, 12, 11], a: 'one' }
  //   becomes
  //     'one 3 2 zzz 10 12 11'
  //
  // Strings are returned as-is
  // Numbers get converted to string
  // `null` and `undefined` values are filtered out
  // Dates are converted to their native string format

  var stringifyObjectValues = function stringifyObjectValues(value) {
    if (isUndefinedOrNull(value)) {
      return '';
    } // Arrays are also object, and keys just returns the array indexes
    // Date objects we convert to strings


    if (isObject(value) && !isDate(value)) {
      return keys(value).sort() // Sort to prevent SSR issues on pre-rendered sorted tables
      .map(function (k) {
        return stringifyObjectValues(value[k]);
      }).filter(function (v) {
        return !!v;
      }) // Ignore empty strings
      .join(' ');
    }

    return toString(value);
  };

  // Constants used by table helpers
  var FIELD_KEY_CELL_VARIANT = '_cellVariants';
  var FIELD_KEY_ROW_VARIANT = '_rowVariant';
  var FIELD_KEY_SHOW_DETAILS = '_showDetails'; // Object of item keys that should be ignored for headers and
  // stringification and filter events

  var IGNORED_FIELD_KEYS = [FIELD_KEY_CELL_VARIANT, FIELD_KEY_ROW_VARIANT, FIELD_KEY_SHOW_DETAILS].reduce(function (result, key) {
    return _objectSpread2$3(_objectSpread2$3({}, result), {}, _defineProperty({}, key, true));
  }, {}); // Filter CSS selector for click/dblclick/etc. events
  // If any of these selectors match the clicked element, we ignore the event

  var EVENT_FILTER = ['a', 'a *', // Include content inside links
  'button', 'button *', // Include content inside buttons
  'input:not(.disabled):not([disabled])', 'select:not(.disabled):not([disabled])', 'textarea:not(.disabled):not([disabled])', '[role="link"]', '[role="link"] *', '[role="button"]', '[role="button"] *', '[tabindex]:not(.disabled):not([disabled])'].join(',');

  var sanitizeRow = function sanitizeRow(row, ignoreFields, includeFields) {
    var fieldsObj = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
    // We first need to format the row based on the field configurations
    // This ensures that we add formatted values for keys that may not
    // exist in the row itself
    var formattedRow = keys(fieldsObj).reduce(function (result, key) {
      var field = fieldsObj[key];
      var filterByFormatted = field.filterByFormatted;
      var formatter = isFunction$1(filterByFormatted) ?
      /* istanbul ignore next */
      filterByFormatted : filterByFormatted ?
      /* istanbul ignore next */
      field.formatter : null;

      if (isFunction$1(formatter)) {
        result[key] = formatter(row[key], key, row);
      }

      return result;
    }, clone(row)); // Determine the allowed keys:
    //   - Ignore special fields that start with `_`
    //   - Ignore fields in the `ignoreFields` array
    //   - Include only fields in the `includeFields` array

    var allowedKeys = keys(formattedRow).filter(function (key) {
      return !IGNORED_FIELD_KEYS[key] && !(isArray(ignoreFields) && ignoreFields.length > 0 && arrayIncludes(ignoreFields, key)) && !(isArray(includeFields) && includeFields.length > 0 && !arrayIncludes(includeFields, key));
    });
    return pick$1(formattedRow, allowedKeys);
  };

  // TODO: Add option to stringify `scopedSlot` items

  var stringifyRecordValues = function stringifyRecordValues(row, ignoreFields, includeFields, fieldsObj) {
    return isObject(row) ? stringifyObjectValues(sanitizeRow(row, ignoreFields, includeFields, fieldsObj)) :
    /* istanbul ignore next */
    '';
  };

  var DEBOUNCE_DEPRECATED_MSG = 'Prop "filter-debounce" is deprecated. Use the debounce feature of "<b-form-input>" instead.'; // --- Props ---

  var props$p = {
    filter: makeProp([].concat(_toConsumableArray$1(PROP_TYPE_ARRAY_OBJECT_STRING), [PROP_TYPE_REG_EXP])),
    filterDebounce: makeProp(PROP_TYPE_NUMBER_STRING, 0, function (value) {
      return RX_DIGITS.test(String(value));
    }),
    filterFunction: makeProp(PROP_TYPE_FUNCTION),
    filterIgnoredFields: makeProp(PROP_TYPE_ARRAY, []),
    filterIncludedFields: makeProp(PROP_TYPE_ARRAY, [])
  }; // --- Mixin ---
  // @vue/component

  var filteringMixin = extend({
    props: props$p,
    data: function data() {
      return {
        // Flag for displaying which empty slot to show and some event triggering
        isFiltered: false,
        // Where we store the copy of the filter criteria after debouncing
        // We pre-set it with the sanitized filter value
        localFilter: this.filterSanitize(this.filter)
      };
    },
    computed: {
      computedFilterIgnored: function computedFilterIgnored() {
        return concat(this.filterIgnoredFields || []).filter(identity);
      },
      computedFilterIncluded: function computedFilterIncluded() {
        return concat(this.filterIncludedFields || []).filter(identity);
      },
      computedFilterDebounce: function computedFilterDebounce() {
        var ms = toInteger(this.filterDebounce, 0);
        /* istanbul ignore next */

        if (ms > 0) {
          warn(DEBOUNCE_DEPRECATED_MSG, NAME_TABLE);
        }

        return ms;
      },
      localFiltering: function localFiltering() {
        return this.hasProvider ? !!this.noProviderFiltering : true;
      },
      // For watching changes to `filteredItems` vs `localItems`
      filteredCheck: function filteredCheck() {
        var filteredItems = this.filteredItems,
            localItems = this.localItems,
            localFilter = this.localFilter;
        return {
          filteredItems: filteredItems,
          localItems: localItems,
          localFilter: localFilter
        };
      },
      // Sanitized/normalize filter-function prop
      localFilterFn: function localFilterFn() {
        // Return `null` to signal to use internal filter function
        var filterFunction = this.filterFunction;
        return hasPropFunction(filterFunction) ? filterFunction : null;
      },
      // Returns the records in `localItems` that match the filter criteria
      // Returns the original `localItems` array if not sorting
      filteredItems: function filteredItems() {
        // Note the criteria is debounced and sanitized
        var items = this.localItems,
            criteria = this.localFilter; // Resolve the filtering function, when requested
        // We prefer the provided filtering function and fallback to the internal one
        // When no filtering criteria is specified the filtering factories will return `null`

        var filterFn = this.localFiltering ? this.filterFnFactory(this.localFilterFn, criteria) || this.defaultFilterFnFactory(criteria) : null; // We only do local filtering when requested and there are records to filter

        return filterFn && items.length > 0 ? items.filter(filterFn) : items;
      }
    },
    watch: {
      // Watch for debounce being set to 0
      computedFilterDebounce: function computedFilterDebounce(newValue) {
        if (!newValue && this.$_filterTimer) {
          this.clearFilterTimer();
          this.localFilter = this.filterSanitize(this.filter);
        }
      },
      // Watch for changes to the filter criteria, and debounce if necessary
      filter: {
        // We need a deep watcher in case the user passes
        // an object when using `filter-function`
        deep: true,
        handler: function handler(newCriteria) {
          var _this = this;

          var timeout = this.computedFilterDebounce;
          this.clearFilterTimer();

          if (timeout && timeout > 0) {
            // If we have a debounce time, delay the update of `localFilter`
            this.$_filterTimer = setTimeout(function () {
              _this.localFilter = _this.filterSanitize(newCriteria);
            }, timeout);
          } else {
            // Otherwise, immediately update `localFilter` with `newFilter` value
            this.localFilter = this.filterSanitize(newCriteria);
          }
        }
      },
      // Watch for changes to the filter criteria and filtered items vs `localItems`
      // Set visual state and emit events as required
      filteredCheck: function filteredCheck(_ref) {
        var filteredItems = _ref.filteredItems,
            localFilter = _ref.localFilter;
        // Determine if the dataset is filtered or not
        var isFiltered = false;

        if (!localFilter) {
          // If filter criteria is falsey
          isFiltered = false;
        } else if (looseEqual(localFilter, []) || looseEqual(localFilter, {})) {
          // If filter criteria is an empty array or object
          isFiltered = false;
        } else if (localFilter) {
          // If filter criteria is truthy
          isFiltered = true;
        }

        if (isFiltered) {
          this.$emit(EVENT_NAME_FILTERED, filteredItems, filteredItems.length);
        }

        this.isFiltered = isFiltered;
      },
      isFiltered: function isFiltered(newValue, oldValue) {
        if (newValue === false && oldValue === true) {
          // We need to emit a filtered event if `isFiltered` transitions from `true` to
          // `false` so that users can update their pagination controls
          var localItems = this.localItems;
          this.$emit(EVENT_NAME_FILTERED, localItems, localItems.length);
        }
      }
    },
    created: function created() {
      var _this2 = this;

      // Create private non-reactive props
      this.$_filterTimer = null; // If filter is "pre-set", set the criteria
      // This will trigger any watchers/dependents
      // this.localFilter = this.filterSanitize(this.filter)
      // Set the initial filtered state in a `$nextTick()` so that
      // we trigger a filtered event if needed

      this.$nextTick(function () {
        _this2.isFiltered = Boolean(_this2.localFilter);
      });
    },
    beforeDestroy: function beforeDestroy() {
      this.clearFilterTimer();
    },
    methods: {
      clearFilterTimer: function clearFilterTimer() {
        clearTimeout(this.$_filterTimer);
        this.$_filterTimer = null;
      },
      filterSanitize: function filterSanitize(criteria) {
        // Sanitizes filter criteria based on internal or external filtering
        if (this.localFiltering && !this.localFilterFn && !(isString(criteria) || isRegExp(criteria))) {
          // If using internal filter function, which only accepts string or RegExp,
          // return '' to signify no filter
          return '';
        } // Could be a string, object or array, as needed by external filter function
        // We use `cloneDeep` to ensure we have a new copy of an object or array
        // without Vue's reactive observers


        return cloneDeep(criteria);
      },
      // Filter Function factories
      filterFnFactory: function filterFnFactory(filterFn, criteria) {
        // Wrapper factory for external filter functions
        // Wrap the provided filter-function and return a new function
        // Returns `null` if no filter-function defined or if criteria is falsey
        // Rather than directly grabbing `this.computedLocalFilterFn` or `this.filterFunction`
        // we have it passed, so that the caller computed prop will be reactive to changes
        // in the original filter-function (as this routine is a method)
        if (!filterFn || !isFunction$1(filterFn) || !criteria || looseEqual(criteria, []) || looseEqual(criteria, {})) {
          return null;
        } // Build the wrapped filter test function, passing the criteria to the provided function


        var fn = function fn(item) {
          // Generated function returns true if the criteria matches part
          // of the serialized data, otherwise false
          return filterFn(item, criteria);
        }; // Return the wrapped function


        return fn;
      },
      defaultFilterFnFactory: function defaultFilterFnFactory(criteria) {
        var _this3 = this;

        // Generates the default filter function, using the given filter criteria
        // Returns `null` if no criteria or criteria format not supported
        if (!criteria || !(isString(criteria) || isRegExp(criteria))) {
          // Built in filter can only support strings or RegExp criteria (at the moment)
          return null;
        } // Build the RegExp needed for filtering


        var regExp = criteria;

        if (isString(regExp)) {
          // Escape special RegExp characters in the string and convert contiguous
          // whitespace to \s+ matches
          var pattern = escapeRegExp(criteria).replace(RX_SPACES, '\\s+'); // Build the RegExp (no need for global flag, as we only need
          // to find the value once in the string)

          regExp = new RegExp(".*".concat(pattern, ".*"), 'i');
        } // Generate the wrapped filter test function to use


        var fn = function fn(item) {
          // This searches all row values (and sub property values) in the entire (excluding
          // special `_` prefixed keys), because we convert the record to a space-separated
          // string containing all the value properties (recursively), even ones that are
          // not visible (not specified in this.fields)
          // Users can ignore filtering on specific fields, or on only certain fields,
          // and can optionall specify searching results of fields with formatter
          //
          // TODO: Enable searching on scoped slots (optional, as it will be SLOW)
          //
          // Generated function returns true if the criteria matches part of
          // the serialized data, otherwise false
          //
          // We set `lastIndex = 0` on the `RegExp` in case someone specifies the `/g` global flag
          regExp.lastIndex = 0;
          return regExp.test(stringifyRecordValues(item, _this3.computedFilterIgnored, _this3.computedFilterIncluded, _this3.computedFieldsObj));
        }; // Return the generated function


        return fn;
      }
    }
  });

  var processField = function processField(key, value) {
    var field = null;

    if (isString(value)) {
      // Label shortcut
      field = {
        key: key,
        label: value
      };
    } else if (isFunction$1(value)) {
      // Formatter shortcut
      field = {
        key: key,
        formatter: value
      };
    } else if (isObject(value)) {
      field = clone(value);
      field.key = field.key || key;
    } else if (value !== false) {
      // Fallback to just key

      /* istanbul ignore next */
      field = {
        key: key
      };
    }

    return field;
  }; // We normalize fields into an array of objects
  // [ { key:..., label:..., ...}, {...}, ..., {..}]


  var normalizeFields = function normalizeFields(origFields, items) {
    var fields = [];

    if (isArray(origFields)) {
      // Normalize array Form
      origFields.filter(identity).forEach(function (f) {
        if (isString(f)) {
          fields.push({
            key: f,
            label: startCase(f)
          });
        } else if (isObject(f) && f.key && isString(f.key)) {
          // Full object definition. We use assign so that we don't mutate the original
          fields.push(clone(f));
        } else if (isObject(f) && keys(f).length === 1) {
          // Shortcut object (i.e. { 'foo_bar': 'This is Foo Bar' }
          var key = keys(f)[0];
          var field = processField(key, f[key]);

          if (field) {
            fields.push(field);
          }
        }
      });
    } // If no field provided, take a sample from first record (if exits)


    if (fields.length === 0 && isArray(items) && items.length > 0) {
      var sample = items[0];
      keys(sample).forEach(function (k) {
        if (!IGNORED_FIELD_KEYS[k]) {
          fields.push({
            key: k,
            label: startCase(k)
          });
        }
      });
    } // Ensure we have a unique array of fields and that they have String labels


    var memo = {};
    return fields.filter(function (f) {
      if (!memo[f.key]) {
        memo[f.key] = true;
        f.label = isString(f.label) ? f.label : startCase(f.key);
        return true;
      }

      return false;
    });
  };

  var _makeModelMixin$2 = makeModelMixin('value', {
    type: PROP_TYPE_ARRAY,
    defaultValue: []
  }),
      modelMixin$2 = _makeModelMixin$2.mixin,
      modelProps$2 = _makeModelMixin$2.props,
      MODEL_PROP_NAME$2 = _makeModelMixin$2.prop,
      MODEL_EVENT_NAME$2 = _makeModelMixin$2.event;

  var props$o = sortKeys(_objectSpread2$3(_objectSpread2$3({}, modelProps$2), {}, _defineProperty({
    fields: makeProp(PROP_TYPE_ARRAY, null),
    // Provider mixin adds in `Function` type
    items: makeProp(PROP_TYPE_ARRAY, []),
    // Primary key for record
    // If provided the value in each row must be unique!
    primaryKey: makeProp(PROP_TYPE_STRING)
  }, MODEL_PROP_NAME$2, makeProp(PROP_TYPE_ARRAY, [])))); // --- Mixin ---
  // @vue/component

  var itemsMixin = extend({
    mixins: [modelMixin$2, useParentMixin],
    props: props$o,
    data: function data() {
      var items = this.items;
      return {
        // Our local copy of the items
        // Must be an array
        localItems: isArray(items) ? items.slice() : []
      };
    },
    computed: {
      computedFields: function computedFields() {
        // We normalize fields into an array of objects
        // `[ { key:..., label:..., ...}, {...}, ..., {..}]`
        return normalizeFields(this.fields, this.localItems);
      },
      computedFieldsObj: function computedFieldsObj() {
        // Fields as a simple lookup hash object
        // Mainly for formatter lookup and use in `scopedSlots` for convenience
        // If the field has a formatter, it normalizes formatter to a
        // function ref or `undefined` if no formatter
        var bvParent = this.bvParent;
        return this.computedFields.reduce(function (obj, f) {
          // We use object spread here so we don't mutate the original field object
          obj[f.key] = clone(f);

          if (f.formatter) {
            // Normalize formatter to a function ref or `undefined`
            var formatter = f.formatter;

            if (isString(formatter) && isFunction$1(bvParent[formatter])) {
              formatter = bvParent[formatter];
            } else if (!isFunction$1(formatter)) {
              /* istanbul ignore next */
              formatter = undefined;
            } // Return formatter function or `undefined` if none


            obj[f.key].formatter = formatter;
          }

          return obj;
        }, {});
      },
      computedItems: function computedItems() {
        var _safeVueInstance = safeVueInstance(this),
            paginatedItems = _safeVueInstance.paginatedItems,
            sortedItems = _safeVueInstance.sortedItems,
            filteredItems = _safeVueInstance.filteredItems,
            localItems = _safeVueInstance.localItems; // Fallback if various mixins not provided


        return (paginatedItems || sortedItems || filteredItems || localItems ||
        /* istanbul ignore next */
        []).slice();
      },
      context: function context() {
        var _safeVueInstance2 = safeVueInstance(this),
            perPage = _safeVueInstance2.perPage,
            currentPage = _safeVueInstance2.currentPage; // Current state of sorting, filtering and pagination props/values


        return {
          filter: this.localFilter,
          sortBy: this.localSortBy,
          sortDesc: this.localSortDesc,
          perPage: mathMax(toInteger(perPage, 0), 0),
          currentPage: mathMax(toInteger(currentPage, 0), 1),
          apiUrl: this.apiUrl
        };
      }
    },
    watch: {
      items: function items(newValue) {
        // Set `localItems`/`filteredItems` to a copy of the provided array
        this.localItems = isArray(newValue) ? newValue.slice() : [];
      },
      // Watch for changes on `computedItems` and update the `v-model`
      computedItems: function computedItems(newValue, oldValue) {
        if (!looseEqual(newValue, oldValue)) {
          this.$emit(MODEL_EVENT_NAME$2, newValue);
        }
      },
      // Watch for context changes
      context: function context(newValue, oldValue) {
        // Emit context information for external paging/filtering/sorting handling
        if (!looseEqual(newValue, oldValue)) {
          this.$emit(EVENT_NAME_CONTEXT_CHANGED, newValue);
        }
      }
    },
    mounted: function mounted() {
      // Initially update the `v-model` of displayed items
      this.$emit(MODEL_EVENT_NAME$2, this.computedItems);
    },
    methods: {
      // Method to get the formatter method for a given field key
      getFieldFormatter: function getFieldFormatter(key) {
        var field = this.computedFieldsObj[key]; // `this.computedFieldsObj` has pre-normalized the formatter to a
        // function ref if present, otherwise `undefined`

        return field ? field.formatter : undefined;
      }
    }
  });

  var props$n = {
    currentPage: makeProp(PROP_TYPE_NUMBER_STRING, 1),
    perPage: makeProp(PROP_TYPE_NUMBER_STRING, 0)
  }; // --- Mixin ---
  // @vue/component

  var paginationMixin = extend({
    props: props$n,
    computed: {
      localPaging: function localPaging() {
        return this.hasProvider ? !!this.noProviderPaging : true;
      },
      paginatedItems: function paginatedItems() {
        var _safeVueInstance = safeVueInstance(this),
            sortedItems = _safeVueInstance.sortedItems,
            filteredItems = _safeVueInstance.filteredItems,
            localItems = _safeVueInstance.localItems;

        var items = sortedItems || filteredItems || localItems || [];
        var currentPage = mathMax(toInteger(this.currentPage, 1), 1);
        var perPage = mathMax(toInteger(this.perPage, 0), 0); // Apply local pagination

        if (this.localPaging && perPage) {
          // Grab the current page of data (which may be past filtered items limit)
          items = items.slice((currentPage - 1) * perPage, currentPage * perPage);
        } // Return the items to display in the table


        return items;
      }
    }
  });

  var ROOT_EVENT_NAME_REFRESHED = getRootEventName(NAME_TABLE, EVENT_NAME_REFRESHED);
  var ROOT_ACTION_EVENT_NAME_REFRESH = getRootActionEventName(NAME_TABLE, EVENT_NAME_REFRESH); // --- Props ---

  var props$m = {
    // Passed to the context object
    // Not used by `<b-table>` directly
    apiUrl: makeProp(PROP_TYPE_STRING),
    // Adds in 'Function' support
    items: makeProp(PROP_TYPE_ARRAY_FUNCTION, []),
    noProviderFiltering: makeProp(PROP_TYPE_BOOLEAN, false),
    noProviderPaging: makeProp(PROP_TYPE_BOOLEAN, false),
    noProviderSorting: makeProp(PROP_TYPE_BOOLEAN, false)
  }; // --- Mixin ---
  // @vue/component

  var providerMixin = extend({
    mixins: [listenOnRootMixin],
    props: props$m,
    computed: {
      hasProvider: function hasProvider() {
        return isFunction$1(this.items);
      },
      providerTriggerContext: function providerTriggerContext() {
        // Used to trigger the provider function via a watcher. Only the fields that
        // are needed for triggering a provider update are included. Note that the
        // regular this.context is sent to the provider during fetches though, as they
        // may need all the prop info.
        var ctx = {
          apiUrl: this.apiUrl,
          filter: null,
          sortBy: null,
          sortDesc: null,
          perPage: null,
          currentPage: null
        };

        if (!this.noProviderFiltering) {
          // Either a string, or could be an object or array.
          ctx.filter = this.localFilter;
        }

        if (!this.noProviderSorting) {
          ctx.sortBy = this.localSortBy;
          ctx.sortDesc = this.localSortDesc;
        }

        if (!this.noProviderPaging) {
          ctx.perPage = this.perPage;
          ctx.currentPage = this.currentPage;
        }

        return clone(ctx);
      }
    },
    watch: {
      // Provider update triggering
      items: function items(newValue) {
        // If a new provider has been specified, trigger an update
        if (this.hasProvider || isFunction$1(newValue)) {
          this.$nextTick(this._providerUpdate);
        }
      },
      providerTriggerContext: function providerTriggerContext(newValue, oldValue) {
        // Trigger the provider to update as the relevant context values have changed.
        if (!looseEqual(newValue, oldValue)) {
          this.$nextTick(this._providerUpdate);
        }
      }
    },
    mounted: function mounted() {
      var _this = this;

      // Call the items provider if necessary
      if (this.hasProvider && (!this.localItems || this.localItems.length === 0)) {
        // Fetch on mount if localItems is empty
        this._providerUpdate();
      } // Listen for global messages to tell us to force refresh the table


      this.listenOnRoot(ROOT_ACTION_EVENT_NAME_REFRESH, function (id) {
        if (id === _this.id || id === _this) {
          _this.refresh();
        }
      });
    },
    methods: {
      refresh: function refresh() {
        var _safeVueInstance = safeVueInstance(this),
            items = _safeVueInstance.items,
            refresh = _safeVueInstance.refresh,
            computedBusy = _safeVueInstance.computedBusy; // Public Method: Force a refresh of the provider function


        this.$off(EVENT_NAME_REFRESHED, refresh);

        if (computedBusy) {
          // Can't force an update when forced busy by user (busy prop === true)
          if (this.localBusy && this.hasProvider) {
            // But if provider running (localBusy), re-schedule refresh once `refreshed` emitted
            this.$on(EVENT_NAME_REFRESHED, refresh);
          }
        } else {
          this.clearSelected();

          if (this.hasProvider) {
            this.$nextTick(this._providerUpdate);
          } else {
            /* istanbul ignore next */
            this.localItems = isArray(items) ? items.slice() : [];
          }
        }
      },
      // Provider related methods
      _providerSetLocal: function _providerSetLocal(items) {
        this.localItems = isArray(items) ? items.slice() : [];
        this.localBusy = false;
        this.$emit(EVENT_NAME_REFRESHED); // New root emit

        if (this.id) {
          this.emitOnRoot(ROOT_EVENT_NAME_REFRESHED, this.id);
        }
      },
      _providerUpdate: function _providerUpdate() {
        var _this2 = this;

        // Refresh the provider function items.
        if (!this.hasProvider) {
          // Do nothing if no provider
          return;
        } // If table is busy, wait until refreshed before calling again


        if (safeVueInstance(this).computedBusy) {
          // Schedule a new refresh once `refreshed` is emitted
          this.$nextTick(this.refresh);
          return;
        } // Set internal busy state


        this.localBusy = true; // Call provider function with context and optional callback after DOM is fully updated

        this.$nextTick(function () {
          try {
            // Call provider function passing it the context and optional callback
            var data = _this2.items(_this2.context, _this2._providerSetLocal);

            if (isPromise(data)) {
              // Provider returned Promise
              data.then(function (items) {
                // Provider resolved with items
                _this2._providerSetLocal(items);
              });
            } else if (isArray(data)) {
              // Provider returned Array data
              _this2._providerSetLocal(data);
            } else {
              /* istanbul ignore if */
              if (_this2.items.length !== 2) {
                // Check number of arguments provider function requested
                // Provider not using callback (didn't request second argument), so we clear
                // busy state as most likely there was an error in the provider function

                /* istanbul ignore next */
                warn("Provider function didn't request callback and did not return a promise or data.", NAME_TABLE);
                _this2.localBusy = false;
              }
            }
          } catch (e)
          /* istanbul ignore next */
          {
            // Provider function borked on us, so we spew out a warning
            // and clear the busy state
            warn("Provider function error [".concat(e.name, "] ").concat(e.message, "."), NAME_TABLE);
            _this2.localBusy = false;

            _this2.$off(EVENT_NAME_REFRESHED, _this2.refresh);
          }
        });
      }
    }
  });

  var SELECT_MODES = ['range', 'multi', 'single'];
  var ROLE_GRID = 'grid'; // --- Props ---

  var props$l = {
    // Disable use of click handlers for row selection
    noSelectOnClick: makeProp(PROP_TYPE_BOOLEAN, false),
    selectMode: makeProp(PROP_TYPE_STRING, 'multi', function (value) {
      return arrayIncludes(SELECT_MODES, value);
    }),
    selectable: makeProp(PROP_TYPE_BOOLEAN, false),
    selectedVariant: makeProp(PROP_TYPE_STRING, 'active')
  }; // --- Mixin ---
  // @vue/component

  var selectableMixin = extend({
    props: props$l,
    data: function data() {
      return {
        selectedRows: [],
        selectedLastRow: -1
      };
    },
    computed: {
      isSelectable: function isSelectable() {
        return this.selectable && this.selectMode;
      },
      hasSelectableRowClick: function hasSelectableRowClick() {
        return this.isSelectable && !this.noSelectOnClick;
      },
      supportsSelectableRows: function supportsSelectableRows() {
        return true;
      },
      selectableHasSelection: function selectableHasSelection() {
        var selectedRows = this.selectedRows;
        return this.isSelectable && selectedRows && selectedRows.length > 0 && selectedRows.some(identity);
      },
      selectableIsMultiSelect: function selectableIsMultiSelect() {
        return this.isSelectable && arrayIncludes(['range', 'multi'], this.selectMode);
      },
      selectableTableClasses: function selectableTableClasses() {
        var _ref;

        var isSelectable = this.isSelectable;
        return _ref = {
          'b-table-selectable': isSelectable
        }, _defineProperty(_ref, "b-table-select-".concat(this.selectMode), isSelectable), _defineProperty(_ref, 'b-table-selecting', this.selectableHasSelection), _defineProperty(_ref, 'b-table-selectable-no-click', isSelectable && !this.hasSelectableRowClick), _ref;
      },
      selectableTableAttrs: function selectableTableAttrs() {
        if (!this.isSelectable) {
          return {};
        }

        var role = this.bvAttrs.role || ROLE_GRID;
        return {
          role: role,
          // TODO:
          //   Should this attribute not be included when `no-select-on-click` is set
          //   since this attribute implies keyboard navigation?
          'aria-multiselectable': role === ROLE_GRID ? toString(this.selectableIsMultiSelect) : null
        };
      }
    },
    watch: {
      computedItems: function computedItems(newValue, oldValue) {
        // Reset for selectable
        var equal = false;

        if (this.isSelectable && this.selectedRows.length > 0) {
          // Quick check against array length
          equal = isArray(newValue) && isArray(oldValue) && newValue.length === oldValue.length;

          for (var i = 0; equal && i < newValue.length; i++) {
            // Look for the first non-loosely equal row, after ignoring reserved fields
            equal = looseEqual(sanitizeRow(newValue[i]), sanitizeRow(oldValue[i]));
          }
        }

        if (!equal) {
          this.clearSelected();
        }
      },
      selectable: function selectable(newValue) {
        this.clearSelected();
        this.setSelectionHandlers(newValue);
      },
      selectMode: function selectMode() {
        this.clearSelected();
      },
      hasSelectableRowClick: function hasSelectableRowClick(newValue) {
        this.clearSelected();
        this.setSelectionHandlers(!newValue);
      },
      selectedRows: function selectedRows(_selectedRows, oldValue) {
        var _this = this;

        if (this.isSelectable && !looseEqual(_selectedRows, oldValue)) {
          var items = []; // `.forEach()` skips over non-existent indices (on sparse arrays)

          _selectedRows.forEach(function (v, idx) {
            if (v) {
              items.push(_this.computedItems[idx]);
            }
          });

          this.$emit(EVENT_NAME_ROW_SELECTED, items);
        }
      }
    },
    beforeMount: function beforeMount() {
      // Set up handlers if needed
      if (this.isSelectable) {
        this.setSelectionHandlers(true);
      }
    },
    methods: {
      // Public methods
      selectRow: function selectRow(index) {
        // Select a particular row (indexed based on computedItems)
        if (this.isSelectable && isNumber(index) && index >= 0 && index < this.computedItems.length && !this.isRowSelected(index)) {
          var selectedRows = this.selectableIsMultiSelect ? this.selectedRows.slice() : [];
          selectedRows[index] = true;
          this.selectedLastClicked = -1;
          this.selectedRows = selectedRows;
        }
      },
      unselectRow: function unselectRow(index) {
        // Un-select a particular row (indexed based on `computedItems`)
        if (this.isSelectable && isNumber(index) && this.isRowSelected(index)) {
          var selectedRows = this.selectedRows.slice();
          selectedRows[index] = false;
          this.selectedLastClicked = -1;
          this.selectedRows = selectedRows;
        }
      },
      selectAllRows: function selectAllRows() {
        var length = this.computedItems.length;

        if (this.isSelectable && length > 0) {
          this.selectedLastClicked = -1;
          this.selectedRows = this.selectableIsMultiSelect ? createArray(length, true) : [true];
        }
      },
      isRowSelected: function isRowSelected(index) {
        // Determine if a row is selected (indexed based on `computedItems`)
        return !!(isNumber(index) && this.selectedRows[index]);
      },
      clearSelected: function clearSelected() {
        // Clear any active selected row(s)
        this.selectedLastClicked = -1;
        this.selectedRows = [];
      },
      // Internal private methods
      selectableRowClasses: function selectableRowClasses(index) {
        if (this.isSelectable && this.isRowSelected(index)) {
          var variant = this.selectedVariant;
          return _defineProperty({
            'b-table-row-selected': true
          }, "".concat(this.dark ? 'bg' : 'table', "-").concat(variant), variant);
        }

        return {};
      },
      selectableRowAttrs: function selectableRowAttrs(index) {
        return {
          'aria-selected': !this.isSelectable ? null : this.isRowSelected(index) ? 'true' : 'false'
        };
      },
      setSelectionHandlers: function setSelectionHandlers(on) {
        var method = on && !this.noSelectOnClick ? '$on' : '$off'; // Handle row-clicked event

        this[method](EVENT_NAME_ROW_CLICKED, this.selectionHandler); // Clear selection on filter, pagination, and sort changes

        this[method](EVENT_NAME_FILTERED, this.clearSelected);
        this[method](EVENT_NAME_CONTEXT_CHANGED, this.clearSelected);
      },
      selectionHandler: function selectionHandler(item, index, event) {
        /* istanbul ignore if: should never happen */
        if (!this.isSelectable || this.noSelectOnClick) {
          // Don't do anything if table is not in selectable mode
          this.clearSelected();
          return;
        }

        var selectMode = this.selectMode,
            selectedLastRow = this.selectedLastRow;
        var selectedRows = this.selectedRows.slice();
        var selected = !selectedRows[index]; // Note 'multi' mode needs no special event handling

        if (selectMode === 'single') {
          selectedRows = [];
        } else if (selectMode === 'range') {
          if (selectedLastRow > -1 && event.shiftKey) {
            // range
            for (var idx = mathMin(selectedLastRow, index); idx <= mathMax(selectedLastRow, index); idx++) {
              selectedRows[idx] = true;
            }

            selected = true;
          } else {
            if (!(event.ctrlKey || event.metaKey)) {
              // Clear range selection if any
              selectedRows = [];
              selected = true;
            }

            if (selected) this.selectedLastRow = index;
          }
        }

        selectedRows[index] = selected;
        this.selectedRows = selectedRows;
      }
    }
  });

  /*
   * Consistent and stable sort function across JavaScript platforms
   *
   * Inconsistent sorts can cause SSR problems between client and server
   * such as in <b-table> if sortBy is applied to the data on server side render.
   * Chrome and V8 native sorts are inconsistent/unstable
   *
   * This function uses native sort with fallback to index compare when the a and b
   * compare returns 0
   *
   * Algorithm based on:
   * https://stackoverflow.com/questions/1427608/fast-stable-sorting-algorithm-implementation-in-javascript/45422645#45422645
   *
   * @param {array} array to sort
   * @param {function} sort compare function
   * @return {array}
   */
  var stableSort$1 = function stableSort(array, compareFn) {
    // Using `.bind(compareFn)` on the wrapped anonymous function improves
    // performance by avoiding the function call setup. We don't use an arrow
    // function here as it binds `this` to the `stableSort` context rather than
    // the `compareFn` context, which wouldn't give us the performance increase.
    return array.map(function (a, index) {
      return [index, a];
    }).sort(function (a, b) {
      return this(a[1], b[1]) || a[0] - b[0];
    }.bind(compareFn)).map(function (e) {
      return e[1];
    });
  };

  var normalizeValue = function normalizeValue(value) {
    if (isUndefinedOrNull(value)) {
      return '';
    }

    if (isNumeric$1(value)) {
      return toFloat(value, value);
    }

    return value;
  }; // Default sort compare routine
  //
  // TODO:
  //   Add option to sort by multiple columns (tri-state per column,
  //   plus order of columns in sort) where `sortBy` could be an array
  //   of objects `[ {key: 'foo', sortDir: 'asc'}, {key:'bar', sortDir: 'desc'} ...]`
  //   or an array of arrays `[ ['foo','asc'], ['bar','desc'] ]`
  //   Multisort will most likely be handled in `mixin-sort.js` by
  //   calling this method for each sortBy


  var defaultSortCompare = function defaultSortCompare(a, b) {
    var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},
        _ref$sortBy = _ref.sortBy,
        sortBy = _ref$sortBy === void 0 ? null : _ref$sortBy,
        _ref$formatter = _ref.formatter,
        formatter = _ref$formatter === void 0 ? null : _ref$formatter,
        _ref$locale = _ref.locale,
        locale = _ref$locale === void 0 ? undefined : _ref$locale,
        _ref$localeOptions = _ref.localeOptions,
        localeOptions = _ref$localeOptions === void 0 ? {} : _ref$localeOptions,
        _ref$nullLast = _ref.nullLast,
        nullLast = _ref$nullLast === void 0 ? false : _ref$nullLast;

    // Get the value by `sortBy`
    var aa = get(a, sortBy, null);
    var bb = get(b, sortBy, null); // Apply user-provided formatter

    if (isFunction$1(formatter)) {
      aa = formatter(aa, sortBy, a);
      bb = formatter(bb, sortBy, b);
    } // Internally normalize value
    // `null` / `undefined` => ''
    // `'0'` => `0`


    aa = normalizeValue(aa);
    bb = normalizeValue(bb);

    if (isDate(aa) && isDate(bb) || isNumber(aa) && isNumber(bb)) {
      // Special case for comparing dates and numbers
      // Internally dates are compared via their epoch number values
      return aa < bb ? -1 : aa > bb ? 1 : 0;
    } else if (nullLast && aa === '' && bb !== '') {
      // Special case when sorting `null` / `undefined` / '' last
      return 1;
    } else if (nullLast && aa !== '' && bb === '') {
      // Special case when sorting `null` / `undefined` / '' last
      return -1;
    } // Do localized string comparison


    return stringifyObjectValues(aa).localeCompare(stringifyObjectValues(bb), locale, localeOptions);
  };

  var _props, _watch$3;

  var MODEL_PROP_NAME_SORT_BY = 'sortBy';
  var MODEL_EVENT_NAME_SORT_BY = MODEL_EVENT_NAME_PREFIX + MODEL_PROP_NAME_SORT_BY;
  var MODEL_PROP_NAME_SORT_DESC = 'sortDesc';
  var MODEL_EVENT_NAME_SORT_DESC = MODEL_EVENT_NAME_PREFIX + MODEL_PROP_NAME_SORT_DESC;
  var SORT_DIRECTION_ASC = 'asc';
  var SORT_DIRECTION_DESC = 'desc';
  var SORT_DIRECTION_LAST = 'last';
  var SORT_DIRECTIONS = [SORT_DIRECTION_ASC, SORT_DIRECTION_DESC, SORT_DIRECTION_LAST]; // --- Props ---

  var props$k = (_props = {
    labelSortAsc: makeProp(PROP_TYPE_STRING, 'Click to sort ascending'),
    labelSortClear: makeProp(PROP_TYPE_STRING, 'Click to clear sorting'),
    labelSortDesc: makeProp(PROP_TYPE_STRING, 'Click to sort descending'),
    noFooterSorting: makeProp(PROP_TYPE_BOOLEAN, false),
    noLocalSorting: makeProp(PROP_TYPE_BOOLEAN, false),
    // Another prop that should have had a better name
    // It should be `noSortClear` (on non-sortable headers)
    // We will need to make sure the documentation is clear on what
    // this prop does (as well as in the code for future reference)
    noSortReset: makeProp(PROP_TYPE_BOOLEAN, false)
  }, _defineProperty(_props, MODEL_PROP_NAME_SORT_BY, makeProp(PROP_TYPE_STRING)), _defineProperty(_props, "sortCompare", makeProp(PROP_TYPE_FUNCTION)), _defineProperty(_props, "sortCompareLocale", makeProp(PROP_TYPE_ARRAY_STRING)), _defineProperty(_props, "sortCompareOptions", makeProp(PROP_TYPE_OBJECT, {
    numeric: true
  })), _defineProperty(_props, MODEL_PROP_NAME_SORT_DESC, makeProp(PROP_TYPE_BOOLEAN, false)), _defineProperty(_props, "sortDirection", makeProp(PROP_TYPE_STRING, SORT_DIRECTION_ASC, function (value) {
    return arrayIncludes(SORT_DIRECTIONS, value);
  })), _defineProperty(_props, "sortIconLeft", makeProp(PROP_TYPE_BOOLEAN, false)), _defineProperty(_props, "sortNullLast", makeProp(PROP_TYPE_BOOLEAN, false)), _props); // --- Mixin ---
  // @vue/component

  var sortingMixin = extend({
    props: props$k,
    data: function data() {
      return {
        localSortBy: this[MODEL_PROP_NAME_SORT_BY] || '',
        localSortDesc: this[MODEL_PROP_NAME_SORT_DESC] || false
      };
    },
    computed: {
      localSorting: function localSorting() {
        return this.hasProvider ? !!this.noProviderSorting : !this.noLocalSorting;
      },
      isSortable: function isSortable() {
        return this.computedFields.some(function (f) {
          return f.sortable;
        });
      },
      // Sorts the filtered items and returns a new array of the sorted items
      // When not sorted, the original items array will be returned
      sortedItems: function sortedItems() {
        var _safeVueInstance = safeVueInstance(this),
            sortBy = _safeVueInstance.localSortBy,
            sortDesc = _safeVueInstance.localSortDesc,
            locale = _safeVueInstance.sortCompareLocale,
            nullLast = _safeVueInstance.sortNullLast,
            sortCompare = _safeVueInstance.sortCompare,
            localSorting = _safeVueInstance.localSorting,
            filteredItems = _safeVueInstance.filteredItems,
            localItems = _safeVueInstance.localItems;

        var items = (filteredItems || localItems || []).slice();

        var localeOptions = _objectSpread2$3(_objectSpread2$3({}, this.sortCompareOptions), {}, {
          usage: 'sort'
        });

        if (sortBy && localSorting) {
          var field = this.computedFieldsObj[sortBy] || {};
          var sortByFormatted = field.sortByFormatted;
          var formatter = isFunction$1(sortByFormatted) ?
          /* istanbul ignore next */
          sortByFormatted : sortByFormatted ? this.getFieldFormatter(sortBy) : undefined; // `stableSort` returns a new array, and leaves the original array intact

          return stableSort$1(items, function (a, b) {
            var result = null; // Call user provided `sortCompare` routine first

            if (isFunction$1(sortCompare)) {
              // TODO:
              //   Change the `sortCompare` signature to the one of `defaultSortCompare`
              //   with the next major version bump
              result = sortCompare(a, b, sortBy, sortDesc, formatter, localeOptions, locale);
            } // Fallback to built-in `defaultSortCompare` if `sortCompare`
            // is not defined or returns `null`/`false`


            if (isUndefinedOrNull(result) || result === false) {
              result = defaultSortCompare(a, b, {
                sortBy: sortBy,
                formatter: formatter,
                locale: locale,
                localeOptions: localeOptions,
                nullLast: nullLast
              });
            } // Negate result if sorting in descending order


            return (result || 0) * (sortDesc ? -1 : 1);
          });
        }

        return items;
      }
    },
    watch: (_watch$3 = {
      /* istanbul ignore next: pain in the butt to test */
      isSortable: function isSortable(newValue) {
        if (newValue) {
          if (this.isSortable) {
            this.$on(EVENT_NAME_HEAD_CLICKED, this.handleSort);
          }
        } else {
          this.$off(EVENT_NAME_HEAD_CLICKED, this.handleSort);
        }
      }
    }, _defineProperty(_watch$3, MODEL_PROP_NAME_SORT_DESC, function (newValue) {
      /* istanbul ignore next */
      if (newValue === this.localSortDesc) {
        return;
      }

      this.localSortDesc = newValue || false;
    }), _defineProperty(_watch$3, MODEL_PROP_NAME_SORT_BY, function (newValue) {
      /* istanbul ignore next */
      if (newValue === this.localSortBy) {
        return;
      }

      this.localSortBy = newValue || '';
    }), _defineProperty(_watch$3, "localSortDesc", function localSortDesc(newValue, oldValue) {
      // Emit update to sort-desc.sync
      if (newValue !== oldValue) {
        this.$emit(MODEL_EVENT_NAME_SORT_DESC, newValue);
      }
    }), _defineProperty(_watch$3, "localSortBy", function localSortBy(newValue, oldValue) {
      if (newValue !== oldValue) {
        this.$emit(MODEL_EVENT_NAME_SORT_BY, newValue);
      }
    }), _watch$3),
    created: function created() {
      if (this.isSortable) {
        this.$on(EVENT_NAME_HEAD_CLICKED, this.handleSort);
      }
    },
    methods: {
      // Handlers
      // Need to move from thead-mixin
      handleSort: function handleSort(key, field, event, isFoot) {
        var _this = this;

        if (!this.isSortable) {
          /* istanbul ignore next */
          return;
        }

        if (isFoot && this.noFooterSorting) {
          return;
        } // TODO: make this tri-state sorting
        // cycle desc => asc => none => desc => ...


        var sortChanged = false;

        var toggleLocalSortDesc = function toggleLocalSortDesc() {
          var sortDirection = field.sortDirection || _this.sortDirection;

          if (sortDirection === SORT_DIRECTION_ASC) {
            _this.localSortDesc = false;
          } else if (sortDirection === SORT_DIRECTION_DESC) {
            _this.localSortDesc = true;
          } else ;
        };

        if (field.sortable) {
          var sortKey = !this.localSorting && field.sortKey ? field.sortKey : key;

          if (this.localSortBy === sortKey) {
            // Change sorting direction on current column
            this.localSortDesc = !this.localSortDesc;
          } else {
            // Start sorting this column ascending
            this.localSortBy = sortKey; // this.localSortDesc = false

            toggleLocalSortDesc();
          }

          sortChanged = true;
        } else if (this.localSortBy && !this.noSortReset) {
          this.localSortBy = '';
          toggleLocalSortDesc();
          sortChanged = true;
        }

        if (sortChanged) {
          // Sorting parameters changed
          this.$emit(EVENT_NAME_SORT_CHANGED, this.context);
        }
      },
      // methods to compute classes and attrs for thead>th cells
      sortTheadThClasses: function sortTheadThClasses(key, field, isFoot) {
        return {
          // If sortable and sortIconLeft are true, then place sort icon on the left
          'b-table-sort-icon-left': field.sortable && this.sortIconLeft && !(isFoot && this.noFooterSorting)
        };
      },
      sortTheadThAttrs: function sortTheadThAttrs(key, field, isFoot) {
        var _field$sortKey;

        var isSortable = this.isSortable,
            noFooterSorting = this.noFooterSorting,
            localSortDesc = this.localSortDesc,
            localSortBy = this.localSortBy,
            localSorting = this.localSorting;

        if (!isSortable || isFoot && noFooterSorting) {
          // No attributes if not a sortable table
          return {};
        }

        var sortable = field.sortable;
        var sortKey = !localSorting ? (_field$sortKey = field.sortKey) !== null && _field$sortKey !== void 0 ? _field$sortKey : key : key; // Assemble the aria-sort attribute value

        var ariaSort = sortable && localSortBy === sortKey ? localSortDesc ? 'descending' : 'ascending' : sortable ? 'none' : null; // Return the attribute

        return {
          'aria-sort': ariaSort
        };
      },
      // A label to be placed in an `.sr-only` element in the header cell
      sortTheadThLabel: function sortTheadThLabel(key, field, isFoot) {
        // No label if not a sortable table
        if (!this.isSortable || isFoot && this.noFooterSorting) {
          return null;
        }

        var localSortBy = this.localSortBy,
            localSortDesc = this.localSortDesc,
            labelSortAsc = this.labelSortAsc,
            labelSortDesc = this.labelSortDesc;
        var sortable = field.sortable; // The correctness of these labels is very important for screen reader users

        var labelSorting = '';

        if (sortable) {
          if (localSortBy === key) {
            // Currently sorted sortable column
            labelSorting = localSortDesc ? labelSortAsc : labelSortDesc;
          } else {
            // Not currently sorted sortable column
            // Not using nested ternary's here for clarity/readability
            // Default for `aria-label`
            labelSorting = localSortDesc ? labelSortDesc : labelSortAsc; // Handle `sortDirection` setting

            var sortDirection = this.sortDirection || field.sortDirection;

            if (sortDirection === SORT_DIRECTION_ASC) {
              labelSorting = labelSortAsc;
            } else if (sortDirection === SORT_DIRECTION_DESC) {
              labelSorting = labelSortDesc;
            }
          }
        } else if (!this.noSortReset) {
          // Non sortable column
          labelSorting = localSortBy ? this.labelSortClear : '';
        } // Return the `.sr-only` sort label or `null` if no label


        return trim(labelSorting) || null;
      }
    }
  });

  var props$j = {
    stacked: makeProp(PROP_TYPE_BOOLEAN_STRING, false)
  }; // --- Mixin ---
  // @vue/component

  var stackedMixin = extend({
    props: props$j,
    computed: {
      isStacked: function isStacked() {
        var stacked = this.stacked; // `true` when always stacked, or returns breakpoint specified

        return stacked === '' ? true : stacked;
      },
      isStackedAlways: function isStackedAlways() {
        return this.isStacked === true;
      },
      stackedTableClasses: function stackedTableClasses() {
        var isStackedAlways = this.isStackedAlways;
        return _defineProperty({
          'b-table-stacked': isStackedAlways
        }, "b-table-stacked-".concat(this.stacked), !isStackedAlways && this.isStacked);
      }
    }
  });

  // Includes all main table styling options
  // --- Props ---

  var props$i = {
    bordered: makeProp(PROP_TYPE_BOOLEAN, false),
    borderless: makeProp(PROP_TYPE_BOOLEAN, false),
    captionTop: makeProp(PROP_TYPE_BOOLEAN, false),
    dark: makeProp(PROP_TYPE_BOOLEAN, false),
    fixed: makeProp(PROP_TYPE_BOOLEAN, false),
    hover: makeProp(PROP_TYPE_BOOLEAN, false),
    noBorderCollapse: makeProp(PROP_TYPE_BOOLEAN, false),
    outlined: makeProp(PROP_TYPE_BOOLEAN, false),
    responsive: makeProp(PROP_TYPE_BOOLEAN_STRING, false),
    small: makeProp(PROP_TYPE_BOOLEAN, false),
    // If a string, it is assumed to be the table `max-height` value
    stickyHeader: makeProp(PROP_TYPE_BOOLEAN_STRING, false),
    striped: makeProp(PROP_TYPE_BOOLEAN, false),
    tableClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    tableVariant: makeProp(PROP_TYPE_STRING)
  }; // --- Mixin ---
  // @vue/component

  var tableRendererMixin = extend({
    mixins: [attrsMixin],
    provide: function provide() {
      var _this = this;

      return {
        getBvTable: function getBvTable() {
          return _this;
        }
      };
    },
    // Don't place attributes on root element automatically,
    // as table could be wrapped in responsive `<div>`
    inheritAttrs: false,
    props: props$i,
    computed: {
      isTableSimple: function isTableSimple() {
        return false;
      },
      // Layout related computed props
      isResponsive: function isResponsive() {
        var responsive = this.responsive;
        return responsive === '' ? true : responsive;
      },
      isStickyHeader: function isStickyHeader() {
        var stickyHeader = this.stickyHeader;
        stickyHeader = stickyHeader === '' ? true : stickyHeader;
        return this.isStacked ? false : stickyHeader;
      },
      wrapperClasses: function wrapperClasses() {
        var isResponsive = this.isResponsive;
        return [this.isStickyHeader ? 'b-table-sticky-header' : '', isResponsive === true ? 'table-responsive' : isResponsive ? "table-responsive-".concat(this.responsive) : ''].filter(identity);
      },
      wrapperStyles: function wrapperStyles() {
        var isStickyHeader = this.isStickyHeader;
        return isStickyHeader && !isBoolean(isStickyHeader) ? {
          maxHeight: isStickyHeader
        } : {};
      },
      tableClasses: function tableClasses() {
        var _safeVueInstance = safeVueInstance(this),
            hover = _safeVueInstance.hover,
            tableVariant = _safeVueInstance.tableVariant,
            selectableTableClasses = _safeVueInstance.selectableTableClasses,
            stackedTableClasses = _safeVueInstance.stackedTableClasses,
            tableClass = _safeVueInstance.tableClass,
            computedBusy = _safeVueInstance.computedBusy;

        hover = this.isTableSimple ? hover : hover && this.computedItems.length > 0 && !computedBusy;
        return [// User supplied classes
        tableClass, // Styling classes
        {
          'table-striped': this.striped,
          'table-hover': hover,
          'table-dark': this.dark,
          'table-bordered': this.bordered,
          'table-borderless': this.borderless,
          'table-sm': this.small,
          // The following are b-table custom styles
          border: this.outlined,
          'b-table-fixed': this.fixed,
          'b-table-caption-top': this.captionTop,
          'b-table-no-border-collapse': this.noBorderCollapse
        }, tableVariant ? "".concat(this.dark ? 'bg' : 'table', "-").concat(tableVariant) : '', // Stacked table classes
        stackedTableClasses, // Selectable classes
        selectableTableClasses];
      },
      tableAttrs: function tableAttrs() {
        var _safeVueInstance2 = safeVueInstance(this),
            items = _safeVueInstance2.computedItems,
            filteredItems = _safeVueInstance2.filteredItems,
            fields = _safeVueInstance2.computedFields,
            selectableTableAttrs = _safeVueInstance2.selectableTableAttrs,
            computedBusy = _safeVueInstance2.computedBusy;

        var ariaAttrs = this.isTableSimple ? {} : {
          'aria-busy': toString(computedBusy),
          'aria-colcount': toString(fields.length),
          // Preserve user supplied `aria-describedby`, if provided
          'aria-describedby': this.bvAttrs['aria-describedby'] || this.$refs.caption ? this.captionId : null
        };
        var rowCount = items && filteredItems && filteredItems.length > items.length ? toString(filteredItems.length) : null;
        return _objectSpread2$3(_objectSpread2$3(_objectSpread2$3({
          // We set `aria-rowcount` before merging in `$attrs`,
          // in case user has supplied their own
          'aria-rowcount': rowCount
        }, this.bvAttrs), {}, {
          // Now we can override any `$attrs` here
          id: this.safeId(),
          role: this.bvAttrs.role || 'table'
        }, ariaAttrs), selectableTableAttrs);
      }
    },
    render: function render(h) {
      var _safeVueInstance3 = safeVueInstance(this),
          wrapperClasses = _safeVueInstance3.wrapperClasses,
          renderCaption = _safeVueInstance3.renderCaption,
          renderColgroup = _safeVueInstance3.renderColgroup,
          renderThead = _safeVueInstance3.renderThead,
          renderTbody = _safeVueInstance3.renderTbody,
          renderTfoot = _safeVueInstance3.renderTfoot;

      var $content = [];

      if (this.isTableSimple) {
        $content.push(this.normalizeSlot());
      } else {
        // Build the `<caption>` (from caption mixin)
        $content.push(renderCaption ? renderCaption() : null); // Build the `<colgroup>`

        $content.push(renderColgroup ? renderColgroup() : null); // Build the `<thead>`

        $content.push(renderThead ? renderThead() : null); // Build the `<tbody>`

        $content.push(renderTbody ? renderTbody() : null); // Build the `<tfoot>`

        $content.push(renderTfoot ? renderTfoot() : null);
      } // Assemble `<table>`


      var $table = h('table', {
        staticClass: 'table b-table',
        class: this.tableClasses,
        attrs: this.tableAttrs,
        key: 'b-table'
      }, $content.filter(identity)); // Add responsive/sticky wrapper if needed and return table

      return wrapperClasses.length > 0 ? h('div', {
        class: wrapperClasses,
        style: this.wrapperStyles,
        key: 'wrap'
      }, [$table]) : $table;
    }
  });

  var props$h = makePropsConfigurable({
    tbodyTransitionHandlers: makeProp(PROP_TYPE_OBJECT),
    tbodyTransitionProps: makeProp(PROP_TYPE_OBJECT)
  }, NAME_TBODY); // --- Main component ---
  // TODO:
  //   In Bootstrap v5, we won't need "sniffing" as table element variants properly inherit
  //   to the child elements, so this can be converted to a functional component
  // @vue/component

  var BTbody = /*#__PURE__*/extend({
    name: NAME_TBODY,
    mixins: [attrsMixin, listenersMixin, normalizeSlotMixin],
    provide: function provide() {
      var _this = this;

      return {
        getBvTableRowGroup: function getBvTableRowGroup() {
          return _this;
        }
      };
    },
    inject: {
      // Sniffed by `<b-tr>` / `<b-td>` / `<b-th>`
      getBvTable: {
        default:
        /* istanbul ignore next */
        function _default() {
          return function () {
            return {};
          };
        }
      }
    },
    inheritAttrs: false,
    props: props$h,
    computed: {
      bvTable: function bvTable() {
        return this.getBvTable();
      },
      // Sniffed by `<b-tr>` / `<b-td>` / `<b-th>`
      isTbody: function isTbody() {
        return true;
      },
      // Sniffed by `<b-tr>` / `<b-td>` / `<b-th>`
      isDark: function isDark() {
        return this.bvTable.dark;
      },
      // Sniffed by `<b-tr>` / `<b-td>` / `<b-th>`
      isStacked: function isStacked() {
        return this.bvTable.isStacked;
      },
      // Sniffed by `<b-tr>` / `<b-td>` / `<b-th>`
      isResponsive: function isResponsive() {
        return this.bvTable.isResponsive;
      },
      // Sniffed by `<b-tr>` / `<b-td>` / `<b-th>`
      // Sticky headers are only supported in thead
      isStickyHeader: function isStickyHeader() {
        return false;
      },
      // Sniffed by `<b-tr>` / `<b-td>` / `<b-th>`
      // Needed to handle header background classes, due to lack of
      // background color inheritance with Bootstrap v4 table CSS
      hasStickyHeader: function hasStickyHeader() {
        return !this.isStacked && this.bvTable.stickyHeader;
      },
      // Sniffed by `<b-tr>` / `<b-td>` / `<b-th>`
      tableVariant: function tableVariant() {
        return this.bvTable.tableVariant;
      },
      isTransitionGroup: function isTransitionGroup() {
        return this.tbodyTransitionProps || this.tbodyTransitionHandlers;
      },
      tbodyAttrs: function tbodyAttrs() {
        return _objectSpread2$3({
          role: 'rowgroup'
        }, this.bvAttrs);
      },
      tbodyProps: function tbodyProps() {
        var tbodyTransitionProps = this.tbodyTransitionProps;
        return tbodyTransitionProps ? _objectSpread2$3(_objectSpread2$3({}, tbodyTransitionProps), {}, {
          tag: 'tbody'
        }) : {};
      }
    },
    render: function render(h) {
      var data = {
        props: this.tbodyProps,
        attrs: this.tbodyAttrs
      };

      if (this.isTransitionGroup) {
        // We use native listeners if a transition group for any delegated events
        data.on = this.tbodyTransitionHandlers || {};
        data.nativeOn = this.bvListeners;
      } else {
        // Otherwise we place any listeners on the tbody element
        data.on = this.bvListeners;
      }

      return h(this.isTransitionGroup ? 'transition-group' : 'tbody', data, this.normalizeSlot());
    }
  });

  var TABLE_TAG_NAMES = ['TD', 'TH', 'TR']; // Returns `true` if we should ignore the click/double-click/keypress event
  // Avoids having the user need to use `@click.stop` on the form control

  var filterEvent = function filterEvent(event) {
    // Exit early when we don't have a target element
    if (!event || !event.target) {
      /* istanbul ignore next */
      return false;
    }

    var el = event.target; // Exit early when element is disabled or a table element

    if (el.disabled || TABLE_TAG_NAMES.indexOf(el.tagName) !== -1) {
      return false;
    } // Ignore the click when it was inside a dropdown menu


    if (closest('.dropdown-menu', el)) {
      return true;
    }

    var label = el.tagName === 'LABEL' ? el : closest('label', el); // If the label's form control is not disabled then we don't propagate event
    // Modern browsers have `label.control` that references the associated input, but IE 11
    // does not have this property on the label element, so we resort to DOM lookups

    if (label) {
      var labelFor = getAttr(label, 'for');
      var input = labelFor ? getById(labelFor) : select('input, select, textarea', label);

      if (input && !input.disabled) {
        return true;
      }
    } // Otherwise check if the event target matches one of the selectors in the
    // event filter (i.e. anchors, non disabled inputs, etc.)
    // Return `true` if we should ignore the event


    return matches(el, EVENT_FILTER);
  };

  // Used to filter out click events caused by the mouse up at end of selection
  //
  // Accepts an element as only argument to test to see if selection overlaps or is
  // contained within the element

  var textSelectionActive = function textSelectionActive() {
    var el = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : document;
    var sel = getSel();
    return sel && sel.toString().trim() !== '' && sel.containsNode && isElement(el) ?
    /* istanbul ignore next */
    sel.containsNode(el, true) : false;
  };

  var props$g = makePropsConfigurable(props$u, NAME_TH); // --- Main component ---
  // TODO:
  //   In Bootstrap v5, we won't need "sniffing" as table element variants properly inherit
  //   to the child elements, so this can be converted to a functional component
  // @vue/component

  var BTh = /*#__PURE__*/extend({
    name: NAME_TH,
    extends: BTd,
    props: props$g,
    computed: {
      tag: function tag() {
        return 'th';
      }
    }
  });

  var props$f = {
    detailsTdClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    tbodyTrAttr: makeProp(PROP_TYPE_OBJECT_FUNCTION),
    tbodyTrClass: makeProp([].concat(_toConsumableArray$1(PROP_TYPE_ARRAY_OBJECT_STRING), [PROP_TYPE_FUNCTION]))
  }; // --- Mixin ---
  // @vue/component

  var tbodyRowMixin = extend({
    mixins: [useParentMixin],
    props: props$f,
    methods: {
      // Methods for computing classes, attributes and styles for table cells
      getTdValues: function getTdValues(item, key, tdValue, defaultValue) {
        var bvParent = this.bvParent;

        if (tdValue) {
          var value = get(item, key, '');

          if (isFunction$1(tdValue)) {
            return tdValue(value, key, item);
          } else if (isString(tdValue) && isFunction$1(bvParent[tdValue])) {
            return bvParent[tdValue](value, key, item);
          }

          return tdValue;
        }

        return defaultValue;
      },
      getThValues: function getThValues(item, key, thValue, type, defaultValue) {
        var bvParent = this.bvParent;

        if (thValue) {
          var value = get(item, key, '');

          if (isFunction$1(thValue)) {
            return thValue(value, key, item, type);
          } else if (isString(thValue) && isFunction$1(bvParent[thValue])) {
            return bvParent[thValue](value, key, item, type);
          }

          return thValue;
        }

        return defaultValue;
      },
      // Method to get the value for a field
      getFormattedValue: function getFormattedValue(item, field) {
        var key = field.key;
        var formatter = this.getFieldFormatter(key);
        var value = get(item, key, null);

        if (isFunction$1(formatter)) {
          value = formatter(value, key, item);
        }

        return isUndefinedOrNull(value) ? '' : value;
      },
      // Factory function methods
      toggleDetailsFactory: function toggleDetailsFactory(hasDetailsSlot, item) {
        var _this = this;

        // Returns a function to toggle a row's details slot
        return function () {
          if (hasDetailsSlot) {
            _this.$set(item, FIELD_KEY_SHOW_DETAILS, !item[FIELD_KEY_SHOW_DETAILS]);
          }
        };
      },
      // Row event handlers
      rowHovered: function rowHovered(event) {
        // `mouseenter` handler (non-bubbling)
        // `this.tbodyRowEventStopped` from tbody mixin
        if (!this.tbodyRowEventStopped(event)) {
          // `this.emitTbodyRowEvent` from tbody mixin
          this.emitTbodyRowEvent(EVENT_NAME_ROW_HOVERED, event);
        }
      },
      rowUnhovered: function rowUnhovered(event) {
        // `mouseleave` handler (non-bubbling)
        // `this.tbodyRowEventStopped` from tbody mixin
        if (!this.tbodyRowEventStopped(event)) {
          // `this.emitTbodyRowEvent` from tbody mixin
          this.emitTbodyRowEvent(EVENT_NAME_ROW_UNHOVERED, event);
        }
      },
      // Renders a TD or TH for a row's field
      renderTbodyRowCell: function renderTbodyRowCell(field, colIndex, item, rowIndex) {
        var _this2 = this;

        var isStacked = this.isStacked;
        var key = field.key,
            label = field.label,
            isRowHeader = field.isRowHeader;
        var h = this.$createElement;
        var hasDetailsSlot = this.hasNormalizedSlot(SLOT_NAME_ROW_DETAILS);
        var formatted = this.getFormattedValue(item, field);
        var stickyColumn = !isStacked && (this.isResponsive || this.stickyHeader) && field.stickyColumn; // We only uses the helper components for sticky columns to
        // improve performance of BTable/BTableLite by reducing the
        // total number of vue instances created during render

        var cellTag = stickyColumn ? isRowHeader ? BTh : BTd : isRowHeader ? 'th' : 'td';
        var cellVariant = item[FIELD_KEY_CELL_VARIANT] && item[FIELD_KEY_CELL_VARIANT][key] ? item[FIELD_KEY_CELL_VARIANT][key] : field.variant || null;
        var data = {
          // For the Vue key, we concatenate the column index and
          // field key (as field keys could be duplicated)
          // TODO: Although we do prevent duplicate field keys...
          //   So we could change this to: `row-${rowIndex}-cell-${key}`
          class: [field.class ? field.class : '', this.getTdValues(item, key, field.tdClass, '')],
          props: {},
          attrs: _objectSpread2$3({
            'aria-colindex': String(colIndex + 1)
          }, isRowHeader ? this.getThValues(item, key, field.thAttr, 'row', {}) : this.getTdValues(item, key, field.tdAttr, {})),
          key: "row-".concat(rowIndex, "-cell-").concat(colIndex, "-").concat(key)
        };

        if (stickyColumn) {
          // We are using the helper BTd or BTh
          data.props = {
            stackedHeading: isStacked ? label : null,
            stickyColumn: true,
            variant: cellVariant
          };
        } else {
          // Using native TD or TH element, so we need to
          // add in the attributes and variant class
          data.attrs['data-label'] = isStacked && !isUndefinedOrNull(label) ? toString(label) : null;
          data.attrs.role = isRowHeader ? 'rowheader' : 'cell';
          data.attrs.scope = isRowHeader ? 'row' : null; // Add in the variant class

          if (cellVariant) {
            data.class.push("".concat(this.dark ? 'bg' : 'table', "-").concat(cellVariant));
          }
        }

        var slotScope = {
          item: item,
          index: rowIndex,
          field: field,
          unformatted: get(item, key, ''),
          value: formatted,
          toggleDetails: this.toggleDetailsFactory(hasDetailsSlot, item),
          detailsShowing: Boolean(item[FIELD_KEY_SHOW_DETAILS])
        }; // If table supports selectable mode, then add in the following scope
        // this.supportsSelectableRows will be undefined if mixin isn't loaded

        if (safeVueInstance(this).supportsSelectableRows) {
          slotScope.rowSelected = this.isRowSelected(rowIndex);

          slotScope.selectRow = function () {
            return _this2.selectRow(rowIndex);
          };

          slotScope.unselectRow = function () {
            return _this2.unselectRow(rowIndex);
          };
        } // The new `v-slot` syntax doesn't like a slot name starting with
        // a square bracket and if using in-document HTML templates, the
        // v-slot attributes are lower-cased by the browser.
        // Switched to round bracket syntax to prevent confusion with
        // dynamic slot name syntax.
        // We look for slots in this order: `cell(${key})`, `cell(${key.toLowerCase()})`, 'cell()'
        // Slot names are now cached by mixin tbody in `this.$_bodyFieldSlotNameCache`
        // Will be `null` if no slot (or fallback slot) exists


        var slotName = this.$_bodyFieldSlotNameCache[key];
        var $childNodes = slotName ? this.normalizeSlot(slotName, slotScope) : toString(formatted);

        if (this.isStacked) {
          // We wrap in a DIV to ensure rendered as a single cell when visually stacked!
          $childNodes = [h('div', [$childNodes])];
        } // Render either a td or th cell


        return h(cellTag, data, [$childNodes]);
      },
      // Renders an item's row (or rows if details supported)
      renderTbodyRow: function renderTbodyRow(item, rowIndex) {
        var _this3 = this;

        var _safeVueInstance = safeVueInstance(this),
            fields = _safeVueInstance.computedFields,
            striped = _safeVueInstance.striped,
            primaryKey = _safeVueInstance.primaryKey,
            currentPage = _safeVueInstance.currentPage,
            perPage = _safeVueInstance.perPage,
            tbodyTrClass = _safeVueInstance.tbodyTrClass,
            tbodyTrAttr = _safeVueInstance.tbodyTrAttr,
            hasSelectableRowClick = _safeVueInstance.hasSelectableRowClick;

        var h = this.$createElement;
        var hasDetailsSlot = this.hasNormalizedSlot(SLOT_NAME_ROW_DETAILS);
        var rowShowDetails = item[FIELD_KEY_SHOW_DETAILS] && hasDetailsSlot;
        var hasRowClickHandler = this.$listeners[EVENT_NAME_ROW_CLICKED] || hasSelectableRowClick; // We can return more than one TR if rowDetails enabled

        var $rows = []; // Details ID needed for `aria-details` when details showing
        // We set it to `null` when not showing so that attribute
        // does not appear on the element

        var detailsId = rowShowDetails ? this.safeId("_details_".concat(rowIndex, "_")) : null; // For each item data field in row

        var $tds = fields.map(function (field, colIndex) {
          return _this3.renderTbodyRowCell(field, colIndex, item, rowIndex);
        }); // Calculate the row number in the dataset (indexed from 1)

        var ariaRowIndex = null;

        if (currentPage && perPage && perPage > 0) {
          ariaRowIndex = String((currentPage - 1) * perPage + rowIndex + 1);
        } // Create a unique :key to help ensure that sub components are re-rendered rather than
        // re-used, which can cause issues. If a primary key is not provided we use the rendered
        // rows index within the tbody.
        // See: https://github.com/bootstrap-vue/bootstrap-vue/issues/2410


        var primaryKeyValue = toString(get(item, primaryKey)) || null;
        var rowKey = primaryKeyValue || toString(rowIndex); // If primary key is provided, use it to generate a unique ID on each tbody > tr
        // In the format of '{tableId}__row_{primaryKeyValue}'

        var rowId = primaryKeyValue ? this.safeId("_row_".concat(primaryKeyValue)) : null; // Selectable classes and attributes

        var selectableClasses = safeVueInstance(this).selectableRowClasses ? this.selectableRowClasses(rowIndex) : {};
        var selectableAttrs = safeVueInstance(this).selectableRowAttrs ? this.selectableRowAttrs(rowIndex) : {}; // Additional classes and attributes

        var userTrClasses = isFunction$1(tbodyTrClass) ? tbodyTrClass(item, 'row') : tbodyTrClass;
        var userTrAttrs = isFunction$1(tbodyTrAttr) ?
        /* istanbul ignore next */
        tbodyTrAttr(item, 'row') : tbodyTrAttr; // Add the item row

        $rows.push(h(BTr, _defineProperty({
          class: [userTrClasses, selectableClasses, rowShowDetails ? 'b-table-has-details' : ''],
          props: {
            variant: item[FIELD_KEY_ROW_VARIANT] || null
          },
          attrs: _objectSpread2$3(_objectSpread2$3({
            id: rowId
          }, userTrAttrs), {}, {
            // Users cannot override the following attributes
            tabindex: hasRowClickHandler ? '0' : null,
            'data-pk': primaryKeyValue || null,
            'aria-details': detailsId,
            'aria-owns': detailsId,
            'aria-rowindex': ariaRowIndex
          }, selectableAttrs),
          on: {
            // Note: These events are not A11Y friendly!
            mouseenter: this.rowHovered,
            mouseleave: this.rowUnhovered
          },
          key: "__b-table-row-".concat(rowKey, "__"),
          ref: 'item-rows'
        }, REF_FOR_KEY, true), $tds)); // Row Details slot

        if (rowShowDetails) {
          var detailsScope = {
            item: item,
            index: rowIndex,
            fields: fields,
            toggleDetails: this.toggleDetailsFactory(hasDetailsSlot, item)
          }; // If table supports selectable mode, then add in the following scope
          // this.supportsSelectableRows will be undefined if mixin isn't loaded

          if (safeVueInstance(this).supportsSelectableRows) {
            detailsScope.rowSelected = this.isRowSelected(rowIndex);

            detailsScope.selectRow = function () {
              return _this3.selectRow(rowIndex);
            };

            detailsScope.unselectRow = function () {
              return _this3.unselectRow(rowIndex);
            };
          } // Render the details slot in a TD


          var $details = h(BTd, {
            props: {
              colspan: fields.length
            },
            class: this.detailsTdClass
          }, [this.normalizeSlot(SLOT_NAME_ROW_DETAILS, detailsScope)]); // Add a hidden row to keep table row striping consistent when details showing
          // Only added if the table is striped

          if (striped) {
            $rows.push( // We don't use `BTr` here as we don't need the extra functionality
            h('tr', {
              staticClass: 'd-none',
              attrs: {
                'aria-hidden': 'true',
                role: 'presentation'
              },
              key: "__b-table-details-stripe__".concat(rowKey)
            }));
          } // Add the actual details row


          var userDetailsTrClasses = isFunction$1(this.tbodyTrClass) ?
          /* istanbul ignore next */
          this.tbodyTrClass(item, SLOT_NAME_ROW_DETAILS) : this.tbodyTrClass;
          var userDetailsTrAttrs = isFunction$1(this.tbodyTrAttr) ?
          /* istanbul ignore next */
          this.tbodyTrAttr(item, SLOT_NAME_ROW_DETAILS) : this.tbodyTrAttr;
          $rows.push(h(BTr, {
            staticClass: 'b-table-details',
            class: [userDetailsTrClasses],
            props: {
              variant: item[FIELD_KEY_ROW_VARIANT] || null
            },
            attrs: _objectSpread2$3(_objectSpread2$3({}, userDetailsTrAttrs), {}, {
              // Users cannot override the following attributes
              id: detailsId,
              tabindex: '-1'
            }),
            key: "__b-table-details__".concat(rowKey)
          }, [$details]));
        } else if (hasDetailsSlot) {
          // Only add the placeholder if a the table has a row-details slot defined (but not shown)
          $rows.push(h());

          if (striped) {
            // Add extra placeholder if table is striped
            $rows.push(h());
          }
        } // Return the row(s)


        return $rows;
      }
    }
  });

  var getCellSlotName = function getCellSlotName(value) {
    return "cell(".concat(value || '', ")");
  }; // --- Props ---


  var props$e = sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$h), props$f), {}, {
    tbodyClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING)
  })); // --- Mixin ---
  // @vue/component

  var tbodyMixin = extend({
    mixins: [tbodyRowMixin],
    props: props$e,
    beforeDestroy: function beforeDestroy() {
      this.$_bodyFieldSlotNameCache = null;
    },
    methods: {
      // Returns all the item TR elements (excludes detail and spacer rows)
      // `this.$refs['item-rows']` is an array of item TR components/elements
      // Rows should all be `<b-tr>` components, but we map to TR elements
      // Also note that `this.$refs['item-rows']` may not always be in document order
      getTbodyTrs: function getTbodyTrs() {
        var $refs = this.$refs;
        var tbody = $refs.tbody ? $refs.tbody.$el || $refs.tbody : null;
        var trs = ($refs['item-rows'] || []).map(function (tr) {
          return tr.$el || tr;
        });
        return tbody && tbody.children && tbody.children.length > 0 && trs && trs.length > 0 ? from(tbody.children).filter(function (tr) {
          return arrayIncludes(trs, tr);
        }) :
        /* istanbul ignore next */
        [];
      },
      // Returns index of a particular TBODY item TR
      // We set `true` on closest to include self in result
      getTbodyTrIndex: function getTbodyTrIndex(el) {
        /* istanbul ignore next: should not normally happen */
        if (!isElement(el)) {
          return -1;
        }

        var tr = el.tagName === 'TR' ? el : closest('tr', el, true);
        return tr ? this.getTbodyTrs().indexOf(tr) : -1;
      },
      // Emits a row event, with the item object, row index and original event
      emitTbodyRowEvent: function emitTbodyRowEvent(type, event) {
        if (type && this.hasListener(type) && event && event.target) {
          var rowIndex = this.getTbodyTrIndex(event.target);

          if (rowIndex > -1) {
            // The array of TRs correlate to the `computedItems` array
            var item = this.computedItems[rowIndex];
            this.$emit(type, item, rowIndex, event);
          }
        }
      },
      tbodyRowEventStopped: function tbodyRowEventStopped(event) {
        return this.stopIfBusy && this.stopIfBusy(event);
      },
      // Delegated row event handlers
      onTbodyRowKeydown: function onTbodyRowKeydown(event) {
        // Keyboard navigation and row click emulation
        var target = event.target,
            keyCode = event.keyCode;

        if (this.tbodyRowEventStopped(event) || target.tagName !== 'TR' || !isActiveElement(target) || target.tabIndex !== 0) {
          // Early exit if not an item row TR
          return;
        }

        if (arrayIncludes([CODE_ENTER, CODE_SPACE], keyCode)) {
          // Emulated click for keyboard users, transfer to click handler
          stopEvent(event);
          this.onTBodyRowClicked(event);
        } else if (arrayIncludes([CODE_UP, CODE_DOWN, CODE_HOME, CODE_END], keyCode)) {
          // Keyboard navigation
          var rowIndex = this.getTbodyTrIndex(target);

          if (rowIndex > -1) {
            stopEvent(event);
            var trs = this.getTbodyTrs();
            var shift = event.shiftKey;

            if (keyCode === CODE_HOME || shift && keyCode === CODE_UP) {
              // Focus first row
              attemptFocus(trs[0]);
            } else if (keyCode === CODE_END || shift && keyCode === CODE_DOWN) {
              // Focus last row
              attemptFocus(trs[trs.length - 1]);
            } else if (keyCode === CODE_UP && rowIndex > 0) {
              // Focus previous row
              attemptFocus(trs[rowIndex - 1]);
            } else if (keyCode === CODE_DOWN && rowIndex < trs.length - 1) {
              // Focus next row
              attemptFocus(trs[rowIndex + 1]);
            }
          }
        }
      },
      onTBodyRowClicked: function onTBodyRowClicked(event) {
        var $refs = this.$refs;
        var tbody = $refs.tbody ? $refs.tbody.$el || $refs.tbody : null; // Don't emit event when the table is busy, the user clicked
        // on a non-disabled control or is selecting text

        if (this.tbodyRowEventStopped(event) || filterEvent(event) || textSelectionActive(tbody || this.$el)) {
          return;
        }

        this.emitTbodyRowEvent(EVENT_NAME_ROW_CLICKED, event);
      },
      onTbodyRowMiddleMouseRowClicked: function onTbodyRowMiddleMouseRowClicked(event) {
        if (!this.tbodyRowEventStopped(event) && event.which === 2) {
          this.emitTbodyRowEvent(EVENT_NAME_ROW_MIDDLE_CLICKED, event);
        }
      },
      onTbodyRowContextmenu: function onTbodyRowContextmenu(event) {
        if (!this.tbodyRowEventStopped(event)) {
          this.emitTbodyRowEvent(EVENT_NAME_ROW_CONTEXTMENU, event);
        }
      },
      onTbodyRowDblClicked: function onTbodyRowDblClicked(event) {
        if (!this.tbodyRowEventStopped(event) && !filterEvent(event)) {
          this.emitTbodyRowEvent(EVENT_NAME_ROW_DBLCLICKED, event);
        }
      },
      // Render the tbody element and children
      // Note:
      //   Row hover handlers are handled by the tbody-row mixin
      //   As mouseenter/mouseleave events do not bubble
      renderTbody: function renderTbody() {
        var _this = this;

        var _safeVueInstance = safeVueInstance(this),
            items = _safeVueInstance.computedItems,
            renderBusy = _safeVueInstance.renderBusy,
            renderTopRow = _safeVueInstance.renderTopRow,
            renderEmpty = _safeVueInstance.renderEmpty,
            renderBottomRow = _safeVueInstance.renderBottomRow,
            hasSelectableRowClick = _safeVueInstance.hasSelectableRowClick;

        var h = this.$createElement;
        var hasRowClickHandler = this.hasListener(EVENT_NAME_ROW_CLICKED) || hasSelectableRowClick; // Prepare the tbody rows

        var $rows = []; // Add the item data rows or the busy slot

        var $busy = renderBusy ? renderBusy() : null;

        if ($busy) {
          // If table is busy and a busy slot, then return only the busy "row" indicator
          $rows.push($busy);
        } else {
          // Table isn't busy, or we don't have a busy slot
          // Create a slot cache for improved performance when looking up cell slot names
          // Values will be keyed by the field's `key` and will store the slot's name
          // Slots could be dynamic (i.e. `v-if`), so we must compute on each render
          // Used by tbody-row mixin render helper
          var cache = {};
          var defaultSlotName = getCellSlotName();
          defaultSlotName = this.hasNormalizedSlot(defaultSlotName) ? defaultSlotName : null;
          this.computedFields.forEach(function (field) {
            var key = field.key;
            var slotName = getCellSlotName(key);
            var lowercaseSlotName = getCellSlotName(key.toLowerCase());
            cache[key] = _this.hasNormalizedSlot(slotName) ? slotName : _this.hasNormalizedSlot(lowercaseSlotName) ?
            /* istanbul ignore next */
            lowercaseSlotName : defaultSlotName;
          }); // Created as a non-reactive property so to not trigger component updates
          // Must be a fresh object each render

          this.$_bodyFieldSlotNameCache = cache; // Add static top row slot (hidden in visibly stacked mode
          // as we can't control `data-label` attr)

          $rows.push(renderTopRow ? renderTopRow() : h()); // Render the rows

          items.forEach(function (item, rowIndex) {
            // Render the individual item row (rows if details slot)
            $rows.push(_this.renderTbodyRow(item, rowIndex));
          }); // Empty items / empty filtered row slot (only shows if `items.length < 1`)

          $rows.push(renderEmpty ? renderEmpty() : h()); // Static bottom row slot (hidden in visibly stacked mode
          // as we can't control `data-label` attr)

          $rows.push(renderBottomRow ? renderBottomRow() : h());
        } // Note: these events will only emit if a listener is registered


        var handlers = {
          auxclick: this.onTbodyRowMiddleMouseRowClicked,
          // TODO:
          //   Perhaps we do want to automatically prevent the
          //   default context menu from showing if there is a
          //   `row-contextmenu` listener registered
          contextmenu: this.onTbodyRowContextmenu,
          // The following event(s) is not considered A11Y friendly
          dblclick: this.onTbodyRowDblClicked // Hover events (`mouseenter`/`mouseleave`) are handled by `tbody-row` mixin

        }; // Add in click/keydown listeners if needed

        if (hasRowClickHandler) {
          handlers.click = this.onTBodyRowClicked;
          handlers.keydown = this.onTbodyRowKeydown;
        } // Assemble rows into the tbody


        var $tbody = h(BTbody, {
          class: this.tbodyClass || null,
          props: pluckProps(props$h, this.$props),
          // BTbody transfers all native event listeners to the root element
          // TODO: Only set the handlers if the table is not busy
          on: handlers,
          ref: 'tbody'
        }, $rows); // Return the assembled tbody

        return $tbody;
      }
    }
  });

  var props$d = makePropsConfigurable({
    // Supported values: 'lite', 'dark', or null
    footVariant: makeProp(PROP_TYPE_STRING)
  }, NAME_TFOOT); // --- Main component ---
  // TODO:
  //   In Bootstrap v5, we won't need "sniffing" as table element variants properly inherit
  //   to the child elements, so this can be converted to a functional component
  // @vue/component

  var BTfoot = /*#__PURE__*/extend({
    name: NAME_TFOOT,
    mixins: [attrsMixin, listenersMixin, normalizeSlotMixin],
    provide: function provide() {
      var _this = this;

      return {
        getBvTableRowGroup: function getBvTableRowGroup() {
          return _this;
        }
      };
    },
    inject: {
      // Sniffed by `<b-tr>` / `<b-td>` / `<b-th>`
      getBvTable: {
        default:
        /* istanbul ignore next */
        function _default() {
          return function () {
            return {};
          };
        }
      }
    },
    inheritAttrs: false,
    props: props$d,
    computed: {
      bvTable: function bvTable() {
        return this.getBvTable();
      },
      // Sniffed by `<b-tr>` / `<b-td>` / `<b-th>`
      isTfoot: function isTfoot() {
        return true;
      },
      // Sniffed by `<b-tr>` / `<b-td>` / `<b-th>`
      isDark: function isDark() {
        return this.bvTable.dark;
      },
      // Sniffed by `<b-tr>` / `<b-td>` / `<b-th>`
      isStacked: function isStacked() {
        return this.bvTable.isStacked;
      },
      // Sniffed by `<b-tr>` / `<b-td>` / `<b-th>`
      isResponsive: function isResponsive() {
        return this.bvTable.isResponsive;
      },
      // Sniffed by `<b-tr>` / `<b-td>` / `<b-th>`
      // Sticky headers are only supported in thead
      isStickyHeader: function isStickyHeader() {
        return false;
      },
      // Sniffed by `<b-tr>` / `<b-td>` / `<b-th>`
      // Needed to handle header background classes, due to lack of
      // background color inheritance with Bootstrap v4 table CSS
      hasStickyHeader: function hasStickyHeader() {
        return !this.isStacked && this.bvTable.stickyHeader;
      },
      // Sniffed by `<b-tr>` / `<b-td>` / `<b-th>`
      tableVariant: function tableVariant() {
        return this.bvTable.tableVariant;
      },
      tfootClasses: function tfootClasses() {
        return [this.footVariant ? "thead-".concat(this.footVariant) : null];
      },
      tfootAttrs: function tfootAttrs() {
        return _objectSpread2$3(_objectSpread2$3({}, this.bvAttrs), {}, {
          role: 'rowgroup'
        });
      }
    },
    render: function render(h) {
      return h('tfoot', {
        class: this.tfootClasses,
        attrs: this.tfootAttrs,
        // Pass down any native listeners
        on: this.bvListeners
      }, this.normalizeSlot());
    }
  });

  var props$c = {
    footClone: makeProp(PROP_TYPE_BOOLEAN, false),
    // Any Bootstrap theme variant (or custom)
    // Falls back to `headRowVariant`
    footRowVariant: makeProp(PROP_TYPE_STRING),
    // 'dark', 'light', or `null` (or custom)
    footVariant: makeProp(PROP_TYPE_STRING),
    tfootClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    tfootTrClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING)
  }; // --- Mixin ---
  // @vue/component

  var tfootMixin = extend({
    props: props$c,
    methods: {
      renderTFootCustom: function renderTFootCustom() {
        var h = this.$createElement;

        if (this.hasNormalizedSlot(SLOT_NAME_CUSTOM_FOOT)) {
          return h(BTfoot, {
            class: this.tfootClass || null,
            props: {
              footVariant: this.footVariant || this.headVariant || null
            },
            key: 'bv-tfoot-custom'
          }, this.normalizeSlot(SLOT_NAME_CUSTOM_FOOT, {
            items: this.computedItems.slice(),
            fields: this.computedFields.slice(),
            columns: this.computedFields.length
          }));
        }

        return h();
      },
      renderTfoot: function renderTfoot() {
        // Passing true to renderThead will make it render a tfoot
        return this.footClone ? this.renderThead(true) : this.renderTFootCustom();
      }
    }
  });

  var props$b = makePropsConfigurable({
    // Also sniffed by `<b-tr>` / `<b-td>` / `<b-th>`
    // Supported values: 'lite', 'dark', or `null`
    headVariant: makeProp(PROP_TYPE_STRING)
  }, NAME_THEAD); // --- Main component ---
  // TODO:
  //   In Bootstrap v5, we won't need "sniffing" as table element variants properly inherit
  //   to the child elements, so this can be converted to a functional component
  // @vue/component

  var BThead = /*#__PURE__*/extend({
    name: NAME_THEAD,
    mixins: [attrsMixin, listenersMixin, normalizeSlotMixin],
    provide: function provide() {
      var _this = this;

      return {
        getBvTableRowGroup: function getBvTableRowGroup() {
          return _this;
        }
      };
    },
    inject: {
      // Sniffed by `<b-tr>` / `<b-td>` / `<b-th>`
      getBvTable: {
        default:
        /* istanbul ignore next */
        function _default() {
          return function () {
            return {};
          };
        }
      }
    },
    inheritAttrs: false,
    props: props$b,
    computed: {
      bvTable: function bvTable() {
        return this.getBvTable();
      },
      // Sniffed by `<b-tr>` / `<b-td>` / `<b-th>`
      isThead: function isThead() {
        return true;
      },
      // Sniffed by `<b-tr>` / `<b-td>` / `<b-th>`
      isDark: function isDark() {
        return this.bvTable.dark;
      },
      // Sniffed by `<b-tr>` / `<b-td>` / `<b-th>`
      isStacked: function isStacked() {
        return this.bvTable.isStacked;
      },
      // Sniffed by `<b-tr>` / `<b-td>` / `<b-th>`
      isResponsive: function isResponsive() {
        return this.bvTable.isResponsive;
      },
      // Sniffed by `<b-tr>` / `<b-td>` / `<b-th>`
      // Needed to handle header background classes, due to lack of
      // background color inheritance with Bootstrap v4 table CSS
      // Sticky headers only apply to cells in table `thead`
      isStickyHeader: function isStickyHeader() {
        return !this.isStacked && this.bvTable.stickyHeader;
      },
      // Sniffed by `<b-tr>` / `<b-td>` / `<b-th>`
      // Needed to handle header background classes, due to lack of
      // background color inheritance with Bootstrap v4 table CSS
      hasStickyHeader: function hasStickyHeader() {
        return !this.isStacked && this.bvTable.stickyHeader;
      },
      // Sniffed by `<b-tr>` / `<b-td>` / `<b-th>`
      tableVariant: function tableVariant() {
        return this.bvTable.tableVariant;
      },
      theadClasses: function theadClasses() {
        return [this.headVariant ? "thead-".concat(this.headVariant) : null];
      },
      theadAttrs: function theadAttrs() {
        return _objectSpread2$3({
          role: 'rowgroup'
        }, this.bvAttrs);
      }
    },
    render: function render(h) {
      return h('thead', {
        class: this.theadClasses,
        attrs: this.theadAttrs,
        // Pass down any native listeners
        on: this.bvListeners
      }, this.normalizeSlot());
    }
  });

  var getHeadSlotName = function getHeadSlotName(value) {
    return "head(".concat(value || '', ")");
  };

  var getFootSlotName = function getFootSlotName(value) {
    return "foot(".concat(value || '', ")");
  }; // --- Props ---


  var props$a = {
    // Any Bootstrap theme variant (or custom)
    headRowVariant: makeProp(PROP_TYPE_STRING),
    // 'light', 'dark' or `null` (or custom)
    headVariant: makeProp(PROP_TYPE_STRING),
    theadClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    theadTrClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING)
  }; // --- Mixin ---
  // @vue/component

  var theadMixin = extend({
    props: props$a,
    methods: {
      fieldClasses: function fieldClasses(field) {
        // Header field (<th>) classes
        return [field.class ? field.class : '', field.thClass ? field.thClass : ''];
      },
      headClicked: function headClicked(event, field, isFoot) {
        if (this.stopIfBusy && this.stopIfBusy(event)) {
          // If table is busy (via provider) then don't propagate
          return;
        } else if (filterEvent(event)) {
          // Clicked on a non-disabled control so ignore
          return;
        } else if (textSelectionActive(this.$el)) {
          // User is selecting text, so ignore

          /* istanbul ignore next: JSDOM doesn't support getSelection() */
          return;
        }

        stopEvent(event);
        this.$emit(EVENT_NAME_HEAD_CLICKED, field.key, field, event, isFoot);
      },
      renderThead: function renderThead() {
        var _this = this;

        var isFoot = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;

        var _safeVueInstance = safeVueInstance(this),
            fields = _safeVueInstance.computedFields,
            isSortable = _safeVueInstance.isSortable,
            isSelectable = _safeVueInstance.isSelectable,
            headVariant = _safeVueInstance.headVariant,
            footVariant = _safeVueInstance.footVariant,
            headRowVariant = _safeVueInstance.headRowVariant,
            footRowVariant = _safeVueInstance.footRowVariant;

        var h = this.$createElement; // In always stacked mode, we don't bother rendering the head/foot
        // Or if no field headings (empty table)

        if (this.isStackedAlways || fields.length === 0) {
          return h();
        }

        var hasHeadClickListener = isSortable || this.hasListener(EVENT_NAME_HEAD_CLICKED); // Reference to `selectAllRows` and `clearSelected()`, if table is selectable

        var selectAllRows = isSelectable ? this.selectAllRows : noop;
        var clearSelected = isSelectable ? this.clearSelected : noop; // Helper function to generate a field <th> cell

        var makeCell = function makeCell(field, colIndex) {
          var label = field.label,
              labelHtml = field.labelHtml,
              variant = field.variant,
              stickyColumn = field.stickyColumn,
              key = field.key;
          var ariaLabel = null;

          if (!field.label.trim() && !field.headerTitle) {
            // In case field's label and title are empty/blank
            // We need to add a hint about what the column is about for non-sighted users

            /* istanbul ignore next */
            ariaLabel = startCase(field.key);
          }

          var on = {};

          if (hasHeadClickListener) {
            on.click = function (event) {
              _this.headClicked(event, field, isFoot);
            };

            on.keydown = function (event) {
              var keyCode = event.keyCode;

              if (keyCode === CODE_ENTER || keyCode === CODE_SPACE) {
                _this.headClicked(event, field, isFoot);
              }
            };
          }

          var sortAttrs = isSortable ? _this.sortTheadThAttrs(key, field, isFoot) : {};
          var sortClass = isSortable ? _this.sortTheadThClasses(key, field, isFoot) : null;
          var sortLabel = isSortable ? _this.sortTheadThLabel(key, field, isFoot) : null;
          var data = {
            class: [{
              // We need to make the header cell relative when we have
              // a `.sr-only` sort label to work around overflow issues
              'position-relative': sortLabel
            }, _this.fieldClasses(field), sortClass],
            props: {
              variant: variant,
              stickyColumn: stickyColumn
            },
            style: field.thStyle || {},
            attrs: _objectSpread2$3(_objectSpread2$3({
              // We only add a `tabindex` of `0` if there is a head-clicked listener
              // and the current field is sortable
              tabindex: hasHeadClickListener && field.sortable ? '0' : null,
              abbr: field.headerAbbr || null,
              title: field.headerTitle || null,
              'aria-colindex': colIndex + 1,
              'aria-label': ariaLabel
            }, _this.getThValues(null, key, field.thAttr, isFoot ? 'foot' : 'head', {})), sortAttrs),
            on: on,
            key: key
          }; // Handle edge case where in-document templates are used with new
          // `v-slot:name` syntax where the browser lower-cases the v-slot's
          // name (attributes become lower cased when parsed by the browser)
          // We have replaced the square bracket syntax with round brackets
          // to prevent confusion with dynamic slot names

          var slotNames = [getHeadSlotName(key), getHeadSlotName(key.toLowerCase()), getHeadSlotName()]; // Footer will fallback to header slot names

          if (isFoot) {
            slotNames = [getFootSlotName(key), getFootSlotName(key.toLowerCase()), getFootSlotName()].concat(_toConsumableArray$1(slotNames));
          }

          var scope = {
            label: label,
            column: key,
            field: field,
            isFoot: isFoot,
            // Add in row select methods
            selectAllRows: selectAllRows,
            clearSelected: clearSelected
          };
          var $content = _this.normalizeSlot(slotNames, scope) || h('div', {
            domProps: htmlOrText(labelHtml, label)
          });
          var $srLabel = sortLabel ? h('span', {
            staticClass: 'sr-only'
          }, " (".concat(sortLabel, ")")) : null; // Return the header cell

          return h(BTh, data, [$content, $srLabel].filter(identity));
        }; // Generate the array of <th> cells


        var $cells = fields.map(makeCell).filter(identity); // Generate the row(s)

        var $trs = [];

        if (isFoot) {
          $trs.push(h(BTr, {
            class: this.tfootTrClass,
            props: {
              variant: isUndefinedOrNull(footRowVariant) ? headRowVariant :
              /* istanbul ignore next */
              footRowVariant
            }
          }, $cells));
        } else {
          var scope = {
            columns: fields.length,
            fields: fields,
            // Add in row select methods
            selectAllRows: selectAllRows,
            clearSelected: clearSelected
          };
          $trs.push(this.normalizeSlot(SLOT_NAME_THEAD_TOP, scope) || h());
          $trs.push(h(BTr, {
            class: this.theadTrClass,
            props: {
              variant: headRowVariant
            }
          }, $cells));
        }

        return h(isFoot ? BTfoot : BThead, {
          class: (isFoot ? this.tfootClass : this.theadClass) || null,
          props: isFoot ? {
            footVariant: footVariant || headVariant || null
          } : {
            headVariant: headVariant || null
          },
          key: isFoot ? 'bv-tfoot' : 'bv-thead'
        }, $trs);
      }
    }
  });

  var props$9 = {}; // --- Mixin ---
  // @vue/component

  var topRowMixin = extend({
    methods: {
      renderTopRow: function renderTopRow() {
        var fields = this.computedFields,
            stacked = this.stacked,
            tbodyTrClass = this.tbodyTrClass,
            tbodyTrAttr = this.tbodyTrAttr;
        var h = this.$createElement; // Add static Top Row slot (hidden in visibly stacked mode as we can't control the data-label)
        // If in *always* stacked mode, we don't bother rendering the row

        if (!this.hasNormalizedSlot(SLOT_NAME_TOP_ROW) || stacked === true || stacked === '') {
          return h();
        }

        return h(BTr, {
          staticClass: 'b-table-top-row',
          class: [isFunction$1(tbodyTrClass) ? tbodyTrClass(null, 'row-top') : tbodyTrClass],
          attrs: isFunction$1(tbodyTrAttr) ? tbodyTrAttr(null, 'row-top') : tbodyTrAttr,
          key: 'b-top-row'
        }, [this.normalizeSlot(SLOT_NAME_TOP_ROW, {
          columns: fields.length,
          fields: fields
        })]);
      }
    }
  });

  var props$8 = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$25), props$v), props$t), props$s), props$r), props$q), props$p), props$o), props$n), props$m), props$l), props$k), props$j), props$i), props$e), props$c), props$a), props$9)), NAME_TABLE); // --- Main component ---
  // @vue/component

  var BTable = /*#__PURE__*/extend({
    name: NAME_TABLE,
    // Order of mixins is important!
    // They are merged from first to last, followed by this component
    mixins: [// General mixins
    attrsMixin, hasListenerMixin, idMixin, normalizeSlotMixin, // Required table mixins
    itemsMixin, tableRendererMixin, stackedMixin, theadMixin, tfootMixin, tbodyMixin, // Table features mixins
    stackedMixin, filteringMixin, sortingMixin, paginationMixin, captionMixin, colgroupMixin, selectableMixin, emptyMixin, topRowMixin, bottomRowMixin, busyMixin, providerMixin],
    props: props$8 // Render function is provided by `tableRendererMixin`

  });

  var props$7 = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$25), props$s), props$r), props$o), props$j), props$i), props$e), props$c), props$a)), NAME_TABLE_LITE); // --- Main component ---
  // @vue/component

  var BTableLite = /*#__PURE__*/extend({
    name: NAME_TABLE_LITE,
    // Order of mixins is important!
    // They are merged from first to last, followed by this component
    mixins: [// General mixins
    attrsMixin, hasListenerMixin, idMixin, normalizeSlotMixin, // Required table mixins
    itemsMixin, tableRendererMixin, stackedMixin, theadMixin, tfootMixin, tbodyMixin, // Table features mixins
    // These are pretty lightweight, and are useful for lightweight tables
    captionMixin, colgroupMixin],
    props: props$7 // Render function is provided by `tableRendererMixin`

  });

  var props$6 = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$25), props$j), props$i)), NAME_TABLE_SIMPLE); // --- Main component ---
  // @vue/component

  var BTableSimple = /*#__PURE__*/extend({
    name: NAME_TABLE_SIMPLE,
    // Order of mixins is important!
    // They are merged from first to last, followed by this component
    mixins: [// General mixins
    attrsMixin, hasListenerMixin, idMixin, normalizeSlotMixin, // Required table mixins
    tableRendererMixin, // Table features mixins
    // Stacked requires extra handling by users via
    // the table cell `stacked-heading` prop
    stackedMixin],
    props: props$6,
    computed: {
      isTableSimple: function isTableSimple() {
        return true;
      }
    } // Render function is provided by `tableRendererMixin`

  });

  var TableLitePlugin = /*#__PURE__*/pluginFactory({
    components: {
      BTableLite: BTableLite
    }
  });
  var TableSimplePlugin = /*#__PURE__*/pluginFactory({
    components: {
      BTableSimple: BTableSimple,
      BTbody: BTbody,
      BThead: BThead,
      BTfoot: BTfoot,
      BTr: BTr,
      BTd: BTd,
      BTh: BTh
    }
  });
  var TablePlugin = /*#__PURE__*/pluginFactory({
    components: {
      BTable: BTable
    },
    plugins: {
      TableLitePlugin: TableLitePlugin,
      TableSimplePlugin: TableSimplePlugin
    }
  });

  var isPositiveNumber = function isPositiveNumber(value) {
    return value > 0;
  }; // --- Props ---


  var props$5 = makePropsConfigurable({
    animation: makeProp(PROP_TYPE_STRING),
    columns: makeProp(PROP_TYPE_NUMBER, 5, isPositiveNumber),
    hideHeader: makeProp(PROP_TYPE_BOOLEAN, false),
    rows: makeProp(PROP_TYPE_NUMBER, 3, isPositiveNumber),
    showFooter: makeProp(PROP_TYPE_BOOLEAN, false),
    tableProps: makeProp(PROP_TYPE_OBJECT, {})
  }, NAME_SKELETON_TABLE); // --- Main component ---
  // @vue/component

  var BSkeletonTable = /*#__PURE__*/extend({
    name: NAME_SKELETON_TABLE,
    functional: true,
    props: props$5,
    render: function render(h, _ref) {
      var data = _ref.data,
          props = _ref.props;
      var animation = props.animation,
          columns = props.columns;
      var $th = h('th', [h(BSkeleton, {
        props: {
          animation: animation
        }
      })]);
      var $thTr = h('tr', createArray(columns, $th));
      var $td = h('td', [h(BSkeleton, {
        props: {
          width: '75%',
          animation: animation
        }
      })]);
      var $tdTr = h('tr', createArray(columns, $td));
      var $tbody = h('tbody', createArray(props.rows, $tdTr));
      var $thead = !props.hideHeader ? h('thead', [$thTr]) : h();
      var $tfoot = props.showFooter ? h('tfoot', [$thTr]) : h();
      return h(BTableSimple, a(data, {
        props: _objectSpread2$3({}, props.tableProps)
      }), [$thead, $tbody, $tfoot]);
    }
  });

  var props$4 = makePropsConfigurable({
    loading: makeProp(PROP_TYPE_BOOLEAN, false)
  }, NAME_SKELETON_WRAPPER); // --- Main component ---
  // @vue/component

  var BSkeletonWrapper = /*#__PURE__*/extend({
    name: NAME_SKELETON_WRAPPER,
    functional: true,
    props: props$4,
    render: function render(h, _ref) {
      var data = _ref.data,
          props = _ref.props,
          slots = _ref.slots,
          scopedSlots = _ref.scopedSlots;
      var $slots = slots();
      var $scopedSlots = scopedSlots || {};
      var slotScope = {};

      if (props.loading) {
        return h('div', a(data, {
          attrs: {
            role: 'alert',
            'aria-live': 'polite',
            'aria-busy': true
          },
          staticClass: 'b-skeleton-wrapper',
          key: 'loading'
        }), normalizeSlot(SLOT_NAME_LOADING, slotScope, $scopedSlots, $slots));
      }

      return normalizeSlot(SLOT_NAME_DEFAULT, slotScope, $scopedSlots, $slots);
    }
  });

  var SkeletonPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BSkeleton: BSkeleton,
      BSkeletonIcon: BSkeletonIcon,
      BSkeletonImg: BSkeletonImg,
      BSkeletonTable: BSkeletonTable,
      BSkeletonWrapper: BSkeletonWrapper
    }
  });

  var SpinnerPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BSpinner: BSpinner
    }
  });

  var _watch$2;

  var _makeModelMixin$1 = makeModelMixin('value', {
    type: PROP_TYPE_NUMBER
  }),
      modelMixin$1 = _makeModelMixin$1.mixin,
      modelProps$1 = _makeModelMixin$1.props,
      MODEL_PROP_NAME$1 = _makeModelMixin$1.prop,
      MODEL_EVENT_NAME$1 = _makeModelMixin$1.event; // --- Helper methods ---
  // Filter function to filter out disabled tabs


  var notDisabled = function notDisabled(tab) {
    return !tab.disabled;
  }; // --- Helper components ---
  // @vue/component


  var BVTabButton = /*#__PURE__*/extend({
    name: NAME_TAB_BUTTON_HELPER,
    inject: {
      getBvTabs: {
        default:
        /* istanbul ignore next */
        function _default() {
          return function () {
            return {};
          };
        }
      }
    },
    props: {
      controls: makeProp(PROP_TYPE_STRING),
      id: makeProp(PROP_TYPE_STRING),
      noKeyNav: makeProp(PROP_TYPE_BOOLEAN, false),
      posInSet: makeProp(PROP_TYPE_NUMBER),
      setSize: makeProp(PROP_TYPE_NUMBER),
      // Reference to the child <b-tab> instance
      tab: makeProp(),
      tabIndex: makeProp(PROP_TYPE_NUMBER)
    },
    computed: {
      bvTabs: function bvTabs() {
        return this.getBvTabs();
      }
    },
    methods: {
      focus: function focus() {
        attemptFocus(this.$refs.link);
      },
      handleEvent: function handleEvent(event) {
        /* istanbul ignore next */
        if (this.tab.disabled) {
          return;
        }

        var type = event.type,
            keyCode = event.keyCode,
            shiftKey = event.shiftKey;

        if (type === 'click') {
          stopEvent(event);
          this.$emit(EVENT_NAME_CLICK, event);
        } else if (type === 'keydown' && keyCode === CODE_SPACE) {
          // For ARIA tabs the SPACE key will also trigger a click/select
          // Even with keyboard navigation disabled, SPACE should "click" the button
          // See: https://github.com/bootstrap-vue/bootstrap-vue/issues/4323
          stopEvent(event);
          this.$emit(EVENT_NAME_CLICK, event);
        } else if (type === 'keydown' && !this.noKeyNav) {
          // For keyboard navigation
          if ([CODE_UP, CODE_LEFT, CODE_HOME].indexOf(keyCode) !== -1) {
            stopEvent(event);

            if (shiftKey || keyCode === CODE_HOME) {
              this.$emit(EVENT_NAME_FIRST, event);
            } else {
              this.$emit(EVENT_NAME_PREV, event);
            }
          } else if ([CODE_DOWN, CODE_RIGHT, CODE_END].indexOf(keyCode) !== -1) {
            stopEvent(event);

            if (shiftKey || keyCode === CODE_END) {
              this.$emit(EVENT_NAME_LAST, event);
            } else {
              this.$emit(EVENT_NAME_NEXT, event);
            }
          }
        }
      }
    },
    render: function render(h) {
      var id = this.id,
          tabIndex = this.tabIndex,
          setSize = this.setSize,
          posInSet = this.posInSet,
          controls = this.controls,
          handleEvent = this.handleEvent;
      var _this$tab = this.tab,
          title = _this$tab.title,
          localActive = _this$tab.localActive,
          disabled = _this$tab.disabled,
          titleItemClass = _this$tab.titleItemClass,
          titleLinkClass = _this$tab.titleLinkClass,
          titleLinkAttributes = _this$tab.titleLinkAttributes;
      var $link = h(BLink, {
        staticClass: 'nav-link',
        class: [{
          active: localActive && !disabled,
          disabled: disabled
        }, titleLinkClass, // Apply <b-tabs> `activeNavItemClass` styles when the tab is active
        localActive ? this.bvTabs.activeNavItemClass : null],
        props: {
          disabled: disabled
        },
        attrs: _objectSpread2$3(_objectSpread2$3({}, titleLinkAttributes), {}, {
          id: id,
          role: 'tab',
          // Roving tab index when keynav enabled
          tabindex: tabIndex,
          'aria-selected': localActive && !disabled ? 'true' : 'false',
          'aria-setsize': setSize,
          'aria-posinset': posInSet,
          'aria-controls': controls
        }),
        on: {
          click: handleEvent,
          keydown: handleEvent
        },
        ref: 'link'
      }, [this.tab.normalizeSlot(SLOT_NAME_TITLE) || title]);
      return h('li', {
        staticClass: 'nav-item',
        class: [titleItemClass],
        attrs: {
          role: 'presentation'
        }
      }, [$link]);
    }
  }); // --- Props ---

  var navProps = omit(props$U, ['tabs', 'isNavBar', 'cardHeader']);
  var props$3 = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$25), modelProps$1), navProps), {}, {
    // Only applied to the currently active `<b-nav-item>`
    activeNavItemClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    // Only applied to the currently active `<b-tab>`
    // This prop is sniffed by the `<b-tab>` child
    activeTabClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    card: makeProp(PROP_TYPE_BOOLEAN, false),
    contentClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    // Synonym for 'bottom'
    end: makeProp(PROP_TYPE_BOOLEAN, false),
    // This prop is sniffed by the `<b-tab>` child
    lazy: makeProp(PROP_TYPE_BOOLEAN, false),
    navClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    navWrapperClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    noFade: makeProp(PROP_TYPE_BOOLEAN, false),
    noKeyNav: makeProp(PROP_TYPE_BOOLEAN, false),
    noNavStyle: makeProp(PROP_TYPE_BOOLEAN, false),
    tag: makeProp(PROP_TYPE_STRING, 'div')
  })), NAME_TABS); // --- Main component ---
  // @vue/component

  var BTabs = /*#__PURE__*/extend({
    name: NAME_TABS,
    mixins: [idMixin, modelMixin$1, normalizeSlotMixin],
    provide: function provide() {
      var _this = this;

      return {
        getBvTabs: function getBvTabs() {
          return _this;
        }
      };
    },
    props: props$3,
    data: function data() {
      return {
        // Index of current tab
        currentTab: toInteger(this[MODEL_PROP_NAME$1], -1),
        // Array of direct child `<b-tab>` instances, in DOM order
        tabs: [],
        // Array of child instances registered (for triggering reactive updates)
        registeredTabs: []
      };
    },
    computed: {
      fade: function fade() {
        // This computed prop is sniffed by the tab child
        return !this.noFade;
      },
      localNavClass: function localNavClass() {
        var classes = [];

        if (this.card && this.vertical) {
          classes.push('card-header', 'h-100', 'border-bottom-0', 'rounded-0');
        }

        return [].concat(classes, [this.navClass]);
      }
    },
    watch: (_watch$2 = {}, _defineProperty(_watch$2, MODEL_PROP_NAME$1, function (newValue, oldValue) {
      if (newValue !== oldValue) {
        newValue = toInteger(newValue, -1);
        oldValue = toInteger(oldValue, 0);
        var $tab = this.tabs[newValue];

        if ($tab && !$tab.disabled) {
          this.activateTab($tab);
        } else {
          // Try next or prev tabs
          if (newValue < oldValue) {
            this.previousTab();
          } else {
            this.nextTab();
          }
        }
      }
    }), _defineProperty(_watch$2, "currentTab", function currentTab(newValue) {
      var index = -1; // Ensure only one tab is active at most

      this.tabs.forEach(function ($tab, i) {
        if (i === newValue && !$tab.disabled) {
          $tab.localActive = true;
          index = i;
        } else {
          $tab.localActive = false;
        }
      }); // Update the v-model

      this.$emit(MODEL_EVENT_NAME$1, index);
    }), _defineProperty(_watch$2, "tabs", function tabs(newValue, oldValue) {
      var _this2 = this;

      // We use `_uid` instead of `safeId()`, as the later is changed in a `$nextTick()`
      // if no explicit ID is provided, causing duplicate emits
      if (!looseEqual(newValue.map(function ($tab) {
        return $tab[COMPONENT_UID_KEY];
      }), oldValue.map(function ($tab) {
        return $tab[COMPONENT_UID_KEY];
      }))) {
        // In a `$nextTick()` to ensure `currentTab` has been set first
        this.$nextTick(function () {
          // We emit shallow copies of the new and old arrays of tabs,
          // to prevent users from potentially mutating the internal arrays
          _this2.$emit(EVENT_NAME_CHANGED, newValue.slice(), oldValue.slice());
        });
      }
    }), _defineProperty(_watch$2, "registeredTabs", function registeredTabs() {
      this.updateTabs();
    }), _watch$2),
    created: function created() {
      // Create private non-reactive props
      this.$_observer = null;
    },
    mounted: function mounted() {
      this.setObserver(true);
    },
    beforeDestroy: function beforeDestroy() {
      this.setObserver(false); // Ensure no references to child instances exist

      this.tabs = [];
    },
    methods: {
      registerTab: function registerTab($tab) {
        if (!arrayIncludes(this.registeredTabs, $tab)) {
          this.registeredTabs.push($tab);
        }
      },
      unregisterTab: function unregisterTab($tab) {
        this.registeredTabs = this.registeredTabs.slice().filter(function ($t) {
          return $t !== $tab;
        });
      },
      // DOM observer is needed to detect changes in order of tabs
      setObserver: function setObserver() {
        var _this3 = this;

        var on = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
        this.$_observer && this.$_observer.disconnect();
        this.$_observer = null;

        if (on) {
          /* istanbul ignore next: difficult to test mutation observer in JSDOM */
          var handler = function handler() {
            _this3.$nextTick(function () {
              requestAF(function () {
                _this3.updateTabs();
              });
            });
          }; // Watch for changes to `<b-tab>` sub components


          this.$_observer = observeDom(this.$refs.content, handler, {
            childList: true,
            subtree: false,
            attributes: true,
            attributeFilter: ['id']
          });
        }
      },
      getTabs: function getTabs() {
        var $tabs = this.registeredTabs; // Dropped intentionally
        // .filter(
        //   $tab => $tab.$children.filter($t => $t && $t._isTab).length === 0
        // )
        // DOM Order of Tabs

        var order = [];
        /* istanbul ignore next: too difficult to test */

        if (IS_BROWSER && $tabs.length > 0) {
          // We rely on the DOM when mounted to get the "true" order of the `<b-tab>` children
          // `querySelectorAll()` always returns elements in document order, regardless of
          // order specified in the selector
          var selector = $tabs.map(function ($tab) {
            return "#".concat($tab.safeId());
          }).join(', ');
          order = selectAll(selector, this.$el).map(function ($el) {
            return $el.id;
          }).filter(identity);
        } // Stable sort keeps the original order if not found in the `order` array,
        // which will be an empty array before mount


        return stableSort$1($tabs, function (a, b) {
          return order.indexOf(a.safeId()) - order.indexOf(b.safeId());
        });
      },
      updateTabs: function updateTabs() {
        var $tabs = this.getTabs(); // Find last active non-disabled tab in current tabs
        // We trust tab state over `currentTab`, in case tabs were added/removed/re-ordered

        var tabIndex = $tabs.indexOf($tabs.slice().reverse().find(function ($tab) {
          return $tab.localActive && !$tab.disabled;
        })); // Else try setting to `currentTab`

        if (tabIndex < 0) {
          var currentTab = this.currentTab;

          if (currentTab >= $tabs.length) {
            // Handle last tab being removed, so find the last non-disabled tab
            tabIndex = $tabs.indexOf($tabs.slice().reverse().find(notDisabled));
          } else if ($tabs[currentTab] && !$tabs[currentTab].disabled) {
            // Current tab is not disabled
            tabIndex = currentTab;
          }
        } // Else find first non-disabled tab in current tabs


        if (tabIndex < 0) {
          tabIndex = $tabs.indexOf($tabs.find(notDisabled));
        } // Ensure only one tab is active at a time


        $tabs.forEach(function ($tab, index) {
          $tab.localActive = index === tabIndex;
        });
        this.tabs = $tabs;
        this.currentTab = tabIndex;
      },
      // Find a button that controls a tab, given the tab reference
      // Returns the button vm instance
      getButtonForTab: function getButtonForTab($tab) {
        return (this.$refs.buttons || []).find(function ($btn) {
          return $btn.tab === $tab;
        });
      },
      // Force a button to re-render its content, given a `<b-tab>` instance
      // Called by `<b-tab>` on `update()`
      updateButton: function updateButton($tab) {
        var $button = this.getButtonForTab($tab);

        if ($button && $button.$forceUpdate) {
          $button.$forceUpdate();
        }
      },
      // Activate a tab given a `<b-tab>` instance
      // Also accessed by `<b-tab>`
      activateTab: function activateTab($tab) {
        var currentTab = this.currentTab,
            $tabs = this.tabs;
        var result = false;

        if ($tab) {
          var index = $tabs.indexOf($tab);

          if (index !== currentTab && index > -1 && !$tab.disabled) {
            var tabEvent = new BvEvent(EVENT_NAME_ACTIVATE_TAB, {
              cancelable: true,
              vueTarget: this,
              componentId: this.safeId()
            });
            this.$emit(tabEvent.type, index, currentTab, tabEvent);

            if (!tabEvent.defaultPrevented) {
              this.currentTab = index;
              result = true;
            }
          }
        } // Couldn't set tab, so ensure v-model is up to date

        /* istanbul ignore next: should rarely happen */


        if (!result && this[MODEL_PROP_NAME$1] !== currentTab) {
          this.$emit(MODEL_EVENT_NAME$1, currentTab);
        }

        return result;
      },
      // Deactivate a tab given a `<b-tab>` instance
      // Accessed by `<b-tab>`
      deactivateTab: function deactivateTab($tab) {
        if ($tab) {
          // Find first non-disabled tab that isn't the one being deactivated
          // If no tabs are available, then don't deactivate current tab
          return this.activateTab(this.tabs.filter(function ($t) {
            return $t !== $tab;
          }).find(notDisabled));
        }
        /* istanbul ignore next: should never/rarely happen */


        return false;
      },
      // Focus a tab button given its `<b-tab>` instance
      focusButton: function focusButton($tab) {
        var _this4 = this;

        // Wrap in `$nextTick()` to ensure DOM has completed rendering
        this.$nextTick(function () {
          attemptFocus(_this4.getButtonForTab($tab));
        });
      },
      // Emit a click event on a specified `<b-tab>` component instance
      emitTabClick: function emitTabClick(tab, event) {
        if (isEvent(event) && tab && tab.$emit && !tab.disabled) {
          tab.$emit(EVENT_NAME_CLICK, event);
        }
      },
      // Click handler
      clickTab: function clickTab($tab, event) {
        this.activateTab($tab);
        this.emitTabClick($tab, event);
      },
      // Move to first non-disabled tab
      firstTab: function firstTab(focus) {
        var $tab = this.tabs.find(notDisabled);

        if (this.activateTab($tab) && focus) {
          this.focusButton($tab);
          this.emitTabClick($tab, focus);
        }
      },
      // Move to previous non-disabled tab
      previousTab: function previousTab(focus) {
        var currentIndex = mathMax(this.currentTab, 0);
        var $tab = this.tabs.slice(0, currentIndex).reverse().find(notDisabled);

        if (this.activateTab($tab) && focus) {
          this.focusButton($tab);
          this.emitTabClick($tab, focus);
        }
      },
      // Move to next non-disabled tab
      nextTab: function nextTab(focus) {
        var currentIndex = mathMax(this.currentTab, -1);
        var $tab = this.tabs.slice(currentIndex + 1).find(notDisabled);

        if (this.activateTab($tab) && focus) {
          this.focusButton($tab);
          this.emitTabClick($tab, focus);
        }
      },
      // Move to last non-disabled tab
      lastTab: function lastTab(focus) {
        var $tab = this.tabs.slice().reverse().find(notDisabled);

        if (this.activateTab($tab) && focus) {
          this.focusButton($tab);
          this.emitTabClick($tab, focus);
        }
      }
    },
    render: function render(h) {
      var _this5 = this;

      var align = this.align,
          card = this.card,
          end = this.end,
          fill = this.fill,
          firstTab = this.firstTab,
          justified = this.justified,
          lastTab = this.lastTab,
          nextTab = this.nextTab,
          noKeyNav = this.noKeyNav,
          noNavStyle = this.noNavStyle,
          pills = this.pills,
          previousTab = this.previousTab,
          small = this.small,
          $tabs = this.tabs,
          vertical = this.vertical; // Currently active tab

      var $activeTab = $tabs.find(function ($tab) {
        return $tab.localActive && !$tab.disabled;
      }); // Tab button to allow focusing when no active tab found (keynav only)

      var $fallbackTab = $tabs.find(function ($tab) {
        return !$tab.disabled;
      }); // For each `<b-tab>` found create the tab buttons

      var $buttons = $tabs.map(function ($tab, index) {
        var _on;

        var safeId = $tab.safeId; // Ensure at least one tab button is focusable when keynav enabled (if possible)

        var tabIndex = null;

        if (!noKeyNav) {
          // Buttons are not in tab index unless active, or a fallback tab
          tabIndex = -1;

          if ($tab === $activeTab || !$activeTab && $tab === $fallbackTab) {
            // Place tab button in tab sequence
            tabIndex = null;
          }
        }

        return h(BVTabButton, _defineProperty({
          props: {
            controls: safeId ? safeId() : null,
            id: $tab.controlledBy || (safeId ? safeId("_BV_tab_button_") : null),
            noKeyNav: noKeyNav,
            posInSet: index + 1,
            setSize: $tabs.length,
            tab: $tab,
            tabIndex: tabIndex
          },
          on: (_on = {}, _defineProperty(_on, EVENT_NAME_CLICK, function (event) {
            _this5.clickTab($tab, event);
          }), _defineProperty(_on, EVENT_NAME_FIRST, firstTab), _defineProperty(_on, EVENT_NAME_PREV, previousTab), _defineProperty(_on, EVENT_NAME_NEXT, nextTab), _defineProperty(_on, EVENT_NAME_LAST, lastTab), _on),
          key: $tab[COMPONENT_UID_KEY] || index,
          ref: 'buttons'
        }, REF_FOR_KEY, true));
      });
      var $nav = h(BNav, {
        class: this.localNavClass,
        attrs: {
          role: 'tablist',
          id: this.safeId('_BV_tab_controls_')
        },
        props: {
          fill: fill,
          justified: justified,
          align: align,
          tabs: !noNavStyle && !pills,
          pills: !noNavStyle && pills,
          vertical: vertical,
          small: small,
          cardHeader: card && !vertical
        },
        ref: 'nav'
      }, [this.normalizeSlot(SLOT_NAME_TABS_START) || h(), $buttons, this.normalizeSlot(SLOT_NAME_TABS_END) || h()]);
      $nav = h('div', {
        class: [{
          'card-header': card && !vertical && !end,
          'card-footer': card && !vertical && end,
          'col-auto': vertical
        }, this.navWrapperClass],
        key: 'bv-tabs-nav'
      }, [$nav]);
      var $children = this.normalizeSlot() || [];
      var $empty = h();

      if ($children.length === 0) {
        $empty = h('div', {
          class: ['tab-pane', 'active', {
            'card-body': card
          }],
          key: 'bv-empty-tab'
        }, this.normalizeSlot(SLOT_NAME_EMPTY));
      }

      var $content = h('div', {
        staticClass: 'tab-content',
        class: [{
          col: vertical
        }, this.contentClass],
        attrs: {
          id: this.safeId('_BV_tab_container_')
        },
        key: 'bv-content',
        ref: 'content'
      }, [$children, $empty]); // Render final output

      return h(this.tag, {
        staticClass: 'tabs',
        class: {
          row: vertical,
          'no-gutters': vertical && card
        },
        attrs: {
          id: this.safeId()
        }
      }, [end ? $content : h(), $nav, end ? h() : $content]);
    }
  });

  var _objectSpread2, _watch$1;

  var MODEL_PROP_NAME_ACTIVE = 'active';
  var MODEL_EVENT_NAME_ACTIVE = MODEL_EVENT_NAME_PREFIX + MODEL_PROP_NAME_ACTIVE; // --- Props ---

  var props$2 = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3({}, props$25), {}, (_objectSpread2 = {}, _defineProperty(_objectSpread2, MODEL_PROP_NAME_ACTIVE, makeProp(PROP_TYPE_BOOLEAN, false)), _defineProperty(_objectSpread2, "buttonId", makeProp(PROP_TYPE_STRING)), _defineProperty(_objectSpread2, "disabled", makeProp(PROP_TYPE_BOOLEAN, false)), _defineProperty(_objectSpread2, "lazy", makeProp(PROP_TYPE_BOOLEAN, false)), _defineProperty(_objectSpread2, "noBody", makeProp(PROP_TYPE_BOOLEAN, false)), _defineProperty(_objectSpread2, "tag", makeProp(PROP_TYPE_STRING, 'div')), _defineProperty(_objectSpread2, "title", makeProp(PROP_TYPE_STRING)), _defineProperty(_objectSpread2, "titleItemClass", makeProp(PROP_TYPE_ARRAY_OBJECT_STRING)), _defineProperty(_objectSpread2, "titleLinkAttributes", makeProp(PROP_TYPE_OBJECT)), _defineProperty(_objectSpread2, "titleLinkClass", makeProp(PROP_TYPE_ARRAY_OBJECT_STRING)), _objectSpread2))), NAME_TAB); // --- Main component ---
  // @vue/component

  var BTab = /*#__PURE__*/extend({
    name: NAME_TAB,
    mixins: [idMixin, normalizeSlotMixin],
    inject: {
      getBvTabs: {
        default: function _default() {
          return function () {
            return {};
          };
        }
      }
    },
    props: props$2,
    data: function data() {
      return {
        localActive: this[MODEL_PROP_NAME_ACTIVE] && !this.disabled
      };
    },
    computed: {
      bvTabs: function bvTabs() {
        return this.getBvTabs();
      },
      // For parent sniffing of child
      _isTab: function _isTab() {
        return true;
      },
      tabClasses: function tabClasses() {
        var active = this.localActive,
            disabled = this.disabled;
        return [{
          active: active,
          disabled: disabled,
          'card-body': this.bvTabs.card && !this.noBody
        }, // Apply <b-tabs> `activeTabClass` styles when this tab is active
        active ? this.bvTabs.activeTabClass : null];
      },
      controlledBy: function controlledBy() {
        return this.buttonId || this.safeId('__BV_tab_button__');
      },
      computedNoFade: function computedNoFade() {
        return !(this.bvTabs.fade || false);
      },
      computedLazy: function computedLazy() {
        return this.bvTabs.lazy || this.lazy;
      }
    },
    watch: (_watch$1 = {}, _defineProperty(_watch$1, MODEL_PROP_NAME_ACTIVE, function (newValue, oldValue) {
      if (newValue !== oldValue) {
        if (newValue) {
          // If activated post mount
          this.activate();
        } else {
          /* istanbul ignore next */
          if (!this.deactivate()) {
            // Tab couldn't be deactivated, so we reset the synced active prop
            // Deactivation will fail if no other tabs to activate
            this.$emit(MODEL_EVENT_NAME_ACTIVE, this.localActive);
          }
        }
      }
    }), _defineProperty(_watch$1, "disabled", function disabled(newValue, oldValue) {
      if (newValue !== oldValue) {
        var firstTab = this.bvTabs.firstTab;

        if (newValue && this.localActive && firstTab) {
          this.localActive = false;
          firstTab();
        }
      }
    }), _defineProperty(_watch$1, "localActive", function localActive(newValue) {
      // Make `active` prop work with `.sync` modifier
      this.$emit(MODEL_EVENT_NAME_ACTIVE, newValue);
    }), _watch$1),
    mounted: function mounted() {
      // Inform `<b-tabs>` of our presence
      this.registerTab();
    },
    updated: function updated() {
      // Force the tab button content to update (since slots are not reactive)
      // Only done if we have a title slot, as the title prop is reactive
      var updateButton = this.bvTabs.updateButton;

      if (updateButton && this.hasNormalizedSlot(SLOT_NAME_TITLE)) {
        updateButton(this);
      }
    },
    beforeDestroy: function beforeDestroy() {
      // Inform `<b-tabs>` of our departure
      this.unregisterTab();
    },
    methods: {
      // Private methods
      registerTab: function registerTab() {
        // Inform `<b-tabs>` of our presence
        var registerTab = this.bvTabs.registerTab;

        if (registerTab) {
          registerTab(this);
        }
      },
      unregisterTab: function unregisterTab() {
        // Inform `<b-tabs>` of our departure
        var unregisterTab = this.bvTabs.unregisterTab;

        if (unregisterTab) {
          unregisterTab(this);
        }
      },
      // Public methods
      activate: function activate() {
        // Not inside a `<b-tabs>` component or tab is disabled
        var activateTab = this.bvTabs.activateTab;
        return activateTab && !this.disabled ? activateTab(this) : false;
      },
      deactivate: function deactivate() {
        // Not inside a `<b-tabs>` component or not active to begin with
        var deactivateTab = this.bvTabs.deactivateTab;
        return deactivateTab && this.localActive ? deactivateTab(this) : false;
      }
    },
    render: function render(h) {
      var localActive = this.localActive;
      var $content = h(this.tag, {
        staticClass: 'tab-pane',
        class: this.tabClasses,
        directives: [{
          name: 'show',
          value: localActive
        }],
        attrs: {
          role: 'tabpanel',
          id: this.safeId(),
          'aria-hidden': localActive ? 'false' : 'true',
          'aria-labelledby': this.controlledBy || null
        },
        ref: 'panel'
      }, // Render content lazily if requested
      [localActive || !this.computedLazy ? this.normalizeSlot() : h()]);
      return h(BVTransition, {
        props: {
          mode: 'out-in',
          noFade: this.computedNoFade
        }
      }, [$content]);
    }
  });

  var TabsPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BTabs: BTabs,
      BTab: BTab
    }
  });

  var TimePlugin = /*#__PURE__*/pluginFactory({
    components: {
      BTime: BTime
    }
  });

  function _typeof(obj) {
    if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
      _typeof = function (obj) {
        return typeof obj;
      };
    } else {
      _typeof = function (obj) {
        return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
      };
    }

    return _typeof(obj);
  }

  function _toConsumableArray(arr) {
    return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
  }

  function _arrayWithoutHoles(arr) {
    if (Array.isArray(arr)) {
      for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];

      return arr2;
    }
  }

  function _iterableToArray(iter) {
    if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
  }

  function _nonIterableSpread() {
    throw new TypeError("Invalid attempt to spread non-iterable instance");
  }

  var inBrowser = typeof window !== 'undefined';
  function freeze(item) {
    if (Array.isArray(item) || _typeof(item) === 'object') {
      return Object.freeze(item);
    }

    return item;
  }
  function combinePassengers(transports) {
    var slotProps = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
    return transports.reduce(function (passengers, transport) {
      var temp = transport.passengers[0];
      var newPassengers = typeof temp === 'function' ? temp(slotProps) : transport.passengers;
      return passengers.concat(newPassengers);
    }, []);
  }
  function stableSort(array, compareFn) {
    return array.map(function (v, idx) {
      return [idx, v];
    }).sort(function (a, b) {
      return compareFn(a[1], b[1]) || a[0] - b[0];
    }).map(function (c) {
      return c[1];
    });
  }
  function pick(obj, keys) {
    return keys.reduce(function (acc, key) {
      if (obj.hasOwnProperty(key)) {
        acc[key] = obj[key];
      }

      return acc;
    }, {});
  }

  var transports = {};
  var targets = {};
  var sources = {};
  var Wormhole = Vue__default['default'].extend({
    data: function data() {
      return {
        transports: transports,
        targets: targets,
        sources: sources,
        trackInstances: inBrowser
      };
    },
    methods: {
      open: function open(transport) {
        if (!inBrowser) return;
        var to = transport.to,
            from = transport.from,
            passengers = transport.passengers,
            _transport$order = transport.order,
            order = _transport$order === void 0 ? Infinity : _transport$order;
        if (!to || !from || !passengers) return;
        var newTransport = {
          to: to,
          from: from,
          passengers: freeze(passengers),
          order: order
        };
        var keys = Object.keys(this.transports);

        if (keys.indexOf(to) === -1) {
          Vue__default['default'].set(this.transports, to, []);
        }

        var currentIndex = this.$_getTransportIndex(newTransport); // Copying the array here so that the PortalTarget change event will actually contain two distinct arrays

        var newTransports = this.transports[to].slice(0);

        if (currentIndex === -1) {
          newTransports.push(newTransport);
        } else {
          newTransports[currentIndex] = newTransport;
        }

        this.transports[to] = stableSort(newTransports, function (a, b) {
          return a.order - b.order;
        });
      },
      close: function close(transport) {
        var force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
        var to = transport.to,
            from = transport.from;
        if (!to || !from && force === false) return;

        if (!this.transports[to]) {
          return;
        }

        if (force) {
          this.transports[to] = [];
        } else {
          var index = this.$_getTransportIndex(transport);

          if (index >= 0) {
            // Copying the array here so that the PortalTarget change event will actually contain two distinct arrays
            var newTransports = this.transports[to].slice(0);
            newTransports.splice(index, 1);
            this.transports[to] = newTransports;
          }
        }
      },
      registerTarget: function registerTarget(target, vm, force) {
        if (!inBrowser) return;

        if (this.trackInstances && !force && this.targets[target]) {
          console.warn("[portal-vue]: Target ".concat(target, " already exists"));
        }

        this.$set(this.targets, target, Object.freeze([vm]));
      },
      unregisterTarget: function unregisterTarget(target) {
        this.$delete(this.targets, target);
      },
      registerSource: function registerSource(source, vm, force) {
        if (!inBrowser) return;

        if (this.trackInstances && !force && this.sources[source]) {
          console.warn("[portal-vue]: source ".concat(source, " already exists"));
        }

        this.$set(this.sources, source, Object.freeze([vm]));
      },
      unregisterSource: function unregisterSource(source) {
        this.$delete(this.sources, source);
      },
      hasTarget: function hasTarget(to) {
        return !!(this.targets[to] && this.targets[to][0]);
      },
      hasSource: function hasSource(to) {
        return !!(this.sources[to] && this.sources[to][0]);
      },
      hasContentFor: function hasContentFor(to) {
        return !!this.transports[to] && !!this.transports[to].length;
      },
      // Internal
      $_getTransportIndex: function $_getTransportIndex(_ref) {
        var to = _ref.to,
            from = _ref.from;

        for (var i in this.transports[to]) {
          if (this.transports[to][i].from === from) {
            return +i;
          }
        }

        return -1;
      }
    }
  });
  var wormhole = new Wormhole(transports);

  var _id = 1;
  var Portal = Vue__default['default'].extend({
    name: 'portal',
    props: {
      disabled: {
        type: Boolean
      },
      name: {
        type: String,
        default: function _default() {
          return String(_id++);
        }
      },
      order: {
        type: Number,
        default: 0
      },
      slim: {
        type: Boolean
      },
      slotProps: {
        type: Object,
        default: function _default() {
          return {};
        }
      },
      tag: {
        type: String,
        default: 'DIV'
      },
      to: {
        type: String,
        default: function _default() {
          return String(Math.round(Math.random() * 10000000));
        }
      }
    },
    created: function created() {
      var _this = this;

      this.$nextTick(function () {
        wormhole.registerSource(_this.name, _this);
      });
    },
    mounted: function mounted() {
      if (!this.disabled) {
        this.sendUpdate();
      }
    },
    updated: function updated() {
      if (this.disabled) {
        this.clear();
      } else {
        this.sendUpdate();
      }
    },
    beforeDestroy: function beforeDestroy() {
      wormhole.unregisterSource(this.name);
      this.clear();
    },
    watch: {
      to: function to(newValue, oldValue) {
        oldValue && oldValue !== newValue && this.clear(oldValue);
        this.sendUpdate();
      }
    },
    methods: {
      clear: function clear(target) {
        var closer = {
          from: this.name,
          to: target || this.to
        };
        wormhole.close(closer);
      },
      normalizeSlots: function normalizeSlots() {
        return this.$scopedSlots.default ? [this.$scopedSlots.default] : this.$slots.default;
      },
      normalizeOwnChildren: function normalizeOwnChildren(children) {
        return typeof children === 'function' ? children(this.slotProps) : children;
      },
      sendUpdate: function sendUpdate() {
        var slotContent = this.normalizeSlots();

        if (slotContent) {
          var transport = {
            from: this.name,
            to: this.to,
            passengers: _toConsumableArray(slotContent),
            order: this.order
          };
          wormhole.open(transport);
        } else {
          this.clear();
        }
      }
    },
    render: function render(h) {
      var children = this.$slots.default || this.$scopedSlots.default || [];
      var Tag = this.tag;

      if (children && this.disabled) {
        return children.length <= 1 && this.slim ? this.normalizeOwnChildren(children)[0] : h(Tag, [this.normalizeOwnChildren(children)]);
      } else {
        return this.slim ? h() : h(Tag, {
          class: {
            'v-portal': true
          },
          style: {
            display: 'none'
          },
          key: 'v-portal-placeholder'
        });
      }
    }
  });

  var PortalTarget = Vue__default['default'].extend({
    name: 'portalTarget',
    props: {
      multiple: {
        type: Boolean,
        default: false
      },
      name: {
        type: String,
        required: true
      },
      slim: {
        type: Boolean,
        default: false
      },
      slotProps: {
        type: Object,
        default: function _default() {
          return {};
        }
      },
      tag: {
        type: String,
        default: 'div'
      },
      transition: {
        type: [String, Object, Function]
      }
    },
    data: function data() {
      return {
        transports: wormhole.transports,
        firstRender: true
      };
    },
    created: function created() {
      var _this = this;

      this.$nextTick(function () {
        wormhole.registerTarget(_this.name, _this);
      });
    },
    watch: {
      ownTransports: function ownTransports() {
        this.$emit('change', this.children().length > 0);
      },
      name: function name(newVal, oldVal) {
        /**
         * TODO
         * This should warn as well ...
         */
        wormhole.unregisterTarget(oldVal);
        wormhole.registerTarget(newVal, this);
      }
    },
    mounted: function mounted() {
      var _this2 = this;

      if (this.transition) {
        this.$nextTick(function () {
          // only when we have a transition, because it causes a re-render
          _this2.firstRender = false;
        });
      }
    },
    beforeDestroy: function beforeDestroy() {
      wormhole.unregisterTarget(this.name);
    },
    computed: {
      ownTransports: function ownTransports() {
        var transports = this.transports[this.name] || [];

        if (this.multiple) {
          return transports;
        }

        return transports.length === 0 ? [] : [transports[transports.length - 1]];
      },
      passengers: function passengers() {
        return combinePassengers(this.ownTransports, this.slotProps);
      }
    },
    methods: {
      // can't be a computed prop because it has to "react" to $slot changes.
      children: function children() {
        return this.passengers.length !== 0 ? this.passengers : this.$scopedSlots.default ? this.$scopedSlots.default(this.slotProps) : this.$slots.default || [];
      },
      // can't be a computed prop because it has to "react" to this.children().
      noWrapper: function noWrapper() {
        var noWrapper = this.slim && !this.transition;

        if (noWrapper && this.children().length > 1) {
          console.warn('[portal-vue]: PortalTarget with `slim` option received more than one child element.');
        }

        return noWrapper;
      }
    },
    render: function render(h) {
      var noWrapper = this.noWrapper();
      var children = this.children();
      var Tag = this.transition || this.tag;
      return noWrapper ? children[0] : this.slim && !Tag ? h() : h(Tag, {
        props: {
          // if we have a transition component, pass the tag if it exists
          tag: this.transition && this.tag ? this.tag : undefined
        },
        class: {
          'vue-portal-target': true
        }
      }, children);
    }
  });

  var _id$1 = 0;
  var portalProps = ['disabled', 'name', 'order', 'slim', 'slotProps', 'tag', 'to'];
  var targetProps = ['multiple', 'transition'];
  Vue__default['default'].extend({
    name: 'MountingPortal',
    inheritAttrs: false,
    props: {
      append: {
        type: [Boolean, String]
      },
      bail: {
        type: Boolean
      },
      mountTo: {
        type: String,
        required: true
      },
      // Portal
      disabled: {
        type: Boolean
      },
      // name for the portal
      name: {
        type: String,
        default: function _default() {
          return 'mounted_' + String(_id$1++);
        }
      },
      order: {
        type: Number,
        default: 0
      },
      slim: {
        type: Boolean
      },
      slotProps: {
        type: Object,
        default: function _default() {
          return {};
        }
      },
      tag: {
        type: String,
        default: 'DIV'
      },
      // name for the target
      to: {
        type: String,
        default: function _default() {
          return String(Math.round(Math.random() * 10000000));
        }
      },
      // Target
      multiple: {
        type: Boolean,
        default: false
      },
      targetSlim: {
        type: Boolean
      },
      targetSlotProps: {
        type: Object,
        default: function _default() {
          return {};
        }
      },
      targetTag: {
        type: String,
        default: 'div'
      },
      transition: {
        type: [String, Object, Function]
      }
    },
    created: function created() {
      if (typeof document === 'undefined') return;
      var el = document.querySelector(this.mountTo);

      if (!el) {
        console.error("[portal-vue]: Mount Point '".concat(this.mountTo, "' not found in document"));
        return;
      }

      var props = this.$props; // Target already exists

      if (wormhole.targets[props.name]) {
        if (props.bail) {
          console.warn("[portal-vue]: Target ".concat(props.name, " is already mounted.\n        Aborting because 'bail: true' is set"));
        } else {
          this.portalTarget = wormhole.targets[props.name];
        }

        return;
      }

      var append = props.append;

      if (append) {
        var type = typeof append === 'string' ? append : 'DIV';
        var mountEl = document.createElement(type);
        el.appendChild(mountEl);
        el = mountEl;
      } // get props for target from $props
      // we have to rename a few of them


      var _props = pick(this.$props, targetProps);

      _props.slim = this.targetSlim;
      _props.tag = this.targetTag;
      _props.slotProps = this.targetSlotProps;
      _props.name = this.to;
      this.portalTarget = new PortalTarget({
        el: el,
        parent: this.$parent || this,
        propsData: _props
      });
    },
    beforeDestroy: function beforeDestroy() {
      var target = this.portalTarget;

      if (this.append) {
        var el = target.$el;
        el.parentNode.removeChild(el);
      }

      target.$destroy();
    },
    render: function render(h) {
      if (!this.portalTarget) {
        console.warn("[portal-vue] Target wasn't mounted");
        return h();
      } // if there's no "manual" scoped slot, so we create a <Portal> ourselves


      if (!this.$scopedSlots.manual) {
        var props = pick(this.$props, portalProps);
        return h(Portal, {
          props: props,
          attrs: this.$attrs,
          on: this.$listeners,
          scopedSlots: this.$scopedSlots
        }, this.$slots.default);
      } // else, we render the scoped slot


      var content = this.$scopedSlots.manual({
        to: this.to
      }); // if user used <template> for the scoped slot
      // content will be an array

      if (Array.isArray(content)) {
        content = content[0];
      }

      if (!content) return h();
      return content;
    }
  });

  // @vue/component

  var DefaultTransition = /*#__PURE__*/extend({
    mixins: [normalizeSlotMixin],
    data: function data() {
      return {
        // Transition classes base name
        name: 'b-toaster'
      };
    },
    methods: {
      onAfterEnter: function onAfterEnter(el) {
        var _this = this;

        // Work around a Vue.js bug where `*-enter-to` class is not removed
        // See: https://github.com/vuejs/vue/pull/7901
        // The `*-move` class is also stuck on elements that moved,
        // but there are no JavaScript hooks to handle after move
        // See: https://github.com/vuejs/vue/pull/7906
        requestAF(function () {
          removeClass(el, "".concat(_this.name, "-enter-to"));
        });
      }
    },
    render: function render(h) {
      return h('transition-group', {
        props: {
          tag: 'div',
          name: this.name
        },
        on: {
          afterEnter: this.onAfterEnter
        }
      }, this.normalizeSlot());
    }
  }); // --- Props ---

  var props$1 = makePropsConfigurable({
    // Allowed: 'true' or 'false' or `null`
    ariaAtomic: makeProp(PROP_TYPE_STRING),
    ariaLive: makeProp(PROP_TYPE_STRING),
    name: makeProp(PROP_TYPE_STRING, undefined, true),
    // Required
    // Aria role
    role: makeProp(PROP_TYPE_STRING)
  }, NAME_TOASTER); // --- Main component ---
  // @vue/component

  var BToaster = /*#__PURE__*/extend({
    name: NAME_TOASTER,
    mixins: [listenOnRootMixin],
    props: props$1,
    data: function data() {
      return {
        // We don't render on SSR or if a an existing target found
        doRender: false,
        dead: false,
        // Toaster names cannot change once created
        staticName: this.name
      };
    },
    beforeMount: function beforeMount() {
      var name = this.name;
      this.staticName = name;
      /* istanbul ignore if */

      if (wormhole.hasTarget(name)) {
        warn("A \"<portal-target>\" with name \"".concat(name, "\" already exists in the document."), NAME_TOASTER);
        this.dead = true;
      } else {
        this.doRender = true;
      }
    },
    beforeDestroy: function beforeDestroy() {
      // Let toasts made with `this.$bvToast.toast()` know that this toaster
      // is being destroyed and should should also destroy/hide themselves
      if (this.doRender) {
        this.emitOnRoot(getRootEventName(NAME_TOASTER, EVENT_NAME_DESTROYED), this.name);
      }
    },
    destroyed: function destroyed() {
      // Remove from DOM if needed
      var $el = this.$el;
      /* istanbul ignore next: difficult to test */

      if ($el && $el.parentNode) {
        $el.parentNode.removeChild($el);
      }
    },
    render: function render(h) {
      var $toaster = h('div', {
        class: ['d-none', {
          'b-dead-toaster': this.dead
        }]
      });

      if (this.doRender) {
        var $target = h(PortalTarget, {
          staticClass: 'b-toaster-slot',
          props: {
            name: this.staticName,
            multiple: true,
            tag: 'div',
            slim: false,
            // transition: this.transition || DefaultTransition
            transition: DefaultTransition
          }
        });
        $toaster = h('div', {
          staticClass: 'b-toaster',
          class: [this.staticName],
          attrs: {
            id: this.staticName,
            // Fallback to null to make sure attribute doesn't exist
            role: this.role || null,
            'aria-live': this.ariaLive,
            'aria-atomic': this.ariaAtomic
          }
        }, [$target]);
      }

      return $toaster;
    }
  });

  var _watch;

  var _makeModelMixin = makeModelMixin('visible', {
    type: PROP_TYPE_BOOLEAN,
    defaultValue: false,
    event: EVENT_NAME_CHANGE
  }),
      modelMixin = _makeModelMixin.mixin,
      modelProps = _makeModelMixin.props,
      MODEL_PROP_NAME = _makeModelMixin.prop,
      MODEL_EVENT_NAME = _makeModelMixin.event;

  var MIN_DURATION = 1000; // --- Props ---

  var linkProps = pick$1(props$2f, ['href', 'to']);
  var props = makePropsConfigurable(sortKeys(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, props$25), modelProps), linkProps), {}, {
    appendToast: makeProp(PROP_TYPE_BOOLEAN, false),
    autoHideDelay: makeProp(PROP_TYPE_NUMBER_STRING, 5000),
    bodyClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    headerClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    headerTag: makeProp(PROP_TYPE_STRING, 'header'),
    // Switches role to 'status' and aria-live to 'polite'
    isStatus: makeProp(PROP_TYPE_BOOLEAN, false),
    noAutoHide: makeProp(PROP_TYPE_BOOLEAN, false),
    noCloseButton: makeProp(PROP_TYPE_BOOLEAN, false),
    noFade: makeProp(PROP_TYPE_BOOLEAN, false),
    noHoverPause: makeProp(PROP_TYPE_BOOLEAN, false),
    solid: makeProp(PROP_TYPE_BOOLEAN, false),
    // Render the toast in place, rather than in a portal-target
    static: makeProp(PROP_TYPE_BOOLEAN, false),
    title: makeProp(PROP_TYPE_STRING),
    toastClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
    toaster: makeProp(PROP_TYPE_STRING, 'b-toaster-top-right'),
    variant: makeProp(PROP_TYPE_STRING)
  })), NAME_TOAST); // --- Main component ---
  // @vue/component

  var BToast = /*#__PURE__*/extend({
    name: NAME_TOAST,
    mixins: [attrsMixin, idMixin, modelMixin, listenOnRootMixin, normalizeSlotMixin, scopedStyleMixin],
    inheritAttrs: false,
    props: props,
    data: function data() {
      return {
        isMounted: false,
        doRender: false,
        localShow: false,
        isTransitioning: false,
        isHiding: false,
        order: 0,
        dismissStarted: 0,
        resumeDismiss: 0
      };
    },
    computed: {
      toastClasses: function toastClasses() {
        var appendToast = this.appendToast,
            variant = this.variant;
        return _defineProperty({
          'b-toast-solid': this.solid,
          'b-toast-append': appendToast,
          'b-toast-prepend': !appendToast
        }, "b-toast-".concat(variant), variant);
      },
      slotScope: function slotScope() {
        var hide = this.hide;
        return {
          hide: hide
        };
      },
      computedDuration: function computedDuration() {
        // Minimum supported duration is 1 second
        return mathMax(toInteger(this.autoHideDelay, 0), MIN_DURATION);
      },
      computedToaster: function computedToaster() {
        return String(this.toaster);
      },
      transitionHandlers: function transitionHandlers() {
        return {
          beforeEnter: this.onBeforeEnter,
          afterEnter: this.onAfterEnter,
          beforeLeave: this.onBeforeLeave,
          afterLeave: this.onAfterLeave
        };
      },
      computedAttrs: function computedAttrs() {
        return _objectSpread2$3(_objectSpread2$3({}, this.bvAttrs), {}, {
          id: this.safeId(),
          tabindex: '0'
        });
      }
    },
    watch: (_watch = {}, _defineProperty(_watch, MODEL_PROP_NAME, function (newValue) {
      this[newValue ? 'show' : 'hide']();
    }), _defineProperty(_watch, "localShow", function localShow(newValue) {
      if (newValue !== this[MODEL_PROP_NAME]) {
        this.$emit(MODEL_EVENT_NAME, newValue);
      }
    }), _defineProperty(_watch, "toaster", function toaster() {
      // If toaster target changed, make sure toaster exists
      this.$nextTick(this.ensureToaster);
    }), _defineProperty(_watch, "static", function _static(newValue) {
      // If static changes to true, and the toast is showing,
      // ensure the toaster target exists
      if (newValue && this.localShow) {
        this.ensureToaster();
      }
    }), _watch),
    created: function created() {
      // Create private non-reactive props
      this.$_dismissTimer = null;
    },
    mounted: function mounted() {
      var _this = this;

      this.isMounted = true;
      this.$nextTick(function () {
        if (_this[MODEL_PROP_NAME]) {
          requestAF(function () {
            _this.show();
          });
        }
      }); // Listen for global $root show events

      this.listenOnRoot(getRootActionEventName(NAME_TOAST, EVENT_NAME_SHOW), function (id) {
        if (id === _this.safeId()) {
          _this.show();
        }
      }); // Listen for global $root hide events

      this.listenOnRoot(getRootActionEventName(NAME_TOAST, EVENT_NAME_HIDE), function (id) {
        if (!id || id === _this.safeId()) {
          _this.hide();
        }
      }); // Make sure we hide when toaster is destroyed

      /* istanbul ignore next: difficult to test */

      this.listenOnRoot(getRootEventName(NAME_TOASTER, EVENT_NAME_DESTROYED), function (toaster) {
        /* istanbul ignore next */
        if (toaster === _this.computedToaster) {
          _this.hide();
        }
      });
    },
    beforeDestroy: function beforeDestroy() {
      this.clearDismissTimer();
    },
    methods: {
      show: function show() {
        var _this2 = this;

        if (!this.localShow) {
          this.ensureToaster();
          var showEvent = this.buildEvent(EVENT_NAME_SHOW);
          this.emitEvent(showEvent);
          this.dismissStarted = this.resumeDismiss = 0;
          this.order = Date.now() * (this.appendToast ? 1 : -1);
          this.isHiding = false;
          this.doRender = true;
          this.$nextTick(function () {
            // We show the toast after we have rendered the portal and b-toast wrapper
            // so that screen readers will properly announce the toast
            requestAF(function () {
              _this2.localShow = true;
            });
          });
        }
      },
      hide: function hide() {
        var _this3 = this;

        if (this.localShow) {
          var hideEvent = this.buildEvent(EVENT_NAME_HIDE);
          this.emitEvent(hideEvent);
          this.setHoverHandler(false);
          this.dismissStarted = this.resumeDismiss = 0;
          this.clearDismissTimer();
          this.isHiding = true;
          requestAF(function () {
            _this3.localShow = false;
          });
        }
      },
      buildEvent: function buildEvent(type) {
        var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
        return new BvEvent(type, _objectSpread2$3(_objectSpread2$3({
          cancelable: false,
          target: this.$el || null,
          relatedTarget: null
        }, options), {}, {
          vueTarget: this,
          componentId: this.safeId()
        }));
      },
      emitEvent: function emitEvent(bvEvent) {
        var type = bvEvent.type;
        this.emitOnRoot(getRootEventName(NAME_TOAST, type), bvEvent);
        this.$emit(type, bvEvent);
      },
      ensureToaster: function ensureToaster() {
        if (this.static) {
          return;
        }

        var computedToaster = this.computedToaster;

        if (!wormhole.hasTarget(computedToaster)) {
          var div = document.createElement('div');
          document.body.appendChild(div);
          var toaster = createNewChildComponent(this.bvEventRoot, BToaster, {
            propsData: {
              name: computedToaster
            }
          });
          toaster.$mount(div);
        }
      },
      startDismissTimer: function startDismissTimer() {
        this.clearDismissTimer();

        if (!this.noAutoHide) {
          this.$_dismissTimer = setTimeout(this.hide, this.resumeDismiss || this.computedDuration);
          this.dismissStarted = Date.now();
          this.resumeDismiss = 0;
        }
      },
      clearDismissTimer: function clearDismissTimer() {
        clearTimeout(this.$_dismissTimer);
        this.$_dismissTimer = null;
      },
      setHoverHandler: function setHoverHandler(on) {
        var el = this.$refs['b-toast'];
        eventOnOff(on, el, 'mouseenter', this.onPause, EVENT_OPTIONS_NO_CAPTURE);
        eventOnOff(on, el, 'mouseleave', this.onUnPause, EVENT_OPTIONS_NO_CAPTURE);
      },
      onPause: function onPause() {
        // Determine time remaining, and then pause timer
        if (this.noAutoHide || this.noHoverPause || !this.$_dismissTimer || this.resumeDismiss) {
          return;
        }

        var passed = Date.now() - this.dismissStarted;

        if (passed > 0) {
          this.clearDismissTimer();
          this.resumeDismiss = mathMax(this.computedDuration - passed, MIN_DURATION);
        }
      },
      onUnPause: function onUnPause() {
        // Restart timer with max of time remaining or 1 second
        if (this.noAutoHide || this.noHoverPause || !this.resumeDismiss) {
          this.resumeDismiss = this.dismissStarted = 0;
          return;
        }

        this.startDismissTimer();
      },
      onLinkClick: function onLinkClick() {
        var _this4 = this;

        // We delay the close to allow time for the
        // browser to process the link click
        this.$nextTick(function () {
          requestAF(function () {
            _this4.hide();
          });
        });
      },
      onBeforeEnter: function onBeforeEnter() {
        this.isTransitioning = true;
      },
      onAfterEnter: function onAfterEnter() {
        this.isTransitioning = false;
        var hiddenEvent = this.buildEvent(EVENT_NAME_SHOWN);
        this.emitEvent(hiddenEvent);
        this.startDismissTimer();
        this.setHoverHandler(true);
      },
      onBeforeLeave: function onBeforeLeave() {
        this.isTransitioning = true;
      },
      onAfterLeave: function onAfterLeave() {
        this.isTransitioning = false;
        this.order = 0;
        this.resumeDismiss = this.dismissStarted = 0;
        var hiddenEvent = this.buildEvent(EVENT_NAME_HIDDEN);
        this.emitEvent(hiddenEvent);
        this.doRender = false;
      },
      // Render helper for generating the toast
      makeToast: function makeToast(h) {
        var _this5 = this;

        var title = this.title,
            slotScope = this.slotScope;
        var link = isLink$1(this);
        var $headerContent = [];
        var $title = this.normalizeSlot(SLOT_NAME_TOAST_TITLE, slotScope);

        if ($title) {
          $headerContent.push($title);
        } else if (title) {
          $headerContent.push(h('strong', {
            staticClass: 'mr-2'
          }, title));
        }

        if (!this.noCloseButton) {
          $headerContent.push(h(BButtonClose, {
            staticClass: 'ml-auto mb-1',
            on: {
              click: function click() {
                _this5.hide();
              }
            }
          }));
        }

        var $header = h();

        if ($headerContent.length > 0) {
          $header = h(this.headerTag, {
            staticClass: 'toast-header',
            class: this.headerClass
          }, $headerContent);
        }

        var $body = h(link ? BLink : 'div', {
          staticClass: 'toast-body',
          class: this.bodyClass,
          props: link ? pluckProps(linkProps, this) : {},
          on: link ? {
            click: this.onLinkClick
          } : {}
        }, this.normalizeSlot(SLOT_NAME_DEFAULT, slotScope));
        return h('div', {
          staticClass: 'toast',
          class: this.toastClass,
          attrs: this.computedAttrs,
          key: "toast-".concat(this[COMPONENT_UID_KEY]),
          ref: 'toast'
        }, [$header, $body]);
      }
    },
    render: function render(h) {
      if (!this.doRender || !this.isMounted) {
        return h();
      }

      var order = this.order,
          isStatic = this.static,
          isHiding = this.isHiding,
          isStatus = this.isStatus;
      var name = "b-toast-".concat(this[COMPONENT_UID_KEY]);
      var $toast = h('div', {
        staticClass: 'b-toast',
        class: this.toastClasses,
        attrs: _objectSpread2$3(_objectSpread2$3({}, isStatic ? {} : this.scopedStyleAttrs), {}, {
          id: this.safeId('_toast_outer'),
          role: isHiding ? null : isStatus ? 'status' : 'alert',
          'aria-live': isHiding ? null : isStatus ? 'polite' : 'assertive',
          'aria-atomic': isHiding ? null : 'true'
        }),
        key: name,
        ref: 'b-toast'
      }, [h(BVTransition, {
        props: {
          noFade: this.noFade
        },
        on: this.transitionHandlers
      }, [this.localShow ? this.makeToast(h) : h()])]);
      return h(Portal, {
        props: {
          name: name,
          to: this.computedToaster,
          order: order,
          slim: true,
          disabled: isStatic
        }
      }, [$toast]);
    }
  });

  var PROP_NAME = '$bvToast';
  var PROP_NAME_PRIV = '_bv__toast'; // Base toast props that are allowed
  // Some may be ignored or overridden on some message boxes
  // Prop ID is allowed, but really only should be used for testing
  // We need to add it in explicitly as it comes from the `idMixin`

  var BASE_PROPS = ['id'].concat(_toConsumableArray$1(keys(omit(props, ['static', 'visible'])))); // Map prop names to toast slot names

  var propsToSlots = {
    toastContent: 'default',
    title: 'toast-title'
  }; // --- Helper methods ---
  // Method to filter only recognized props that are not undefined

  var filterOptions = function filterOptions(options) {
    return BASE_PROPS.reduce(function (memo, key) {
      if (!isUndefined(options[key])) {
        memo[key] = options[key];
      }

      return memo;
    }, {});
  }; // Method to install `$bvToast` VM injection


  var plugin = function plugin(Vue) {
    // Create a private sub-component constructor that
    // extends BToast and self-destructs after hidden
    // @vue/component
    var BVToastPop = Vue.extend({
      name: NAME_TOAST_POP,
      extends: BToast,
      mixins: [useParentMixin],
      destroyed: function destroyed() {
        // Make sure we not in document any more
        var $el = this.$el;

        if ($el && $el.parentNode) {
          $el.parentNode.removeChild($el);
        }
      },
      mounted: function mounted() {
        var _this = this;

        // Self destruct handler
        var handleDestroy = function handleDestroy() {
          // Ensure the toast has been force hidden
          _this.localShow = false;
          _this.doRender = false;

          _this.$nextTick(function () {
            _this.$nextTick(function () {
              // In a `requestAF()` to release control back to application
              // and to allow the portal-target time to remove the content
              requestAF(function () {
                _this.$destroy();
              });
            });
          });
        }; // Self destruct if parent destroyed


        this.bvParent.$once(HOOK_EVENT_NAME_DESTROYED, handleDestroy); // Self destruct after hidden

        this.$once(EVENT_NAME_HIDDEN, handleDestroy); // Self destruct when toaster is destroyed

        this.listenOnRoot(getRootEventName(NAME_TOASTER, EVENT_NAME_DESTROYED), function (toaster) {
          /* istanbul ignore next: hard to test */
          if (toaster === _this.toaster) {
            handleDestroy();
          }
        });
      }
    }); // Private method to generate the on-demand toast

    var makeToast = function makeToast(props, parent) {
      if (warnNotClient(PROP_NAME)) {
        /* istanbul ignore next */
        return;
      } // Create an instance of `BVToastPop` component


      var toast = createNewChildComponent(parent, BVToastPop, {
        // We set parent as the local VM so these toasts can emit events on the
        // app `$root`, and it ensures `BToast` is destroyed when parent is destroyed
        propsData: _objectSpread2$3(_objectSpread2$3(_objectSpread2$3({}, filterOptions(getComponentConfig(NAME_TOAST))), omit(props, keys(propsToSlots))), {}, {
          // Props that can't be overridden
          static: false,
          visible: true
        })
      }); // Convert certain props to slots

      keys(propsToSlots).forEach(function (prop) {
        var value = props[prop];

        if (!isUndefined(value)) {
          // Can be a string, or array of VNodes
          if (prop === 'title' && isString(value)) {
            // Special case for title if it is a string, we wrap in a <strong>
            value = [parent.$createElement('strong', {
              class: 'mr-2'
            }, value)];
          }

          toast.$slots[propsToSlots[prop]] = concat(value);
        }
      }); // Create a mount point (a DIV) and mount it (which triggers the show)

      var div = document.createElement('div');
      document.body.appendChild(div);
      toast.$mount(div);
    }; // Declare BvToast instance property class


    var BvToast = /*#__PURE__*/function () {
      function BvToast(vm) {
        _classCallCheck(this, BvToast);

        // Assign the new properties to this instance
        assign(this, {
          _vm: vm,
          _root: getEventRoot(vm)
        }); // Set these properties as read-only and non-enumerable

        defineProperties(this, {
          _vm: readonlyDescriptor(),
          _root: readonlyDescriptor()
        });
      } // --- Public Instance methods ---
      // Opens a user defined toast and returns immediately


      _createClass(BvToast, [{
        key: "toast",
        value: function toast(content) {
          var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

          if (!content || warnNotClient(PROP_NAME)) {
            /* istanbul ignore next */
            return;
          }

          makeToast(_objectSpread2$3(_objectSpread2$3({}, filterOptions(options)), {}, {
            toastContent: content
          }), this._vm);
        } // shows a `<b-toast>` component with the specified ID

      }, {
        key: "show",
        value: function show(id) {
          if (id) {
            this._root.$emit(getRootActionEventName(NAME_TOAST, EVENT_NAME_SHOW), id);
          }
        } // Hide a toast with specified ID, or if not ID all toasts

      }, {
        key: "hide",
        value: function hide() {
          var id = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;

          this._root.$emit(getRootActionEventName(NAME_TOAST, EVENT_NAME_HIDE), id);
        }
      }]);

      return BvToast;
    }(); // Add our instance mixin


    Vue.mixin({
      beforeCreate: function beforeCreate() {
        // Because we need access to `$root` for `$emits`, and VM for parenting,
        // we have to create a fresh instance of `BvToast` for each VM
        this[PROP_NAME_PRIV] = new BvToast(this);
      }
    }); // Define our read-only `$bvToast` instance property
    // Placed in an if just in case in HMR mode

    if (!hasOwnProperty(Vue.prototype, PROP_NAME)) {
      defineProperty$1(Vue.prototype, PROP_NAME, {
        get: function get() {
          /* istanbul ignore next */
          if (!this || !this[PROP_NAME_PRIV]) {
            warn("\"".concat(PROP_NAME, "\" must be accessed from a Vue instance \"this\" context."), NAME_TOAST);
          }

          return this[PROP_NAME_PRIV];
        }
      });
    }
  };

  var BVToastPlugin = /*#__PURE__*/pluginFactory({
    plugins: {
      plugin: plugin
    }
  });

  var ToastPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BToast: BToast,
      BToaster: BToaster
    },
    // $bvToast injection
    plugins: {
      BVToastPlugin: BVToastPlugin
    }
  });

  var BV_TOOLTIP = '__BV_Tooltip__'; // Default trigger

  var DefaultTrigger = 'hover focus'; // Valid event triggers

  var validTriggers = {
    focus: true,
    hover: true,
    click: true,
    blur: true,
    manual: true
  }; // Directive modifier test regular expressions. Pre-compile for performance

  var htmlRE = /^html$/i;
  var noninteractiveRE = /^noninteractive$/i;
  var noFadeRE = /^nofade$/i;
  var placementRE = /^(auto|top(left|right)?|bottom(left|right)?|left(top|bottom)?|right(top|bottom)?)$/i;
  var boundaryRE = /^(window|viewport|scrollParent)$/i;
  var delayRE = /^d\d+$/i;
  var delayShowRE = /^ds\d+$/i;
  var delayHideRE = /^dh\d+$/i;
  var offsetRE$1 = /^o-?\d+$/i;
  var variantRE = /^v-.+$/i;
  var spacesRE = /\s+/; // Build a Tooltip config based on bindings (if any)
  // Arguments and modifiers take precedence over passed value config object

  var parseBindings$1 = function parseBindings(bindings, vnode)
  /* istanbul ignore next: not easy to test */
  {
    // We start out with a basic config
    var config = {
      title: undefined,
      trigger: '',
      // Default set below if needed
      placement: 'top',
      fallbackPlacement: 'flip',
      container: false,
      // Default of body
      animation: true,
      offset: 0,
      id: null,
      html: false,
      interactive: true,
      disabled: false,
      delay: getComponentConfig(NAME_TOOLTIP, 'delay', 50),
      boundary: String(getComponentConfig(NAME_TOOLTIP, 'boundary', 'scrollParent')),
      boundaryPadding: toInteger(getComponentConfig(NAME_TOOLTIP, 'boundaryPadding', 5), 0),
      variant: getComponentConfig(NAME_TOOLTIP, 'variant'),
      customClass: getComponentConfig(NAME_TOOLTIP, 'customClass')
    }; // Process `bindings.value`

    if (isString(bindings.value) || isNumber(bindings.value)) {
      // Value is tooltip content (HTML optionally supported)
      config.title = bindings.value;
    } else if (isFunction$1(bindings.value)) {
      // Title generator function
      config.title = bindings.value;
    } else if (isPlainObject(bindings.value)) {
      // Value is config object, so merge
      config = _objectSpread2$3(_objectSpread2$3({}, config), bindings.value);
    } // If title is not provided, try title attribute


    if (isUndefined(config.title)) {
      // Try attribute
      var attrs = isVue3 ? vnode.props : (vnode.data || {}).attrs;
      config.title = attrs && !isUndefinedOrNull(attrs.title) ? attrs.title : undefined;
    } // Normalize delay


    if (!isPlainObject(config.delay)) {
      config.delay = {
        show: toInteger(config.delay, 0),
        hide: toInteger(config.delay, 0)
      };
    } // If argument, assume element ID of container element


    if (bindings.arg) {
      // Element ID specified as arg
      // We must prepend '#' to become a CSS selector
      config.container = "#".concat(bindings.arg);
    } // Process modifiers


    keys(bindings.modifiers).forEach(function (mod) {
      if (htmlRE.test(mod)) {
        // Title allows HTML
        config.html = true;
      } else if (noninteractiveRE.test(mod)) {
        // Noninteractive
        config.interactive = false;
      } else if (noFadeRE.test(mod)) {
        // No animation
        config.animation = false;
      } else if (placementRE.test(mod)) {
        // Placement of tooltip
        config.placement = mod;
      } else if (boundaryRE.test(mod)) {
        // Boundary of tooltip
        mod = mod === 'scrollparent' ? 'scrollParent' : mod;
        config.boundary = mod;
      } else if (delayRE.test(mod)) {
        // Delay value
        var delay = toInteger(mod.slice(1), 0);
        config.delay.show = delay;
        config.delay.hide = delay;
      } else if (delayShowRE.test(mod)) {
        // Delay show value
        config.delay.show = toInteger(mod.slice(2), 0);
      } else if (delayHideRE.test(mod)) {
        // Delay hide value
        config.delay.hide = toInteger(mod.slice(2), 0);
      } else if (offsetRE$1.test(mod)) {
        // Offset value, negative allowed
        config.offset = toInteger(mod.slice(1), 0);
      } else if (variantRE.test(mod)) {
        // Variant
        config.variant = mod.slice(2) || null;
      }
    }); // Special handling of event trigger modifiers trigger is
    // a space separated list

    var selectedTriggers = {}; // Parse current config object trigger

    concat(config.trigger || '').filter(identity).join(' ').trim().toLowerCase().split(spacesRE).forEach(function (trigger) {
      if (validTriggers[trigger]) {
        selectedTriggers[trigger] = true;
      }
    }); // Parse modifiers for triggers

    keys(bindings.modifiers).forEach(function (mod) {
      mod = mod.toLowerCase();

      if (validTriggers[mod]) {
        // If modifier is a valid trigger
        selectedTriggers[mod] = true;
      }
    }); // Sanitize triggers

    config.trigger = keys(selectedTriggers).join(' ');

    if (config.trigger === 'blur') {
      // Blur by itself is useless, so convert it to 'focus'
      config.trigger = 'focus';
    }

    if (!config.trigger) {
      // Use default trigger
      config.trigger = DefaultTrigger;
    } // Return the config


    return config;
  }; // Add/update Tooltip on our element


  var applyTooltip = function applyTooltip(el, bindings, vnode) {
    if (!IS_BROWSER) {
      /* istanbul ignore next */
      return;
    }

    var config = parseBindings$1(bindings, vnode);

    if (!el[BV_TOOLTIP]) {
      var parent = getInstanceFromDirective(vnode, bindings);
      el[BV_TOOLTIP] = createNewChildComponent(parent, BVTooltip, {
        // Add the parent's scoped style attribute data
        _scopeId: getScopeId(parent, undefined)
      });
      el[BV_TOOLTIP].__bv_prev_data__ = {};
      el[BV_TOOLTIP].$on(EVENT_NAME_SHOW, function ()
      /* istanbul ignore next: for now */
      {
        // Before showing the tooltip, we update the title if it is a function
        if (isFunction$1(config.title)) {
          el[BV_TOOLTIP].updateData({
            title: config.title(el)
          });
        }
      });
    }

    var data = {
      title: config.title,
      triggers: config.trigger,
      placement: config.placement,
      fallbackPlacement: config.fallbackPlacement,
      variant: config.variant,
      customClass: config.customClass,
      container: config.container,
      boundary: config.boundary,
      delay: config.delay,
      offset: config.offset,
      noFade: !config.animation,
      id: config.id,
      interactive: config.interactive,
      disabled: config.disabled,
      html: config.html
    };
    var oldData = el[BV_TOOLTIP].__bv_prev_data__;
    el[BV_TOOLTIP].__bv_prev_data__ = data;

    if (!looseEqual(data, oldData)) {
      // We only update the instance if data has changed
      var newData = {
        target: el
      };
      keys(data).forEach(function (prop) {
        // We only pass data properties that have changed
        if (data[prop] !== oldData[prop]) {
          // if title is a function, we execute it here
          newData[prop] = prop === 'title' && isFunction$1(data[prop]) ? data[prop](el) : data[prop];
        }
      });
      el[BV_TOOLTIP].updateData(newData);
    }
  }; // Remove Tooltip on our element


  var removeTooltip = function removeTooltip(el) {
    if (el[BV_TOOLTIP]) {
      el[BV_TOOLTIP].$destroy();
      el[BV_TOOLTIP] = null;
    }

    delete el[BV_TOOLTIP];
  }; // Export our directive


  var VBTooltip = {
    bind: function bind(el, bindings, vnode) {
      applyTooltip(el, bindings, vnode);
    },
    // We use `componentUpdated` here instead of `update`, as the former
    // waits until the containing component and children have finished updating
    componentUpdated: function componentUpdated(el, bindings, vnode) {
      // Performed in a `$nextTick()` to prevent render update loops
      nextTick(function () {
        applyTooltip(el, bindings, vnode);
      });
    },
    unbind: function unbind(el) {
      removeTooltip(el);
    }
  };

  var VBTooltipPlugin = /*#__PURE__*/pluginFactory({
    directives: {
      VBTooltip: VBTooltip
    }
  });

  var TooltipPlugin = /*#__PURE__*/pluginFactory({
    components: {
      BTooltip: BTooltip
    },
    plugins: {
      VBTooltipPlugin: VBTooltipPlugin
    }
  });

  var componentsPlugin = /*#__PURE__*/pluginFactory({
    plugins: {
      AlertPlugin: AlertPlugin,
      AspectPlugin: AspectPlugin,
      AvatarPlugin: AvatarPlugin,
      BadgePlugin: BadgePlugin,
      BreadcrumbPlugin: BreadcrumbPlugin,
      ButtonPlugin: ButtonPlugin,
      ButtonGroupPlugin: ButtonGroupPlugin,
      ButtonToolbarPlugin: ButtonToolbarPlugin,
      CalendarPlugin: CalendarPlugin,
      CardPlugin: CardPlugin,
      CarouselPlugin: CarouselPlugin,
      CollapsePlugin: CollapsePlugin,
      DropdownPlugin: DropdownPlugin,
      EmbedPlugin: EmbedPlugin,
      FormPlugin: FormPlugin,
      FormCheckboxPlugin: FormCheckboxPlugin,
      FormDatepickerPlugin: FormDatepickerPlugin,
      FormFilePlugin: FormFilePlugin,
      FormGroupPlugin: FormGroupPlugin,
      FormInputPlugin: FormInputPlugin,
      FormRadioPlugin: FormRadioPlugin,
      FormRatingPlugin: FormRatingPlugin,
      FormSelectPlugin: FormSelectPlugin,
      FormSpinbuttonPlugin: FormSpinbuttonPlugin,
      FormTagsPlugin: FormTagsPlugin,
      FormTextareaPlugin: FormTextareaPlugin,
      FormTimepickerPlugin: FormTimepickerPlugin,
      ImagePlugin: ImagePlugin,
      InputGroupPlugin: InputGroupPlugin,
      JumbotronPlugin: JumbotronPlugin,
      LayoutPlugin: LayoutPlugin,
      LinkPlugin: LinkPlugin,
      ListGroupPlugin: ListGroupPlugin,
      MediaPlugin: MediaPlugin,
      ModalPlugin: ModalPlugin,
      NavPlugin: NavPlugin,
      NavbarPlugin: NavbarPlugin,
      OverlayPlugin: OverlayPlugin,
      PaginationPlugin: PaginationPlugin,
      PaginationNavPlugin: PaginationNavPlugin,
      PopoverPlugin: PopoverPlugin,
      ProgressPlugin: ProgressPlugin,
      SidebarPlugin: SidebarPlugin,
      SkeletonPlugin: SkeletonPlugin,
      SpinnerPlugin: SpinnerPlugin,
      TablePlugin: TablePlugin,
      TabsPlugin: TabsPlugin,
      TimePlugin: TimePlugin,
      ToastPlugin: ToastPlugin,
      TooltipPlugin: TooltipPlugin
    }
  });

  var VBHoverPlugin = /*#__PURE__*/pluginFactory({
    directives: {
      VBHover: VBHover
    }
  });

  var VBModalPlugin = /*#__PURE__*/pluginFactory({
    directives: {
      VBModal: VBModal
    }
  });

  /*
   * Constants / Defaults
   */

  var NAME$1 = 'v-b-scrollspy';
  var CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item';
  var CLASS_NAME_ACTIVE = 'active';
  var SELECTOR_NAV_LIST_GROUP = '.nav, .list-group';
  var SELECTOR_NAV_LINKS = '.nav-link';
  var SELECTOR_NAV_ITEMS = '.nav-item';
  var SELECTOR_LIST_ITEMS = '.list-group-item';
  var SELECTOR_DROPDOWN = '.dropdown, .dropup';
  var SELECTOR_DROPDOWN_ITEMS = '.dropdown-item';
  var SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle';
  var ROOT_EVENT_NAME_ACTIVATE = getRootEventName('BVScrollspy', 'activate');
  var METHOD_OFFSET = 'offset';
  var METHOD_POSITION = 'position';
  var Default = {
    element: 'body',
    offset: 10,
    method: 'auto',
    throttle: 75
  };
  var DefaultType = {
    element: '(string|element|component)',
    offset: 'number',
    method: 'string',
    throttle: 'number'
  }; // Transition Events

  var TransitionEndEvents = ['webkitTransitionEnd', 'transitionend', 'otransitionend', 'oTransitionEnd'];
  /*
   * Utility Methods
   */
  // Better var type detection

  var toType = function toType(obj)
  /* istanbul ignore next: not easy to test */
  {
    return toString$1(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
  }; // Check config properties for expected types

  /* istanbul ignore next */


  var typeCheckConfig = function typeCheckConfig(componentName, config, configTypes)
  /* istanbul ignore next: not easy to test */
  {
    for (var property in configTypes) {
      if (hasOwnProperty(configTypes, property)) {
        var expectedTypes = configTypes[property];
        var value = config[property];
        var valueType = value && isElement(value) ? 'element' : toType(value); // handle Vue instances

        valueType = value && value._isVue ? 'component' : valueType;

        if (!new RegExp(expectedTypes).test(valueType)) {
          /* istanbul ignore next */
          warn("".concat(componentName, ": Option \"").concat(property, "\" provided type \"").concat(valueType, "\" but expected type \"").concat(expectedTypes, "\""));
        }
      }
    }
  };
  /*
   * ------------------------------------------------------------------------
   * Class Definition
   * ------------------------------------------------------------------------
   */

  /* istanbul ignore next: not easy to test */


  var BVScrollspy
  /* istanbul ignore next: not easy to test */
  = /*#__PURE__*/function () {
    function BVScrollspy(element, config, $root) {
      _classCallCheck(this, BVScrollspy);

      // The element we activate links in
      this.$el = element;
      this.$scroller = null;
      this.$selector = [SELECTOR_NAV_LINKS, SELECTOR_LIST_ITEMS, SELECTOR_DROPDOWN_ITEMS].join(',');
      this.$offsets = [];
      this.$targets = [];
      this.$activeTarget = null;
      this.$scrollHeight = 0;
      this.$resizeTimeout = null;
      this.$scrollerObserver = null;
      this.$targetsObserver = null;
      this.$root = $root || null;
      this.$config = null;
      this.updateConfig(config);
    }

    _createClass(BVScrollspy, [{
      key: "updateConfig",
      value: function updateConfig(config, $root) {
        if (this.$scroller) {
          // Just in case out scroll element has changed
          this.unlisten();
          this.$scroller = null;
        }

        var cfg = _objectSpread2$3(_objectSpread2$3({}, this.constructor.Default), config);

        if ($root) {
          this.$root = $root;
        }

        typeCheckConfig(this.constructor.Name, cfg, this.constructor.DefaultType);
        this.$config = cfg;

        if (this.$root) {
          var self = this;
          this.$root.$nextTick(function () {
            self.listen();
          });
        } else {
          this.listen();
        }
      }
    }, {
      key: "dispose",
      value: function dispose() {
        this.unlisten();
        clearTimeout(this.$resizeTimeout);
        this.$resizeTimeout = null;
        this.$el = null;
        this.$config = null;
        this.$scroller = null;
        this.$selector = null;
        this.$offsets = null;
        this.$targets = null;
        this.$activeTarget = null;
        this.$scrollHeight = null;
      }
    }, {
      key: "listen",
      value: function listen() {
        var _this = this;

        var scroller = this.getScroller();

        if (scroller && scroller.tagName !== 'BODY') {
          eventOn(scroller, 'scroll', this, EVENT_OPTIONS_NO_CAPTURE);
        }

        eventOn(window, 'scroll', this, EVENT_OPTIONS_NO_CAPTURE);
        eventOn(window, 'resize', this, EVENT_OPTIONS_NO_CAPTURE);
        eventOn(window, 'orientationchange', this, EVENT_OPTIONS_NO_CAPTURE);
        TransitionEndEvents.forEach(function (eventName) {
          eventOn(window, eventName, _this, EVENT_OPTIONS_NO_CAPTURE);
        });
        this.setObservers(true); // Schedule a refresh

        this.handleEvent('refresh');
      }
    }, {
      key: "unlisten",
      value: function unlisten() {
        var _this2 = this;

        var scroller = this.getScroller();
        this.setObservers(false);

        if (scroller && scroller.tagName !== 'BODY') {
          eventOff(scroller, 'scroll', this, EVENT_OPTIONS_NO_CAPTURE);
        }

        eventOff(window, 'scroll', this, EVENT_OPTIONS_NO_CAPTURE);
        eventOff(window, 'resize', this, EVENT_OPTIONS_NO_CAPTURE);
        eventOff(window, 'orientationchange', this, EVENT_OPTIONS_NO_CAPTURE);
        TransitionEndEvents.forEach(function (eventName) {
          eventOff(window, eventName, _this2, EVENT_OPTIONS_NO_CAPTURE);
        });
      }
    }, {
      key: "setObservers",
      value: function setObservers(on) {
        var _this3 = this;

        // We observe both the scroller for content changes, and the target links
        this.$scrollerObserver && this.$scrollerObserver.disconnect();
        this.$targetsObserver && this.$targetsObserver.disconnect();
        this.$scrollerObserver = null;
        this.$targetsObserver = null;

        if (on) {
          this.$targetsObserver = observeDom(this.$el, function () {
            _this3.handleEvent('mutation');
          }, {
            subtree: true,
            childList: true,
            attributes: true,
            attributeFilter: ['href']
          });
          this.$scrollerObserver = observeDom(this.getScroller(), function () {
            _this3.handleEvent('mutation');
          }, {
            subtree: true,
            childList: true,
            characterData: true,
            attributes: true,
            attributeFilter: ['id', 'style', 'class']
          });
        }
      } // General event handler

    }, {
      key: "handleEvent",
      value: function handleEvent(event) {
        var type = isString(event) ? event : event.type;
        var self = this;

        var resizeThrottle = function resizeThrottle() {
          if (!self.$resizeTimeout) {
            self.$resizeTimeout = setTimeout(function () {
              self.refresh();
              self.process();
              self.$resizeTimeout = null;
            }, self.$config.throttle);
          }
        };

        if (type === 'scroll') {
          if (!this.$scrollerObserver) {
            // Just in case we are added to the DOM before the scroll target is
            // We re-instantiate our listeners, just in case
            this.listen();
          }

          this.process();
        } else if (/(resize|orientationchange|mutation|refresh)/.test(type)) {
          // Postpone these events by throttle time
          resizeThrottle();
        }
      } // Refresh the list of target links on the element we are applied to

    }, {
      key: "refresh",
      value: function refresh() {
        var _this4 = this;

        var scroller = this.getScroller();

        if (!scroller) {
          return;
        }

        var autoMethod = scroller !== scroller.window ? METHOD_POSITION : METHOD_OFFSET;
        var method = this.$config.method === 'auto' ? autoMethod : this.$config.method;
        var methodFn = method === METHOD_POSITION ? position : offset$1;
        var offsetBase = method === METHOD_POSITION ? this.getScrollTop() : 0;
        this.$offsets = [];
        this.$targets = [];
        this.$scrollHeight = this.getScrollHeight(); // Find all the unique link HREFs that we will control

        selectAll(this.$selector, this.$el) // Get HREF value
        .map(function (link) {
          return getAttr(link, 'href');
        }) // Filter out HREFs that do not match our RegExp
        .filter(function (href) {
          return href && RX_HREF.test(href || '');
        }) // Find all elements with ID that match HREF hash
        .map(function (href) {
          // Convert HREF into an ID (including # at beginning)
          var id = href.replace(RX_HREF, '$1').trim();

          if (!id) {
            return null;
          } // Find the element with the ID specified by id


          var el = select(id, scroller);

          if (el && isVisible(el)) {
            return {
              offset: toInteger(methodFn(el).top, 0) + offsetBase,
              target: id
            };
          }

          return null;
        }).filter(identity) // Sort them by their offsets (smallest first)
        .sort(function (a, b) {
          return a.offset - b.offset;
        }) // record only unique targets/offsets
        .reduce(function (memo, item) {
          if (!memo[item.target]) {
            _this4.$offsets.push(item.offset);

            _this4.$targets.push(item.target);

            memo[item.target] = true;
          }

          return memo;
        }, {}); // Return this for easy chaining

        return this;
      } // Handle activating/clearing

    }, {
      key: "process",
      value: function process() {
        var scrollTop = this.getScrollTop() + this.$config.offset;
        var scrollHeight = this.getScrollHeight();
        var maxScroll = this.$config.offset + scrollHeight - this.getOffsetHeight();

        if (this.$scrollHeight !== scrollHeight) {
          this.refresh();
        }

        if (scrollTop >= maxScroll) {
          var target = this.$targets[this.$targets.length - 1];

          if (this.$activeTarget !== target) {
            this.activate(target);
          }

          return;
        }

        if (this.$activeTarget && scrollTop < this.$offsets[0] && this.$offsets[0] > 0) {
          this.$activeTarget = null;
          this.clear();
          return;
        }

        for (var i = this.$offsets.length; i--;) {
          var isActiveTarget = this.$activeTarget !== this.$targets[i] && scrollTop >= this.$offsets[i] && (isUndefined(this.$offsets[i + 1]) || scrollTop < this.$offsets[i + 1]);

          if (isActiveTarget) {
            this.activate(this.$targets[i]);
          }
        }
      }
    }, {
      key: "getScroller",
      value: function getScroller() {
        if (this.$scroller) {
          return this.$scroller;
        }

        var scroller = this.$config.element;

        if (!scroller) {
          return null;
        } else if (isElement(scroller.$el)) {
          scroller = scroller.$el;
        } else if (isString(scroller)) {
          scroller = select(scroller);
        }

        if (!scroller) {
          return null;
        }

        this.$scroller = scroller.tagName === 'BODY' ? window : scroller;
        return this.$scroller;
      }
    }, {
      key: "getScrollTop",
      value: function getScrollTop() {
        var scroller = this.getScroller();
        return scroller === window ? scroller.pageYOffset : scroller.scrollTop;
      }
    }, {
      key: "getScrollHeight",
      value: function getScrollHeight() {
        return this.getScroller().scrollHeight || mathMax(document.body.scrollHeight, document.documentElement.scrollHeight);
      }
    }, {
      key: "getOffsetHeight",
      value: function getOffsetHeight() {
        var scroller = this.getScroller();
        return scroller === window ? window.innerHeight : getBCR(scroller).height;
      }
    }, {
      key: "activate",
      value: function activate(target) {
        var _this5 = this;

        this.$activeTarget = target;
        this.clear(); // Grab the list of target links (<a href="{$target}">)

        var links = selectAll(this.$selector // Split out the base selectors
        .split(',') // Map to a selector that matches links with HREF ending in the ID (including '#')
        .map(function (selector) {
          return "".concat(selector, "[href$=\"").concat(target, "\"]");
        }) // Join back into a single selector string
        .join(','), this.$el);
        links.forEach(function (link) {
          if (hasClass(link, CLASS_NAME_DROPDOWN_ITEM)) {
            // This is a dropdown item, so find the .dropdown-toggle and set its state
            var dropdown = closest(SELECTOR_DROPDOWN, link);

            if (dropdown) {
              _this5.setActiveState(select(SELECTOR_DROPDOWN_TOGGLE, dropdown), true);
            } // Also set this link's state


            _this5.setActiveState(link, true);
          } else {
            // Set triggered link as active
            _this5.setActiveState(link, true);

            if (matches(link.parentElement, SELECTOR_NAV_ITEMS)) {
              // Handle nav-link inside nav-item, and set nav-item active
              _this5.setActiveState(link.parentElement, true);
            } // Set triggered links parents as active
            // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor


            var el = link;

            while (el) {
              el = closest(SELECTOR_NAV_LIST_GROUP, el);
              var sibling = el ? el.previousElementSibling : null;

              if (sibling && matches(sibling, "".concat(SELECTOR_NAV_LINKS, ", ").concat(SELECTOR_LIST_ITEMS))) {
                _this5.setActiveState(sibling, true);
              } // Handle special case where nav-link is inside a nav-item


              if (sibling && matches(sibling, SELECTOR_NAV_ITEMS)) {
                _this5.setActiveState(select(SELECTOR_NAV_LINKS, sibling), true); // Add active state to nav-item as well


                _this5.setActiveState(sibling, true);
              }
            }
          }
        }); // Signal event to via $root, passing ID of activated target and reference to array of links

        if (links && links.length > 0 && this.$root) {
          this.$root.$emit(ROOT_EVENT_NAME_ACTIVATE, target, links);
        }
      }
    }, {
      key: "clear",
      value: function clear() {
        var _this6 = this;

        selectAll("".concat(this.$selector, ", ").concat(SELECTOR_NAV_ITEMS), this.$el).filter(function (el) {
          return hasClass(el, CLASS_NAME_ACTIVE);
        }).forEach(function (el) {
          return _this6.setActiveState(el, false);
        });
      }
    }, {
      key: "setActiveState",
      value: function setActiveState(el, active) {
        if (!el) {
          return;
        }

        if (active) {
          addClass(el, CLASS_NAME_ACTIVE);
        } else {
          removeClass(el, CLASS_NAME_ACTIVE);
        }
      }
    }], [{
      key: "Name",
      get: function get() {
        return NAME$1;
      }
    }, {
      key: "Default",
      get: function get() {
        return Default;
      }
    }, {
      key: "DefaultType",
      get: function get() {
        return DefaultType;
      }
    }]);

    return BVScrollspy;
  }();

  var BV_SCROLLSPY = '__BV_Scrollspy__'; // Pre-compiled regular expressions

  var onlyDigitsRE = /^\d+$/;
  var offsetRE = /^(auto|position|offset)$/; // Build a Scrollspy config based on bindings (if any)
  // Arguments and modifiers take precedence over passed value config object

  /* istanbul ignore next: not easy to test */

  var parseBindings = function parseBindings(bindings)
  /* istanbul ignore next: not easy to test */
  {
    var config = {}; // If argument, assume element ID

    if (bindings.arg) {
      // Element ID specified as arg
      // We must prepend '#' to become a CSS selector
      config.element = "#".concat(bindings.arg);
    } // Process modifiers


    keys(bindings.modifiers).forEach(function (mod) {
      if (onlyDigitsRE.test(mod)) {
        // Offset value
        config.offset = toInteger(mod, 0);
      } else if (offsetRE.test(mod)) {
        // Offset method
        config.method = mod;
      }
    }); // Process value

    if (isString(bindings.value)) {
      // Value is a CSS ID or selector
      config.element = bindings.value;
    } else if (isNumber(bindings.value)) {
      // Value is offset
      config.offset = mathRound(bindings.value);
    } else if (isObject(bindings.value)) {
      // Value is config object
      // Filter the object based on our supported config options
      keys(bindings.value).filter(function (k) {
        return !!BVScrollspy.DefaultType[k];
      }).forEach(function (k) {
        config[k] = bindings.value[k];
      });
    }

    return config;
  }; // Add or update Scrollspy on our element


  var applyScrollspy = function applyScrollspy(el, bindings, vnode)
  /* istanbul ignore next: not easy to test */
  {
    if (!IS_BROWSER) {
      /* istanbul ignore next */
      return;
    }

    var config = parseBindings(bindings);

    if (el[BV_SCROLLSPY]) {
      el[BV_SCROLLSPY].updateConfig(config, getEventRoot(getInstanceFromDirective(vnode, bindings)));
    } else {
      el[BV_SCROLLSPY] = new BVScrollspy(el, config, getEventRoot(getInstanceFromDirective(vnode, bindings)));
    }
  }; // Remove Scrollspy on our element

  /* istanbul ignore next: not easy to test */


  var removeScrollspy = function removeScrollspy(el)
  /* istanbul ignore next: not easy to test */
  {
    if (el[BV_SCROLLSPY]) {
      el[BV_SCROLLSPY].dispose();
      el[BV_SCROLLSPY] = null;
      delete el[BV_SCROLLSPY];
    }
  };
  /*
   * Export our directive
   */


  var VBScrollspy = {
    /* istanbul ignore next: not easy to test */
    bind: function bind(el, bindings, vnode) {
      applyScrollspy(el, bindings, vnode);
    },

    /* istanbul ignore next: not easy to test */
    inserted: function inserted(el, bindings, vnode) {
      applyScrollspy(el, bindings, vnode);
    },

    /* istanbul ignore next: not easy to test */
    update: function update(el, bindings, vnode) {
      if (bindings.value !== bindings.oldValue) {
        applyScrollspy(el, bindings, vnode);
      }
    },

    /* istanbul ignore next: not easy to test */
    componentUpdated: function componentUpdated(el, bindings, vnode) {
      if (bindings.value !== bindings.oldValue) {
        applyScrollspy(el, bindings, vnode);
      }
    },

    /* istanbul ignore next: not easy to test */
    unbind: function unbind(el) {
      removeScrollspy(el);
    }
  };

  var VBScrollspyPlugin = /*#__PURE__*/pluginFactory({
    directives: {
      VBScrollspy: VBScrollspy
    }
  });

  var VBVisiblePlugin = /*#__PURE__*/pluginFactory({
    directives: {
      VBVisible: VBVisible
    }
  });

  var directivesPlugin = /*#__PURE__*/pluginFactory({
    plugins: {
      VBHoverPlugin: VBHoverPlugin,
      VBModalPlugin: VBModalPlugin,
      VBPopoverPlugin: VBPopoverPlugin,
      VBScrollspyPlugin: VBScrollspyPlugin,
      VBTogglePlugin: VBTogglePlugin,
      VBTooltipPlugin: VBTooltipPlugin,
      VBVisiblePlugin: VBVisiblePlugin
    }
  });

  var NAME = 'BootstrapVue'; // --- BootstrapVue installer ---

  var install = /*#__PURE__*/installFactory({
    plugins: {
      componentsPlugin: componentsPlugin,
      directivesPlugin: directivesPlugin
    }
  }); // --- BootstrapVue plugin ---

  var BootstrapVue = /*#__PURE__*/{
    install: install,
    NAME: NAME
  }; // --- Named exports for BvConfigPlugin ---

  // Main entry point for the browser build

  vueUse(BootstrapVue);

  return BootstrapVue;

})));
//# sourceMappingURL=bootstrap-vue.js.map
