155 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			155 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
var _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; };
 | 
						|
 | 
						|
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
 | 
						|
 | 
						|
// @inheritedComponent Popover
 | 
						|
 | 
						|
import React from 'react';
 | 
						|
 | 
						|
import { findDOMNode } from 'react-dom';
 | 
						|
import getScrollbarSize from 'dom-helpers/util/scrollbarSize';
 | 
						|
import withStyles from '../styles/withStyles';
 | 
						|
import Popover from '../Popover';
 | 
						|
import MenuList from './MenuList';
 | 
						|
 | 
						|
 | 
						|
const rtlOrigin = {
 | 
						|
  vertical: 'top',
 | 
						|
  horizontal: 'right'
 | 
						|
};
 | 
						|
 | 
						|
const ltrOrigin = {
 | 
						|
  vertical: 'top',
 | 
						|
  horizontal: 'left'
 | 
						|
};
 | 
						|
 | 
						|
export const styles = {
 | 
						|
  paper: {
 | 
						|
    // specZ: The maximum height of a simple menu should be one or more rows less than the view
 | 
						|
    // height. This ensures a tappable area outside of the simple menu with which to dismiss
 | 
						|
    // the menu.
 | 
						|
    maxHeight: 'calc(100vh - 96px)',
 | 
						|
    // Add iOS momentum scrolling.
 | 
						|
    WebkitOverflowScrolling: 'touch'
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
class Menu extends React.Component {
 | 
						|
  constructor(...args) {
 | 
						|
    var _temp;
 | 
						|
 | 
						|
    return _temp = super(...args), this.getContentAnchorEl = () => {
 | 
						|
      if (!this.menuList || !this.menuList.selectedItem) {
 | 
						|
        // $FlowFixMe
 | 
						|
        return findDOMNode(this.menuList).firstChild;
 | 
						|
      }
 | 
						|
 | 
						|
      return findDOMNode(this.menuList.selectedItem);
 | 
						|
    }, this.menuList = undefined, this.focus = () => {
 | 
						|
      if (this.menuList && this.menuList.selectedItem) {
 | 
						|
        // $FlowFixMe
 | 
						|
        findDOMNode(this.menuList.selectedItem).focus();
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
      const menuList = findDOMNode(this.menuList);
 | 
						|
      if (menuList && menuList.firstChild) {
 | 
						|
        // $FlowFixMe
 | 
						|
        menuList.firstChild.focus();
 | 
						|
      }
 | 
						|
    }, this.handleEnter = element => {
 | 
						|
      const { theme } = this.props;
 | 
						|
 | 
						|
      const menuList = findDOMNode(this.menuList);
 | 
						|
 | 
						|
      // Focus so the scroll computation of the Popover works as expected.
 | 
						|
      this.focus();
 | 
						|
 | 
						|
      // Let's ignore that piece of logic if users are already overriding the width
 | 
						|
      // of the menu.
 | 
						|
      // $FlowFixMe
 | 
						|
      if (menuList && element.clientHeight < menuList.clientHeight && !menuList.style.width) {
 | 
						|
        const size = `${getScrollbarSize()}px`;
 | 
						|
        // $FlowFixMe
 | 
						|
        menuList.style[theme.direction === 'rtl' ? 'paddingLeft' : 'paddingRight'] = size;
 | 
						|
        // $FlowFixMe
 | 
						|
        menuList.style.width = `calc(100% + ${size})`;
 | 
						|
      }
 | 
						|
 | 
						|
      if (this.props.onEnter) {
 | 
						|
        this.props.onEnter(element);
 | 
						|
      }
 | 
						|
    }, this.handleListKeyDown = (event, key) => {
 | 
						|
      if (key === 'tab') {
 | 
						|
        event.preventDefault();
 | 
						|
 | 
						|
        if (this.props.onRequestClose) {
 | 
						|
          this.props.onRequestClose(event);
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }, _temp;
 | 
						|
  }
 | 
						|
 | 
						|
  componentDidMount() {
 | 
						|
    if (this.props.open) {
 | 
						|
      this.focus();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  componentDidUpdate(prevProps) {
 | 
						|
    if (!prevProps.open && this.props.open) {
 | 
						|
      // Needs to refocus as when a menu is rendered into another Modal,
 | 
						|
      // the first modal might change the focus to prevent any leak.
 | 
						|
      this.focus();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  render() {
 | 
						|
    const _props = this.props,
 | 
						|
          {
 | 
						|
      children,
 | 
						|
      classes,
 | 
						|
      MenuListProps,
 | 
						|
      onEnter,
 | 
						|
      PaperProps = {},
 | 
						|
      PopoverClasses,
 | 
						|
      theme
 | 
						|
    } = _props,
 | 
						|
          other = _objectWithoutProperties(_props, ['children', 'classes', 'MenuListProps', 'onEnter', 'PaperProps', 'PopoverClasses', 'theme']);
 | 
						|
 | 
						|
    return React.createElement(
 | 
						|
      Popover,
 | 
						|
      _extends({
 | 
						|
        getContentAnchorEl: this.getContentAnchorEl,
 | 
						|
        classes: PopoverClasses,
 | 
						|
        onEnter: this.handleEnter,
 | 
						|
        anchorOrigin: theme.direction === 'rtl' ? rtlOrigin : ltrOrigin,
 | 
						|
        transformOrigin: theme.direction === 'rtl' ? rtlOrigin : ltrOrigin,
 | 
						|
        PaperProps: _extends({}, PaperProps, {
 | 
						|
          classes: _extends({}, PaperProps.classes, {
 | 
						|
            root: classes.paper
 | 
						|
          })
 | 
						|
        })
 | 
						|
      }, other),
 | 
						|
      React.createElement(
 | 
						|
        MenuList,
 | 
						|
        _extends({
 | 
						|
          'data-mui-test': 'Menu',
 | 
						|
          role: 'menu',
 | 
						|
          onKeyDown: this.handleListKeyDown
 | 
						|
        }, MenuListProps, {
 | 
						|
          ref: node => {
 | 
						|
            this.menuList = node;
 | 
						|
          }
 | 
						|
        }),
 | 
						|
        children
 | 
						|
      )
 | 
						|
    );
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
Menu.defaultProps = {
 | 
						|
  open: false,
 | 
						|
  transitionDuration: 'auto'
 | 
						|
};
 | 
						|
export default withStyles(styles, { withTheme: true, name: 'MuiMenu' })(Menu); |