d2-ui
Version:
394 lines (325 loc) • 11.8 kB
JavaScript
'use strict';
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; };
Object.defineProperty(exports, "__esModule", {
value: true
});
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _reactDom = require('react-dom');
var _reactDom2 = _interopRequireDefault(_reactDom);
var _stylePropable = require('../mixins/style-propable');
var _stylePropable2 = _interopRequireDefault(_stylePropable);
var _events = require('../utils/events');
var _events2 = _interopRequireDefault(_events);
var _propTypes = require('../utils/prop-types');
var _propTypes2 = _interopRequireDefault(_propTypes);
var _menu = require('../menus/menu');
var _menu2 = _interopRequireDefault(_menu);
var _getMuiTheme = require('../styles/getMuiTheme');
var _getMuiTheme2 = _interopRequireDefault(_getMuiTheme);
var _popover = require('../popover/popover');
var _popover2 = _interopRequireDefault(_popover);
var _warning = require('warning');
var _warning2 = _interopRequireDefault(_warning);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
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; }
var IconMenu = _react2.default.createClass({
displayName: 'IconMenu',
propTypes: {
/**
* This is the point on the icon where the menu
* targetOrigin will stick to.
* Options:
* vertical: [top, middle, bottom]
* horizontal: [left, center, right].
*/
anchorOrigin: _propTypes2.default.origin,
/**
* Should be used to pass `MenuItem` components.
*/
children: _react2.default.PropTypes.node,
/**
* The css class name of the root element.
*/
className: _react2.default.PropTypes.string,
/**
* If true, menu will close after an item is touchTapped.
*/
closeOnItemTouchTap: _react2.default.PropTypes.bool,
/**
* This is the IconButton to render. This button will open the menu.
*/
iconButtonElement: _react2.default.PropTypes.element.isRequired,
/**
* The style object to use to override underlying icon style.
*/
iconStyle: _react2.default.PropTypes.object,
/**
* The style object to use to override underlying menu style.
*/
menuStyle: _react2.default.PropTypes.object,
/**
* Fired when a menu item is touchTapped.
*/
onItemTouchTap: _react2.default.PropTypes.func,
/**
* Fired when keyobard focuses on element.
*/
onKeyboardFocus: _react2.default.PropTypes.func,
/**
* Fired when mouse is pressed on element.
*/
onMouseDown: _react2.default.PropTypes.func,
/**
* Fired when mouse enters the element.
*/
onMouseEnter: _react2.default.PropTypes.func,
/**
* Fired when mouse leaves the element.
*/
onMouseLeave: _react2.default.PropTypes.func,
/**
* Fired when mouse is lifted inside the element.
*/
onMouseUp: _react2.default.PropTypes.func,
/**
* Callback function that is fired when the open state
* of the menu is requested to be changed. The provided
* open argument determines whether the menu is requested
* to be opened or closed. Also, the reason argument states
* why the menu got closed or opened. It can be 'keyboard',
* 'iconTap' for open action and 'enter', 'escape', 'itemTap',
* 'clickAway' for close action.
*/
onRequestChange: _react2.default.PropTypes.func,
/**
* Fired when element is touch tapped.
*/
onTouchTap: _react2.default.PropTypes.func,
/**
* Controls whether the IconMenu is opened or not.
*/
open: _react2.default.PropTypes.bool,
/**
* Override the inline-styles of the root element.
*/
style: _react2.default.PropTypes.object,
/**
* This is the point on the menu which will stick to the menu
* origin.
* Options:
* vertical: [top, middle, bottom]
* horizontal: [left, center, right].
*/
targetOrigin: _propTypes2.default.origin,
/**
* Sets the delay in milliseconds before closing the
* menu when an item is clicked.
*/
touchTapCloseDelay: _react2.default.PropTypes.number
},
contextTypes: {
muiTheme: _react2.default.PropTypes.object
},
//for passing default theme context to children
childContextTypes: {
muiTheme: _react2.default.PropTypes.object
},
mixins: [_stylePropable2.default],
getDefaultProps: function getDefaultProps() {
return {
closeOnItemTouchTap: true,
open: null,
onItemTouchTap: function onItemTouchTap() {},
onKeyboardFocus: function onKeyboardFocus() {},
onMouseDown: function onMouseDown() {},
onMouseLeave: function onMouseLeave() {},
onMouseEnter: function onMouseEnter() {},
onMouseUp: function onMouseUp() {},
onTouchTap: function onTouchTap() {},
onRequestChange: function onRequestChange() {},
anchorOrigin: {
vertical: 'top',
horizontal: 'left'
},
targetOrigin: {
vertical: 'top',
horizontal: 'left'
},
touchTapCloseDelay: 200
};
},
getInitialState: function getInitialState() {
if (process.env.NODE_ENV !== 'production') {
this._warningIfNeeded();
}
return {
muiTheme: this.context.muiTheme || (0, _getMuiTheme2.default)(),
iconButtonRef: this.props.iconButtonElement.props.ref || 'iconButton',
menuInitiallyKeyboardFocused: false,
open: false
};
},
getChildContext: function getChildContext() {
return {
muiTheme: this.state.muiTheme
};
},
//to update theme inside state whenever a new theme is passed down
//from the parent / owner using context
componentWillReceiveProps: function componentWillReceiveProps(nextProps, nextContext) {
if (process.env.NODE_ENV !== 'production') {
this._warningIfNeeded();
}
var newMuiTheme = nextContext.muiTheme ? nextContext.muiTheme : this.state.muiTheme;
this.setState({ muiTheme: newMuiTheme });
if (nextProps.open === true || nextProps.open === false) {
this.setState({ open: nextProps.open });
}
},
componentWillUnmount: function componentWillUnmount() {
if (this._timeout) clearTimeout(this._timeout);
},
_warningIfNeeded: function _warningIfNeeded() {
if (this.props.hasOwnProperty('open')) {
process.env.NODE_ENV !== "production" ? (0, _warning2.default)(this.props.hasOwnProperty('closeOnItemTouchTap'), 'closeOnItemTouchTap has been deprecated in favor of open, onRequestChange') : undefined;
}
},
isOpen: function isOpen() {
return this.state.open;
},
close: function close(reason, isKeyboard) {
var _this = this;
if (!this.state.open) {
return;
}
if (this.props.open !== null) {
this.props.onRequestChange(false, reason);
}
this.setState({ open: false }, function () {
//Set focus on the icon button when the menu close
if (isKeyboard) {
var iconButton = _this.refs[_this.state.iconButtonRef];
_reactDom2.default.findDOMNode(iconButton).focus();
iconButton.setKeyboardFocus();
}
});
},
open: function open(reason, event) {
if (this.props.open !== null) {
this.props.onRequestChange(true, reason);
return this.setState({
menuInitiallyKeyboardFocused: _events2.default.isKeyboard(event),
anchorEl: event.currentTarget
});
}
this.setState({
open: true,
menuInitiallyKeyboardFocused: _events2.default.isKeyboard(event),
anchorEl: event.currentTarget
});
event.preventDefault();
},
_handleItemTouchTap: function _handleItemTouchTap(event, child) {
var _this2 = this;
if (this.props.closeOnItemTouchTap) {
(function () {
var isKeyboard = _events2.default.isKeyboard(event);
_this2._timeout = setTimeout(function () {
if (!_this2.isMounted()) {
return;
}
_this2.close(isKeyboard ? 'enter' : 'itemTap', isKeyboard);
}, _this2.props.touchTapCloseDelay);
})();
}
this.props.onItemTouchTap(event, child);
},
_handleMenuEscKeyDown: function _handleMenuEscKeyDown(event) {
this.close('escape', event);
},
render: function render() {
var _this3 = this;
var _props = this.props;
var anchorOrigin = _props.anchorOrigin;
var className = _props.className;
var closeOnItemTouchTap = _props.closeOnItemTouchTap;
var iconButtonElement = _props.iconButtonElement;
var iconStyle = _props.iconStyle;
var onItemTouchTap = _props.onItemTouchTap;
var onKeyboardFocus = _props.onKeyboardFocus;
var onMouseDown = _props.onMouseDown;
var onMouseLeave = _props.onMouseLeave;
var onMouseEnter = _props.onMouseEnter;
var onMouseUp = _props.onMouseUp;
var onTouchTap = _props.onTouchTap;
var menuStyle = _props.menuStyle;
var style = _props.style;
var targetOrigin = _props.targetOrigin;
var other = _objectWithoutProperties(_props, ['anchorOrigin', 'className', 'closeOnItemTouchTap', 'iconButtonElement', 'iconStyle', 'onItemTouchTap', 'onKeyboardFocus', 'onMouseDown', 'onMouseLeave', 'onMouseEnter', 'onMouseUp', 'onTouchTap', 'menuStyle', 'style', 'targetOrigin']);
var _state = this.state;
var open = _state.open;
var anchorEl = _state.anchorEl;
var styles = {
root: {
display: 'inline-block',
position: 'relative'
},
menu: {
position: 'relative'
}
};
var mergedRootStyles = this.mergeStyles(styles.root, style);
var mergedMenuStyles = this.mergeStyles(styles.menu, menuStyle);
var iconButton = _react2.default.cloneElement(iconButtonElement, {
onKeyboardFocus: this.props.onKeyboardFocus,
iconStyle: this.mergeStyles(iconStyle, iconButtonElement.props.iconStyle),
onTouchTap: function onTouchTap(e) {
_this3.open(_events2.default.isKeyboard(e) ? 'keyboard' : 'iconTap', e);
if (iconButtonElement.props.onTouchTap) iconButtonElement.props.onTouchTap(e);
},
ref: this.state.iconButtonRef
});
var menu = _react2.default.createElement(
_menu2.default,
_extends({}, other, {
animateOpen: true,
initiallyKeyboardFocused: this.state.menuInitiallyKeyboardFocused,
onEscKeyDown: this._handleMenuEscKeyDown,
onItemTouchTap: this._handleItemTouchTap,
zDepth: 0,
style: mergedMenuStyles
}),
this.props.children
);
return _react2.default.createElement(
'div',
{
className: className,
onMouseDown: onMouseDown,
onMouseLeave: onMouseLeave,
onMouseEnter: onMouseEnter,
onMouseUp: onMouseUp,
onTouchTap: onTouchTap,
style: this.prepareStyles(mergedRootStyles)
},
iconButton,
_react2.default.createElement(
_popover2.default,
{
anchorOrigin: anchorOrigin,
targetOrigin: targetOrigin,
open: open,
anchorEl: anchorEl,
childContextTypes: this.constructor.childContextTypes,
useLayerForClickAway: false,
onRequestClose: this.close,
context: this.context
},
menu
)
);
}
});
exports.default = IconMenu;
module.exports = exports['default'];