"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.useFocusTrap = void 0;

var _react = require("react");

var getDocument = function getDocument() {
  return typeof document !== 'undefined' ? document : undefined;
};

var DEFAULT_REF = {
  current: null
};

var useFocusTrap = function useFocusTrap(_ref) {
  var show = _ref.show,
      _ref$refToRestoreFocu = _ref.refToRestoreFocus,
      refToRestoreFocus = _ref$refToRestoreFocu === void 0 ? DEFAULT_REF : _ref$refToRestoreFocu;
  var modalRef = (0, _react.useRef)(null);
  var computedRefToRestoreFocus = (0, _react.useRef)(refToRestoreFocus.current);
  var isVisible = (0, _react.useRef)(false);
  var childFocusSet = (0, _react.useRef)();
  (0, _react.useMemo)(function () {
    // gets the documents current active element so we can go back to focusing on it on close
    // we do this on memo because this has to happen before render (& before useEffects). This won't always restore 100%
    // as useMemo isn't guaranteed to always memoize
    var documentElement = getDocument();

    if (show && documentElement && !computedRefToRestoreFocus.current) {
      computedRefToRestoreFocus.current = documentElement.activeElement;
    }
  }, [show]);
  (0, _react.useLayoutEffect)(function () {
    // on mount, we listen for a focus event, if there is one we assume a child is trying to focus, so we
    // refocus the child
    var documentElement = getDocument();

    function trapFocus(_ref2) {
      var previousFocusTarget = _ref2.relatedTarget,
          target = _ref2.target;
      var modal = modalRef.current; // for the first focus

      if (!childFocusSet.current && modal && // related target is the target we're focusing away from. If it exists inside the modal, we should re-focus it
      previousFocusTarget instanceof HTMLElement && modal.contains(previousFocusTarget) && // parent.contains(parent) is true, so we don't want to double focus
      modal !== previousFocusTarget) {
        childFocusSet.current = true; // Refocus to the previous focus target if and only if the new target is *not* another
        // child of the modal.

        if (previousFocusTarget && target && ( // $FlowFixMe target isn't a Node as required by contains.
        !modal.contains(target) || modal === target)) {
          previousFocusTarget.focus();
        }
      } // for all focuses after - we trap the focus so they can't shift-tab outside the modal


      if (childFocusSet.current && target && modal && target instanceof HTMLElement && !modal.contains(target)) {
        modal.focus();
      }
    }

    if (show && documentElement && !childFocusSet.current) {
      documentElement.addEventListener('focus', trapFocus, true);
    }

    return function () {
      if (documentElement) {
        documentElement.removeEventListener('focus', trapFocus, true);
      }
    };
  }, [show, modalRef, childFocusSet]);
  (0, _react.useLayoutEffect)(function () {
    var isNowVisible = show && !isVisible.current;
    var isNowHidden = !show && isVisible.current;

    if (isNowVisible) {
      isVisible.current = true;
      var modal = modalRef.current;

      if (modal) {
        modal.setAttribute('tabIndex', '-1');
        modal.focus();
      }
    }

    if (isNowHidden) {
      isVisible.current = false; // try and focus the passed in refToRestoreFocus

      if (refToRestoreFocus.current instanceof HTMLElement) {
        return refToRestoreFocus.current.focus();
      } // otherwise, use the computed one


      if (computedRefToRestoreFocus.current instanceof HTMLElement) {
        return computedRefToRestoreFocus.current.focus();
      }
    }
  }, [show, modalRef, refToRestoreFocus]);
  return modalRef;
};

exports.useFocusTrap = useFocusTrap;