import React__default, { useMemo, useRef, useReducer, useEffect, useContext, forwardRef, useState, useCallback } from 'react';
import _pt from 'prop-types';
import { makeId, checkStyles, isFunction, forwardRefWithAs, useForkedRef, wrapEvent, usePrevious, isString, noop, createNamedContext, getOwnerDocument } from '../../utils/dist/utils.esm.esm.js';
import { useId } from '../../auto-id/dist/auto-id.esm.esm.js';
import { useDescendants, DescendantProvider, useDescendantKeyDown, createDescendantContext, useDescendant } from '../../descendants/dist/descendants.esm.esm.js';
import Popover from '../../popover/dist/popover.esm.esm.js';

function _extends() {
  _extends = Object.assign || function (target) {
    for (var i = 1; i < arguments.length; i++) {
      var source = arguments[i];

      for (var key in source) {
        if (Object.prototype.hasOwnProperty.call(source, key)) {
          target[key] = source[key];
        }
      }
    }

    return target;
  };

  return _extends.apply(this, arguments);
}

function _objectWithoutPropertiesLoose(source, excluded) {
  if (source == null) return {};
  var target = {};
  var sourceKeys = Object.keys(source);
  var key, i;

  for (i = 0; i < sourceKeys.length; i++) {
    key = sourceKeys[i];
    if (excluded.indexOf(key) >= 0) continue;
    target[key] = source[key];
  }

  return target;
}

// Actions

var CLEAR_SELECTION_INDEX = "CLEAR_SELECTION_INDEX";
var CLICK_MENU_ITEM = "CLICK_MENU_ITEM";
var CLOSE_MENU = "CLOSE_MENU";
var OPEN_MENU_AT_FIRST_ITEM = "OPEN_MENU_AT_FIRST_ITEM";
var OPEN_MENU_CLEARED = "OPEN_MENU_CLEARED";
var SEARCH_FOR_ITEM = "SEARCH_FOR_ITEM";
var SELECT_ITEM_AT_INDEX = "SELECT_ITEM_AT_INDEX";
var SET_BUTTON_ID = "SET_BUTTON_ID";
var MenuDescendantContext = /*#__PURE__*/createDescendantContext("MenuDescendantContext");
var MenuContext = /*#__PURE__*/createNamedContext("MenuContext", {});
var initialState = {
  // The button ID is needed for aria controls and can be set directly and
  // updated for top-level use via context. Otherwise a default is set by useId.
  // TODO: Consider deprecating direct ID in 1.0 in favor of id at the top level
  //       for passing deterministic IDs to descendent components.
  buttonId: null,
  // Whether or not the menu is expanded
  isExpanded: false,
  // When a user begins typing a character string, the selection will change if
  // a matching item is found
  typeaheadQuery: "",
  // The index of the current selected item. When the selection is cleared a
  // value of -1 is used.
  selectionIndex: -1
}; ////////////////////////////////////////////////////////////////////////////////

/**
 * Menu
 *
 * The wrapper component for the other components. No DOM element is rendered.
 *
 * @see Docs https://reacttraining.com/reach-ui/menu-button#menu
 */

var Menu = function Menu(_ref) {
  var id = _ref.id,
      children = _ref.children;
  var buttonRef = useRef(null);
  var menuRef = useRef(null);
  var popoverRef = useRef(null);

  var _useDescendants = useDescendants(),
      descendants = _useDescendants[0],
      setDescendants = _useDescendants[1];

  var _useReducer = useReducer(reducer, initialState),
      state = _useReducer[0],
      dispatch = _useReducer[1];

  var _id = useId(id);

  var menuId = id || makeId("menu", _id); // We use an event listener attached to the window to capture outside clicks
  // that close the menu. We don't want the initial button click to trigger this
  // when a menu is closed, so we can track this behavior in a ref for now.
  // We shouldn't need this when we rewrite with state machine logic.

  var buttonClickedRef = useRef(false); // We will put children callbacks in a ref to avoid triggering endless render
  // loops when using render props if the app code doesn't useCallback
  // https://github.com/reach/reach-ui/issues/523

  var selectCallbacks = useRef([]);
  var context = {
    buttonRef: buttonRef,
    dispatch: dispatch,
    menuId: menuId,
    menuRef: menuRef,
    popoverRef: popoverRef,
    buttonClickedRef: buttonClickedRef,
    selectCallbacks: selectCallbacks,
    state: state
  }; // When the menu is open, focus is placed on the menu itself so that
  // keyboard navigation is still possible.

  useEffect(function () {
    if (state.isExpanded) {
      // @ts-ignore
      window.__REACH_DISABLE_TOOLTIPS = true;
      window.requestAnimationFrame(function () {
        focus(menuRef.current);
      });
    } else {
      // We want to ignore the immediate focus of a tooltip so it doesn't pop
      // up again when the menu closes, only pops up when focus returns again
      // to the tooltip (like native OS tooltips).
      // @ts-ignore
      window.__REACH_DISABLE_TOOLTIPS = false;
    }
  }, [state.isExpanded]);
  useEffect(function () {
    return checkStyles("menu-button");
  }, []);
  return React__default.createElement(DescendantProvider, {
    context: MenuDescendantContext,
    items: descendants,
    set: setDescendants
  }, React__default.createElement(MenuContext.Provider, {
    value: context
  }, isFunction(children) ? children({
    isExpanded: state.isExpanded,
    // TODO: Remove in 1.0
    isOpen: state.isExpanded
  }) : children));
};

if (process.env.NODE_ENV !== "production") {
  Menu.displayName = "Menu";
  Menu.propTypes = {
    children: /*#__PURE__*/_pt.oneOfType([_pt.func, _pt.node])
  };
} ////////////////////////////////////////////////////////////////////////////////

/**
 * MenuButton
 *
 * Wraps a DOM `button` that toggles the opening and closing of the dropdown
 * menu. Must be rendered inside of a `<Menu>`.
 *
 * @see Docs https://reacttraining.com/reach-ui/menu-button#menubutton
 */


var MenuButton = /*#__PURE__*/forwardRefWithAs(function MenuButton(_ref2, forwardedRef) {
  var _ref2$as = _ref2.as,
      Comp = _ref2$as === void 0 ? "button" : _ref2$as,
      onKeyDown = _ref2.onKeyDown,
      onMouseDown = _ref2.onMouseDown,
      id = _ref2.id,
      props = _objectWithoutPropertiesLoose(_ref2, ["as", "onKeyDown", "onMouseDown", "id"]);

  var _useContext = useContext(MenuContext),
      buttonRef = _useContext.buttonRef,
      buttonClickedRef = _useContext.buttonClickedRef,
      menuId = _useContext.menuId,
      _useContext$state = _useContext.state,
      buttonId = _useContext$state.buttonId,
      isExpanded = _useContext$state.isExpanded,
      dispatch = _useContext.dispatch;

  var ref = useForkedRef(buttonRef, forwardedRef);
  useEffect(function () {
    var newButtonId = id != null ? id : menuId ? makeId("menu-button", menuId) : "menu-button";

    if (buttonId !== newButtonId) {
      dispatch({
        type: SET_BUTTON_ID,
        payload: newButtonId
      });
    }
  }, [buttonId, dispatch, id, menuId]);

  function handleKeyDown(event) {
    switch (event.key) {
      case "ArrowDown":
      case "ArrowUp":
        event.preventDefault(); // prevent scroll

        dispatch({
          type: OPEN_MENU_AT_FIRST_ITEM
        });
        break;

      case "Enter":
      case " ":
        dispatch({
          type: OPEN_MENU_AT_FIRST_ITEM
        });
        break;
    }
  }

  function handleMouseDown(event) {
    if (!isExpanded) {
      buttonClickedRef.current = true;
    }

    if (isRightClick(event.nativeEvent)) {
      return;
    } else if (isExpanded) {
      dispatch({
        type: CLOSE_MENU,
        payload: {
          buttonRef: buttonRef
        }
      });
    } else {
      dispatch({
        type: OPEN_MENU_CLEARED
      });
    }
  }

  return React__default.createElement(Comp // When the menu is displayed, the element with role `button` has
  // `aria-expanded` set to `true`. When the menu is hidden, it is
  // recommended that `aria-expanded` is not present.
  // https://www.w3.org/TR/wai-aria-practices-1.2/#menubutton
  , Object.assign({
    "aria-expanded": isExpanded ? true : undefined,
    "aria-haspopup": true,
    "aria-controls": menuId
  }, props, {
    ref: ref,
    "data-reach-menu-button": "",
    id: buttonId || undefined,
    onKeyDown: wrapEvent(onKeyDown, handleKeyDown),
    onMouseDown: wrapEvent(onMouseDown, handleMouseDown),
    type: "button"
  }));
});

if (process.env.NODE_ENV !== "production") {
  MenuButton.displayName = "MenuButton";
  MenuButton.propTypes = {
    children: _pt.node
  };
} ////////////////////////////////////////////////////////////////////////////////

/**
 * MenuItemImpl
 *
 * MenuItem and MenuLink share most of the same functionality captured here.
 */


var MenuItemImpl = /*#__PURE__*/forwardRefWithAs(function MenuItemImpl(_ref3, forwardedRef) {
  var Comp = _ref3.as,
      indexProp = _ref3.index,
      _ref3$isLink = _ref3.isLink,
      isLink = _ref3$isLink === void 0 ? false : _ref3$isLink,
      onClick = _ref3.onClick,
      onDragStart = _ref3.onDragStart,
      onMouseDown = _ref3.onMouseDown,
      onMouseEnter = _ref3.onMouseEnter,
      onMouseLeave = _ref3.onMouseLeave,
      onMouseMove = _ref3.onMouseMove,
      onMouseUp = _ref3.onMouseUp,
      onSelect = _ref3.onSelect,
      valueTextProp = _ref3.valueText,
      props = _objectWithoutPropertiesLoose(_ref3, ["as", "index", "isLink", "onClick", "onDragStart", "onMouseDown", "onMouseEnter", "onMouseLeave", "onMouseMove", "onMouseUp", "onSelect", "valueText"]);

  var _useContext2 = useContext(MenuContext),
      buttonRef = _useContext2.buttonRef,
      dispatch = _useContext2.dispatch,
      selectCallbacks = _useContext2.selectCallbacks,
      selectionIndex = _useContext2.state.selectionIndex;

  var ownRef = useRef(null); // After the ref is mounted to the DOM node, we check to see if we have an
  // explicit valueText prop before looking for the node's textContent for
  // typeahead functionality.

  var _useState = useState(valueTextProp || ""),
      valueText = _useState[0],
      setValueText = _useState[1];

  var setValueTextFromDom = useCallback(function (node) {
    if (node) {
      ownRef.current = node;

      if (!valueTextProp || node.textContent && valueText !== node.textContent) {
        setValueText(node.textContent);
      }
    }
  }, [valueText, valueTextProp]);
  var ref = useForkedRef(forwardedRef, setValueTextFromDom);
  var mouseEventStarted = useRef(false);
  var index = useDescendant({
    context: MenuDescendantContext,
    element: ownRef.current,
    key: valueText,
    isLink: isLink
  }, indexProp);
  var isSelected = index === selectionIndex; // Update the callback ref array on every render

  selectCallbacks.current[index] = onSelect;

  function select() {
    focus(buttonRef.current);
    onSelect && onSelect();
    dispatch({
      type: CLICK_MENU_ITEM
    });
  }

  function handleClick(event) {
    if (isLink && !isRightClick(event.nativeEvent)) {
      select();
    }
  }

  function handleDragStart(event) {
    // Because we don't preventDefault on mousedown for links (we need the
    // native click event), clicking and holding on a link triggers a
    // dragstart which we don't want.
    if (isLink) {
      event.preventDefault();
    }
  }

  function handleMouseDown(event) {
    if (isRightClick(event.nativeEvent)) return;

    if (isLink) {
      // Signal that the mouse is down so we can react call the right function
      // if the user is clicking on a link.
      mouseEventStarted.current = true;
    } else {
      event.preventDefault();
    }
  }

  function handleMouseEnter(event) {
    if (!isSelected && index != null) {
      dispatch({
        type: SELECT_ITEM_AT_INDEX,
        payload: {
          index: index
        }
      });
    }
  }

  function handleMouseLeave(event) {
    // Clear out selection when mouse over a non-menu item child.
    dispatch({
      type: CLEAR_SELECTION_INDEX
    });
  }

  function handleMouseMove(event) {
    if (!isSelected && index != null) {
      dispatch({
        type: SELECT_ITEM_AT_INDEX,
        payload: {
          index: index
        }
      });
    }
  }

  function handleMouseUp(event) {
    if (isRightClick(event.nativeEvent)) return;

    if (isLink) {
      // If a mousedown event was initiated on a menu link followed by a
      // mouseup event on the same link, we do nothing; a click event will
      // come next and handle selection. Otherwise, we trigger a click event.
      if (mouseEventStarted.current) {
        mouseEventStarted.current = false;
      } else if (ownRef.current) {
        ownRef.current.click();
      }
    } else {
      select();
    }
  } // Any time a mouseup event occurs anywhere in the document, we reset the
  // mouseEventStarted ref so we can check it again when needed.


  useEffect(function () {
    var ownerDocument = getOwnerDocument(ownRef.current) || document;

    var listener = function listener() {
      return mouseEventStarted.current = false;
    };

    ownerDocument.addEventListener("mouseup", listener);
    return function () {
      return ownerDocument.removeEventListener("mouseup", listener);
    };
  }, []);
  return React__default.createElement(Comp, Object.assign({
    role: "menuitem",
    id: useMenuItemId(index),
    tabIndex: -1
  }, props, {
    ref: ref,
    "data-reach-menu-item": "",
    "data-selected": isSelected ? "" : undefined,
    "data-valuetext": valueText,
    onClick: wrapEvent(onClick, handleClick),
    onDragStart: wrapEvent(onDragStart, handleDragStart),
    onMouseDown: wrapEvent(onMouseDown, handleMouseDown),
    onMouseEnter: wrapEvent(onMouseEnter, handleMouseEnter),
    onMouseLeave: wrapEvent(onMouseLeave, handleMouseLeave),
    onMouseMove: wrapEvent(onMouseMove, handleMouseMove),
    onMouseUp: wrapEvent(onMouseUp, handleMouseUp)
  }));
}); ////////////////////////////////////////////////////////////////////////////////

/**
 * MenuItem
 *
 * Handles menu selection. Must be a direct child of a `<MenuList>`.
 *
 * @see Docs https://reacttraining.com/reach-ui/menu-button#menuitem
 */

var MenuItem = /*#__PURE__*/forwardRefWithAs(function MenuItem(_ref4, forwardedRef) {
  var _ref4$as = _ref4.as,
      as = _ref4$as === void 0 ? "div" : _ref4$as,
      props = _objectWithoutPropertiesLoose(_ref4, ["as"]);

  return React__default.createElement(MenuItemImpl, Object.assign({}, props, {
    ref: forwardedRef,
    as: as
  }));
});

if (process.env.NODE_ENV !== "production") {
  MenuItem.displayName = "MenuItem";
  MenuItem.propTypes = {
    as: _pt.any,
    onSelect: _pt.func.isRequired
  };
} ////////////////////////////////////////////////////////////////////////////////

/**
 * MenuItems
 *
 * A low-level wrapper for menu items. Compose it with `MenuPopover` for more
 * control over the nested components and their rendered DOM nodes, or if you
 * need to nest arbitrary components between the outer wrapper and your list.
 *
 * @see Docs https://reacttraining.com/reach-ui/menu-button#menuitems
 */


var MenuItems = /*#__PURE__*/forwardRefWithAs(function MenuItems(_ref5, forwardedRef) {
  var _ref5$as = _ref5.as,
      Comp = _ref5$as === void 0 ? "div" : _ref5$as,
      children = _ref5.children,
      id = _ref5.id,
      onKeyDown = _ref5.onKeyDown,
      props = _objectWithoutPropertiesLoose(_ref5, ["as", "children", "id", "onKeyDown"]);

  var _useContext3 = useContext(MenuContext),
      menuId = _useContext3.menuId,
      dispatch = _useContext3.dispatch,
      buttonRef = _useContext3.buttonRef,
      menuRef = _useContext3.menuRef,
      selectCallbacks = _useContext3.selectCallbacks,
      _useContext3$state = _useContext3.state,
      isExpanded = _useContext3$state.isExpanded,
      buttonId = _useContext3$state.buttonId,
      selectionIndex = _useContext3$state.selectionIndex,
      typeaheadQuery = _useContext3$state.typeaheadQuery;

  var _useContext4 = useContext(MenuDescendantContext),
      menuItems = _useContext4.descendants;

  var ref = useForkedRef(menuRef, forwardedRef);
  useEffect(function () {
    // Respond to user char key input with typeahead
    var match = findItemFromTypeahead(menuItems, typeaheadQuery);

    if (typeaheadQuery && match != null) {
      dispatch({
        type: SELECT_ITEM_AT_INDEX,
        payload: {
          index: match
        }
      });
    }

    var timeout = window.setTimeout(function () {
      return typeaheadQuery && dispatch({
        type: SEARCH_FOR_ITEM,
        payload: ""
      });
    }, 1000);
    return function () {
      return window.clearTimeout(timeout);
    };
  }, [dispatch, menuItems, typeaheadQuery]);
  var prevMenuItemsLength = usePrevious(menuItems.length);
  var prevSelected = usePrevious(menuItems[selectionIndex]);
  var prevSelectionIndex = usePrevious(selectionIndex);
  useEffect(function () {
    if (selectionIndex > menuItems.length - 1) {
      // If for some reason our selection index is larger than our possible
      // index range (let's say the last item is selected and the list
      // dynamically updates), we need to select the last item in the list.
      dispatch({
        type: SELECT_ITEM_AT_INDEX,
        payload: {
          index: menuItems.length - 1
        }
      });
    } else if ( // Checks if
    //  - menu length has changed
    //  - selection index has not changed BUT selected item has changed
    //
    // This prevents any dynamic adding/removing of menu items from actually
    // changing a user's expected selection.
    prevMenuItemsLength !== menuItems.length && selectionIndex > -1 && prevSelected && prevSelectionIndex === selectionIndex && menuItems[selectionIndex] !== prevSelected) {
      dispatch({
        type: SELECT_ITEM_AT_INDEX,
        payload: {
          index: menuItems.findIndex(function (i) {
            return i.key === prevSelected.key;
          })
        }
      });
    }
  }, [dispatch, menuItems, prevMenuItemsLength, prevSelected, prevSelectionIndex, selectionIndex]);
  var handleKeyDown = wrapEvent(function handleKeyDown(event) {
    var key = event.key;

    if (!isExpanded) {
      return;
    }

    switch (key) {
      case "Enter":
      case " ":
        var selected = menuItems.find(function (item) {
          return item.index === selectionIndex;
        }); // For links, the Enter key will trigger a click by default, but for
        // consistent behavior across menu items we'll trigger a click when
        // the spacebar is pressed.

        if (selected) {
          if (selected.isLink && selected.element) {
            selected.element.click();
          } else {
            event.preventDefault(); // Focus the button first by default when an item is selected.
            // We fire the onSelect callback next so the app can manage
            // focus if needed.

            focus(buttonRef.current);
            selectCallbacks.current[selected.index] && selectCallbacks.current[selected.index]();
            dispatch({
              type: CLICK_MENU_ITEM
            });
          }
        }

        break;

      case "Escape":
        focus(buttonRef.current);
        dispatch({
          type: CLOSE_MENU,
          payload: {
            buttonRef: buttonRef
          }
        });
        break;

      case "Tab":
        // prevent leaving
        event.preventDefault();
        break;

      default:
        // Check if a user is typing some char keys and respond by setting
        // the query state.
        if (isString(key) && key.length === 1) {
          var query = typeaheadQuery + key.toLowerCase();
          dispatch({
            type: SEARCH_FOR_ITEM,
            payload: query
          });
        }

        break;
    }
  }, useDescendantKeyDown(MenuDescendantContext, {
    currentIndex: selectionIndex,
    orientation: "vertical",
    rotate: false,
    callback: function callback(index) {
      dispatch({
        type: SELECT_ITEM_AT_INDEX,
        payload: {
          index: index
        }
      });
    },
    key: "index"
  }));
  return (// TODO: Should probably file a but in jsx-a11y, but this is correct
    // according to https://www.w3.org/TR/wai-aria-practices-1.2/examples/menu-button/menu-button-actions-active-descendant.html
    // eslint-disable-next-line jsx-a11y/aria-activedescendant-has-tabindex
    React__default.createElement(Comp // Refers to the descendant menuitem element that is visually indicated
    // as focused.
    // https://www.w3.org/TR/wai-aria-practices-1.2/examples/menu-button/menu-button-actions-active-descendant.html
    , Object.assign({
      "aria-activedescendant": useMenuItemId(selectionIndex) || undefined,
      "aria-labelledby": buttonId || undefined,
      // The element that contains the menu items displayed by activating the
      // button has role menu.
      // https://www.w3.org/TR/wai-aria-practices-1.2/#menubutton
      role: "menu",
      tabIndex: -1
    }, props, {
      ref: ref,
      "data-reach-menu-items": "",
      id: menuId,
      onKeyDown: wrapEvent(onKeyDown, handleKeyDown)
    }), children)
  );
});

if (process.env.NODE_ENV !== "production") {
  MenuItems.displayName = "MenuItems";
  MenuItems.propTypes = {
    children: _pt.node
  };
} ////////////////////////////////////////////////////////////////////////////////

/**
 * MenuLink
 *
 * Handles linking to a different page in the menu. By default it renders `<a>`,
 * but also accepts any other kind of Link as long as the `Link` uses the
 * `React.forwardRef` API.
 *
 * Must be a direct child of a `<MenuList>`.
 *
 * @see Docs https://reacttraining.com/reach-ui/menu-button#menulink
 */


var MenuLink = /*#__PURE__*/forwardRefWithAs(function MenuLink(_ref6, forwardedRef) {
  var _ref6$as = _ref6.as,
      as = _ref6$as === void 0 ? "a" : _ref6$as,
      component = _ref6.component,
      onSelect = _ref6.onSelect,
      props = _objectWithoutPropertiesLoose(_ref6, ["as", "component", "onSelect"]);

  if (component) {
    console.warn("[@reach/menu-button]: Please use the `as` prop instead of `component`.");
  }

  return React__default.createElement("div", {
    role: "none",
    tabIndex: -1
  }, React__default.createElement(MenuItemImpl, Object.assign({}, props, {
    ref: forwardedRef,
    "data-reach-menu-link": "",
    as: as,
    isLink: true,
    onSelect: onSelect || noop
  })));
});

if (process.env.NODE_ENV !== "production") {
  MenuLink.displayName = "MenuLink";
  MenuLink.propTypes = {
    as: _pt.any,
    component: _pt.any
  };
} ////////////////////////////////////////////////////////////////////////////////

/**
 * MenuList
 *
 * Wraps a DOM element that renders the menu items. Must be rendered inside of
 * a `<Menu>`.
 *
 * @see Docs https://reacttraining.com/reach-ui/menu-button#menulist
 */


var MenuList = /*#__PURE__*/forwardRef(function MenuList(_ref7, forwardedRef) {
  var _ref7$portal = _ref7.portal,
      portal = _ref7$portal === void 0 ? true : _ref7$portal,
      props = _objectWithoutPropertiesLoose(_ref7, ["portal"]);

  return React__default.createElement(MenuPopover, {
    portal: portal
  }, React__default.createElement(MenuItems, Object.assign({}, props, {
    ref: forwardedRef,
    "data-reach-menu-list": ""
  })));
});

if (process.env.NODE_ENV !== "production") {
  MenuList.displayName = "MenuList";
  MenuList.propTypes = {
    children: _pt.node.isRequired
  };
} ////////////////////////////////////////////////////////////////////////////////

/**
 * MenuPopover
 *
 * A low-level wrapper for the popover that appears when a menu button is open.
 * You can compose it with `MenuItems` for more control over the nested
 * components and their rendered DOM nodes, or if you need to nest arbitrary
 * components between the outer wrapper and your list.
 *
 * @see Docs https://reacttraining.com/reach-ui/menu-button#menupopover
 */


var MenuPopover = /*#__PURE__*/forwardRef(function MenuPopover(_ref8, forwardedRef) {
  var children = _ref8.children,
      _ref8$portal = _ref8.portal,
      portal = _ref8$portal === void 0 ? true : _ref8$portal,
      position = _ref8.position,
      props = _objectWithoutPropertiesLoose(_ref8, ["children", "portal", "position"]);

  var _useContext5 = useContext(MenuContext),
      buttonRef = _useContext5.buttonRef,
      buttonClickedRef = _useContext5.buttonClickedRef,
      dispatch = _useContext5.dispatch,
      menuRef = _useContext5.menuRef,
      popoverRef = _useContext5.popoverRef,
      isExpanded = _useContext5.state.isExpanded;

  var ref = useForkedRef(popoverRef, forwardedRef);
  useEffect(function () {
    function listener(event) {
      if (buttonClickedRef.current) {
        buttonClickedRef.current = false;
      } else {
        var relatedTarget = event.relatedTarget,
            target = event.target; // We on want to close only if focus rests outside the menu

        if (isExpanded && popoverRef.current) {
          var _popoverRef$current;

          if (!((_popoverRef$current = popoverRef.current) === null || _popoverRef$current === void 0 ? void 0 : _popoverRef$current.contains(relatedTarget || target))) {
            dispatch({
              type: CLOSE_MENU,
              payload: {
                buttonRef: buttonRef
              }
            });
          }
        }
      }
    }

    window.addEventListener("mousedown", listener);
    return function () {
      window.removeEventListener("mousedown", listener);
    };
  }, [buttonClickedRef, buttonRef, dispatch, isExpanded, menuRef, popoverRef]);

  var commonProps = _extends({
    ref: ref,
    // TODO: remove in 1.0
    "data-reach-menu": "",
    "data-reach-menu-popover": "",
    hidden: !isExpanded,
    children: children
  }, props);

  return portal ? React__default.createElement(Popover, Object.assign({}, commonProps, {
    targetRef: buttonRef,
    position: position
  })) : React__default.createElement("div", Object.assign({}, commonProps));
});

if (process.env.NODE_ENV !== "production") {
  MenuPopover.displayName = "MenuPopover";
  MenuPopover.propTypes = {
    children: _pt.node
  };
} ////////////////////////////////////////////////////////////////////////////////

/**
 * A hook that exposes data for a given `Menu` component to its descendants.
 *
 * @see Docs https://reacttraining.com/reach-ui/menu-button#usemenubuttoncontext
 */


function useMenuButtonContext() {
  var _useContext6 = useContext(MenuContext),
      isExpanded = _useContext6.state.isExpanded;

  return useMemo(function () {
    return {
      isExpanded: isExpanded
    };
  }, [isExpanded]);
} ////////////////////////////////////////////////////////////////////////////////

/**
 * When a user's typed input matches the string displayed in a menu item, it is
 * expected that the matching menu item is selected. This is our matching
 * function.
 */

function findItemFromTypeahead(items, string) {
  if (string === void 0) {
    string = "";
  }

  if (!string) {
    return null;
  }

  var found = items.find(function (_ref9) {
    var _element$dataset, _element$dataset$valu;

    var element = _ref9.element;
    return element === null || element === void 0 ? void 0 : (_element$dataset = element.dataset) === null || _element$dataset === void 0 ? void 0 : (_element$dataset$valu = _element$dataset.valuetext) === null || _element$dataset$valu === void 0 ? void 0 : _element$dataset$valu.toLowerCase().startsWith(string);
  });
  return found ? items.indexOf(found) : null;
}

function useMenuItemId(index) {
  var _useContext7 = useContext(MenuContext),
      menuId = _useContext7.menuId;

  return index != null && index > -1 ? makeId("option-" + index, menuId) : undefined;
}

function isRightClick(nativeEvent) {
  return nativeEvent.which === 3 || nativeEvent.button === 2;
}

function focus(element) {
  element && element.focus();
}

function reducer(state, action) {
  if (action === void 0) {
    action = {};
  }

  switch (action.type) {
    case CLICK_MENU_ITEM:
      return _extends({}, state, {
        isExpanded: false,
        selectionIndex: -1
      });

    case CLOSE_MENU:
      return _extends({}, state, {
        isExpanded: false,
        selectionIndex: -1
      });

    case OPEN_MENU_AT_FIRST_ITEM:
      return _extends({}, state, {
        isExpanded: true,
        selectionIndex: 0
      });

    case OPEN_MENU_CLEARED:
      return _extends({}, state, {
        isExpanded: true,
        selectionIndex: -1
      });

    case SELECT_ITEM_AT_INDEX:
      if (action.payload.index >= 0) {
        return _extends({}, state, {
          selectionIndex: action.payload.max != null ? Math.min(Math.max(action.payload.index, 0), action.payload.max) : Math.max(action.payload.index, 0)
        });
      }

      return state;

    case CLEAR_SELECTION_INDEX:
      return _extends({}, state, {
        selectionIndex: -1
      });

    case SET_BUTTON_ID:
      return _extends({}, state, {
        buttonId: action.payload
      });

    case SEARCH_FOR_ITEM:
      if (typeof action.payload !== "undefined") {
        return _extends({}, state, {
          typeaheadQuery: action.payload
        });
      }

      return state;

    default:
      return state;
  }
}

export { Menu, MenuButton, MenuItem, MenuItems, MenuLink, MenuList, MenuPopover, useMenuButtonContext };
//# sourceMappingURL=menu-button.esm.esm.js.map
