react-bootstrap
Version:
Bootstrap 3 components build with React
209 lines (165 loc) • 6.61 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
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 _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _classnames = require('classnames');
var _classnames2 = _interopRequireDefault(_classnames);
var _BootstrapMixin = require('./BootstrapMixin');
var _BootstrapMixin2 = _interopRequireDefault(_BootstrapMixin);
var _FadeMixin = require('./FadeMixin');
var _FadeMixin2 = _interopRequireDefault(_FadeMixin);
var _utilsDomUtils = require('./utils/domUtils');
var _utilsDomUtils2 = _interopRequireDefault(_utilsDomUtils);
var _utilsEventListener = require('./utils/EventListener');
var _utilsEventListener2 = _interopRequireDefault(_utilsEventListener);
// TODO:
// - aria-labelledby
// - Add `modal-body` div if only one child passed in that doesn't already have it
// - Tests
var Modal = _react2['default'].createClass({
displayName: 'Modal',
mixins: [_BootstrapMixin2['default'], _FadeMixin2['default']],
propTypes: {
title: _react2['default'].PropTypes.node,
backdrop: _react2['default'].PropTypes.oneOf(['static', true, false]),
keyboard: _react2['default'].PropTypes.bool,
closeButton: _react2['default'].PropTypes.bool,
animation: _react2['default'].PropTypes.bool,
onRequestHide: _react2['default'].PropTypes.func.isRequired,
dialogClassName: _react2['default'].PropTypes.string
},
getDefaultProps: function getDefaultProps() {
return {
bsClass: 'modal',
backdrop: true,
keyboard: true,
animation: true,
closeButton: true
};
},
render: function render() {
var modalStyle = { display: 'block' };
var dialogClasses = this.getBsClassSet();
delete dialogClasses.modal;
dialogClasses['modal-dialog'] = true;
var classes = {
modal: true,
fade: this.props.animation,
'in': !this.props.animation
};
var modal = _react2['default'].createElement(
'div',
_extends({}, this.props, {
title: null,
tabIndex: '-1',
role: 'dialog',
style: modalStyle,
className: (0, _classnames2['default'])(this.props.className, classes),
onClick: this.props.backdrop === true ? this.handleBackdropClick : null,
ref: 'modal' }),
_react2['default'].createElement(
'div',
{ className: (0, _classnames2['default'])(this.props.dialogClassName, dialogClasses) },
_react2['default'].createElement(
'div',
{ className: 'modal-content' },
this.props.title ? this.renderHeader() : null,
this.props.children
)
)
);
return this.props.backdrop ? this.renderBackdrop(modal) : modal;
},
renderBackdrop: function renderBackdrop(modal) {
var classes = {
'modal-backdrop': true,
fade: this.props.animation,
'in': !this.props.animation
};
var onClick = this.props.backdrop === true ? this.handleBackdropClick : null;
return _react2['default'].createElement(
'div',
null,
_react2['default'].createElement('div', { className: (0, _classnames2['default'])(classes), ref: 'backdrop', onClick: onClick }),
modal
);
},
renderHeader: function renderHeader() {
var closeButton = undefined;
if (this.props.closeButton) {
closeButton = _react2['default'].createElement(
'button',
{ type: 'button', className: 'close', 'aria-hidden': 'true', onClick: this.props.onRequestHide },
'×'
);
}
return _react2['default'].createElement(
'div',
{ className: 'modal-header' },
closeButton,
this.renderTitle()
);
},
renderTitle: function renderTitle() {
return _react2['default'].isValidElement(this.props.title) ? this.props.title : _react2['default'].createElement(
'h4',
{ className: 'modal-title' },
this.props.title
);
},
iosClickHack: function iosClickHack() {
// IOS only allows click events to be delegated to the document on elements
// it considers 'clickable' - anchors, buttons, etc. We fake a click handler on the
// DOM nodes themselves. Remove if handled by React: https://github.com/facebook/react/issues/1169
_react2['default'].findDOMNode(this.refs.modal).onclick = function () {};
_react2['default'].findDOMNode(this.refs.backdrop).onclick = function () {};
},
componentDidMount: function componentDidMount() {
this._onDocumentKeyupListener = _utilsEventListener2['default'].listen(_utilsDomUtils2['default'].ownerDocument(this), 'keyup', this.handleDocumentKeyUp);
var container = this.props.container && _react2['default'].findDOMNode(this.props.container) || _utilsDomUtils2['default'].ownerDocument(this).body;
container.className += container.className.length ? ' modal-open' : 'modal-open';
this.focusModalContent();
if (this.props.backdrop) {
this.iosClickHack();
}
},
componentDidUpdate: function componentDidUpdate(prevProps) {
if (this.props.backdrop && this.props.backdrop !== prevProps.backdrop) {
this.iosClickHack();
}
},
componentWillUnmount: function componentWillUnmount() {
this._onDocumentKeyupListener.remove();
var container = this.props.container && _react2['default'].findDOMNode(this.props.container) || _utilsDomUtils2['default'].ownerDocument(this).body;
container.className = container.className.replace(/ ?modal-open/, '');
this.restoreLastFocus();
},
handleBackdropClick: function handleBackdropClick(e) {
if (e.target !== e.currentTarget) {
return;
}
this.props.onRequestHide();
},
handleDocumentKeyUp: function handleDocumentKeyUp(e) {
if (this.props.keyboard && e.keyCode === 27) {
this.props.onRequestHide();
}
},
focusModalContent: function focusModalContent() {
this.lastFocus = _utilsDomUtils2['default'].ownerDocument(this).activeElement;
var modalContent = _react2['default'].findDOMNode(this.refs.modal);
modalContent.focus();
},
restoreLastFocus: function restoreLastFocus() {
if (this.lastFocus) {
this.lastFocus.focus();
this.lastFocus = null;
}
}
});
exports['default'] = Modal;
module.exports = exports['default'];