import _defineProperty from '@babel/runtime/helpers/defineProperty';
import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
import _objectWithoutProperties from '@babel/runtime/helpers/objectWithoutProperties';
import 'core-js/modules/es.symbol.js';
import 'core-js/modules/es.array.filter.js';
import 'core-js/modules/es.array.iterator.js';
import 'core-js/modules/es.map.js';
import 'core-js/modules/es.object.get-own-property-descriptor.js';
import 'core-js/modules/es.object.get-own-property-descriptors.js';
import 'core-js/modules/es.object.keys.js';
import 'core-js/modules/es.object.to-string.js';
import 'core-js/modules/es.string.iterator.js';
import 'core-js/modules/web.dom-collections.for-each.js';
import 'core-js/modules/web.dom-collections.iterator.js';
import { useRef, useState, useEffect } from 'react';
import warning from 'warning';
import { browserSupports } from '../utils/componentUtilityFunctions.js';
import { usePrevious } from './usePrevious.js';

var _excluded = ["setIsVisible", "unobserveAfterVisible"];
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; }
var observers = new Map();
var removeObserver = function removeObserver(element) {
  if (observers.has(element)) {
    var observer = observers.get(element);
    observer.disconnect();
    observers.delete(element);
  }
};
var getObserver = function getObserver(element, _ref) {
  var setIsVisible = _ref.setIsVisible,
    unobserveAfterVisible = _ref.unobserveAfterVisible,
    options = _objectWithoutProperties(_ref, _excluded);
  if (!observers.has(element)) {
    observers.set(element, new IntersectionObserver(function (_ref2, observer) {
      var _ref3 = _slicedToArray(_ref2, 1),
        entry = _ref3[0];
      setIsVisible(entry.isIntersecting);
      if (unobserveAfterVisible && entry.isIntersecting) {
        observer.unobserve(element);
        removeObserver(element);
      }
    }, options));
  }
  return observers.get(element);
};
var defaultOptions = {
  /** a callback that will be triggered when the ref element visibility changes */
  // eslint-disable-next-line no-unused-vars
  onChange: function onChange(_ref4) {
    _ref4.isVisible;
  },
  /**
   * what percentage of the element must be visible for onChange to be called (0.0 through 1.0)
   * 0.0 means any pixel is visible
   * 1.0 means all pixels are visible
   * */
  threshold: 0.0,
  /**
   * The element, relative to the element being observed, that determines if it is visible.
   * For example, if this is left null the element is tracked against the window, but if a scrollable
   * div is given, the visibility is checked against that scrollable area instead.
   */
  container: null,
  /**
   * A string, in the form of a css margin (ie. `100px 0px 100px 0px`, units MUST be included), that
   * sets the bounds of the visible area. If you want this to expand to trigger visibility outside
   * of the root element, simply give it a large padding. In the example above, `100px 0px 100px 0`
   * expands the visible area 100px above and below the container, so any elements that come within
   * 100px of the top or bottom of the container will be treated as visible. This allows elements to
   * be pre-loaded off screen as a user is scrolling.
   */
  padding: '50% 0px 50% 0px',
  /**
   * If true, stop tracking the element after it has become visible otherwise, it will continue to
   * track the element and trigger onChange each time it changes visibility
   */
  unobserveAfterVisible: false
};

/**
 * A simple hook to return a bool telling if the given element is visible on the screen. It can be
 * used to load a single item or multiple items.
 *
 * @param {*} elementRef html element to check if it's visible
 * @param {object} options see defaultOptions above
 * @returns Array an array containing [isVisible: bool]
 */
var useVisibilityObserver = function useVisibilityObserver(elementRef, options) {
  if (!browserSupports('IntersectionObserver')) {
    warning(!("development" !== "production"), 'The current browser does not support IntersectionObserver. You will need to include a IntersectionObserver polyfill for this component to function properly.') ;
    return [true];
  }
  var _defaultOptions$optio = _objectSpread(_objectSpread({}, defaultOptions), options),
    onChange = _defaultOptions$optio.onChange,
    threshold = _defaultOptions$optio.threshold,
    container = _defaultOptions$optio.container,
    padding = _defaultOptions$optio.padding,
    unobserveAfterVisible = _defaultOptions$optio.unobserveAfterVisible;

  /* eslint-disable react-hooks/rules-of-hooks */
  var observerRef = useRef(null);
  var _useState = useState(false),
    _useState2 = _slicedToArray(_useState, 2),
    isVisible = _useState2[0],
    setIsVisible = _useState2[1];
  var previousIsVisible = usePrevious(isVisible, false);
  useEffect(function () {
    if (isVisible !== previousIsVisible) {
      onChange({
        isVisible: isVisible
      });
    }
  }, [isVisible, onChange, previousIsVisible]);
  useEffect(function () {
    var elementToObserve = elementRef.current;
    if (elementToObserve) {
      observerRef.current = getObserver(elementToObserve, {
        setIsVisible: setIsVisible,
        unobserveAfterVisible: unobserveAfterVisible,
        root: container,
        rootMargin: padding,
        threshold: threshold
      });
      observerRef.current.observe(elementToObserve);
    }
    return function () {
      if (observerRef.current) {
        removeObserver(elementToObserve);
      }
    };
  }, [container, elementRef, padding, threshold, unobserveAfterVisible]);
  /* eslint-enable react-hooks/rules-of-hooks */

  return [isVisible];
};
var useVisibilityObserver$1 = useVisibilityObserver;

export { useVisibilityObserver$1 as default };
