text: "use strict";
  
  var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
  
  var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  
  exports.__esModule = true;
  exports["default"] = void 0;
  
  var _matches = _interopRequireDefault(require("dom-helpers/matches"));
  
  var _querySelectorAll = _interopRequireDefault(require("dom-helpers/querySelectorAll"));
  
  var _react = _interopRequireWildcard(require("react"));
  
  var _propTypes = _interopRequireDefault(require("prop-types"));
  
  var _uncontrollable = require("uncontrollable");
  
  var _usePrevious = _interopRequireDefault(require("@restart/hooks/usePrevious"));
  
  var _useForceUpdate = _interopRequireDefault(require("@restart/hooks/useForceUpdate"));
  
  var _useGlobalListener = _interopRequireDefault(require("@restart/hooks/useGlobalListener"));
  
  var _useEventCallback = _interopRequireDefault(require("@restart/hooks/useEventCallback"));
  
  var _DropdownContext = _interopRequireDefault(require("./DropdownContext"));
  
  var _DropdownMenu = _interopRequireDefault(require("./DropdownMenu"));
  
  var _DropdownToggle = _interopRequireDefault(require("./DropdownToggle"));
  
  var propTypes = {
    /**
     * A render prop that returns the root dropdown element. The `props`
     * argument should spread through to an element containing _both_ the
     * menu and toggle in order to handle keyboard events for focus management.
     *
     * @type {Function ({
     *   props: {
     *     onKeyDown: (SyntheticEvent) => void,
     *   },
     * }) => React.Element}
     */
    children: _propTypes["default"].node,
  
    /**
     * Determines the direction and location of the Menu in relation to it's Toggle.
     */
    drop: _propTypes["default"].oneOf(['up', 'left', 'right', 'down']),
  
    /**
     * Controls the focus behavior for when the Dropdown is opened. Set to
     * `true` to always focus the first menu item, `keyboard` to focus only when
     * navigating via the keyboard, or `false` to disable completely
     *
     * The Default behavior is `false` **unless** the Menu has a `role="menu"`
     * where it will default to `keyboard` to match the recommended [ARIA Authoring practices](https://www.w3.org/TR/wai-aria-practices-1.1/#menubutton).
     */
    focusFirstItemOnShow: _propTypes["default"].oneOf([false, true, 'keyboard']),
  
    /**
     * A css slector string that will return __focusable__ menu items.
     * Selectors should be relative to the menu component:
     * e.g. ` > li:not('.disabled')`
     */
    itemSelector: _propTypes["default"].string,
  
    /**
     * Align the menu to the 'end' side of the placement side of the Dropdown toggle. The default placement is `top-start` or `bottom-start`.
     */
    alignEnd: _propTypes["default"].bool,
  
    /**
     * Whether or not the Dropdown is visible.
     *
     * @controllable onToggle
     */
    show: _propTypes["default"].bool,
  
    /**
     * Sets the initial show position of the Dropdown.
     */
    defaultShow: _propTypes["default"].bool,
  
    /**
     * A callback fired when the Dropdown wishes to change visibility. Called with the requested
     * `show` value, the DOM event, and the source that fired it: `'click'`,`'keydown'`,`'rootClose'`, or `'select'`.
     *
     * ```ts static
     * function(
     *   isOpen: boolean,
     *   event: SyntheticEvent,
     * ): void
     * ```
     *
     * @controllable show
     */
    onToggle: _propTypes["default"].func
  };
  
  function useRefWithUpdate() {
    var forceUpdate = (0, _useForceUpdate["default"])();
    var ref = (0, _react.useRef)(null);
    var attachRef = (0, _react.useCallback)(function (element) {
      ref.current = element; // ensure that a menu set triggers an update for consumers
  
      forceUpdate();
    }, [forceUpdate]);
    return [ref, attachRef];
  }
  /**
   * @displayName Dropdown
   */
  
  
  function Dropdown(_ref) {
    var drop = _ref.drop,
        alignEnd = _ref.alignEnd,
        defaultShow = _ref.defaultShow,
        rawShow = _ref.show,
        rawOnToggle = _ref.onToggle,
        _ref$itemSelector = _ref.itemSelector,
        itemSelector = _ref$itemSelector === void 0 ? '* > *' : _ref$itemSelector,
        focusFirstItemOnShow = _ref.focusFirstItemOnShow,
        children = _ref.children;
  
    var _useUncontrolledProp = (0, _uncontrollable.useUncontrolledProp)(rawShow, defaultShow, rawOnToggle),
        show = _useUncontrolledProp[0],
        onToggle = _useUncontrolledProp[1]; // We use normal refs instead of useCallbackRef in order to populate the
    // the value as quickly as possible, otherwise the effect to focus the element
    // may run before the state value is set
  
  
    var _useRefWithUpdate = useRefWithUpdate(),
        menuRef = _useRefWithUpdate[0],
        setMenu = _useRefWithUpdate[1];
  
    var menuElement = menuRef.current;
  
    var _useRefWithUpdate2 = useRefWithUpdate(),
        toggleRef = _useRefWithUpdate2[0],
        setToggle = _useRefWithUpdate2[1];
  
    var toggleElement = toggleRef.current;
    var lastShow = (0, _usePrevious["default"])(show);
    var lastSourceEvent = (0, _react.useRef)(null);
    var focusInDropdown = (0, _react.useRef)(false);
    var toggle = (0, _react.useCallback)(function (nextShow, event) {
      onToggle(nextShow, event);
    }, [onToggle]);
    var context = (0, _react.useMemo)(function () {
      return {
        toggle: toggle,
        drop: drop,
        show: show,
        alignEnd: alignEnd,
        menuElement: menuElement,
        toggleElement: toggleElement,
        setMenu: setMenu,
        setToggle: setToggle
      };
    }, [toggle, drop, show, alignEnd, menuElement, toggleElement, setMenu, setToggle]);
  
    if (menuElement && lastShow && !show) {
      focusInDropdown.current = menuElement.contains(document.activeElement);
    }
  
    var focusToggle = (0, _useEventCallback["default"])(function () {
      if (toggleElement && toggleElement.focus) {
        toggleElement.focus();
      }
    });
    var maybeFocusFirst = (0, _useEventCallback["default"])(function () {
      var type = lastSourceEvent.current;
      var focusType = focusFirstItemOnShow;
  
      if (focusType == null) {
        focusType = menuRef.current && (0, _matches["default"])(menuRef.current, '[role=menu]') ? 'keyboard' : false;
      }
  
      if (focusType === false || focusType === 'keyboard' && !/^key.+$/.test(type)) {
        return;
      }
  
      var first = (0, _querySelectorAll["default"])(menuRef.current, itemSelector)[0];
      if (first && first.focus) first.focus();
    });
    (0, _react.useEffect)(function () {
      if (show) maybeFocusFirst();else if (focusInDropdown.current) {
        focusInDropdown.current = false;
        focusToggle();
      } // only `show` should be changing
    }, [show, focusInDropdown, focusToggle, maybeFocusFirst]);
    (0, _react.useEffect)(function () {
      lastSourceEvent.current = null;
    });
  
    var getNextFocusedChild = function getNextFocusedChild(current, offset) {
      if (!menuRef.current) return null;
      var items = (0, _querySelectorAll["default"])(menuRef.current, itemSelector);
      var index = items.indexOf(current) + offset;
      index = Math.max(0, Math.min(index, items.length));
      return items[index];
    };
  
    (0, _useGlobalListener["default"])('keydown', function (event) {
      var _menuRef$current, _toggleRef$current;
  
      var key = event.key;
      var target = event.target;
      var fromMenu = (_menuRef$current = menuRef.current) == null ? void 0 : _menuRef$current.contains(target);
      var fromToggle = (_toggleRef$current = toggleRef.current) == null ? void 0 : _toggleRef$current.contains(target); // Second only to https://github.com/twbs/bootstrap/blob/8cfbf6933b8a0146ac3fbc369f19e520bd1ebdac/js/src/dropdown.js#L400
      // in inscrutability
  
      var isInput = /input|textarea/i.test(target.tagName);
  
      if (isInput && (key === ' ' || key !== 'Escape' && fromMenu)) {
        return;
      }
  
      if (!fromMenu && !fromToggle) {
        return;
      }
  
      lastSourceEvent.current = event.type;
  
      switch (key) {
        case 'ArrowUp':
          {
            var next = getNextFocusedChild(target, -1);
            if (next && next.focus) next.focus();
            event.preventDefault();
            return;
          }
  
        case 'ArrowDown':
          event.preventDefault();
  
          if (!show) {
            onToggle(true, event);
          } else {
            var _next = getNextFocusedChild(target, 1);
  
            if (_next && _next.focus) _next.focus();
          }
  
          return;
  
        case 'Escape':
        case 'Tab':
          if (key === 'Escape') {
            event.preventDefault();
            event.stopPropagation();
          }
  
          onToggle(false, event);
          break;
  
        default:
      }
    });
    return /*#__PURE__*/_react["default"].createElement(_DropdownContext["default"].Provider, {
      value: context
    }, children);
  }
  
  Dropdown.displayName = 'ReactOverlaysDropdown';
  Dropdown.propTypes = propTypes;
  Dropdown.Menu = _DropdownMenu["default"];
  Dropdown.Toggle = _DropdownToggle["default"];
  var _default = Dropdown;
  exports["default"] = _default;
  module.exports = exports.default;