diff --git a/lib/components/Modal.js b/lib/components/Modal.js index 36252c1e..e74b19e4 100644 --- a/lib/components/Modal.js +++ b/lib/components/Modal.js @@ -3,6 +3,7 @@ var ReactDOM = require('react-dom'); var ExecutionEnvironment = require('exenv'); var ModalPortal = React.createFactory(require('./ModalPortal')); var ariaAppHider = require('../helpers/ariaAppHider'); +var refCount = require('../helpers/refCount'); var elementClass = require('element-class'); var renderSubtreeIntoContainer = require("react-dom").unstable_renderSubtreeIntoContainer; var Assign = require('lodash.assign'); @@ -61,12 +62,16 @@ var Modal = React.createClass({ this.node = document.createElement('div'); this.node.className = this.props.portalClassName; + if (this.props.isOpen) refCount.add(this); + var parent = getParentElement(this.props.parentSelector); parent.appendChild(this.node); this.renderPortal(this.props); }, componentWillReceiveProps: function(newProps) { + if (newProps.isOpen) refCount.add(this); + if (!newProps.isOpen) refCount.remove(this); var currentParent = getParentElement(this.props.parentSelector); var newParent = getParentElement(newProps.parentSelector); @@ -79,6 +84,8 @@ var Modal = React.createClass({ }, componentWillUnmount: function() { + refCount.remove(this); + if (this.props.ariaHideApp) { ariaAppHider.show(this.props.appElement); } @@ -105,11 +112,13 @@ var Modal = React.createClass({ ReactDOM.unmountComponentAtNode(this.node); var parent = getParentElement(this.props.parentSelector); parent.removeChild(this.node); - elementClass(document.body).remove('ReactModal__Body--open'); + if (refCount.count() === 0) { + elementClass(document.body).remove('ReactModal__Body--open'); + } }, renderPortal: function(props) { - if (props.isOpen) { + if (props.isOpen || refCount.count() > 0) { elementClass(document.body).add('ReactModal__Body--open'); } else { elementClass(document.body).remove('ReactModal__Body--open'); diff --git a/lib/helpers/refCount.js b/lib/helpers/refCount.js new file mode 100644 index 00000000..8bcfdd49 --- /dev/null +++ b/lib/helpers/refCount.js @@ -0,0 +1,19 @@ +const modals = []; + +export function add (element) { + if (modals.indexOf(element) === -1) { + modals.push(element); + } +} + +export function remove (element) { + const index = modals.indexOf(element); + if (index === -1) { + return; + } + modals.splice(index, 1); +} + +export function count () { + return modals.length; +} diff --git a/specs/Modal.spec.js b/specs/Modal.spec.js index 0fb47fc3..65e80c22 100644 --- a/specs/Modal.spec.js +++ b/specs/Modal.spec.js @@ -98,11 +98,15 @@ describe('Modal', () => { }); }); - it('give back focus to previous element or modal.', function (done) { - var modal = renderModal({ + it('give back focus to previous element or modal.', (done) => { + function cleanup () { + unmountModal(); + done(); + } + const modal = renderModal({ isOpen: true, - onRequestClose: function () { - done(); + onRequestClose () { + cleanup(); } }, null); @@ -215,6 +219,17 @@ describe('Modal', () => { Modal.defaultStyles.content.position = previousStyle; }); + it('should remove class from body when no modals opened', () => { + const findReactModalOpenClass = () => document.body.className.indexOf('ReactModal__Body--open'); + renderModal({ isOpen: true }); + renderModal({ isOpen: true }); + expect(findReactModalOpenClass() > -1).toBe(true); + unmountModal(); + expect(findReactModalOpenClass() > -1).toBe(true); + unmountModal(); + expect(findReactModalOpenClass() === -1).toBe(true); + }); + it('adds class to body when open', function() { renderModal({ isOpen: false }); expect(document.body.className.indexOf('ReactModal__Body--open') !== -1).toEqual(false);