Last active
September 2, 2024 04:01
-
-
Save insin/8449696 to your computer and use it in GitHub Desktop.
A Bootstrap (3) modal mixin for React / MIT License
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** @jsx React.DOM */ | |
var BootstrapModalMixin = function() { | |
var handlerProps = | |
['handleShow', 'handleShown', 'handleHide', 'handleHidden'] | |
var bsModalEvents = { | |
handleShow: 'show.bs.modal' | |
, handleShown: 'shown.bs.modal' | |
, handleHide: 'hide.bs.modal' | |
, handleHidden: 'hidden.bs.modal' | |
} | |
return { | |
propTypes: { | |
handleShow: React.PropTypes.func | |
, handleShown: React.PropTypes.func | |
, handleHide: React.PropTypes.func | |
, handleHidden: React.PropTypes.func | |
, backdrop: React.PropTypes.bool | |
, keyboard: React.PropTypes.bool | |
, show: React.PropTypes.bool | |
, remote: React.PropTypes.string | |
} | |
, getDefaultProps: function() { | |
return { | |
backdrop: true | |
, keyboard: true | |
, show: true | |
, remote: '' | |
} | |
} | |
, componentDidMount: function() { | |
var $modal = $(this.getDOMNode()).modal({ | |
backdrop: this.props.backdrop | |
, keyboard: this.props.keyboard | |
, show: this.props.show | |
, remote: this.props.remote | |
}) | |
handlerProps.forEach(function(prop) { | |
if (this[prop]) { | |
$modal.on(bsModalEvents[prop], this[prop]) | |
} | |
if (this.props[prop]) { | |
$modal.on(bsModalEvents[prop], this.props[prop]) | |
} | |
}.bind(this)) | |
} | |
, componentWillUnmount: function() { | |
var $modal = $(this.getDOMNode()) | |
handlerProps.forEach(function(prop) { | |
if (this[prop]) { | |
$modal.off(bsModalEvents[prop], this[prop]) | |
} | |
if (this.props[prop]) { | |
$modal.off(bsModalEvents[prop], this.props[prop]) | |
} | |
}.bind(this)) | |
} | |
, hide: function() { | |
$(this.getDOMNode()).modal('hide') | |
} | |
, show: function() { | |
$(this.getDOMNode()).modal('show') | |
} | |
, toggle: function() { | |
$(this.getDOMNode()).modal('toggle') | |
} | |
, renderCloseButton: function() { | |
return <button | |
type="button" | |
className="close" | |
onClick={this.hide} | |
dangerouslySetInnerHTML={{__html: '×'}} | |
/> | |
} | |
} | |
}() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** @jsx React.DOM */ | |
var ExampleModal = React.createClass({ | |
mixins: [BootstrapModalMixin] | |
, render: function() { | |
var buttons = this.props.buttons.map(function(button) { | |
return <button type="button" className={'btn btn-' + button.type} onClick={button.handler}> | |
{button.text} | |
</button> | |
}) | |
return <div className="modal fade"> | |
<div className="modal-dialog"> | |
<div className="modal-content"> | |
<div className="modal-header"> | |
{this.renderCloseButton()} | |
<strong>{this.props.header}</strong> | |
</div> | |
<div className="modal-body"> | |
{this.props.children} | |
</div> | |
<div className="modal-footer"> | |
{buttons} | |
</div> | |
</div> | |
</div> | |
</div> | |
} | |
}) | |
var ExampleApp = React.createClass({ | |
getInitialState: function() { | |
return { | |
logs: [] | |
} | |
} | |
, render: function() { | |
var buttons = [ | |
{type: 'danger', text: 'Hide Modal', handler: this.handleExternalHide} | |
, {type: 'primary', text: 'Do Nothing', handler: this.handleDoingNothing} | |
] | |
var logs = this.state.logs.map(function(log) { | |
return <div className={'alert alert-' + log.type}> | |
[<strong>{log.time}</strong>] {log.message} | |
</div> | |
}) | |
return <div className="panel panel-default"> | |
<div className="panel-heading"> | |
<h3 className="panel-title">Demo</h3> | |
</div> | |
<div className="panel-body"> | |
<button type="button" className="btn btn-primary btn-lg btn-block" onClick={this.handleShowModal}>Show Modal</button> | |
<h3>Logs</h3> | |
{logs} | |
</div> | |
<ExampleModal ref="modal" | |
show={false} | |
header="Example Modal" | |
buttons={buttons} | |
handleShow={this.handleLog.bind(this, 'Modal about to show', 'info')} | |
handleShown={this.handleLog.bind(this, 'Modal showing', 'success')} | |
handleHide={this.handleLog.bind(this, 'Modal about to hide', 'warning')} | |
handleHidden={this.handleLog.bind(this, 'Modal hidden', 'danger')} | |
> | |
<p>I'm the content.</p> | |
<p>That's about it, really.</p> | |
</ExampleModal> | |
</div> | |
} | |
, handleShowModal: function() { | |
this.refs.modal.show() | |
} | |
, handleExternalHide: function() { | |
this.refs.modal.hide() | |
} | |
, handleDoingNothing: function() { | |
this.handleLog("Remember I said I'd do nothing? ...I lied!", 'danger') | |
} | |
, handleLog: function(message, type) { | |
this.setState({ | |
logs: [{ type: type | |
, time: new Date().toLocaleTimeString() | |
, message: message}].concat(this.state.logs.slice(0, 3)) | |
}) | |
} | |
}) | |
React.renderComponent(<ExampleApp/>, document.getElementById('example')) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>BootstrapModalMixin for React components</title> | |
<script src="http://fb.me/react-0.8.0.js"></script> | |
<script src="http://fb.me/JSXTransformer-0.8.0.js"></script> | |
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script> | |
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/js/bootstrap.min.js"></script> | |
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css"> | |
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap-theme.min.css"> | |
</head> | |
<body> | |
<div class="container"> | |
<div class="page-header"> | |
<h1>BootstrapModalMixin for <a href="http://facebook.github.io/react/">React components</a></h1> | |
<p>A <a href="http://facebook.github.io/react/docs/reusable-components.html">mixin for components</a> which act as <a href="http://getbootstrap.com/javascript/#modals">Bootstrap modals</a>, providing:</p> | |
<ul> | |
<li>Registration of the component as a modal at the appropriate point in the component lifecycle | |
<ul> | |
<li>Components are responsible for providing full modal contents in their own <code>render</code> method</lI> | |
</ul> | |
</li> | |
<li>Properties for modal configuration, with default values as per Bootstrap's defaults | |
<ul> | |
<li><code>backdrop</code></li> | |
<li><code>keyboard</code></li> | |
<li><code>show</code></li> | |
<li><code>remote</code></li> | |
</ul> | |
</li> | |
<li>Registration and removal of event handlers with React-style naming conventions when any of the following properties are part of the modal component's prototype or are passed in as component props (in that order) | |
<ul> | |
<li><code>handleShow</code></li> | |
<li><code>handleShown</code></li> | |
<li><code>handleHide</code></li> | |
<li><code>handleHidden</code></li> | |
</ul> | |
</li> | |
<li>A convenience method for rendering a <span style="font-size: 21px">×</span> close button: <code>renderCloseButton()</code></li> | |
</ul> | |
</div> | |
<div id="example"></div> | |
<div class="panel panel-default"> | |
<div class="panel-heading"> | |
<h3 class="panel-title">Code</h3> | |
</div> | |
<div class="panel-body"> | |
<script src="https://gist.github.com/insin/8449696.js"></script> | |
</div> | |
</div> | |
</div> | |
<script type="text/jsx" src="BootstrapModalMixin.js"></script> | |
<script type="text/jsx" src="example.js"></script> | |
<a href="https://gist.github.com/insin/8449696"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on GitHub"></a> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for this helpful gist, Jonny! One question though: Wouldn't it be a cleaner approach to get totally rid of the Bootstrap specific jQuery bindings for showing/hiding the component and replace it with some react style (un)mounting and transitions based on component state values (maybe also routing state...)? I'm just starting with react, so this just came to my mind when trying to think the "react way"...