"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.useMenuContext = useMenuContext;
exports.MenuItem = exports.MenuList = exports.MenuGroup = exports.MenuDivider = exports.MenuButton = exports.Menu = void 0;

var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));

var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));

var _autoId = require("@reach/auto-id");

var _react = _interopRequireWildcard(require("react"));

var _Box = require("../Box");

var _Divider = require("../Divider");

var _useForkRef = require("../hooks/useForkRef");

var _usePrevious = require("../hooks/usePrevious");

var _Popper = require("../Popper");

var _PseudoBox = require("../PseudoBox");

var _Text = require("../Text");

var _getFocusables = require("../utils/getFocusables");

var _wrapEvent = require("../utils/wrapEvent");

var _styles = require("./styles");

function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }

function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }

var __jsx = _react["default"].createElement;
var MenuContext = /*#__PURE__*/(0, _react.createContext)({});

var Menu = function Menu(_ref) {
  var children = _ref.children,
      isOpenProp = _ref.isOpen,
      defaultIsOpen = _ref.defaultIsOpen,
      onOpen = _ref.onOpen,
      onClose = _ref.onClose,
      _ref$autoSelect = _ref.autoSelect,
      autoSelect = _ref$autoSelect === void 0 ? true : _ref$autoSelect,
      _ref$closeOnBlur = _ref.closeOnBlur,
      closeOnBlur = _ref$closeOnBlur === void 0 ? true : _ref$closeOnBlur,
      _ref$closeOnSelect = _ref.closeOnSelect,
      closeOnSelect = _ref$closeOnSelect === void 0 ? true : _ref$closeOnSelect,
      defaultActiveIndex = _ref.defaultActiveIndex,
      placement = _ref.placement;

  var _useState = (0, _react.useState)(defaultActiveIndex || -1),
      activeIndex = _useState[0],
      setActiveIndex = _useState[1];

  var _useState2 = (0, _react.useState)(defaultIsOpen || false),
      isOpen = _useState2[0],
      setIsOpen = _useState2[1];

  var _useRef = (0, _react.useRef)(isOpenProp != null),
      isControlled = _useRef.current;

  var _isOpen = isControlled ? isOpenProp : isOpen;

  var menuId = "menu-".concat((0, _autoId.useId)());
  var buttonId = "menubutton-".concat((0, _autoId.useId)());
  var focusableItems = (0, _react.useRef)(null);
  var menuRef = (0, _react.useRef)(null);
  var buttonRef = (0, _react.useRef)(null);

  var initTabIndex = function initTabIndex() {
    focusableItems.current.forEach(function (node, index) {
      return index === 0 && node.setAttribute('tabindex', 0);
    });
  };

  (0, _react.useEffect)(function () {
    if (_isOpen && menuRef && menuRef.current) {
      var focusables = (0, _getFocusables.getFocusables)(menuRef.current).filter(function (node) {
        return ['menuitem', 'menuitemradio', 'menuitemcheckbox'].includes(node.getAttribute('role'));
      });
      focusableItems.current = menuRef.current ? focusables : [];
      initTabIndex();
    }
  }, [_isOpen]);

  var updateTabIndex = function updateTabIndex(index) {
    if (focusableItems.current && focusableItems.current.length > 0) {
      var nodeAtIndex = focusableItems.current[index];
      focusableItems.current.forEach(function (node) {
        if (node !== nodeAtIndex) {
          node.setAttribute('tabindex', -1);
        }
      });
      nodeAtIndex.setAttribute('tabindex', 0);
    }
  };

  var resetTabIndex = function resetTabIndex() {
    if (focusableItems.current) {
      focusableItems.current.forEach(function (node) {
        return node.setAttribute('tabindex', -1);
      });
    }
  };

  var wasPreviouslyOpen = (0, _usePrevious.usePrevious)(_isOpen);
  (0, _react.useEffect)(function () {
    if (activeIndex !== -1) {
      if (focusableItems.current && focusableItems.current[activeIndex]) {
        focusableItems.current[activeIndex].focus();
      }

      updateTabIndex(activeIndex);
    }

    if (activeIndex === -1 && !_isOpen && wasPreviouslyOpen && buttonRef.current) {
      buttonRef.current.focus();
    }

    if (activeIndex === -1 && _isOpen && menuRef.current) {
      menuRef.current.focus();
    }
  }, [activeIndex, _isOpen, buttonRef, menuRef, wasPreviouslyOpen]);

  var openMenu = function openMenu() {
    if (!isControlled) {
      setIsOpen(true);
    }

    if (onOpen) {
      onOpen();
    }
  };

  var focusOnFirstItem = function focusOnFirstItem() {
    openMenu();
    setActiveIndex(0);
  };

  var focusAtIndex = function focusAtIndex(index) {
    setActiveIndex(index);
  };

  var focusOnLastItem = function focusOnLastItem() {
    openMenu();
    setActiveIndex(focusableItems.current && focusableItems.current.length - 1);
  };

  var closeMenu = function closeMenu() {
    if (!isControlled) {
      setIsOpen(false);
    }

    if (onClose) {
      onClose();
    }

    setActiveIndex(-1);
    resetTabIndex();
  };

  var context = {
    activeIndex: activeIndex,
    isOpen: _isOpen,
    focusAtIndex: focusAtIndex,
    focusOnLastItem: focusOnLastItem,
    focusOnFirstItem: focusOnFirstItem,
    closeMenu: closeMenu,
    buttonRef: buttonRef,
    menuRef: menuRef,
    focusableItems: focusableItems,
    placement: placement,
    menuId: menuId,
    buttonId: buttonId,
    openMenu: openMenu,
    autoSelect: autoSelect,
    closeOnSelect: closeOnSelect,
    closeOnBlur: closeOnBlur
  };
  return __jsx(MenuContext.Provider, {
    value: context
  }, typeof children === 'function' ? children({
    isOpen: _isOpen,
    onClose: closeMenu
  }) : children);
};

exports.Menu = Menu;

function useMenuContext() {
  var context = (0, _react.useContext)(MenuContext);

  if (context === undefined) {
    throw new Error('useMenuContext must be used within a MenuContext Provider');
  }

  return context;
} //


var PseudoButton = /*#__PURE__*/(0, _react.forwardRef)(function (props, ref) {
  return __jsx(_PseudoBox.PseudoBox, (0, _extends2["default"])({
    ref: ref,
    as: "button"
  }, props));
}); //

var MenuButton = /*#__PURE__*/(0, _react.forwardRef)(function (_ref2, ref) {
  var onClick = _ref2.onClick,
      onKeyDown = _ref2.onKeyDown,
      _ref2$as = _ref2.as,
      Comp = _ref2$as === void 0 ? PseudoButton : _ref2$as,
      rest = (0, _objectWithoutProperties2["default"])(_ref2, ["onClick", "onKeyDown", "as"]);

  // @ts-ignore
  var _useMenuContext = useMenuContext(),
      isOpen = _useMenuContext.isOpen,
      focusOnLastItem = _useMenuContext.focusOnLastItem,
      focusOnFirstItem = _useMenuContext.focusOnFirstItem,
      closeMenu = _useMenuContext.closeMenu,
      menuId = _useMenuContext.menuId,
      buttonId = _useMenuContext.buttonId,
      autoSelect = _useMenuContext.autoSelect,
      openMenu = _useMenuContext.openMenu,
      buttonRef = _useMenuContext.buttonRef;

  var menuButtonRef = (0, _useForkRef.useForkRef)(buttonRef, ref);
  return __jsx(Comp, (0, _extends2["default"])({
    "aria-haspopup": "menu",
    "aria-expanded": isOpen,
    "aria-controls": menuId,
    id: buttonId,
    role: "button",
    ref: menuButtonRef,
    onClick: (0, _wrapEvent.wrapEvent)(onClick, function () {
      if (isOpen) {
        closeMenu();
      } else if (autoSelect) {
        focusOnFirstItem();
      } else {
        openMenu();
      }
    }),
    onKeyDown: (0, _wrapEvent.wrapEvent)(onKeyDown, function (event) {
      if (event.key === 'ArrowDown') {
        event.preventDefault();
        focusOnFirstItem();
      }

      if (event.key === 'ArrowUp') {
        event.preventDefault();
        focusOnLastItem();
      }
    })
  }, rest));
}); //

exports.MenuButton = MenuButton;

var MenuList = function MenuList(_ref3) {
  var onKeyDown = _ref3.onKeyDown,
      onBlur = _ref3.onBlur,
      _ref3$usePortal = _ref3.usePortal,
      usePortal = _ref3$usePortal === void 0 ? false : _ref3$usePortal,
      props = (0, _objectWithoutProperties2["default"])(_ref3, ["onKeyDown", "onBlur", "usePortal"]);

  var _useMenuContext2 = useMenuContext(),
      index = _useMenuContext2.activeIndex,
      isOpen = _useMenuContext2.isOpen,
      focusAtIndex = _useMenuContext2.focusAtIndex,
      focusOnFirstItem = _useMenuContext2.focusOnFirstItem,
      focusOnLastItem = _useMenuContext2.focusOnLastItem,
      closeMenu = _useMenuContext2.closeMenu,
      focusableItems = _useMenuContext2.focusableItems,
      buttonRef = _useMenuContext2.buttonRef,
      menuId = _useMenuContext2.menuId,
      buttonId = _useMenuContext2.buttonId,
      menuRef = _useMenuContext2.menuRef,
      closeOnBlur = _useMenuContext2.closeOnBlur,
      placement = _useMenuContext2.placement;

  var handleKeyDown = function handleKeyDown(event) {
    var count = focusableItems.current && focusableItems.current.length;
    var nextIndex;

    if (event.key === 'ArrowDown') {
      event.preventDefault();
      nextIndex = (index + 1) % count;
      focusAtIndex(nextIndex);
    } else if (event.key === 'ArrowUp') {
      event.preventDefault();
      nextIndex = (index - 1 + count) % count;
      focusAtIndex(nextIndex);
    } else if (event.key === 'Home') {
      focusOnFirstItem();
    } else if (event.key === 'End') {
      focusOnLastItem();
    } else if (event.key === 'Tab') {
      event.preventDefault();
    } else if (event.key === 'Escape') {
      closeMenu();
    } // Set focus based on first character


    if (/^[a-z0-9_-]$/i.test(event.key)) {
      event.stopPropagation();
      event.preventDefault();
      var foundNode = focusableItems.current.find(function (item) {
        return item.textContent.toLowerCase().startsWith(event.key);
      });

      if (foundNode) {
        nextIndex = focusableItems.current.indexOf(foundNode);
        focusAtIndex(nextIndex);
      }
    }

    if (onKeyDown) {
      onKeyDown(event);
    }
  }; // Close the menu on blur


  var handleBlur = function handleBlur(event) {
    if (closeOnBlur && isOpen && menuRef.current && buttonRef.current && !menuRef.current.contains(event.relatedTarget) && !buttonRef.current.contains(event.relatedTarget)) {
      closeMenu();
    }

    if (onBlur) {
      onBlur(event);
    }
  };

  var menuStyleProps = (0, _styles.useMenuStyle)(null);
  return __jsx(_Popper.Popper, (0, _extends2["default"])({
    usePortal: usePortal,
    isOpen: isOpen,
    anchorEl: buttonRef.current,
    placement: placement,
    modifiers: {
      preventOverflow: {
        enabled: true,
        boundariesElement: 'viewport'
      }
    },
    role: "menu",
    ref: menuRef,
    id: menuId,
    "aria-labelledby": buttonId,
    onKeyDown: handleKeyDown,
    onBlur: handleBlur
  }, menuStyleProps, props));
}; //


exports.MenuList = MenuList;
var MenuItem = /*#__PURE__*/(0, _react.forwardRef)(function (_ref4, ref) {
  var isDisabled = _ref4.isDisabled,
      onClick = _ref4.onClick,
      onMouseLeave = _ref4.onMouseLeave,
      onMouseEnter = _ref4.onMouseEnter,
      onKeyDown = _ref4.onKeyDown,
      _ref4$role = _ref4.role,
      role = _ref4$role === void 0 ? 'menuitem' : _ref4$role,
      props = (0, _objectWithoutProperties2["default"])(_ref4, ["isDisabled", "onClick", "onMouseLeave", "onMouseEnter", "onKeyDown", "role"]);

  // @ts-ignore
  var _useMenuContext3 = useMenuContext(),
      focusableItems = _useMenuContext3.focusableItems,
      focusAtIndex = _useMenuContext3.focusAtIndex,
      closeOnSelect = _useMenuContext3.closeOnSelect,
      closeMenu = _useMenuContext3.closeMenu;

  var menuItemStyleProps = (0, _styles.useMenuItemStyle)(null);
  return __jsx(_PseudoBox.PseudoBox, (0, _extends2["default"])({
    as: "button",
    ref: ref,
    role: role,
    tabIndex: -1,
    disabled: isDisabled,
    "aria-disabled": isDisabled,
    onClick: (0, _wrapEvent.wrapEvent)(onClick, function (event) {
      if (isDisabled) {
        event.stopPropagation();
        event.preventDefault();
        return;
      }

      if (closeOnSelect) {
        closeMenu();
      }
    }),
    onMouseEnter: (0, _wrapEvent.wrapEvent)(onMouseEnter, function (event) {
      if (isDisabled) {
        event.stopPropagation();
        event.preventDefault();
        return;
      }

      if (focusableItems !== null && focusableItems !== void 0 && focusableItems.current && focusableItems.current.length > 0) {
        var nextIndex = focusableItems.current.indexOf(event.currentTarget);
        focusAtIndex(nextIndex);
      }
    }),
    onMouseLeave: (0, _wrapEvent.wrapEvent)(onMouseLeave, function () {
      focusAtIndex(-1);
    }),
    onKeyDown: (0, _wrapEvent.wrapEvent)(onKeyDown, function (event) {
      if (isDisabled) return;

      if (event.key === 'Enter' || event.key === ' ') {
        event.preventDefault();

        if (onClick) {
          onClick(event);
        }

        if (closeOnSelect) {
          closeMenu();
        }
      }
    })
  }, menuItemStyleProps, props));
}); //

exports.MenuItem = MenuItem;
var MenuDivider = /*#__PURE__*/(0, _react.forwardRef)(function (props, ref) {
  return __jsx(_Divider.Divider, (0, _extends2["default"])({
    ref: ref,
    orientation: "horizontal"
  }, props));
}); //

exports.MenuDivider = MenuDivider;
var MenuGroup = /*#__PURE__*/(0, _react.forwardRef)(function (_ref5, ref) {
  var children = _ref5.children,
      title = _ref5.title,
      rest = (0, _objectWithoutProperties2["default"])(_ref5, ["children", "title"]);
  return __jsx(_Box.Box, {
    ref: ref,
    role: "group"
  }, title && __jsx(_Text.Text, (0, _extends2["default"])({
    mx: "spacing",
    my: "spacing-sm",
    fontWeight: "semibold"
  }, rest), title), children);
});
exports.MenuGroup = MenuGroup;
//# sourceMappingURL=Menu.js.map