"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 useFocusTrap = function useFocusTrap(_ref) {
  var show = _ref.show,
      _ref$refToRestoreFocu = _ref.refToRestoreFocus,
      refToRestoreFocus = _ref$refToRestoreFocu === void 0 ? {
    current: null
  } : _ref$refToRestoreFocu;
  var modalRef = (0, _react.useRef)(null);
  var computedRefToRestoreFocus = (0, _react.useRef)(refToRestoreFocus.current);
  var initialMountFocusSet = (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;

        if (previousFocusTarget) {
          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 modal = modalRef.current;

    if (show && modal && !initialMountFocusSet.current) {
      modal.setAttribute('tabIndex', '-1');
      modal.focus();
      initialMountFocusSet.current = true;
    }

    var restoreFocusElement = refToRestoreFocus.current;
    var computedRestoreFocusElement = computedRefToRestoreFocus.current;

    if (!show) {
      // on dismount, we first try and focus the passed in refToRestoreFocus
      if (restoreFocusElement && restoreFocusElement instanceof HTMLElement) {
        return restoreFocusElement.focus();
      } // otherwise, use the computed one


      if (computedRestoreFocusElement && computedRestoreFocusElement instanceof HTMLElement) {
        return computedRestoreFocusElement.focus();
      }

      initialMountFocusSet.current = false;
    }
  }, [show, modalRef, refToRestoreFocus]);
  return modalRef;
};

exports.useFocusTrap = useFocusTrap;