function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
import { NAME_TOOLTIP } from '../../constants/components';
import { IS_BROWSER } from '../../constants/env';
import { EVENT_NAME_SHOW } from '../../constants/events';
import { concat } from '../../utils/array';
import { isVue3, nextTick } from '../../vue';
import { getComponentConfig } from '../../utils/config';
import { getScopeId } from '../../utils/get-scope-id';
import { identity } from '../../utils/identity';
import { getInstanceFromDirective } from '../../utils/get-instance-from-directive';
import { isFunction, isNumber, isPlainObject, isString, isUndefined, isUndefinedOrNull } from '../../utils/inspect';
import { looseEqual } from '../../utils/loose-equal';
import { toInteger } from '../../utils/number';
import { keys } from '../../utils/object';
import { createNewChildComponent } from '../../utils/create-new-child-component';
import { BVTooltip } from '../../components/tooltip/helpers/bv-tooltip';

// Key which we use to store tooltip object on element
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 = /^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 = 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(bindings.value)) {
    // Title generator function
    config.title = bindings.value;
  } else if (isPlainObject(bindings.value)) {
    // Value is config object, so merge
    config = _objectSpread(_objectSpread({}, 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.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(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(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(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
export 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);
  }
};