import './es.array.includes-d05e3b05.js';
import './es.object.to-string-9e0d4e1d.js';
import './es.object.keys-9aa2f274.js';
import './es.string.includes-00e9ada6.js';
import BaseButton from './BaseButton-5edf9a92.js';
import { i as i18n } from './i18n-ad4a7ece.js';
import { n as normalizeComponent } from './normalize-component-1b2cdbb6.js';
import './well-known-symbol-6e9136be.js';
import './object-keys-24d2d6fd.js';
import './classof-2816ca36.js';
import './is-regexp-58409ce7.js';
import './es.symbol.description-aad7a663.js';
import './array-species-create-6fc0b2c4.js';
import './set-to-string-tag-aa9c05b1.js';
import './array-iteration-ec419780.js';
import './function-bind-context-b3fabf77.js';
import './utils-758ec5e2.js';
import './typeof-6c6d8d7a.js';
import './unsupportedIterableToArray-577176bf.js';
import './es.array.join-407e20e6.js';
import './array-method-is-strict-52649d4d.js';
import './es.array.map-2dfef513.js';
import './array-method-has-species-support-4ec91b65.js';
import './regexp-exec-abstract-6a5efbab.js';
import './string-multibyte-1626d420.js';
import './regexp-flags-e2ab70ab.js';
import './es.string.split-7ed30d2b.js';
import './es.array.slice-27d0c7ca.js';
import './create-property-2fc26c80.js';
import './es.regexp.to-string-71ed70dc.js';
import './es.string.replace-b4ea85c2.js';
import './es.array.sort-fea6d291.js';
import './web.dom-collections.for-each-ccc220dc.js';
import './dom-iterables-b6f5ef3b.js';
import './BaseIcon-d0b5435d.js';
import './es.array.concat-669570ef.js';
import './BaseBoxTooltip-6833b6c7.js';

/**
 * a row that can display options responsively either hidden behind an options button
 * or directly
 */

var script = {
  name: 'BaseOptions',
  components: {
    BaseButton: BaseButton
  },
  mixins: [i18n],
  props: {
    /**
     * set showing of option buttons from outside<br>
     *   the [.sync modifier](https://vuejs.org/v2/guide/components-custom-events.html#sync-Modifier) may be used on this prop
     */
    showOptions: {
      type: Boolean,
      default: false
    },

    /**
     * hide options completely (necessary if only before or after slot elements should remain)
     */
    optionsHidden: {
      type: Boolean,
      default: false
    },

    /**
     * define alignment of options button and options
     */
    alignOptions: {
      type: String,
      default: 'right',
      validator: function validator(val) {
        return ['left', 'right'].includes(val);
      }
    },

    /**
     * define in which scenario an options button should be shown<br>
     *   **always**: always show the options button<br>
     *   **mobile**: only show options button when window size < 640px<br>
     *   **never**: never show the options button - just show the available options directly
     */
    useOptionsButtonOn: {
      type: String,
      default: 'always',
      validator: function validator(val) {
        return ['always', 'mobile', 'never'].includes(val);
      }
    },

    /**
     * define the options button text as an object with `show` (=text that should be
     * shown with options hidden) and `hide` (=text that should be shown with options visible)<br>
     *   values can be either plain strings or a string leading to a localization file<br>
     *   (only relevant if `useOptionsButtonOn` is different from 'never')
     */
    optionsButtonText: {
      type: Object,
      default: function _default() {
        return {
          show: 'options',
          hide: 'return'
        };
      },
      validator: function validator(val) {
        return 'show' in val && 'hide' in val;
      }
    },

    /**
     * define the icon for the options button as an object with `show` (=icon that should be
     * shown with options hidden) and `hide` (=icon that should be shown with options visible)<br>
     *   see [BaseIcon](#baseicon) for available icons<br>
     *   (only relevant if `useOptionsButtonOn` is different from 'never')
     */
    optionsButtonIcon: {
      type: Object,
      default: function _default() {
        return {
          show: 'options-menu',
          hide: 'remove'
        };
      },
      validator: function validator(val) {
        return 'show' in val && 'hide' in val;
      }
    },

    /**
     * define if slot after-options should be shown before or after options
     * if row wraps because of space issues<br>
     *   (only relevant with use of options button)
     */
    showAfterOptionsBelow: {
      type: Boolean,
      default: true
    },

    /**
     * in order to display options one can either use the slot 'options' or specify a
     * config via 'optionsConfig' prop. If the latter option is used the following properties
     * need to be provided:<br>
     *   **text** {string} - the text displayed in the button<br>
     *   **icon** {string} - the icon name to display
     *    (for available icons see [BaseIcon](#baseicon) )<br>
     *   **value** {string} - the value emitted on button click<br>
     */
    optionsConfig: {
      type: Array,
      default: function _default() {
        return [{
          text: 'delete',
          icon: 'waste-bin',
          value: 'delete'
        }];
      },
      validator: function validator(val) {
        return val.every(function (action) {
          var requiredProps = ['text', 'icon', 'value'];
          var actionProps = Object.keys(action);
          return requiredProps.every(function (prop) {
            return actionProps.includes(prop);
          });
        });
      }
    }
  },
  data: function data() {
    return {
      /**
       * internal variable for options toggle
       * @type {boolean}
       */
      showOptionsInt: false,

      /**
       * is window size < 640px
       * @type {boolean}
       */
      isMobile: true,

      /**
       * total row width needed to calc if options and after options
       * should be shown inline
       * @type {number}
       */
      rowWidth: 4000,

      /**
       * beforeOptions element width needed to calc if options
       * should be shown inline
       * @type {number}
       */
      beforeOptionsWidth: 0,

      /**
       * afterOptions element width needed to calc if options
       * should be shown inline
       * @type {number}
       */
      afterOptionsWidth: 0,

      /**
       * options button element width needed to calc if options
       * should be shown inline
       * @type {number}
       */
      optionsButtonWidth: 0,

      /**
       * width remaining inline for the actual action buttons to be rendered
       * @type {number}
       */
      remainingActionsWidth: 4000,

      /**
       * beforeOptions element width needed to calc if options
       * should be shown inline
       * @type {number}
       */
      actionButtonsWidth: 0,

      /**
       * for removing chips via backspace, to get delay after
       * keydown event
       * @type {?number}
       */
      timeout: null,

      /**
       * resize observer for specific element (instead of window)
       */
      resizeObserver: null,

      /**
       * mutation observer for specific element
       */
      mutationObserver: null
    };
  },
  computed: {
    /**
     * translate prop into boolean value to see if options
     * button should be shown
     * @returns {Boolean}
     */
    useOptionsButton: function useOptionsButton() {
      return this.useOptionsButtonOn === 'always' || this.useOptionsButtonOn === 'mobile' && this.isMobile;
    },

    /**
     * determine if options should be shown inline or below options row
     * @returns {Boolean}
     */
    showOptionsInline: function showOptionsInline() {
      return this.remainingActionsWidth - this.actionButtonsWidth > 0 || !this.useOptionsButton;
    },

    /**
     * determine if afterOptions slot should be shown above or below options in a
     * wrapping situation
     */
    showAfterOptionsInline: function showAfterOptionsInline() {
      // show options inline if
      // a) the slot was actually used and
      return this.afterSlotHasData // b) options button is not used and there is enough space for them or
      && (!this.useOptionsButton && this.remainingActionsWidth > this.actionButtonsWidth // c) options button is used and there is enough space left inline or
      // showAfterOptionsBelow is false
      || this.useOptionsButton && (!this.showAfterOptionsBelow || this.remainingActionsWidth > 0));
    },

    /**
     * determine if action buttons need to be flex-wrapped
     */
    wrapActions: function wrapActions() {
      return this.rowWidth <= this.actionButtonsWidth;
    },
    wrapHeaderActions: function wrapHeaderActions() {
      return this.rowWidth - this.beforeOptionsWidth < this.actionButtonsWidth;
    },

    /**
     * determine if before slot has data
     * @returns {Boolean}
     */
    beforeSlotHasData: function beforeSlotHasData() {
      return !!this.$slots.beforeOptions;
    },

    /**
     * determine if after slot has data
     * @returns {Boolean}
     */
    afterSlotHasData: function afterSlotHasData() {
      return !!this.$slots.afterOptions;
    }
  },
  watch: {
    // watch options toggle to recalculate the remaining size
    // for options (= should they be shown inline or below)
    showOptionsInt: function showOptionsInt(val) {
      if (this.showOptions !== val) {
        /**
         * emitted when options button is toggled (not relevant if 'useOptionsButtonOn' prop
         * is set to 'never')<br>
         *   the .sync modifier can be used on 'showOptions' prop here
         * @event update:show-options
         * @param {boolean} val - was show value set true or false
         */
        this.$emit('update:show-options', val);
      }
    },
    // update show options internal value if different from parent
    showOptions: {
      handler: function handler(val) {
        if (this.showOptionsInt !== val && this.useOptionsButton) {
          this.showOptionsInt = val;
        }
      },
      immediate: true
    },

    /**
     * watch use options button variable which changes if options button
     * is only used on mobile
     * @param {boolean} val
     */
    useOptionsButton: {
      handler: function handler(val) {
        // make sure options are shown when options button is disabled
        if (!val) {
          this.showOptionsInt = true;
        }
      },
      immediate: true
    },

    /**
     * watch isMobile to have the options transform into options button when
     * useOptionsButtonOn is 'mobile'
     *
     * @param {boolean} val
     */
    isMobile: function isMobile(val) {
      if (this.useOptionsButtonOn === 'mobile' && val) {
        this.showOptionsInt = false;
      }
    }
  },
  mounted: function mounted() {
    // to listen to element with instead of window width create an observer!
    this.initObserver();
  },
  updated: function updated() {
    // calc the width of all fixed width elements (beforeOptions,
    // options button, after Options)
    this.calcFixedElementWidth();

    if (this.showOptionsInt && this.$refs.actions) {
      this.calcOptionsWidth();
    }
  },
  beforeDestroy: function beforeDestroy() {
    if (this.resizeObserver) this.resizeObserver.unobserve(this.$refs.optionsRow);
    if (this.mutationObserver && this.afterSlotHasData) this.mutationObserver.disconnect();
  },
  methods: {
    initObserver: function initObserver() {
      var resizeObserver = new ResizeObserver(this.resizeActions);
      resizeObserver.observe(this.$refs.optionsRow);
      this.resizeObserver = resizeObserver;

      if (this.afterSlotHasData) {
        var mutationObserver = new MutationObserver(this.calcOptionsWidth);
        mutationObserver.observe(this.$refs.afterOptions, {
          childList: true,
          subtree: true
        });
        this.mutationObserver = mutationObserver;
      }
    },
    optionTriggered: function optionTriggered(value) {
      /**
       * emitted if prop `optionsConfig` is used when an options button is clicked
       *
       * @event option-triggered
       * @param {string} value - the value provided in `optionsConfig` object
       */
      this.$emit('option-triggered', value);
    },

    /**
     * method for all resize actions with setTimeout function to prevent
     * triggering to often
     */
    resizeActions: function resizeActions() {
      var _this = this;

      // check if time out was set
      if (this.timeout) {
        // if yes clear old one
        clearTimeout(this.timeout);
        this.timeout = null;
      } // now set new time out


      this.timeout = setTimeout(function () {
        // calc if window size is now mobile
        _this.calcIsMobile();
      }, 200); // no timeout for options positioning for smoother experience
      // calc if options should be shown inline (= enough space left)

      this.calcOptionsWidth();
    },

    /**
     * calculate if size is mobile size after initial render and
     * window resize events
     */
    calcIsMobile: function calcIsMobile() {
      this.isMobile = window.innerWidth < 640;
    },

    /**
     * calculate the variable width elements width after initial render, options toggle
     * or window resize events
     */
    calcOptionsWidth: function calcOptionsWidth() {
      // get the complete options row element
      var optionsRow = this.$refs.optionsRow;

      if (optionsRow) {
        this.rowWidth = optionsRow.clientWidth;
      } // check if it is defined - if yes - calculate the width remaining for the action buttons


      this.remainingActionsWidth = optionsRow ? this.rowWidth - this.beforeOptionsWidth - this.afterOptionsWidth - this.optionsButtonWidth : 0; // get the action button elements

      var actionsElement = this.$refs.actions; // check if it is defined

      if (actionsElement) {
        // if yes - get the width they all together actually take up
        this.actionButtonsWidth = actionsElement.clientWidth;
      }
    },

    /**
     * function for elements width that only has to be calculated once
     */
    calcFixedElementWidth: function calcFixedElementWidth() {
      // check if the slot beforeOptions has elements
      if (this.beforeSlotHasData && this.$refs.beforeOptions) {
        // if yes set the variable with the width of the element
        this.beforeOptionsWidth = this.$refs.beforeOptions.clientWidth;
      } // check if the slot afterOptions has data


      if (this.afterSlotHasData && this.$refs.afterOptions) {
        // if yes set the variable with the width of the element
        this.afterOptionsWidth = this.$refs.afterOptions.clientWidth;
      } // get the options button element


      var optionsButtonElement = this.$refs.optionsButton; // check if it is used and rendered

      if (this.useOptionsButton && optionsButtonElement) {
        // if yes - set the variable to store the button width
        this.optionsButtonWidth = optionsButtonElement.$el.clientWidth;
      }
    }
  }
};

/* script */
var __vue_script__ = script;
/* template */

var __vue_render__ = function __vue_render__() {
  var _vm = this;

  var _h = _vm.$createElement;

  var _c = _vm._self._c || _h;

  return _c('div', {
    staticClass: "base-options"
  }, [_c('div', {
    ref: "optionsRow",
    class: ['base-options__row', "base-options__row-" + _vm.alignOptions, {
      'base-options__row-wrap': !_vm.showOptionsInline || !_vm.useOptionsButton && _vm.remainingActionsWidth < _vm.actionButtonsWidth
    }]
  }, [_vm.beforeSlotHasData ? _c('div', {
    ref: "beforeOptions",
    staticClass: "base-options__before"
  }, [_vm._t("beforeOptions")], 2) : _vm._e(), _vm._v(" "), _vm.alignOptions === 'right' ? _c('div', {
    staticClass: "base-options__spacer"
  }) : _vm._e(), _vm._v(" "), !_vm.optionsHidden && _vm.showOptionsInline && _vm.showOptionsInt ? _c('div', {
    ref: "actions",
    class: ['base-options__options-inline', {
      'base-options__options-inline-wrap': _vm.wrapActions
    }, {
      'base-options__options-inline-left': _vm.alignOptions === 'left'
    }]
  }, [_vm._t("options", function () {
    return [_vm.optionsConfig.length ? _vm._l(_vm.optionsConfig, function (config, index) {
      return _c('BaseButton', {
        key: config.text + '_' + index,
        attrs: {
          "text": config.text,
          "icon": config.icon,
          "has-background-color": false,
          "icon-size": "large",
          "button-style": "single"
        },
        on: {
          "clicked": function clicked($event) {
            return _vm.optionTriggered(config.value);
          }
        }
      });
    }) : _vm._e()];
  })], 2) : _vm._e(), _vm._v(" "), !_vm.optionsHidden && _vm.useOptionsButton ? _c('BaseButton', {
    ref: "optionsButton",
    class: [{
      'base-options__options-button-left': _vm.alignOptions === 'left'
    }],
    attrs: {
      "text": _vm.showOptionsInt ? _vm.getI18nTerm(_vm.optionsButtonText.hide) : _vm.getI18nTerm(_vm.optionsButtonText.show),
      "icon": _vm.showOptionsInt ? _vm.optionsButtonIcon.hide : _vm.optionsButtonIcon.show
    },
    on: {
      "clicked": function clicked($event) {
        _vm.showOptionsInt = !_vm.showOptionsInt;
      }
    }
  }) : _vm._e(), _vm._v(" "), _vm.alignOptions === 'left' ? _c('div', {
    staticClass: "base-options__spacer base-options__spacer-left"
  }) : _vm._e(), _vm._v(" "), _vm.showAfterOptionsInline && _vm.afterSlotHasData ? _c('div', {
    ref: "afterOptions",
    staticClass: "base-options__after-inline"
  }, [_vm._t("afterOptions")], 2) : _vm._e()], 1), _vm._v(" "), _c('transition', {
    attrs: {
      "name": "slide-fade-options"
    }
  }, [!_vm.optionsHidden && _vm.showOptionsInt && !_vm.showOptionsInline ? _c('div', {
    staticClass: "base-options__below"
  }, [_vm._t("options", function () {
    return [_vm.optionsConfig.length ? _vm._l(_vm.optionsConfig, function (config, index) {
      return _c('BaseButton', {
        key: config.text + '_' + index,
        attrs: {
          "text": config.text,
          "icon": config.icon,
          "has-background-color": false,
          "icon-size": "large",
          "button-style": "single"
        },
        on: {
          "clicked": function clicked($event) {
            return _vm.optionTriggered(config.value);
          }
        }
      });
    }) : _vm._e()];
  })], 2) : _vm._e()]), _vm._v(" "), !_vm.showAfterOptionsInline && _vm.afterSlotHasData ? _c('div', {
    staticClass: "base-options__after"
  }, [_vm._t("afterOptions")], 2) : _vm._e()], 1);
};

var __vue_staticRenderFns__ = [];
/* style */

var __vue_inject_styles__ = undefined;
/* scoped */

var __vue_scope_id__ = "data-v-c6c5f404";
/* module identifier */

var __vue_module_identifier__ = undefined;
/* functional template */

var __vue_is_functional_template__ = false;
/* style inject */

/* style inject SSR */

/* style inject shadow dom */

var __vue_component__ = /*#__PURE__*/normalizeComponent({
  render: __vue_render__,
  staticRenderFns: __vue_staticRenderFns__
}, __vue_inject_styles__, __vue_script__, __vue_scope_id__, __vue_is_functional_template__, __vue_module_identifier__, false, undefined, undefined, undefined);

var BaseOptions = __vue_component__;

export { BaseOptions as default };
