material-ui
Version:
React Components that Implement Google's Material Design.
592 lines (522 loc) • 18.9 kB
JavaScript
'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;