Skip to content

Commit

Permalink
Merge pull request reactjs#128 from dorsha/master
Browse files Browse the repository at this point in the history
[added] The ability to decide whether the modal should be closed when clicking the overlay area
  • Loading branch information
claydiffrient committed Mar 26, 2016
2 parents 93c73f3 + 6282c3e commit e8749dd
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 8 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,22 @@ var App = React.createClass({
ReactDOM.render(<App/>, appElement);
```

By default the modal is closed when clicking outside of it (the overlay area). If you want to prevent this behavior you can
pass the 'shouldCloseOnOverlayClick' prop with 'false' value.
```xml
<Modal
isOpen={bool}
onRequestClose={fn}
closeTimeoutMS={n}
shouldCloseOnOverlayClick={false}
style={customStyle}>

<h1>Force Modal</h1>
<p>Modal cannot be closed when clickig the overlay area</p>
<button onClick={handleCloseFunc}>Close Modal...</button>
</Modal>
```

# Demos
* http://reactjs.github.io/react-modal/
* http://reactjs.github.io/react-modal/bootstrap
6 changes: 4 additions & 2 deletions lib/components/Modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,16 @@ var Modal = module.exports = React.createClass({
appElement: React.PropTypes.instanceOf(SafeHTMLElement),
onRequestClose: React.PropTypes.func,
closeTimeoutMS: React.PropTypes.number,
ariaHideApp: React.PropTypes.bool
ariaHideApp: React.PropTypes.bool,
shouldCloseOnOverlayClick: React.PropTypes.bool
},

getDefaultProps: function () {
return {
isOpen: false,
ariaHideApp: true,
closeTimeoutMS: 0
closeTimeoutMS: 0,
shouldCloseOnOverlayClick: true
};
},

Expand Down
10 changes: 6 additions & 4 deletions lib/components/ModalPortal.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,12 @@ var ModalPortal = module.exports = React.createClass({
},

handleOverlayClick: function() {
if (this.ownerHandlesClose())
this.requestClose();
else
this.focusContent();
if (this.props.shouldCloseOnOverlayClick) {
if (this.ownerHandlesClose())
this.requestClose();
else
this.focusContent();
}
},

requestClose: function() {
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"react-dom": "^0.14.0",
"reactify": "^1.1.1",
"rf-release": "0.4.0",
"sinon": "^1.17.3",
"uglify-js": "2.4.24",
"webpack": "^1.12.14",
"webpack-dev-server": "1.11.0"
Expand Down
55 changes: 53 additions & 2 deletions specs/Modal.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ var Modal = require('../lib/components/Modal');
var Simulate = TestUtils.Simulate;
var ariaAppHider = require('../lib/helpers/ariaAppHider');
var button = ReactDOM.button;
var sinon = require('sinon');

describe('Modal', function () {

Expand Down Expand Up @@ -74,6 +75,7 @@ describe('Modal', function () {
equal(props.isOpen, false);
equal(props.ariaHideApp, true);
equal(props.closeTimeoutMS, 0);
equal(props.shouldCloseOnOverlayClick, true);
ReactDOM.unmountComponentAtNode(node);
ariaAppHider.resetForTesting();
});
Expand Down Expand Up @@ -102,13 +104,13 @@ describe('Modal', function () {

it('supports custom className', function() {
var modal = renderModal({isOpen: true, className: 'myClass'});
equal(modal.portal.refs.content.className.contains('myClass'), true);
notEqual(modal.portal.refs.content.className.indexOf('myClass'), -1);
unmountModal();
});

it('supports overlayClassName', function () {
var modal = renderModal({isOpen: true, overlayClassName: 'myOverlayClass'});
equal(modal.portal.refs.overlay.className.contains('myOverlayClass'), true);
notEqual(modal.portal.refs.overlay.className.indexOf('myOverlayClass'), -1);
unmountModal();
});

Expand Down Expand Up @@ -164,6 +166,55 @@ describe('Modal', function () {
unmountModal();
});

describe('should close on overlay click', function() {
afterEach('Unmount modal', function() {
unmountModal();
});

describe('verify props', function() {
it('verify default prop of shouldCloseOnOverlayClick', function () {
var modal = renderModal({isOpen: true});
equal(modal.props.shouldCloseOnOverlayClick, true);
});

it('verify prop of shouldCloseOnOverlayClick', function () {
var modal = renderModal({isOpen: true, shouldCloseOnOverlayClick: false});
equal(modal.props.shouldCloseOnOverlayClick, false);
});
});

describe('verify clicks', function() {
it('verify overlay click when shouldCloseOnOverlayClick sets to false', function () {
var requestCloseCallback = sinon.spy();
var modal = renderModal({
isOpen: true,
shouldCloseOnOverlayClick: false
});
equal(modal.props.isOpen, true);
var overlay = TestUtils.scryRenderedDOMComponentsWithClass(modal.portal, 'ReactModal__Overlay');
equal(overlay.length, 1);
Simulate.click(overlay[0]); // click the overlay
ok(!requestCloseCallback.called)
});

it('verify overlay click when shouldCloseOnOverlayClick sets to true', function() {
var requestCloseCallback = sinon.spy();
var modal = renderModal({
isOpen: true,
shouldCloseOnOverlayClick: true,
onRequestClose: function() {
requestCloseCallback();
}
});
equal(modal.props.isOpen, true);
var overlay = TestUtils.scryRenderedDOMComponentsWithClass(modal.portal, 'ReactModal__Overlay');
equal(overlay.length, 1);
Simulate.click(overlay[0]); // click the overlay
ok(requestCloseCallback.called)
});
});
});

//it('adds --before-close for animations', function() {
//var node = document.createElement('div');

Expand Down
1 change: 1 addition & 0 deletions specs/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ var Modal = React.createFactory(require('../lib/components/Modal'));

ok = assert.ok;
equal = assert.equal;
notEqual = assert.notEqual;
strictEqual = assert.strictEqual;
throws = assert.throws;

Expand Down

0 comments on commit e8749dd

Please sign in to comment.