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 _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), 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); }
// v-b-visible
// Private visibility check directive
// Based on IntersectionObserver
//
// Usage:
//  v-b-visibility.<margin>.<once>="<callback>"
//
//  Value:
//  <callback>: method to be called when visibility state changes, receives one arg:
//     true:  element is visible
//     false: element is not visible
//     null:  IntersectionObserver not supported
//
//  Modifiers:
//    <margin>: a positive decimal value of pixels away from viewport edge
//              before being considered "visible". default is 0
//    <once>:   keyword 'once', meaning when the element becomes visible and
//              callback is called observation/notification will stop.
//
// When used in a render function:
// export default {
//   directives: { 'b-visible': VBVisible },
//   render(h) {
//     h(
//       'div',
//       {
//         directives: [
//           { name: 'b-visible', value=this.callback, modifiers: { '123':true, 'once':true } }
//         ]
//       }
//     )
//   }

import { RX_DIGITS } from '../../constants/regex';
import { requestAF } from '../../utils/dom';
import { isFunction } from '../../utils/inspect';
import { looseEqual } from '../../utils/loose-equal';
import { clone, keys } from '../../utils/object';
import { nextTick } from '../../vue';
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();
  }
  return _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(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;
    }
  }]);
}();
var destroy = function destroy(el) {
  var observer = el[OBSERVER_PROP_NAME];
  if (observer && observer.stop) {
    observer.stop();
  }
  delete el[OBSERVER_PROP_NAME];
};
var bind = 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(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 = 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(el, {
      value: value,
      modifiers: modifiers
    }, vnode);
  }
};

// When directive un-binds from element
var unbind = function unbind(el) {
  // Remove the observer
  destroy(el);
};

// Export the directive
export var VBVisible = {
  bind: bind,
  componentUpdated: componentUpdated,
  unbind: unbind
};