From 4d2ff125229d3b7425bf7e2f11b50e4c9cab39af Mon Sep 17 00:00:00 2001 From: Bruno Dias Date: Tue, 6 Jun 2017 22:06:36 -0300 Subject: [PATCH] [feature] deprecate getParentElement in favor of a local element. This patch will give us the ability to place the modal in any place in the react tree. Each modal can handle its own clean up. Test case was written by @restrry [b9a34155](https://github.com/restrry/react-modal/commit/b9a34155bf37298e99922f77dec8e27292db06d9). --- README.md | 20 ++------------------ docs/README.md | 4 ---- specs/Modal.spec.js | 24 +++++++++++------------- src/components/Modal.js | 33 ++++++++++----------------------- 4 files changed, 23 insertions(+), 58 deletions(-) diff --git a/README.md b/README.md index a46dc668..aee3a2d4 100644 --- a/README.md +++ b/README.md @@ -171,24 +171,8 @@ object will apply to all instances of the modal. ### Appended to custom node -You can choose an element for the modal to be appended to, rather than using -body tag. To do this, provide a function to `parentSelector` prop that return -the element to be used. - -```jsx - -function getParent() { - return document.querySelector('#root'); -} - - -

Modal Content.

-
-``` +`parentSelector` is now deprecated. `` can be appended on any place +and it will correctly manage it's clean up. ### Body class diff --git a/docs/README.md b/docs/README.md index e05c0d2a..56ca3bfe 100644 --- a/docs/README.md +++ b/docs/README.md @@ -83,10 +83,6 @@ import ReactModal from 'react-modal'; String indicating the role of the modal, allowing the 'dialog' role to be applied if desired. */ role="dialog" - /* - Function that will be called to get the parent element that the modal will be attached to. - */ - parentSelector={() => document.body} /* Additional aria attributes (optional). */ diff --git a/specs/Modal.spec.js b/specs/Modal.spec.js index f9861b45..bb97c472 100644 --- a/specs/Modal.spec.js +++ b/specs/Modal.spec.js @@ -61,26 +61,24 @@ export default () => { ReactDOM.unmountComponentAtNode(node); }); - it('renders into the body, not in context', () => { - const node = document.createElement('div'); + it('renders in context, never in document.body', function() { + var node = document.createElement('div'); + var realRef = null; class App extends Component { render() { - return ( -
- - hello - + return ( +
{ realRef = ref; }}> + + hello +
- ); + ); } } Modal.setAppElement(node); ReactDOM.render(, node); - document.body.querySelector( - '.ReactModalPortal' - ).parentNode.should.be.eql( - document.body - ); + var modalParent = node.querySelector('.ReactModalPortal').parentNode; + expect(modalParent).toEqual(realRef); ReactDOM.unmountComponentAtNode(node); }); diff --git a/src/components/Modal.js b/src/components/Modal.js index 00c0203e..018cee61 100644 --- a/src/components/Modal.js +++ b/src/components/Modal.js @@ -10,10 +10,6 @@ export const bodyOpenClassName = 'ReactModal__Body--open'; const renderSubtreeIntoContainer = ReactDOM.unstable_renderSubtreeIntoContainer; -function getParentElement(parentSelector) { - return parentSelector(); -} - export default class Modal extends Component { static setAppElement(element) { ariaAppHider.setElement(element); @@ -53,7 +49,6 @@ export default class Modal extends Component { ariaHideApp: PropTypes.bool, shouldFocusAfter: PropTypes.bool, shouldCloseOnOverlayClick: PropTypes.bool, - parentSelector: PropTypes.func, aria: PropTypes.object, role: PropTypes.string, contentLabel: PropTypes.string @@ -68,7 +63,6 @@ export default class Modal extends Component { closeTimeoutMS: 0, shouldFocusAfterRender: true, shouldCloseOnOverlayClick: true, - parentSelector() { return document.body; } }; static defaultStyles = { @@ -97,12 +91,6 @@ export default class Modal extends Component { }; componentDidMount() { - this.node = document.createElement('div'); - this.node.className = this.props.portalClassName; - - const parent = getParentElement(this.props.parentSelector); - parent.appendChild(this.node); - this.renderPortal(this.props); } @@ -111,14 +99,6 @@ export default class Modal extends Component { // Stop unnecessary renders if modal is remaining closed if (!this.props.isOpen && !isOpen) return; - const currentParent = getParentElement(this.props.parentSelector); - const newParent = getParentElement(newProps.parentSelector); - - if (newParent !== currentParent) { - currentParent.removeChild(this.node); - newParent.appendChild(this.node); - } - this.renderPortal(newProps); } @@ -148,10 +128,13 @@ export default class Modal extends Component { } } + setNodeRef = ref => { + this.node = ref; + } + removePortal = () => { ReactDOM.unmountComponentAtNode(this.node); - const parent = getParentElement(this.props.parentSelector); - parent.removeChild(this.node); + this.portal = null; } renderPortal = props => { @@ -161,6 +144,10 @@ export default class Modal extends Component { } render() { - return null; + return ( +
+ ); } }