UNPKG

material-ui

Version:

React Components that Implement Google's Material Design.

592 lines (522 loc) 18.9 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _extends2 = require('babel-runtime/helpers/extends'); var _extends3 = _interopRequireDefault(_extends2); var _objectWithoutProperties2 = require('babel-runtime/helpers/objectWithoutProperties'); var _objectWithoutProperties3 = _interopRequireDefault(_objectWithoutProperties2); var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); var _inherits2 = require('babel-runtime/helpers/inherits'); var _inherits3 = _interopRequireDefault(_inherits2); var _simpleAssign = require('simple-assign'); var _simpleAssign2 = _interopRequireDefault(_simpleAssign); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _propTypes = require('prop-types'); var _propTypes2 = _interopRequireDefault(_propTypes); var _reactDom = require('react-dom'); var _reactDom2 = _interopRequireDefault(_reactDom); var _transitions = require('../styles/transitions'); var _transitions2 = _interopRequireDefault(_transitions); var _arrowDropDown = require('../svg-icons/navigation/arrow-drop-down'); var _arrowDropDown2 = _interopRequireDefault(_arrowDropDown); var _Menu = require('../Menu/Menu'); var _Menu2 = _interopRequireDefault(_Menu); var _ClearFix = require('../internal/ClearFix'); var _ClearFix2 = _interopRequireDefault(_ClearFix); var _Popover = require('../Popover/Popover'); var _Popover2 = _interopRequireDefault(_Popover); var _PopoverAnimationVertical = require('../Popover/PopoverAnimationVertical'); var _PopoverAnimationVertical2 = _interopRequireDefault(_PopoverAnimationVertical); var _keycode = require('keycode'); var _keycode2 = _interopRequireDefault(_keycode); var _events = require('../utils/events'); var _events2 = _interopRequireDefault(_events); var _IconButton = require('../IconButton'); var _IconButton2 = _interopRequireDefault(_IconButton); var _propTypes3 = require('../utils/propTypes'); var _propTypes4 = _interopRequireDefault(_propTypes3); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function getStyles(props, context) { var disabled = props.disabled; var spacing = context.muiTheme.baseTheme.spacing; var palette = context.muiTheme.baseTheme.palette; var accentColor = context.muiTheme.dropDownMenu.accentColor; return { control: { cursor: disabled ? 'not-allowed' : 'pointer', height: '100%', position: 'relative', width: '100%' }, icon: { fill: accentColor, position: 'absolute', right: spacing.desktopGutterLess, top: (spacing.iconSize - 24) / 2 + spacing.desktopGutterMini / 2 }, iconChildren: { fill: 'inherit' }, label: { color: disabled ? palette.disabledColor : palette.textColor, height: spacing.desktopToolbarHeight + 'px', lineHeight: spacing.desktopToolbarHeight + 'px', overflow: 'hidden', opacity: 1, position: 'relative', paddingLeft: spacing.desktopGutter, paddingRight: spacing.iconSize * 2 + spacing.desktopGutterMini, textOverflow: 'ellipsis', top: 0, whiteSpace: 'nowrap' }, labelWhenOpen: { opacity: 0, top: spacing.desktopToolbarHeight / 8 }, root: { display: 'inline-block', fontSize: spacing.desktopDropDownMenuFontSize, height: spacing.desktopSubheaderHeight, fontFamily: context.muiTheme.baseTheme.fontFamily, outline: 'none', position: 'relative', transition: _transitions2.default.easeOut() }, rootWhenOpen: { opacity: 1 }, underline: { borderTop: 'solid 1px ' + accentColor, bottom: 1, left: 0, margin: '-1px ' + spacing.desktopGutter + 'px', right: 0, position: 'absolute' } }; } var DropDownMenu = function (_Component) { (0, _inherits3.default)(DropDownMenu, _Component); function DropDownMenu() { var _ref; var _temp, _this, _ret; (0, _classCallCheck3.default)(this, DropDownMenu); for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return _ret = (_temp = (_this = (0, _possibleConstructorReturn3.default)(this, (_ref = DropDownMenu.__proto__ || (0, _getPrototypeOf2.default)(DropDownMenu)).call.apply(_ref, [this].concat(args))), _this), _this.state = { open: false }, _this.rootNode = undefined, _this.arrowNode = undefined, _this.handleClickControl = function (event) { event.preventDefault(); if (!_this.props.disabled) { _this.setState({ open: !_this.state.open, anchorEl: _this.rootNode }); } }, _this.handleRequestCloseMenu = function () { _this.close(false); }, _this.handleEscKeyDownMenu = function () { _this.close(true); }, _this.handleKeyDown = function (event) { switch ((0, _keycode2.default)(event)) { case 'up': case 'down': case 'space': case 'enter': event.preventDefault(); _this.setState({ open: true, anchorEl: _this.rootNode }); break; } }, _this.handleItemClick = function (event, child, index) { if (_this.props.multiple) { if (!_this.state.open) { _this.setState({ open: true }); } } else { event.persist(); _this.setState({ open: false }, function () { if (_this.props.onChange) { _this.props.onChange(event, index, child.props.value); } _this.close(_events2.default.isKeyboard(event)); }); } }, _this.handleChange = function (event, value) { if (_this.props.multiple && _this.props.onChange) { _this.props.onChange(event, undefined, value); } }, _this.close = function (isKeyboard) { _this.setState({ open: false }, function () { if (_this.props.onClose) { _this.props.onClose(); } if (isKeyboard) { var dropArrow = _this.arrowNode; var dropNode = _reactDom2.default.findDOMNode(dropArrow); dropNode.focus(); dropArrow.setKeyboardFocus(true); } }); }, _temp), (0, _possibleConstructorReturn3.default)(_this, _ret); } // The nested styles for drop-down-menu are modified by toolbar and possibly // other user components, so it will give full access to its js styles rather // than just the parent. (0, _createClass3.default)(DropDownMenu, [{ key: 'componentDidMount', value: function componentDidMount() { var _this2 = this; if (this.props.autoWidth) { this.setWidth(); } if (this.props.openImmediately) { // TODO: Temporary fix to make openImmediately work with popover. /* eslint-disable react/no-did-mount-set-state */ setTimeout(function () { return _this2.setState({ open: true, anchorEl: _this2.rootNode }); }, 0); /* eslint-enable react/no-did-mount-set-state */ } } }, { key: 'componentWillReceiveProps', value: function componentWillReceiveProps() { if (this.props.autoWidth) { this.setWidth(); } } }, { key: 'getInputNode', /** * This method is deprecated but still here because the TextField * need it in order to work. TODO: That will be addressed later. */ value: function getInputNode() { var _this3 = this; var rootNode = this.rootNode; rootNode.focus = function () { if (!_this3.props.disabled) { _this3.setState({ open: !_this3.state.open, anchorEl: _this3.rootNode }); } }; return rootNode; } }, { key: 'setWidth', value: function setWidth() { var el = this.rootNode; if (!this.props.style || !this.props.style.hasOwnProperty('width')) { el.style.width = 'auto'; } } }, { key: 'render', value: function render() { var _this4 = this; var _props = this.props, animated = _props.animated, animation = _props.animation, autoWidth = _props.autoWidth, multiple = _props.multiple, children = _props.children, className = _props.className, disabled = _props.disabled, iconStyle = _props.iconStyle, labelStyle = _props.labelStyle, listStyle = _props.listStyle, maxHeight = _props.maxHeight, menuStyleProp = _props.menuStyle, selectionRenderer = _props.selectionRenderer, onClose = _props.onClose, openImmediately = _props.openImmediately, menuItemStyle = _props.menuItemStyle, selectedMenuItemStyle = _props.selectedMenuItemStyle, style = _props.style, underlineStyle = _props.underlineStyle, value = _props.value, iconButton = _props.iconButton, anchorOrigin = _props.anchorOrigin, targetOrigin = _props.targetOrigin, other = (0, _objectWithoutProperties3.default)(_props, ['animated', 'animation', 'autoWidth', 'multiple', 'children', 'className', 'disabled', 'iconStyle', 'labelStyle', 'listStyle', 'maxHeight', 'menuStyle', 'selectionRenderer', 'onClose', 'openImmediately', 'menuItemStyle', 'selectedMenuItemStyle', 'style', 'underlineStyle', 'value', 'iconButton', 'anchorOrigin', 'targetOrigin']); var _state = this.state, anchorEl = _state.anchorEl, open = _state.open; var prepareStyles = this.context.muiTheme.prepareStyles; var styles = getStyles(this.props, this.context); var displayValue = ''; if (!multiple) { _react2.default.Children.forEach(children, function (child) { if (child && value === child.props.value) { if (selectionRenderer) { displayValue = selectionRenderer(value, child); } else { // This will need to be improved (in case primaryText is a node) displayValue = child.props.label || child.props.primaryText; } } }); } else { var values = []; var selectionRendererChildren = []; _react2.default.Children.forEach(children, function (child) { if (child && value && value.indexOf(child.props.value) > -1) { if (selectionRenderer) { values.push(child.props.value); selectionRendererChildren.push(child); } else { values.push(child.props.label || child.props.primaryText); } } }); displayValue = []; if (selectionRenderer) { displayValue = selectionRenderer(values, selectionRendererChildren); } else { displayValue = values.join(', '); } } var menuStyle = void 0; if (anchorEl && !autoWidth) { menuStyle = (0, _simpleAssign2.default)({ width: anchorEl.clientWidth }, menuStyleProp); } else { menuStyle = menuStyleProp; } return _react2.default.createElement( 'div', (0, _extends3.default)({}, other, { ref: function ref(node) { _this4.rootNode = node; }, className: className, style: prepareStyles((0, _simpleAssign2.default)({}, styles.root, open && styles.rootWhenOpen, style)) }), _react2.default.createElement( _ClearFix2.default, { style: styles.control, onClick: this.handleClickControl }, _react2.default.createElement( 'div', { style: prepareStyles((0, _simpleAssign2.default)({}, styles.label, open && styles.labelWhenOpen, labelStyle)) }, displayValue ), _react2.default.createElement( _IconButton2.default, { disabled: disabled, onKeyDown: this.handleKeyDown, ref: function ref(node) { _this4.arrowNode = node; }, style: (0, _simpleAssign2.default)({}, styles.icon, iconStyle), iconStyle: styles.iconChildren }, iconButton ), _react2.default.createElement('div', { style: prepareStyles((0, _simpleAssign2.default)({}, styles.underline, underlineStyle)) }) ), _react2.default.createElement( _Popover2.default, { anchorOrigin: anchorOrigin, targetOrigin: targetOrigin, anchorEl: anchorEl, animation: animation || _PopoverAnimationVertical2.default, open: open, animated: animated, onRequestClose: this.handleRequestCloseMenu }, _react2.default.createElement( _Menu2.default, { multiple: multiple, maxHeight: maxHeight, desktop: true, value: value, onEscKeyDown: this.handleEscKeyDownMenu, style: menuStyle, listStyle: listStyle, onItemClick: this.handleItemClick, onChange: this.handleChange, menuItemStyle: menuItemStyle, selectedMenuItemStyle: selectedMenuItemStyle, autoWidth: autoWidth, width: !autoWidth && menuStyle ? menuStyle.width : null }, children ) ) ); } }]); return DropDownMenu; }(_react.Component); DropDownMenu.muiName = 'DropDownMenu'; DropDownMenu.defaultProps = { animated: true, autoWidth: true, disabled: false, iconButton: _react2.default.createElement(_arrowDropDown2.default, null), openImmediately: false, maxHeight: 500, multiple: false, anchorOrigin: { vertical: 'top', horizontal: 'left' } }; DropDownMenu.contextTypes = { muiTheme: _propTypes2.default.object.isRequired }; DropDownMenu.propTypes = process.env.NODE_ENV !== "production" ? { /** * This is the point on the anchor that the popover's * `targetOrigin` will attach to. * Options: * vertical: [top, center, bottom] * horizontal: [left, middle, right]. */ anchorOrigin: _propTypes4.default.origin, /** * If true, the popover will apply transitions when * it gets added to the DOM. */ animated: _propTypes2.default.bool, /** * Override the default animation component used. */ animation: _propTypes2.default.func, /** * The width will automatically be set according to the items inside the menu. * To control this width in css instead, set this prop to `false`. */ autoWidth: _propTypes2.default.bool, /** * The `MenuItem`s to populate the `Menu` with. If the `MenuItems` have the * prop `label` that value will be used to render the representation of that * item within the field. */ children: _propTypes2.default.node, /** * The css class name of the root element. */ className: _propTypes2.default.string, /** * Disables the menu. */ disabled: _propTypes2.default.bool, /** * Overrides default `SvgIcon` dropdown arrow component. */ iconButton: _propTypes2.default.node, /** * Overrides the styles of icon element. */ iconStyle: _propTypes2.default.object, /** * Overrides the styles of label when the `DropDownMenu` is inactive. */ labelStyle: _propTypes2.default.object, /** * The style object to use to override underlying list style. */ listStyle: _propTypes2.default.object, /** * The maximum height of the `Menu` when it is displayed. */ maxHeight: _propTypes2.default.number, /** * Override the inline-styles of menu items. */ menuItemStyle: _propTypes2.default.object, /** * Overrides the styles of `Menu` when the `DropDownMenu` is displayed. */ menuStyle: _propTypes2.default.object, /** * If true, `value` must be an array and the menu will support * multiple selections. */ multiple: _propTypes2.default.bool, /** * Callback function fired when a menu item is clicked, other than the one currently selected. * * @param {object} event Click event targeting the menu item that was clicked. * @param {number} key The index of the clicked menu item in the `children` collection. * @param {any} value If `multiple` is true, the menu's `value` * array with either the menu item's `value` added (if * it wasn't already selected) or omitted (if it was already selected). * Otherwise, the `value` of the menu item. */ onChange: _propTypes2.default.func, /** * Callback function fired when the menu is closed. */ onClose: _propTypes2.default.func, /** * Set to true to have the `DropDownMenu` automatically open on mount. */ openImmediately: _propTypes2.default.bool, /** * Override the inline-styles of selected menu items. */ selectedMenuItemStyle: _propTypes2.default.object, /** * Callback function fired when a menu item is clicked, other than the one currently selected. * * @param {any} value If `multiple` is true, the menu's `value` * array with either the menu item's `value` added (if * it wasn't already selected) or omitted (if it was already selected). * Otherwise, the `value` of the menu item. * @param {any} menuItem The selected `MenuItem`. * If `multiple` is true, this will be an array with the `MenuItem`s matching the `value`s parameter. */ selectionRenderer: _propTypes2.default.func, /** * Override the inline-styles of the root element. */ style: _propTypes2.default.object, /** * This is the point on the popover which will attach to * the anchor's origin. * Options: * vertical: [top, center, bottom] * horizontal: [left, middle, right]. */ targetOrigin: _propTypes4.default.origin, /** * Overrides the inline-styles of the underline. */ underlineStyle: _propTypes2.default.object, /** * If `multiple` is true, an array of the `value`s of the selected * menu items. Otherwise, the `value` of the selected menu item. * If provided, the menu will be a controlled component. */ value: _propTypes2.default.any } : {}; exports.default = DropDownMenu;