UNPKG

@material-ui/core

Version:

React components that implement Google's Material Design.

290 lines (239 loc) 9.32 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = exports.styles = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties")); var _react = _interopRequireDefault(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _clsx = _interopRequireDefault(require("clsx")); var _withStyles = _interopRequireDefault(require("../styles/withStyles")); var _Popover = _interopRequireDefault(require("../Popover")); var _MenuList = _interopRequireDefault(require("../MenuList")); var _reactDom = _interopRequireDefault(require("react-dom")); var _setRef = _interopRequireDefault(require("../utils/setRef")); var _useTheme = _interopRequireDefault(require("../styles/useTheme")); var RTL_ORIGIN = { vertical: 'top', horizontal: 'right' }; var LTR_ORIGIN = { vertical: 'top', horizontal: 'left' }; var styles = { /* Styles applied to the `Paper` component. */ paper: { // specZ: The maximum height of a simple menu should be one or more rows less than the view // height. This ensures a tapable area outside of the simple menu with which to dismiss // the menu. maxHeight: 'calc(100% - 96px)', // Add iOS momentum scrolling. WebkitOverflowScrolling: 'touch' }, /* Styles applied to the `List` component via `MenuList`. */ list: { // We disable the focus ring for mouse, touch and keyboard users. outline: 0 } }; exports.styles = styles; var Menu = _react.default.forwardRef(function Menu(props, ref) { var _props$autoFocus = props.autoFocus, autoFocus = _props$autoFocus === void 0 ? true : _props$autoFocus, children = props.children, classes = props.classes, _props$disableAutoFoc = props.disableAutoFocusItem, disableAutoFocusItem = _props$disableAutoFoc === void 0 ? false : _props$disableAutoFoc, _props$MenuListProps = props.MenuListProps, MenuListProps = _props$MenuListProps === void 0 ? {} : _props$MenuListProps, onClose = props.onClose, onEntering = props.onEntering, open = props.open, _props$PaperProps = props.PaperProps, PaperProps = _props$PaperProps === void 0 ? {} : _props$PaperProps, PopoverClasses = props.PopoverClasses, _props$transitionDura = props.transitionDuration, transitionDuration = _props$transitionDura === void 0 ? 'auto' : _props$transitionDura, _props$variant = props.variant, variant = _props$variant === void 0 ? 'selectedMenu' : _props$variant, other = (0, _objectWithoutProperties2.default)(props, ["autoFocus", "children", "classes", "disableAutoFocusItem", "MenuListProps", "onClose", "onEntering", "open", "PaperProps", "PopoverClasses", "transitionDuration", "variant"]); var theme = (0, _useTheme.default)(); var autoFocusItem = autoFocus && !disableAutoFocusItem && open; var menuListActionsRef = _react.default.useRef(null); var contentAnchorRef = _react.default.useRef(null); var getContentAnchorEl = function getContentAnchorEl() { return contentAnchorRef.current; }; var handleEntering = function handleEntering(element, isAppearing) { if (menuListActionsRef.current) { menuListActionsRef.current.adjustStyleForScrollbar(element, theme); } if (onEntering) { onEntering(element, isAppearing); } }; var handleListKeyDown = function handleListKeyDown(event) { if (event.key === 'Tab') { event.preventDefault(); if (onClose) { onClose(event, 'tabKeyDown'); } } }; /** * the index of the item should receive focus * in a `variant="selectedMenu"` it's the first `selected` item * otherwise it's the very first item. */ var activeItemIndex = -1; // since we inject focus related props into children we have to do a lookahead // to check if there is a `selected` item. We're looking for the last `selected` // item and use the first valid item as a fallback _react.default.Children.map(children, function (child, index) { if (!_react.default.isValidElement(child)) { return; } if (process.env.NODE_ENV !== 'production') { if (child.type === _react.default.Fragment) { console.error(["Material-UI: the Menu component doesn't accept a Fragment as a child.", 'Consider providing an array instead.'].join('\n')); } } if (!child.props.disabled) { if (variant !== "menu" && child.props.selected) { activeItemIndex = index; } else if (activeItemIndex === -1) { activeItemIndex = index; } } }); var items = _react.default.Children.map(children, function (child, index) { if (index === activeItemIndex) { return _react.default.cloneElement(child, { ref: function ref(instance) { // #StrictMode ready contentAnchorRef.current = _reactDom.default.findDOMNode(instance); (0, _setRef.default)(child.ref, instance); } }); } return child; }); return _react.default.createElement(_Popover.default, (0, _extends2.default)({ getContentAnchorEl: getContentAnchorEl, classes: PopoverClasses, onClose: onClose, onEntering: handleEntering, anchorOrigin: theme.direction === 'rtl' ? RTL_ORIGIN : LTR_ORIGIN, transformOrigin: theme.direction === 'rtl' ? RTL_ORIGIN : LTR_ORIGIN, PaperProps: (0, _extends2.default)({}, PaperProps, { classes: (0, _extends2.default)({}, PaperProps.classes, { root: classes.paper }) }), open: open, ref: ref, transitionDuration: transitionDuration }, other), _react.default.createElement(_MenuList.default, (0, _extends2.default)({ onKeyDown: handleListKeyDown, actions: menuListActionsRef, autoFocus: autoFocus && (activeItemIndex === -1 || disableAutoFocusItem), autoFocusItem: autoFocusItem, variant: variant }, MenuListProps, { className: (0, _clsx.default)(classes.list, MenuListProps.className) }), items)); }); process.env.NODE_ENV !== "production" ? Menu.propTypes = { /** * The DOM element used to set the position of the menu. */ anchorEl: _propTypes.default.oneOfType([_propTypes.default.object, _propTypes.default.func]), /** * If `true` (Default) will focus the `[role="menu"]` if no focusable child is found. Disabled * children are not focusable. If you set this prop to `false` focus will be placed * on the parent modal container. This has severe accessibility implications * and should only be considered if you manage focus otherwise. */ autoFocus: _propTypes.default.bool, /** * Menu contents, normally `MenuItem`s. */ children: _propTypes.default.node, /** * Override or extend the styles applied to the component. * See [CSS API](#css) below for more details. */ classes: _propTypes.default.object.isRequired, /** * When opening the menu will not focus the active item but the `[role="menu"]` * unless `autoFocus` is also set to `false`. Not using the default means not * following WAI-ARIA authoring practices. Please be considerate about possible * accessibility implications. */ disableAutoFocusItem: _propTypes.default.bool, /** * Props applied to the [`MenuList`](/api/menu-list/) element. */ MenuListProps: _propTypes.default.object, /** * Callback fired when the component requests to be closed. * * @param {object} event The event source of the callback. * @param {string} reason Can be:`"escapeKeyDown"`, `"backdropClick"`, `"tabKeyDown"`. */ onClose: _propTypes.default.func, /** * Callback fired before the Menu enters. */ onEnter: _propTypes.default.func, /** * Callback fired when the Menu has entered. */ onEntered: _propTypes.default.func, /** * Callback fired when the Menu is entering. */ onEntering: _propTypes.default.func, /** * Callback fired before the Menu exits. */ onExit: _propTypes.default.func, /** * Callback fired when the Menu has exited. */ onExited: _propTypes.default.func, /** * Callback fired when the Menu is exiting. */ onExiting: _propTypes.default.func, /** * If `true`, the menu is visible. */ open: _propTypes.default.bool.isRequired, /** * @ignore */ PaperProps: _propTypes.default.object, /** * `classes` prop applied to the [`Popover`](/api/popover/) element. */ PopoverClasses: _propTypes.default.object, /** * The length of the transition in `ms`, or 'auto' */ transitionDuration: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.shape({ enter: _propTypes.default.number, exit: _propTypes.default.number }), _propTypes.default.oneOf(['auto'])]), /** * The variant to use. Use `menu` to prevent selected items from impacting the initial focus * and the vertical alignment relative to the anchor element. */ variant: _propTypes.default.oneOf(['menu', 'selectedMenu']) } : void 0; var _default = (0, _withStyles.default)(styles, { name: 'MuiMenu' })(Menu); exports.default = _default;