Update react-modal and establish canvas modal style
fixes PLAT-771 Change-Id: Ia7ea6ca7002f1c1926f845d74af3544337c96def Reviewed-on: https://gerrit.instructure.com/44584 Tested-by: Jenkins <jenkins@instructure.com> Product-Review: Colleen Palmer <colleen@instructure.com> Reviewed-by: Colleen Palmer <colleen@instructure.com> QA-Review: Eric Berry <ericb@instructure.com>
This commit is contained in:
parent
e3a8ea8445
commit
3235a5b020
|
@ -1,15 +1,17 @@
|
|||
require [
|
||||
'jquery'
|
||||
'underscore'
|
||||
'react'
|
||||
'compiled/fn/preventDefault'
|
||||
'compiled/views/PublishButtonView'
|
||||
'compiled/views/PublishIconView'
|
||||
'jsx/styleguide/ReactModalExample'
|
||||
'jqueryui/accordion'
|
||||
'jqueryui/tabs'
|
||||
'jqueryui/button'
|
||||
'jqueryui/tooltip'
|
||||
'jquery.instructure_date_and_time'
|
||||
], ($, _, preventDefault, PublishButtonView, PublishIconView) ->
|
||||
], ($, _, React, preventDefault, PublishButtonView, PublishIconView, ReactModalExample) ->
|
||||
|
||||
do ->
|
||||
dialog = $('#dialog-buttons-dialog').dialog({
|
||||
|
@ -19,6 +21,22 @@ require [
|
|||
$('#show-dialog-buttons-dialog').click -> dialog.open()
|
||||
|
||||
|
||||
# React Modal
|
||||
React.renderComponent(
|
||||
ReactModalExample
|
||||
className: 'ReactModal__Content--canvas'
|
||||
overlayClassName: 'ReactModal__Overlay--canvas'
|
||||
, document.getElementById('react-modal-example')
|
||||
);
|
||||
|
||||
React.renderComponent(
|
||||
ReactModalExample
|
||||
label: 'Trigger Confirm Dialog'
|
||||
className: 'ReactModal__Content--canvas ReactModal__Content--mini-modal'
|
||||
overlayClassName: 'ReactModal__Overlay--canvas'
|
||||
, document.getElementById('react-modal-confirm-example')
|
||||
)
|
||||
|
||||
## OLD STYLEGUIDE ##
|
||||
|
||||
iconEventsMap =
|
||||
|
|
|
@ -181,7 +181,7 @@ define [
|
|||
@setState(newState)
|
||||
|
||||
render: withReactDOM ->
|
||||
ReactModal {isOpen: true, onRequestClose: @closeModal, closeTimeoutMS: 10},
|
||||
ReactModal {isOpen: true, onRequestClose: @closeModal, className: 'ReactModal__Content--ef-file-preview', overlayClassName: 'ReactModal__Overlay--ef-file-preview', closeTimeoutMS: 10},
|
||||
div {className: 'ef-file-preview-overlay'},
|
||||
div {className: 'ef-file-preview-header'},
|
||||
h1 {className: 'ef-file-preview-header-filename'},
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
/** React.DOM */
|
||||
|
||||
define([
|
||||
'React',
|
||||
'react-modal'
|
||||
], function(React, Modal) {
|
||||
|
||||
Modal.injectCSS();
|
||||
|
||||
var ReactModalExample = React.createClass({
|
||||
|
||||
getInitialState () {
|
||||
return {
|
||||
modalIsOpen: false
|
||||
}
|
||||
},
|
||||
|
||||
openModal (e) {
|
||||
e.preventDefault();
|
||||
this.setState({ modalIsOpen: true });
|
||||
},
|
||||
|
||||
closeModal () {
|
||||
this.setState({ modalIsOpen: false });
|
||||
},
|
||||
|
||||
handleSubmit () {
|
||||
alert('Submitted');
|
||||
},
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div className="ModalExample">
|
||||
<a href="#" role="button" aria-label="Trigger Modal" className="btn btn-primary" onClick={this.openModal}>Trigger Modal</a>
|
||||
<Modal isOpen={this.state.modalIsOpen} onRequestClose={this.closeModal}>
|
||||
|
||||
<div className="ReactModal__Layout">
|
||||
|
||||
<div className="ReactModal__InnerSection ReactModal__Header">
|
||||
<div className="ReactModal__Header-Title">
|
||||
<h4>Are you ready to submit?</h4>
|
||||
</div>
|
||||
<div className="ReactModal__Header-Actions">
|
||||
<button className="Button Button--link Button--small" type="button" onClick={this.closeModal}>
|
||||
<i className="icon-x"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="ReactModal__InnerSection ReactModal__Body">
|
||||
This will be awesome.
|
||||
</div>
|
||||
|
||||
<div className="ReactModal__InnerSection ReactModal__Footer">
|
||||
<div className="ReactModal__Footer-Actions">
|
||||
<button type="button" className="Button" onClick={this.closeModal}>Cancel</button>
|
||||
<button type="button" className="Button Button--primary" onClick={this.handleSubmit}>Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
React.renderComponent(<ReactModalExample/>, document.getElementById('content'));
|
||||
});
|
|
@ -0,0 +1,78 @@
|
|||
/** @jsx React.DOM */
|
||||
|
||||
define([
|
||||
'react',
|
||||
'react-modal'
|
||||
], function (React, Modal) {
|
||||
|
||||
var ReactModalExample = React.createClass({
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
modalIsOpen: false
|
||||
}
|
||||
},
|
||||
|
||||
openModal(e) {
|
||||
e.preventDefault();
|
||||
this.setState({modalIsOpen: true});
|
||||
},
|
||||
|
||||
closeModal(e) {
|
||||
e.preventDefault();
|
||||
this.setState({modalIsOpen: false});
|
||||
},
|
||||
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
this.setState({modalIsOpen: false});
|
||||
alert('Submitted');
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="ReactModalExample">
|
||||
<a href="#" role="button" aria-label="Trigger Modal" className="btn btn-primary" onClick={this.openModal}>{this.props.label || 'Trigger Modal'}</a>
|
||||
<Modal isOpen={this.state.modalIsOpen}
|
||||
onRequestClose={this.closeModal}
|
||||
className={this.props.className}
|
||||
overlayClassName={this.props.overlayClassName}>
|
||||
|
||||
<div className="ReactModal__Layout">
|
||||
|
||||
<div className="ReactModal__InnerSection ReactModal__Header">
|
||||
<div className="ReactModal__Header-Title">
|
||||
<h4>Modal Title Goes Here</h4>
|
||||
</div>
|
||||
<div className="ReactModal__Header-Actions">
|
||||
<button className="Button Button--link Button--small" type="button" onClick={this.closeModal}>
|
||||
<i className="icon-x"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="ReactModal__InnerSection ReactModal__Body">
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusamus deserunt doloremque, explicabo illo
|
||||
ipsum libero magni odio officia optio perferendis ratione repellat suscipit tempore. Commodi hic sed.
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusamus deserunt doloremque, explicabo illo
|
||||
ipsum libero magni odio officia optio perferendis ratione repellat suscipit tempore. Commodi hic sed.
|
||||
</div>
|
||||
|
||||
<div className="ReactModal__InnerSection ReactModal__Footer">
|
||||
<div className="ReactModal__Footer-Actions">
|
||||
<button type="button" className="btn btn-default" onClick={this.closeModal}>Cancel</button>
|
||||
<button type="button" className="btn btn-primary" onClick={this.handleSubmit}>Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return ReactModalExample;
|
||||
});
|
|
@ -18,6 +18,7 @@
|
|||
@import "inst_tree";
|
||||
@import "misc";
|
||||
@import "new-and-total-badge";
|
||||
@import "react_modal";
|
||||
@import "show_hide_opacity";
|
||||
@import "spacing";
|
||||
@import "alignment";
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
/* @styleguide Modal Dialog - React (new!)
|
||||
|
||||
### Default Canvas modal
|
||||
|
||||
React Modal comes with very few default classes to make it as themeable as possible. If you want plain-vanilla Canvas modal styles, be sure to specify `className: 'ReactModal__Content--canvas'` when you initialize the modal, as follows:
|
||||
|
||||
```javascript
|
||||
React.renderComponent(
|
||||
ReactModalExample(
|
||||
{ className: 'ReactModal__Content--canvas'
|
||||
overlayClassName: 'ReactModal__Overlay--canvas' }
|
||||
), document.getElementById('react-modal-example')
|
||||
);
|
||||
```
|
||||
|
||||
```html
|
||||
<p>
|
||||
<div id="react-modal-example"></div>
|
||||
</p>
|
||||
```
|
||||
|
||||
See `app/jsx/styleguide/ReactModalExample.jsx` for complete example usage.
|
||||
|
||||
<br />
|
||||
### Mini Canvas modal
|
||||
|
||||
For small dialogs like Confirms, the default Canvas modal width might seem too much. The **.ReactModal__Content--mini-modal** class can be appended to the **.ReactModal__Content--canvas** class to render a less wide modal dialog.
|
||||
|
||||
```javascript
|
||||
React.renderComponent(
|
||||
ReactModalExample(
|
||||
{ label: 'Trigger Confirm Dialog',
|
||||
className: 'ReactModal__Content--canvas ReactModal__Content--mini-modal',
|
||||
overlayClassName: 'ReactModal__Overlay--canvas' }
|
||||
), document.getElementById('react-modal-confirm-example')
|
||||
);
|
||||
```
|
||||
|
||||
```html
|
||||
<p>
|
||||
<div id="react-modal-confirm-example"></div>
|
||||
</p>
|
||||
```
|
||||
|
||||
See `app/jsx/examples/ReactModalExample.jsx` for complete example usage.
|
||||
|
||||
*/
|
||||
|
||||
// Global styles for any React modal.
|
||||
// Do not change these or your name will be cursed for generations.
|
||||
.ReactModal__Overlay {
|
||||
transition: opacity 0.2s ease-out;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
background: rgba($canvas-secondary, 0.75);
|
||||
z-index: 150;
|
||||
opacity: 0;
|
||||
|
||||
&.ReactModal__Overlay--after-open {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@mixin ReactModalPadding {
|
||||
padding: 6px;
|
||||
@include breakpoint(tablet) { padding: 12px; }
|
||||
@include breakpoint(desktop) { padding: 16px; }
|
||||
}
|
||||
|
||||
.ReactModal__Content {
|
||||
|
||||
// To accomodate different kinds of modals, styles for
|
||||
// the regular Canvas modal have been scoped under the
|
||||
// .ReactModal__Content--canvas class. So if you want a
|
||||
// normal modal, remember to add className='ReactModal__Content--canvas'
|
||||
// when you initialize the modal in your JSX.
|
||||
// This className will append itself to the .ReactModal__Content
|
||||
// element, and you will get all the nice styles below.
|
||||
|
||||
&.ReactModal__Content--canvas {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
padding: 6px;
|
||||
@include breakpoint(mini-tablet) { padding: 12px; }
|
||||
@include breakpoint(tablet) { padding: 0; }
|
||||
|
||||
.ReactModal__Layout {
|
||||
border-radius: $baseBorderRadius;
|
||||
box-shadow: 0 1px 4px 1px rgba($canvas-secondary, 0.95);
|
||||
|
||||
@include breakpoint(tablet) {
|
||||
max-width: 696px;
|
||||
transition: all 0.5s cubic-bezier(0,1,0.5,1);
|
||||
opacity: 0;
|
||||
transform: rotateX(60deg) scale(0.8);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&.ReactModal__Content--after-open .ReactModal__Layout {
|
||||
@include breakpoint(tablet) {
|
||||
opacity: 1;
|
||||
transform: rotateX(0) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
&.ReactModal__Content--mini-modal {
|
||||
.ReactModal__Layout {
|
||||
@include breakpoint(tablet) { max-width: 384px; }
|
||||
}
|
||||
}
|
||||
|
||||
// ReactModal__InnerSection class exists so that even if
|
||||
// a modal has no header or footer, it still gets nice
|
||||
// rounded corners
|
||||
.ReactModal__InnerSection {
|
||||
&:first-of-type { border-top-left-radius: $baseBorderRadius; border-top-right-radius: $baseBorderRadius; }
|
||||
&:last-of-type { border-bottom-left-radius: $baseBorderRadius; border-bottom-right-radius: $baseBorderRadius; }
|
||||
}
|
||||
|
||||
.ReactModal__Header {
|
||||
@include ReactModalPadding;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: $canvas-light;
|
||||
border-bottom: 1px solid $can-border-light;
|
||||
}
|
||||
|
||||
.ReactModal__Header-Title {
|
||||
flex: 1;
|
||||
// remove margin from heading elements
|
||||
* { margin: 0; }
|
||||
}
|
||||
|
||||
.ReactModal__Header-Actions { text-align: right; }
|
||||
|
||||
.ReactModal__Body {
|
||||
padding: 6px;
|
||||
background: $canvas-light;
|
||||
@include breakpoint(tablet) { padding: 16px; }
|
||||
@include breakpoint(desktop) { padding: 24px; }
|
||||
}
|
||||
|
||||
.ReactModal__Footer {
|
||||
@include ReactModalPadding;
|
||||
background: lighten($canvas-neutral, 5%);
|
||||
border-top: 1px solid $can-border-light;
|
||||
|
||||
@include breakpoint(mini-tablet) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.ReactModal__Footer-Actions {
|
||||
@include breakpoint(mini-tablet) {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.Button, .btn {
|
||||
margin-left: 4px;
|
||||
&:first-of-type { margin-left: 0; }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -9,15 +9,11 @@ $spacing-width: 0;
|
|||
$preview-footer-height: 140px;
|
||||
$preview-header-height: 70px;
|
||||
|
||||
// Make sure that ReactModal gets above everything else
|
||||
.ReactModal__Overlay {
|
||||
z-index: 100;
|
||||
&.ReactModal__Overlay--after-open {
|
||||
background-color: rgba($preview-bg, 0.9);
|
||||
}
|
||||
.ReactModal__Overlay.ReactModal__Overlay--ef-file-preview {
|
||||
background: rgba(black, 0.9);
|
||||
}
|
||||
|
||||
.ReactModal__Content {
|
||||
.ReactModal__Content.ReactModal__Content--ef-file-preview {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,6 @@
|
|||
"ic-sortable": "0.0.2",
|
||||
"react": "0.11.0",
|
||||
"react-router": "0.9.3",
|
||||
"react-modal": "~0.0.2"
|
||||
"react-modal": "0.0.6"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "react-modal",
|
||||
"version": "0.0.2",
|
||||
"version": "0.0.6",
|
||||
"homepage": "https://github.com/rackt/react-modal",
|
||||
"authors": [
|
||||
"Ryan Florence",
|
||||
|
@ -26,14 +26,13 @@
|
|||
"karma.conf.js",
|
||||
"package.json"
|
||||
],
|
||||
"_release": "0.0.2",
|
||||
"_release": "0.0.6",
|
||||
"_resolution": {
|
||||
"type": "version",
|
||||
"tag": "v0.0.2",
|
||||
"commit": "26012856a5100ab55c6fc8e49c199a7cfecdf9ff"
|
||||
"tag": "v0.0.6",
|
||||
"commit": "734acb5b309780b10bc6bd4fb850dd214e5fd948"
|
||||
},
|
||||
"_source": "git://github.com/rackt/react-modal.git",
|
||||
"_target": "~0.0.2",
|
||||
"_originalSource": "react-modal",
|
||||
"_direct": true
|
||||
"_target": "0.0.6",
|
||||
"_originalSource": "react-modal"
|
||||
}
|
|
@ -1,3 +1,29 @@
|
|||
v0.0.6 - Wed, 03 Dec 2014 21:24:45 GMT
|
||||
--------------------------------------
|
||||
|
||||
- [28dbc63](../../commit/28dbc63) [added] Supporting custom overlay className closes #14
|
||||
- [6626dae](../../commit/6626dae) [fixed] erroneous alias in webpack build
|
||||
|
||||
|
||||
v0.0.5 - Thu, 13 Nov 2014 18:55:47 GMT
|
||||
--------------------------------------
|
||||
|
||||
- [b15aa82](../../commit/b15aa82) [added] Supporting custom className
|
||||
- [b7a38de](../../commit/b7a38de) [fixed] Warning caused by trying to focus null element closes #11
|
||||
|
||||
|
||||
v0.0.4 - Tue, 11 Nov 2014 16:08:14 GMT
|
||||
--------------------------------------
|
||||
|
||||
- [e57bab5](../../commit/e57bab5) [fixed] Issue with focus being lost - closes #9
|
||||
|
||||
|
||||
v0.0.3 - Fri, 31 Oct 2014 19:25:20 GMT
|
||||
--------------------------------------
|
||||
|
||||
-
|
||||
|
||||
|
||||
v0.0.2 - Thu, 25 Sep 2014 02:36:47 GMT
|
||||
--------------------------------------
|
||||
|
||||
|
|
|
@ -1,28 +1,29 @@
|
|||
React Modal
|
||||
===========
|
||||
|
||||
Accessible React Modal Dialog Component
|
||||
Accessible React Modal Dialog Component. This isn't ready to be used
|
||||
yet, still under development.
|
||||
|
||||
Accessibility Notes
|
||||
-------------------
|
||||
|
||||
Etc. etc. etc.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
```xml
|
||||
<Modal
|
||||
isOpen={this.state.modalIsOpen}
|
||||
onRequestClose={this.handleModalCloseRequest}
|
||||
closeTimeoutMS={150}
|
||||
isOpen={bool}
|
||||
onRequestClose={fn}
|
||||
closeTimeoutMS={n}
|
||||
>
|
||||
<h1>Modal Content</h1>
|
||||
<p>Etc.</p>
|
||||
</Modal>
|
||||
```
|
||||
|
||||
Accessibility Notes
|
||||
-------------------
|
||||
|
||||
|
||||
|
||||
Inside the app:
|
||||
Inside an app:
|
||||
|
||||
```js
|
||||
/** @jsx React.DOM */
|
||||
|
@ -49,35 +50,23 @@ var App = React.createClass({
|
|||
this.setState({modalIsOpen: false});
|
||||
},
|
||||
|
||||
handleModalCloseRequest: function() {
|
||||
// opportunity to validate something and keep the modal open even if it
|
||||
// requested to be closed
|
||||
this.setState({modalIsOpen: false});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<button onClick={this.openModal}>Open Modal</button>
|
||||
<Modal
|
||||
closeTimeoutMS={150}
|
||||
isOpen={this.state.modalIsOpen}
|
||||
onRequestClose={this.handleModalCloseRequest}
|
||||
onRequestClose={this.closeModal}
|
||||
>
|
||||
<h1>Hello</h1>
|
||||
<h2>Hello</h2>
|
||||
<button onClick={this.closeModal}>close</button>
|
||||
<div>I am a modal</div>
|
||||
<form>
|
||||
<input />
|
||||
<input />
|
||||
<input />
|
||||
<input />
|
||||
<input />
|
||||
<br/>
|
||||
<button>hi</button>
|
||||
<button>hi</button>
|
||||
<button>hi</button>
|
||||
<button>hi</button>
|
||||
<button>tab navigation</button>
|
||||
<button>stays</button>
|
||||
<button>inside</button>
|
||||
<button>the modal</button>
|
||||
</form>
|
||||
</Modal>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "react-modal",
|
||||
"version": "0.0.2",
|
||||
"version": "0.0.6",
|
||||
"homepage": "https://github.com/rackt/react-modal",
|
||||
"authors": [
|
||||
"Ryan Florence",
|
||||
|
|
|
@ -51,7 +51,10 @@ var Modal = module.exports = React.createClass({
|
|||
ariaAppHider.toggle(props.isOpen, props.appElement);
|
||||
}
|
||||
sanitizeProps(props);
|
||||
this.portal = React.renderComponent(ModalPortal(props), this.node);
|
||||
if (this.portal)
|
||||
this.portal.setProps(props);
|
||||
else
|
||||
this.portal = React.renderComponent(ModalPortal(props), this.node);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
|
@ -63,12 +66,12 @@ function sanitizeProps(props) {
|
|||
delete props.ref;
|
||||
}
|
||||
|
||||
|
||||
},{"../helpers/ariaAppHider":3,"../helpers/injectCSS":5,"./ModalPortal":2}],2:[function(_dereq_,module,exports){
|
||||
var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null);
|
||||
var div = React.DOM.div;
|
||||
var focusManager = _dereq_('../helpers/focusManager');
|
||||
var scopeTab = _dereq_('../helpers/scopeTab');
|
||||
var cx = _dereq_('react/lib/cx');
|
||||
|
||||
// so that our CSS is statically analyzable
|
||||
var CLASS_NAMES = {
|
||||
|
@ -100,19 +103,34 @@ var ModalPortal = module.exports = React.createClass({
|
|||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.handleProps(this.props);
|
||||
this.maybeFocus();
|
||||
// Focus needs to be set when mounting and already open
|
||||
if (this.props.isOpen) {
|
||||
this.setFocusAfterRender(true);
|
||||
this.open();
|
||||
}
|
||||
},
|
||||
|
||||
componentWillReceiveProps: function(newProps) {
|
||||
this.handleProps(newProps);
|
||||
// Focus only needs to be set once when the modal is being opened
|
||||
if (!this.props.isOpen && newProps.isOpen) {
|
||||
this.setFocusAfterRender(true);
|
||||
}
|
||||
|
||||
if (newProps.isOpen === true)
|
||||
this.open();
|
||||
else if (newProps.isOpen === false)
|
||||
this.close();
|
||||
},
|
||||
|
||||
handleProps: function(props) {
|
||||
if (props.isOpen === true)
|
||||
this.open();
|
||||
else if (props.isOpen === false)
|
||||
this.close();
|
||||
componentDidUpdate: function () {
|
||||
if (this.focusAfterRender) {
|
||||
this.focusContent();
|
||||
this.setFocusAfterRender(false);
|
||||
}
|
||||
},
|
||||
|
||||
setFocusAfterRender: function (focus) {
|
||||
this.focusAfterRender = focus;
|
||||
},
|
||||
|
||||
open: function() {
|
||||
|
@ -132,15 +150,6 @@ var ModalPortal = module.exports = React.createClass({
|
|||
this.closeWithoutTimeout();
|
||||
},
|
||||
|
||||
componentDidUpdate: function() {
|
||||
this.maybeFocus();
|
||||
},
|
||||
|
||||
maybeFocus: function() {
|
||||
if (this.props.isOpen)
|
||||
this.focusContent();
|
||||
},
|
||||
|
||||
focusContent: function() {
|
||||
this.refs.content.getDOMNode().focus();
|
||||
},
|
||||
|
@ -176,7 +185,7 @@ var ModalPortal = module.exports = React.createClass({
|
|||
},
|
||||
|
||||
requestClose: function() {
|
||||
if (this.ownerHandlesClose)
|
||||
if (this.ownerHandlesClose())
|
||||
this.props.onRequestClose();
|
||||
},
|
||||
|
||||
|
@ -202,13 +211,14 @@ var ModalPortal = module.exports = React.createClass({
|
|||
render: function() {
|
||||
return this.shouldBeClosed() ? div() : (
|
||||
div({
|
||||
className: this.buildClassName('overlay'),
|
||||
ref: "overlay",
|
||||
className: cx(this.buildClassName('overlay'), this.props.overlayClassName),
|
||||
style: this.overlayStyles,
|
||||
onClick: this.handleOverlayClick
|
||||
},
|
||||
div({
|
||||
ref: "content",
|
||||
className: this.buildClassName('content'),
|
||||
className: cx(this.buildClassName('content'), this.props.className),
|
||||
tabIndex: "-1",
|
||||
onClick: stopPropagation,
|
||||
onKeyDown: this.handleKeyDown
|
||||
|
@ -220,8 +230,7 @@ var ModalPortal = module.exports = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
},{"../helpers/focusManager":4,"../helpers/scopeTab":6}],3:[function(_dereq_,module,exports){
|
||||
},{"../helpers/focusManager":4,"../helpers/scopeTab":6,"react/lib/cx":9}],3:[function(_dereq_,module,exports){
|
||||
var _element = null;
|
||||
|
||||
function setElement(element) {
|
||||
|
@ -432,6 +441,45 @@ module.exports = findTabbableDescendants;
|
|||
module.exports = _dereq_('./components/Modal');
|
||||
|
||||
|
||||
},{"./components/Modal":1}]},{},[8])
|
||||
},{"./components/Modal":1}],9:[function(_dereq_,module,exports){
|
||||
/**
|
||||
* Copyright 2013-2014, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule cx
|
||||
*/
|
||||
|
||||
/**
|
||||
* This function is used to mark string literals representing CSS class names
|
||||
* so that they can be transformed statically. This allows for modularization
|
||||
* and minification of CSS class names.
|
||||
*
|
||||
* In static_upstream, this function is actually implemented, but it should
|
||||
* eventually be replaced with something more descriptive, and the transform
|
||||
* that is used in the main stack should be ported for use elsewhere.
|
||||
*
|
||||
* @param string|object className to modularize, or an object of key/values.
|
||||
* In the object case, the values are conditions that
|
||||
* determine if the className keys should be included.
|
||||
* @param [string ...] Variable list of classNames in the string case.
|
||||
* @return string Renderable space-separated CSS className.
|
||||
*/
|
||||
function cx(classNames) {
|
||||
if (typeof classNames == 'object') {
|
||||
return Object.keys(classNames).filter(function(className) {
|
||||
return classNames[className];
|
||||
}).join(' ');
|
||||
} else {
|
||||
return Array.prototype.join.call(arguments, ' ');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = cx;
|
||||
|
||||
},{}]},{},[8])
|
||||
(8)
|
||||
});
|
File diff suppressed because one or more lines are too long
|
@ -50,7 +50,10 @@ var Modal = module.exports = React.createClass({
|
|||
ariaAppHider.toggle(props.isOpen, props.appElement);
|
||||
}
|
||||
sanitizeProps(props);
|
||||
this.portal = React.renderComponent(ModalPortal(props), this.node);
|
||||
if (this.portal)
|
||||
this.portal.setProps(props);
|
||||
else
|
||||
this.portal = React.renderComponent(ModalPortal(props), this.node);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
|
@ -61,4 +64,3 @@ var Modal = module.exports = React.createClass({
|
|||
function sanitizeProps(props) {
|
||||
delete props.ref;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ var React = require('react');
|
|||
var div = React.DOM.div;
|
||||
var focusManager = require('../helpers/focusManager');
|
||||
var scopeTab = require('../helpers/scopeTab');
|
||||
var cx = require('react/lib/cx');
|
||||
|
||||
// so that our CSS is statically analyzable
|
||||
var CLASS_NAMES = {
|
||||
|
@ -33,19 +34,34 @@ var ModalPortal = module.exports = React.createClass({
|
|||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.handleProps(this.props);
|
||||
this.maybeFocus();
|
||||
// Focus needs to be set when mounting and already open
|
||||
if (this.props.isOpen) {
|
||||
this.setFocusAfterRender(true);
|
||||
this.open();
|
||||
}
|
||||
},
|
||||
|
||||
componentWillReceiveProps: function(newProps) {
|
||||
this.handleProps(newProps);
|
||||
// Focus only needs to be set once when the modal is being opened
|
||||
if (!this.props.isOpen && newProps.isOpen) {
|
||||
this.setFocusAfterRender(true);
|
||||
}
|
||||
|
||||
if (newProps.isOpen === true)
|
||||
this.open();
|
||||
else if (newProps.isOpen === false)
|
||||
this.close();
|
||||
},
|
||||
|
||||
handleProps: function(props) {
|
||||
if (props.isOpen === true)
|
||||
this.open();
|
||||
else if (props.isOpen === false)
|
||||
this.close();
|
||||
componentDidUpdate: function () {
|
||||
if (this.focusAfterRender) {
|
||||
this.focusContent();
|
||||
this.setFocusAfterRender(false);
|
||||
}
|
||||
},
|
||||
|
||||
setFocusAfterRender: function (focus) {
|
||||
this.focusAfterRender = focus;
|
||||
},
|
||||
|
||||
open: function() {
|
||||
|
@ -65,15 +81,6 @@ var ModalPortal = module.exports = React.createClass({
|
|||
this.closeWithoutTimeout();
|
||||
},
|
||||
|
||||
componentDidUpdate: function() {
|
||||
this.maybeFocus();
|
||||
},
|
||||
|
||||
maybeFocus: function() {
|
||||
if (this.props.isOpen)
|
||||
this.focusContent();
|
||||
},
|
||||
|
||||
focusContent: function() {
|
||||
this.refs.content.getDOMNode().focus();
|
||||
},
|
||||
|
@ -97,8 +104,8 @@ var ModalPortal = module.exports = React.createClass({
|
|||
},
|
||||
|
||||
handleKeyDown: function(event) {
|
||||
if (event.key == 9 /*tab*/) scopeTab(this.getDOMNode(), event);
|
||||
if (event.key == 27 /*esc*/) this.requestClose();
|
||||
if (event.keyCode == 9 /*tab*/) scopeTab(this.getDOMNode(), event);
|
||||
if (event.keyCode == 27 /*esc*/) this.requestClose();
|
||||
},
|
||||
|
||||
handleOverlayClick: function() {
|
||||
|
@ -109,7 +116,7 @@ var ModalPortal = module.exports = React.createClass({
|
|||
},
|
||||
|
||||
requestClose: function() {
|
||||
if (this.ownerHandlesClose)
|
||||
if (this.ownerHandlesClose())
|
||||
this.props.onRequestClose();
|
||||
},
|
||||
|
||||
|
@ -135,13 +142,14 @@ var ModalPortal = module.exports = React.createClass({
|
|||
render: function() {
|
||||
return this.shouldBeClosed() ? div() : (
|
||||
div({
|
||||
className: this.buildClassName('overlay'),
|
||||
ref: "overlay",
|
||||
className: cx(this.buildClassName('overlay'), this.props.overlayClassName),
|
||||
style: this.overlayStyles,
|
||||
onClick: this.handleOverlayClick
|
||||
},
|
||||
div({
|
||||
ref: "content",
|
||||
className: this.buildClassName('content'),
|
||||
className: cx(this.buildClassName('content'), this.props.className),
|
||||
tabIndex: "-1",
|
||||
onClick: stopPropagation,
|
||||
onKeyDown: this.handleKeyDown
|
||||
|
@ -152,4 +160,3 @@ var ModalPortal = module.exports = React.createClass({
|
|||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/sh
|
||||
mkdir -p dist
|
||||
NODE_ENV=production node_modules/.bin/browserify lib/index.js \
|
||||
-t reactify \
|
||||
-t browserify-shim \
|
||||
-t envify \
|
||||
--detect-globals false \
|
||||
-s ReactModal > dist/react-modal.js
|
||||
node_modules/.bin/uglifyjs dist/react-modal.js \
|
||||
--compress warnings=false > dist/react-modal.min.js
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
node_modules/.bin/webpack-dev-server --inline --content-base examples/
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
#!/bin/sh
|
||||
node_modules/rf-release/node_modules/.bin/changelog -t preview -s
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
scripts/build
|
||||
node_modules/.bin/release
|
|
@ -0,0 +1,2 @@
|
|||
#!/bin/sh
|
||||
NODE_ENV=test node_modules/.bin/karma start "$@"
|
|
@ -0,0 +1,46 @@
|
|||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var webpack = require('webpack');
|
||||
|
||||
var EXAMPLES_DIR = path.resolve(__dirname, 'examples');
|
||||
|
||||
function isDirectory(dir) {
|
||||
return fs.lstatSync(dir).isDirectory();
|
||||
}
|
||||
|
||||
function buildEntries() {
|
||||
return fs.readdirSync(EXAMPLES_DIR).reduce(function (entries, dir) {
|
||||
if (dir === 'build')
|
||||
return entries;
|
||||
|
||||
var isDraft = dir.charAt(0) === '_';
|
||||
|
||||
if (!isDraft && isDirectory(path.join(EXAMPLES_DIR, dir)))
|
||||
entries[dir] = path.join(EXAMPLES_DIR, dir, 'app.js');
|
||||
|
||||
return entries;
|
||||
}, {});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
entry: buildEntries(),
|
||||
|
||||
output: {
|
||||
filename: '[name].js',
|
||||
chunkFilename: '[id].chunk.js',
|
||||
path: 'examples/__build__',
|
||||
publicPath: '/__build__/'
|
||||
},
|
||||
|
||||
module: {
|
||||
loaders: [
|
||||
{ test: /\.js$/, loader: 'jsx-loader?harmony' }
|
||||
]
|
||||
},
|
||||
|
||||
plugins: [
|
||||
new webpack.optimize.CommonsChunkPlugin('shared.js')
|
||||
]
|
||||
|
||||
};
|
Loading…
Reference in New Issue