react-bootstrap
Version:
Bootstrap 3 components build with React
293 lines (233 loc) • 8.16 kB
JavaScript
/*eslint-disable react/prop-types */
'use strict';
var _extends = require('babel-runtime/helpers/extends')['default'];
var _Object$keys = require('babel-runtime/core-js/object/keys')['default'];
var _interopRequireDefault = require('babel-runtime/helpers/interop-require-default')['default'];
exports.__esModule = true;
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _utilsCreateChainedFunction = require('./utils/createChainedFunction');
var _utilsCreateChainedFunction2 = _interopRequireDefault(_utilsCreateChainedFunction);
var _utilsCreateContextWrapper = require('./utils/createContextWrapper');
var _utilsCreateContextWrapper2 = _interopRequireDefault(_utilsCreateContextWrapper);
var _Overlay = require('./Overlay');
var _Overlay2 = _interopRequireDefault(_Overlay);
var _reactLibWarning = require('react/lib/warning');
var _reactLibWarning2 = _interopRequireDefault(_reactLibWarning);
var _lodashObjectPick = require('lodash/object/pick');
/**
* Check if value one is inside or equal to the of value
*
* @param {string} one
* @param {string|array} of
* @returns {boolean}
*/
var _lodashObjectPick2 = _interopRequireDefault(_lodashObjectPick);
function isOneOf(one, of) {
if (Array.isArray(of)) {
return of.indexOf(one) >= 0;
}
return one === of;
}
var OverlayTrigger = _react2['default'].createClass({
displayName: 'OverlayTrigger',
propTypes: _extends({}, _Overlay2['default'].propTypes, {
/**
* Specify which action or actions trigger Overlay visibility
*/
trigger: _react2['default'].PropTypes.oneOfType([_react2['default'].PropTypes.oneOf(['click', 'hover', 'focus']), _react2['default'].PropTypes.arrayOf(_react2['default'].PropTypes.oneOf(['click', 'hover', 'focus']))]),
/**
* A millisecond delay amount to show and hide the Overlay once triggered
*/
delay: _react2['default'].PropTypes.number,
/**
* A millisecond delay amount before showing the Overlay once triggered.
*/
delayShow: _react2['default'].PropTypes.number,
/**
* A millisecond delay amount before hiding the Overlay once triggered.
*/
delayHide: _react2['default'].PropTypes.number,
/**
* The initial visibility state of the Overlay, for more nuanced visibility controll consider
* using the Overlay component directly.
*/
defaultOverlayShown: _react2['default'].PropTypes.bool,
/**
* An element or text to overlay next to the target.
*/
overlay: _react2['default'].PropTypes.node.isRequired,
/**
* @private
*/
onBlur: _react2['default'].PropTypes.func,
/**
* @private
*/
onClick: _react2['default'].PropTypes.func,
/**
* @private
*/
onFocus: _react2['default'].PropTypes.func,
/**
* @private
*/
onMouseEnter: _react2['default'].PropTypes.func,
/**
* @private
*/
onMouseLeave: _react2['default'].PropTypes.func,
//override specific overlay props
/**
* @private
*/
target: function target() {},
/**
* @private
*/
onHide: function onHide() {},
/**
* @private
*/
show: function show() {}
}),
getDefaultProps: function getDefaultProps() {
return {
trigger: ['hover', 'focus']
};
},
getInitialState: function getInitialState() {
return {
isOverlayShown: this.props.defaultOverlayShown == null ? false : this.props.defaultOverlayShown
};
},
show: function show() {
this.setState({
isOverlayShown: true
});
},
hide: function hide() {
this.setState({
isOverlayShown: false
});
},
toggle: function toggle() {
if (this.state.isOverlayShown) {
this.hide();
} else {
this.show();
}
},
componentDidMount: function componentDidMount() {
this._mountNode = document.createElement('div');
_react2['default'].render(this._overlay, this._mountNode);
},
componentWillUnmount: function componentWillUnmount() {
_react2['default'].unmountComponentAtNode(this._mountNode);
this._mountNode = null;
clearTimeout(this._hoverDelay);
},
componentDidUpdate: function componentDidUpdate() {
if (this._mountNode) {
_react2['default'].render(this._overlay, this._mountNode);
}
},
getOverlayTarget: function getOverlayTarget() {
return _react2['default'].findDOMNode(this);
},
getOverlay: function getOverlay() {
var overlayProps = _extends({}, _lodashObjectPick2['default'](this.props, _Object$keys(_Overlay2['default'].propTypes)), {
show: this.state.isOverlayShown,
onHide: this.hide,
target: this.getOverlayTarget,
onExit: this.props.onExit,
onExiting: this.props.onExiting,
onExited: this.props.onExited,
onEnter: this.props.onEnter,
onEntering: this.props.onEntering,
onEntered: this.props.onEntered
});
var overlay = _react.cloneElement(this.props.overlay, {
placement: overlayProps.placement,
container: overlayProps.container
});
return _react2['default'].createElement(
_Overlay2['default'],
overlayProps,
overlay
);
},
render: function render() {
var trigger = _react2['default'].Children.only(this.props.children);
var props = {
'aria-describedby': this.props.overlay.props.id
};
// create in render otherwise owner is lost...
this._overlay = this.getOverlay();
props.onClick = _utilsCreateChainedFunction2['default'](trigger.props.onClick, this.props.onClick);
if (isOneOf('click', this.props.trigger)) {
props.onClick = _utilsCreateChainedFunction2['default'](this.toggle, props.onClick);
}
if (isOneOf('hover', this.props.trigger)) {
_reactLibWarning2['default'](!(this.props.trigger === 'hover'), '[react-bootstrap] Specifying only the `"hover"` trigger limits the visibilty of the overlay to just mouse users. ' + 'Consider also including the `"focus"` trigger so that touch and keyboard only users can see the overlay as well.');
props.onMouseOver = _utilsCreateChainedFunction2['default'](this.handleDelayedShow, this.props.onMouseOver);
props.onMouseOut = _utilsCreateChainedFunction2['default'](this.handleDelayedHide, this.props.onMouseOut);
}
if (isOneOf('focus', this.props.trigger)) {
props.onFocus = _utilsCreateChainedFunction2['default'](this.handleDelayedShow, this.props.onFocus);
props.onBlur = _utilsCreateChainedFunction2['default'](this.handleDelayedHide, this.props.onBlur);
}
return _react.cloneElement(trigger, props);
},
handleDelayedShow: function handleDelayedShow() {
var _this = this;
if (this._hoverDelay != null) {
clearTimeout(this._hoverDelay);
this._hoverDelay = null;
return;
}
var delay = this.props.delayShow != null ? this.props.delayShow : this.props.delay;
if (!delay) {
this.show();
return;
}
this._hoverDelay = setTimeout(function () {
_this._hoverDelay = null;
_this.show();
}, delay);
},
handleDelayedHide: function handleDelayedHide() {
var _this2 = this;
if (this._hoverDelay != null) {
clearTimeout(this._hoverDelay);
this._hoverDelay = null;
return;
}
var delay = this.props.delayHide != null ? this.props.delayHide : this.props.delay;
if (!delay) {
this.hide();
return;
}
this._hoverDelay = setTimeout(function () {
_this2._hoverDelay = null;
_this2.hide();
}, delay);
}
});
/**
* Creates a new OverlayTrigger class that forwards the relevant context
*
* This static method should only be called at the module level, instead of in
* e.g. a render() method, because it's expensive to create new classes.
*
* For example, you would want to have:
*
* > export default OverlayTrigger.withContext({
* > myContextKey: React.PropTypes.object
* > });
*
* and import this when needed.
*/
OverlayTrigger.withContext = _utilsCreateContextWrapper2['default'](OverlayTrigger, 'overlay');
exports['default'] = OverlayTrigger;
module.exports = exports['default'];