'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var react = require('react');

/**
 * Creates DOM element to be used as React root.
 * @returns {HTMLElement}
 */
function createRootElement(id) {
  var rootContainer = document.createElement('div');
  rootContainer.setAttribute('id', id);
  return rootContainer;
}

/**
 * Appends element as last child of body.
 * @param {HTMLElement} rootElem
 */
function addRootElement(rootElem) {
  try {
    if (document.body.lastElementChild) {
      document.body.insertBefore(rootElem, document.body.lastElementChild.nextElementSibling);
    } else {
      console.warn('Failed to add root element, document.body is empty');
    }
  } catch (err) {
    console.warn('Failed to add root element');
  }
}

/**
 * Hook to create a React Portal.
 * Automatically handles creating and tearing-down the root elements (no SRR
 * makes this trivial), so there is no need to ensure the parent target already
 * exists.
 * @example
 * const target = usePortal(id, [id]);
 * return createPortal(children, target);
 * @param {String} id The id of the target container, e.g 'modal' or 'spotlight'
 * @returns {HTMLElement} The DOM node to use as the Portal target.
 */
var usePortal = function usePortal(id) {
  var rootElemRef = react.useRef(null);
  react.useEffect(function () {
    // Look for existing target dom element to append to
    var existingParent = document.querySelector("#".concat(id));
    // Parent is either a new root or the existing dom element
    var parentElem = existingParent || createRootElement(id);

    // If there is no existing DOM element, add a new one.
    if (!existingParent) {
      addRootElement(parentElem);
    }

    // Add the detached element to the parent
    if (rootElemRef.current) {
      parentElem.appendChild(rootElemRef.current);
    }
    return function () {
      if (rootElemRef.current) {
        rootElemRef.current.remove();
      }
      if (parentElem.childNodes.length === -1) {
        parentElem.remove();
      }
    };
  }, []);

  /**
   * It's important we evaluate this lazily:
   * - We need first render to contain the DOM element, so it shouldn't happen
   *     in useEffect. We would normally put this in the constructor().
   * - We can't do 'const rootElemRef = useRef(document.createElement('div))',
   *     since this will run every single render (that's a lot).
   * - We want the ref to consistently point to the same DOM element and only
   *     ever run once.
   * @link https://reactjs.org/docs/hooks-faq.html#how-to-create-expensive-objects-lazily
   */
  var getRootElem = function getRootElem() {
    if (!rootElemRef.current && typeof document !== 'undefined') {
      rootElemRef.current = document.createElement('div');
    }
    return rootElemRef.current;
  };
  return getRootElem();
};

exports.usePortal = usePortal;
