diff --git a/src/Overlay.js b/src/Overlay.js index 6d82a7f401..6debd6f9e7 100644 --- a/src/Overlay.js +++ b/src/Overlay.js @@ -57,13 +57,20 @@ class Overlay extends React.Component { ); if (Transition) { + let { onExit, onExiting, onEnter, onEntering, onEntered } = props; + // This animates the child node by injecting props, so it must precede // anything that adds a wrapping div. child = ( {child} @@ -91,8 +98,12 @@ class Overlay extends React.Component { ); } - handleHidden() { + handleHidden(...args) { this.setState({exited: true}); + + if (this.props.onExited) { + this.props.onExited(...args); + } } } @@ -118,7 +129,37 @@ Overlay.propTypes = { animation: React.PropTypes.oneOfType([ React.PropTypes.bool, CustomPropTypes.elementType - ]) + ]), + + /** + * Callback fired before the Overlay transitions in + */ + onEnter: React.PropTypes.func, + + /** + * Callback fired as the Overlay begins to transition in + */ + onEntering: React.PropTypes.func, + + /** + * Callback fired after the Overlay finishes transitioning in + */ + onEntered: React.PropTypes.func, + + /** + * Callback fired right before the Overlay transitions out + */ + onExit: React.PropTypes.func, + + /** + * Callback fired as the Overlay begins to transition out + */ + onExiting: React.PropTypes.func, + + /** + * Callback fired after the Overlay finishes transitioning out + */ + onExited: React.PropTypes.func }; Overlay.defaultProps = { diff --git a/src/OverlayTrigger.js b/src/OverlayTrigger.js index 783e3b4ee8..1c980b1a68 100644 --- a/src/OverlayTrigger.js +++ b/src/OverlayTrigger.js @@ -5,7 +5,7 @@ import createChainedFunction from './utils/createChainedFunction'; import createContextWrapper from './utils/createContextWrapper'; import Overlay from './Overlay'; import warning from 'react/lib/warning'; - +import pick from 'lodash/object/pick'; /** * Check if value one is inside or equal to the of value * @@ -146,24 +146,26 @@ const OverlayTrigger = React.createClass({ }, getOverlay() { - let props = { - show: this.state.isOverlayShown, - onHide: this.hide, - rootClose: this.props.rootClose, - animation: this.props.animation, + let overlayProps = { + ...pick(this.props, Object.keys(Overlay.propTypes)), + show: this.state.isOverlayShown, + onHide: this.hide, target: this.getOverlayTarget, - placement: this.props.placement, - container: this.props.container, - containerPadding: this.props.containerPadding + onExit: this.props.onExit, + onExiting: this.props.onExiting, + onExited: this.props.onExited, + onEnter: this.props.onEnter, + onEntering: this.props.onEntering, + onEntered: this.props.onEntered }; let overlay = cloneElement(this.props.overlay, { - placement: props.placement, - container: props.container + placement: overlayProps.placement, + container: overlayProps.container }); return ( - + { overlay } ); diff --git a/test/OverlayTriggerSpec.js b/test/OverlayTriggerSpec.js index 768ad20c7c..637f59d2ba 100644 --- a/test/OverlayTriggerSpec.js +++ b/test/OverlayTriggerSpec.js @@ -39,6 +39,41 @@ describe('OverlayTrigger', function() { instance.state.isOverlayShown.should.be.true; }); + it('Should pass transition callbacks to Transition', function (done) { + let count = 0; + let increment = ()=> count++; + + let overlayTrigger; + + let instance = ReactTestUtils.renderIntoDocument( + test} + onHide={()=>{}} + onExit={increment} + onExiting={increment} + onExited={()=> { + increment(); + expect(count).to.equal(6); + done(); + }} + onEnter={increment} + onEntering={increment} + onEntered={()=> { + increment(); + ReactTestUtils.Simulate.click(overlayTrigger); + }} + > + + + ); + + overlayTrigger = React.findDOMNode(instance); + + ReactTestUtils.Simulate.click(overlayTrigger); + }); + + it('Should forward requested context', function() { const contextTypes = { key: React.PropTypes.string