import React from 'react';
import PropTypes from 'prop-types';
import RootRef from '../rootRef';
import { ownerDocument } from './modalUtil'; // You may rely on React.useMemo as a performance optimization, not as a semantic guarantee.
// https://reactjs.org/docs/hooks-reference.html#usememo
// This one has a semantic guarantee

function useMemo(func, values) {
  var ref = React.useRef([]);

  if (ref.current.length !== values.length) {
    ref.current = values;
    func();
    return;
  }

  for (var i = 0; i < values.length; i += 1) {
    if (values[i] !== ref.current[i]) {
      ref.current = values;
      func();
      break;
    }
  }
}
/**
 * @ignore
 */


function TrapFocus(props) {
  var disableAutoFocus = props.disableAutoFocus,
      disableEnforceFocus = props.disableEnforceFocus,
      disableRestoreFocus = props.disableRestoreFocus,
      getDoc = props.getDoc,
      isEnabled = props.isEnabled,
      isOpen = props.isOpen,
      children = props.children;
  var rootRef = React.useRef();
  var ignoreNextEnforceFocus = React.useRef();
  var sentinelStart = React.useRef();
  var sentinelEnd = React.useRef();
  var lastFocus = React.useRef();
  useMemo(function () {
    if (!isOpen) {
      return;
    }

    lastFocus.current = getDoc().activeElement;
  }, [isOpen]); // eslint-disable-line react-hooks/exhaustive-deps

  React.useEffect(function () {
    if (!isOpen) {
      return;
    }

    var doc = ownerDocument(rootRef.current); // We might render an empty child.

    if (!disableAutoFocus && rootRef.current && !rootRef.current.contains(doc.activeElement)) {
      if (!rootRef.current.hasAttribute('tabIndex')) {
        console.warning && console.warning(false, ['NeatUI: the modal content node does not accept focus.', 'For the benefit of assistive technologies, ' + 'the tabIndex of the node is being set to "-1".'].join('\n'));
        rootRef.current.setAttribute('tabIndex', -1);
      }

      rootRef.current.focus();
    }

    var enforceFocus = function enforceFocus() {
      if (disableEnforceFocus || !isEnabled() || ignoreNextEnforceFocus.current) {
        ignoreNextEnforceFocus.current = false;
        return;
      }

      if (!rootRef.current.contains(doc.activeElement)) {
        rootRef.current.focus();
      }
    };

    var loopFocus = function loopFocus(event) {
      // 9 = Tab
      if (disableEnforceFocus || !isEnabled() || event.keyCode !== 9) {
        return;
      } // Make sure the next tab starts from the right place.


      if (doc.activeElement === rootRef.current) {
        // We need to ignore the next enforceFocus as
        // it will try to move the focus back to the rootRef element.
        ignoreNextEnforceFocus.current = true;

        if (event.shiftKey) {
          sentinelEnd.current.focus();
        } else {
          sentinelStart.current.focus();
        }
      }
    };

    doc.addEventListener('focus', enforceFocus, true);
    doc.addEventListener('keydown', loopFocus, true);
    return function () {
      doc.removeEventListener('focus', enforceFocus, true);
      doc.removeEventListener('keydown', loopFocus, true); // restoreLastFocus()

      if (!disableRestoreFocus) {
        // Not all elements in IE 11 have a focus method.
        // Because IE 11 market share is low, we accept the restore focus being broken
        // and we silent the issue.
        if (lastFocus.current.focus) {
          lastFocus.current.focus();
        }

        lastFocus.current = null;
      }
    };
  }, [disableAutoFocus, disableEnforceFocus, disableRestoreFocus, isEnabled, isOpen]);
  return React.createElement(React.Fragment, null, React.createElement("div", {
    tabIndex: 0,
    ref: sentinelStart
  }), React.createElement(RootRef, {
    rootRef: rootRef
  }, children), React.createElement("div", {
    tabIndex: 0,
    ref: sentinelEnd
  }));
}
/**
 * @ignore - internal component.
 */


TrapFocus.propTypes = {
  /**
   * @ignore
   */
  children: PropTypes.element.isRequired,

  /**
   * 如果设置为`true`，对话框组件将不会在打开时自动获得焦点
   */
  disableAutoFocus: PropTypes.bool,

  /**
   * 如果设置为`true`，对话框组件将不会在打开时保持焦点
   */
  disableEnforceFocus: PropTypes.bool,

  /**
   * 如果设置为`true`，对话框组件将不会在关闭后将焦点恢复到打开之前的被聚焦元素
   */
  disableRestoreFocus: PropTypes.bool,

  /**
   * 返回document对象.
   */
  getDoc: PropTypes.func.isRequired,

  /**
   * 是否终止焦点捕捉
   */
  isEnabled: PropTypes.func.isRequired,
  isOpen: PropTypes.bool.isRequired
};
TrapFocus.defaultProps = {
  disableAutoFocus: false,
  disableEnforceFocus: false,
  disableRestoreFocus: false
};
export default TrapFocus;