From 60e2034cc2a83b19da5e5c64be5eeb6c7605a14a Mon Sep 17 00:00:00 2001 From: robinfehr Date: Tue, 3 Jan 2017 12:22:23 +0300 Subject: [PATCH 1/7] add passtrough params to closePortal func - add named params to closePortal func - add babel preset stage 2 for named params --- .babelrc | 2 +- lib/portal.js | 4 ++-- package.json | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.babelrc b/.babelrc index 671a63b..34b287f 100644 --- a/.babelrc +++ b/.babelrc @@ -1,5 +1,5 @@ { - "presets": ["react", "es2015"], + "presets": ["react", "es2015", "stage-2"], "plugins": ["add-module-exports"], "env": { "development": { diff --git a/lib/portal.js b/lib/portal.js index 6497991..d06edb8 100644 --- a/lib/portal.js +++ b/lib/portal.js @@ -79,7 +79,7 @@ export default class Portal extends React.Component { this.renderPortal(props, true); } - closePortal(isUnmounted = false) { + closePortal({ isUnmounted = false, ...rest } = {}) { const resetPortalState = () => { if (this.node) { ReactDOM.unmountComponentAtNode(this.node); @@ -99,7 +99,7 @@ export default class Portal extends React.Component { resetPortalState(); } - this.props.onClose(); + this.props.onClose(rest); } } diff --git a/package.json b/package.json index 5a251b9..a53cc80 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "babel-preset-es2015": "^6.3.13", "babel-preset-react": "^6.3.13", "babel-preset-react-hmre": "^1.0.1", + "babel-preset-stage-2": "^6.18.0", "babel-register": "^6.8.0", "cross-env": "^1.0.7", "enzyme": "^2.3.0", From 2da230d7070b7b86c34752cfd60d6968820cb785 Mon Sep 17 00:00:00 2001 From: robinfehr Date: Tue, 3 Jan 2017 13:13:08 +0300 Subject: [PATCH 2/7] test for passtrough params to closePortal func --- test/portal_spec.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/portal_spec.js b/test/portal_spec.js index 89a2090..2133bcd 100644 --- a/test/portal_spec.js +++ b/test/portal_spec.js @@ -156,6 +156,13 @@ describe('react-portal', () => { assert(props.onClose.calledOnce); }); + it('should call props.onClose() with the passed named params', () => { + const props = { isOpen: true, onClose: spy() }; + const wrapper = mount(

Hi

); + wrapper.instance().closePortal({ namedParam: { propA: 1, propB: 'test' } }); + assert(props.onClose.calledWith({ namedParam: { propA: 1, propB: 'test' } })); + }); + it('should call props.onClose() only once when portal closes and then is unmounted', () => { const div = document.createElement('div'); const props = { isOpen: true, onClose: spy() }; From 52ed406327133dfa160bb9fd2ec070088c407b37 Mon Sep 17 00:00:00 2001 From: robinfehr Date: Tue, 3 Jan 2017 13:27:15 +0300 Subject: [PATCH 3/7] change test description --- test/portal_spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/portal_spec.js b/test/portal_spec.js index 2133bcd..dabf24d 100644 --- a/test/portal_spec.js +++ b/test/portal_spec.js @@ -156,7 +156,7 @@ describe('react-portal', () => { assert(props.onClose.calledOnce); }); - it('should call props.onClose() with the passed named params', () => { + it('should call props.onClose() with the passed named params when closePortal is called with named params', () => { const props = { isOpen: true, onClose: spy() }; const wrapper = mount(

Hi

); wrapper.instance().closePortal({ namedParam: { propA: 1, propB: 'test' } }); From 57fa26112354ee8d8ff79452e63a24cf3c203cd2 Mon Sep 17 00:00:00 2001 From: robinfehr Date: Tue, 3 Jan 2017 13:37:05 +0300 Subject: [PATCH 4/7] adjust test name --- test/portal_spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/portal_spec.js b/test/portal_spec.js index dabf24d..3843e2f 100644 --- a/test/portal_spec.js +++ b/test/portal_spec.js @@ -156,7 +156,7 @@ describe('react-portal', () => { assert(props.onClose.calledOnce); }); - it('should call props.onClose() with the passed named params when closePortal is called with named params', () => { + it('named params on props.onClose() when closePortal is called with named params', () => { const props = { isOpen: true, onClose: spy() }; const wrapper = mount(

Hi

); wrapper.instance().closePortal({ namedParam: { propA: 1, propB: 'test' } }); @@ -184,8 +184,8 @@ describe('react-portal', () => { const div = document.createElement('div'); const props = { isOpen: true }; const wrapper = render(

Hi

, div); - spy(wrapper, 'setState'); unmountComponentAtNode(div); + spy(wrapper, 'setState'); assert.equal(wrapper.setState.callCount, 0); }); }); From 98e5648e8e79abb766949b18b289c7f69f6b406b Mon Sep 17 00:00:00 2001 From: robinfehr Date: Sat, 7 Jan 2017 13:20:31 +0100 Subject: [PATCH 5/7] passtrough params with onClose.bind --- lib/portal.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/portal.js b/lib/portal.js index d06edb8..5a63edc 100644 --- a/lib/portal.js +++ b/lib/portal.js @@ -11,6 +11,7 @@ export default class Portal extends React.Component { super(); this.state = { active: false }; this.handleWrapperClick = this.handleWrapperClick.bind(this); + this.onClose = undefined; this.closePortal = this.closePortal.bind(this); this.handleOutsideMouseClick = this.handleOutsideMouseClick.bind(this); this.handleKeydown = this.handleKeydown.bind(this); @@ -19,6 +20,7 @@ export default class Portal extends React.Component { } componentDidMount() { + this.onClose = this.props.onClose; if (this.props.closeOnEsc) { document.addEventListener('keydown', this.handleKeydown); } @@ -44,6 +46,7 @@ export default class Portal extends React.Component { } } if (!newProps.isOpen && this.state.active) { + this.onClose = newProps.onClose; this.closePortal(); } } @@ -99,7 +102,7 @@ export default class Portal extends React.Component { resetPortalState(); } - this.props.onClose(rest); + this.onClose.call(null, rest); } } From da1fe2c0dbee46727b641627babe553c655dab8d Mon Sep 17 00:00:00 2001 From: robinfehr Date: Sun, 8 Jan 2017 20:29:41 +0100 Subject: [PATCH 6/7] test for pre bound named parameters --- test/portal_spec.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/test/portal_spec.js b/test/portal_spec.js index 3843e2f..0373526 100644 --- a/test/portal_spec.js +++ b/test/portal_spec.js @@ -156,13 +156,24 @@ describe('react-portal', () => { assert(props.onClose.calledOnce); }); - it('named params on props.onClose() when closePortal is called with named params', () => { + it('onClose has named params when closePortal is called directly with named params', () => { const props = { isOpen: true, onClose: spy() }; const wrapper = mount(

Hi

); wrapper.instance().closePortal({ namedParam: { propA: 1, propB: 'test' } }); assert(props.onClose.calledWith({ namedParam: { propA: 1, propB: 'test' } })); }); + it('onClose has named params when named params were pre bound to onClose', () => { + const onCloseFunc = spy(); + const props = { isOpen: true, onClose: () => onCloseFunc({ namedParam: 'test' }) }; + const wrapper = mount(

Hi

); + assert.equal(document.body.lastElementChild, wrapper.instance().node); + assert.equal(document.body.childElementCount, 1); + wrapper.setProps({ isOpen: false, children:

Hi

}); + assert.equal(document.body.childElementCount, 0); + assert(onCloseFunc.calledWith({ namedParam: 'test' })); + }); + it('should call props.onClose() only once when portal closes and then is unmounted', () => { const div = document.createElement('div'); const props = { isOpen: true, onClose: spy() }; From 327b4979ea6fa66b0327129f8b9b03301a5b3125 Mon Sep 17 00:00:00 2001 From: robinfehr Date: Fri, 13 Jan 2017 17:20:35 +0100 Subject: [PATCH 7/7] readme for passtrough params --- README.md | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9ad57ff..292e925 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ React-portal - doesn't leave any mess in DOM after closing - provides its child with **this.props.closePortal** callback - provides **close on ESC** and **close on outside mouse click** out of the box +- the **close** can be bound to parameters - supports absolute positioned components (great for tooltips) - **no dependencies** - **fully covered by tests** @@ -106,8 +107,9 @@ This callback is called when the portal is opened and rendered (useful for anima #### beforeClose: func(DOMNode, removeFromDOM) This callback is called when the closing event is triggered but it prevents normal removal from the DOM. So, you can do some DOMNode animation first and then call removeFromDOM() that removes the portal from DOM. -#### onClose: func +#### onClose: func(params) This callback is called when the portal closes and after beforeClose. +You can bind parameters to the onClose callback. #### onUpdate: func This callback is called when the portal is (re)rendered. @@ -136,7 +138,7 @@ also need an access to `this.props.closePortal()`? You can't just use `{this.pro #### Open modal programmatically -Sometimes you need to open your portal (e.g. modal) automatically. There is no button to click on. No problem, because the portal has the `isOpen` prop, so you can just set it to `true` or `false`. However, then it's completely up to you to take care about the portal closing (ESC, outside click, no `this.props.closePortal` callback...). +Sometimes you need to open your portal (e.g. modal) programmatically. There is no button to click on. No problem, because the portal has the `isOpen` prop, so you can just set it to `true` or `false`. However, then it's completely up to you to take care about the portal closing (ESC, outside click, no `this.props.closePortal` callback...). However, there is a nice trick how to make this happen even without `isOpen`: @@ -153,7 +155,26 @@ this.refs.myPortal.openPortal() // opens the portal, yay! ``` -## Contribution +#### Close portal programmatically with passtrough parameters + +Sometimes you need to close your portal programmatically and pass trough parameters from your portal to the calling instance. +You have two ways you can do it. + +##### Way 1 +You can additionaly add a closure as a passtrough parameter to your onClose callback func. +``` +render() { + const { isOpen, toPassTrough } = this.state; + onCloseFunc(toPassTrough)} + > +} +``` +##### Way 2 +Assuming you have passed the closePortal function to the Portal's children - you can call the closePortal func with parameters. + +``````## Contribution Please, create issues and pull requests.