diff --git a/src/Collapse.js b/src/Collapse.js
index 505c116085..299ec8a625 100644
--- a/src/Collapse.js
+++ b/src/Collapse.js
@@ -115,84 +115,82 @@ class Collapse extends React.Component {
Collapse.propTypes = {
/**
- * Collapse the Component in or out.
+ * Whether the component is entered; triggers the enter or exit animation
*/
- in: React.PropTypes.bool,
+ in: React.PropTypes.bool,
/**
- * Provide the duration of the animation in milliseconds, used to ensure that finishing callbacks are fired even if the
- * original browser transition end events are canceled.
+ * Whether the component should be unmounted (removed from DOM) when exited
*/
- duration: React.PropTypes.number,
+ unmountOnExit: React.PropTypes.bool,
/**
- * Specifies the dimension used when collapsing.
- *
- * _Note: Bootstrap only partially supports 'width'!
- * You will need to supply your own css animation for the `.width` css class._
+ * Whether transition in should run when the Transition component mounts, if
+ * the component is initially entered
*/
- dimension: React.PropTypes.oneOfType([
- React.PropTypes.oneOf(['height', 'width']),
- React.PropTypes.func
- ]),
+ transitionAppear: React.PropTypes.bool,
/**
- * A function that returns the height or width of the animating DOM node. Allows for providing some custom logic how much
- * Collapse component should animate in its specified dimension.
- *
- * `getDimensionValue` is called with the current dimension prop value and the DOM node.
+ * Duration of the animation in milliseconds, to ensure that finishing
+ * callbacks are fired even if the original browser transition end events are
+ * canceled
*/
- getDimensionValue: React.PropTypes.func,
+ duration: React.PropTypes.number,
/**
- * A Callback fired before the component starts to expand.
+ * Callback fired before the "entering" classes are applied
*/
onEnter: React.PropTypes.func,
-
/**
- * A Callback fired immediately after the component starts to expand.
+ * Callback fired after the "entering" classes are applied
*/
onEntering: React.PropTypes.func,
-
/**
- * A Callback fired after the component has expanded.
+ * Callback fired after the "enter" classes are applied
*/
onEntered: React.PropTypes.func,
-
/**
- * A Callback fired before the component starts to collapse.
+ * Callback fired before the "exiting" classes are applied
*/
onExit: React.PropTypes.func,
-
/**
- * A Callback fired immediately after the component starts to collapse.
+ * Callback fired after the "exiting" classes are applied
*/
onExiting: React.PropTypes.func,
-
/**
- * A Callback fired after the component has collapsed.
+ * Callback fired after the "exited" classes are applied
*/
onExited: React.PropTypes.func,
/**
- * Specify whether the transitioning component should be unmounted (removed from the DOM) once the exit animation finishes.
+ * The dimension used when collapsing
+ *
+ * _Note: Bootstrap only partially supports 'width'!
+ * You will need to supply your own CSS animation for the `.width` CSS class._
*/
- unmountOnExit: React.PropTypes.bool,
+ dimension: React.PropTypes.oneOfType([
+ React.PropTypes.oneOf(['height', 'width']),
+ React.PropTypes.func
+ ]),
/**
- * Specify whether the component should collapse or expand when it mounts.
+ * Function that returns the height or width of the animating DOM node
+ *
+ * Allows for providing some custom logic for how much the Collapse component
+ * should animate in its specified dimension. Called with the current
+ * dimension prop value and the DOM node.
*/
- transitionAppear: React.PropTypes.bool
+ getDimensionValue: React.PropTypes.func
};
Collapse.defaultProps = {
- in: false,
+ in: false,
duration: 300,
- dimension: 'height',
- transitionAppear: false,
unmountOnExit: false,
+ transitionAppear: false,
+
+ dimension: 'height',
getDimensionValue
};
export default Collapse;
-
diff --git a/src/Fade.js b/src/Fade.js
index 523508fff5..528e839d85 100644
--- a/src/Fade.js
+++ b/src/Fade.js
@@ -2,87 +2,77 @@ import React from 'react';
import Transition from './Transition';
class Fade extends React.Component {
-
- constructor(props, context){
- super(props, context);
- }
-
render() {
return (
- { this.props.children }
+ {this.props.children}
);
}
}
+// Explicitly copied from Transition for doc generation.
+
Fade.propTypes = {
/**
- * Fade the Component in or out.
+ * Whether the component is entered; triggers the enter or exit animation
*/
- in: React.PropTypes.bool,
+ in: React.PropTypes.bool,
/**
- * Provide the duration of the animation in milliseconds, used to ensure that finishing callbacks are fired even if the
- * original browser transition end events are canceled.
+ * Whether the component should be unmounted (removed from DOM) when exited
*/
- duration: React.PropTypes.number,
+ unmountOnExit: React.PropTypes.bool,
/**
- * A Callback fired before the component starts to fade in.
+ * Whether transition in should run when the Transition component mounts, if
+ * the component is initially entered
*/
- onEnter: React.PropTypes.func,
+ transitionAppear: React.PropTypes.bool,
/**
- * A Callback fired immediately after the component has started to faded in.
+ * Duration of the animation in milliseconds, to ensure that finishing
+ * callbacks are fired even if the original browser transition end events are
+ * canceled
*/
- onEntering: React.PropTypes.func,
+ duration: React.PropTypes.number,
/**
- * A Callback fired after the component has faded in.
+ * Callback fired before the "entering" classes are applied
*/
- onEntered: React.PropTypes.func,
-
+ onEnter: React.PropTypes.func,
/**
- * A Callback fired before the component starts to fade out.
+ * Callback fired after the "entering" classes are applied
*/
- onExit: React.PropTypes.func,
-
+ onEntering: React.PropTypes.func,
/**
- * A Callback fired immediately after the component has started to faded out.
+ * Callback fired after the "enter" classes are applied
*/
- onExiting: React.PropTypes.func,
-
+ onEntered: React.PropTypes.func,
/**
- * A Callback fired after the component has faded out.
+ * Callback fired before the "exiting" classes are applied
*/
- onExited: React.PropTypes.func,
-
-
+ onExit: React.PropTypes.func,
/**
- * Specify whether the transitioning component should be unmounted (removed from the DOM) once the exit animation finishes.
+ * Callback fired after the "exiting" classes are applied
*/
- unmountOnExit: React.PropTypes.bool,
-
+ onExiting: React.PropTypes.func,
/**
- * Specify whether the component should fade in or out when it mounts.
+ * Callback fired after the "exited" classes are applied
*/
- transitionAppear: React.PropTypes.bool
-
+ onExited: React.PropTypes.func
};
Fade.defaultProps = {
- in: false,
+ in: false,
duration: 300,
- dimension: 'height',
- transitionAppear: false,
- unmountOnExit: false
+ unmountOnExit: false,
+ transitionAppear: false
};
export default Fade;
diff --git a/src/Overlay.js b/src/Overlay.js
index 8e3e996e5b..0a4932903e 100644
--- a/src/Overlay.js
+++ b/src/Overlay.js
@@ -7,31 +7,24 @@ import CustomPropTypes from './utils/CustomPropTypes';
import Fade from './Fade';
import classNames from 'classnames';
-
class Overlay extends React.Component {
-
- constructor(props, context){
+ constructor(props, context) {
super(props, context);
- this.state = { exited: false };
+ this.state = {exited: !props.show};
this.onHiddenListener = this.handleHidden.bind(this);
}
componentWillReceiveProps(nextProps) {
- let state = {};
-
- if ( !nextProps.show && this.props.show ){
- state.exiting = true;
- }
-
if (nextProps.show) {
- state = { exited: false, exiting: false };
+ this.setState({exited: false});
+ } else if (!nextProps.animation) {
+ // Otherwise let handleHidden take care of marking exited.
+ this.setState({exited: true});
}
-
- this.setState(state);
}
- render(){
+ render() {
let {
container
, containerPadding
@@ -42,56 +35,63 @@ class Overlay extends React.Component {
, animation: Transition
, ...props } = this.props;
- let child = null;
-
- if ( Transition === true ){
+ if (Transition === true) {
Transition = Fade;
}
- if (props.show || (Transition && this.state.exiting && !this.state.exited)) {
+ // Don't un-render the overlay while it's transitioning out.
+ const mountOverlay = props.show || (Transition && !this.state.exited);
+
+ if (!mountOverlay) {
+ // Don't bother showing anything if we don't have to.
+ return null;
+ }
- child = children;
+ let child = children;
- // Position the child before the animation to avoid `null` DOM nodes
+ if (Transition) {
+ // This animates the child by injecting props, so it must be inner-most.
child = (
-
- { child }
-
+
+ {child}
+
+ );
+ } else {
+ child = cloneElement(
+ child,
+ {className: classNames('in', child.className)}
);
-
- child = Transition
- ? (
-
- { child }
-
- )
- : cloneElement(child, { className: classNames('in', child.className) });
-
- //Adds a wrapping div so it cannot be before Transition
- if (rootClose) {
- child = (
-
- { child }
-
- );
- }
}
+ // This must wrap the transition to avoid position recalculations.
+ child = (
+
+ {child}
+
+ );
+
+ // This goes after everything else because it adds a wrapping div.
+ if (rootClose) {
+ child = (
+
+ {child}
+
+ );
+ }
return (
- { child }
+ {child}
);
}
- handleHidden(){
- this.setState({ exited: true, exiting: false });
+ handleHidden() {
+ this.setState({exited: true});
}
}
diff --git a/src/Position.js b/src/Position.js
index 6b3b8ff9a0..cb4408e041 100644
--- a/src/Position.js
+++ b/src/Position.js
@@ -4,9 +4,9 @@ import { calcOverlayPosition } from './utils/overlayPositionUtils';
import CustomPropTypes from './utils/CustomPropTypes';
class Position extends React.Component {
-
constructor(props, context){
super(props, context);
+
this.state = {
positionLeft: null,
positionTop: null,
@@ -15,33 +15,35 @@ class Position extends React.Component {
};
}
- componentWillMount(){
- this._needsFlush = true;
+ componentDidMount() {
+ this.updatePosition(this.props, this.getTargetSafe(this.props));
}
- componentWillReceiveProps(){
- this._needsFlush = true;
- }
+ componentWillReceiveProps(nextProps) {
+ if (nextProps.target !== this.props.target) {
+ const target = this.getTargetSafe(this.props);
+ const nextTarget = this.getTargetSafe(nextProps);
- componentDidMount(){
- this._maybeUpdatePosition();
- }
- componentDidUpdate(){
- this._maybeUpdatePosition();
+ if (nextTarget !== target) {
+ this.updatePosition(nextProps, nextTarget);
+ }
+ }
}
render() {
- let { children, ...props } = this.props;
- let { positionLeft, positionTop, ...arrows } = this.props.target ? this.state : {};
+ const {children, ...props} = this.props;
+ const {positionLeft, positionTop, ...arrowPosition } = this.state;
+ const child = React.Children.only(children);
return cloneElement(
- React.Children.only(children), {
+ child,
+ {
...props,
- ...arrows,
+ ...arrowPosition,
positionTop,
positionLeft,
style: {
- ...children.props.style,
+ ...child.props.style,
left: positionLeft,
top: positionTop
}
@@ -49,55 +51,62 @@ class Position extends React.Component {
);
}
- _maybeUpdatePosition(){
- if ( this._needsFlush ) {
- this._needsFlush = false;
- this._updatePosition();
+ getTargetSafe(props) {
+ if (!props.target) {
+ return null;
}
+
+ return props.target(props);
}
- _updatePosition() {
- if ( this.props.target == null ){
+ updatePosition(props, target) {
+ if (!target) {
+ this.setState({
+ positionLeft: null,
+ positionTop: null,
+ arrowOffsetLeft: null,
+ arrowOffsetTop: null
+ });
+
return;
}
- let overlay = React.findDOMNode(this);
- let target = React.findDOMNode(this.props.target(this.props));
- let container = React.findDOMNode(this.props.container) || domUtils.ownerDocument(this).body;
-
- this.setState(
- calcOverlayPosition(
- this.props.placement
- , overlay
- , target
- , container
- , this.props.containerPadding));
+ const overlay = React.findDOMNode(this);
+ const container =
+ React.findDOMNode(props.container) || domUtils.ownerDocument(this).body;
+
+ this.setState(calcOverlayPosition(
+ props.placement,
+ overlay,
+ target,
+ container,
+ props.containerPadding
+ ));
}
}
Position.propTypes = {
/**
- * The target DOM node the Component is positioned next too.
+ * Function mapping props to DOM node the component is positioned next to
*/
- target: React.PropTypes.func,
+ target: React.PropTypes.func,
/**
- * The "offsetParent" of the Component
+ * "offsetParent" of the component
*/
- container: CustomPropTypes.mountable,
+ container: CustomPropTypes.mountable,
/**
- * Distance in pixels the Component should be positioned to the edge of the Container.
+ * Minimum spacing in pixels between container border and component border
*/
containerPadding: React.PropTypes.number,
/**
- * The location that the overlay should be positioned to its target.
+ * How to position the component relative to the target
*/
- placement: React.PropTypes.oneOf(['top', 'right', 'bottom', 'left'])
+ placement: React.PropTypes.oneOf(['top', 'right', 'bottom', 'left'])
};
Position.defaultProps = {
containerPadding: 0,
- placement: 'right'
+ placement: 'right'
};
-
export default Position;
diff --git a/src/Transition.js b/src/Transition.js
index a49124aac7..85eb05c5f6 100644
--- a/src/Transition.js
+++ b/src/Transition.js
@@ -2,284 +2,274 @@ import React from 'react';
import TransitionEvents from './utils/TransitionEvents';
import classnames from 'classnames';
-function omit(obj, keys) {
- let included = Object.keys(obj).filter( k => keys.indexOf(k) === -1);
- let newObj = {};
-
- included.forEach( key => newObj[key] = obj[key] );
- return newObj;
-}
-
-function ensureTransitionEnd(node, handler, duration){
- let fired = false;
- let done = e => {
- if (!fired) {
- fired = true;
- handler(e);
- }
- };
-
- if ( node ) {
- TransitionEvents.addEndEventListener(node, done);
- setTimeout(done, duration);
- } else {
- setTimeout(done, 0);
- }
-}
-
-// reading a dimension prop will cause the browser to recalculate,
-// which will let our animations work
-let triggerBrowserReflow = node => node.offsetHeight; //eslint-disable-line no-unused-expressions
+const UNMOUNTED = 0;
+export const EXITED = 1;
+export const ENTERING = 2;
+export const ENTERED = 3;
+export const EXITING = 4;
class Transition extends React.Component {
-
- constructor(props, context){
+ constructor(props, context) {
super(props, context);
- this.state = {
- in: !props.in,
- transitioning: false
- };
+ let initialStatus;
+ if (props.in) {
+ // Perform enter in performNextTransition from componentDidMount.
+ initialStatus = props.transitionAppear ? EXITED : ENTERED;
+ } else {
+ initialStatus = props.unmountOnExit ? UNMOUNTED : EXITED;
+ }
+ this.state = {status: initialStatus};
- this.needsTransition = true;
+ this.nextCallback = null;
}
- componentWillReceiveProps(nextProps) {
- if (nextProps.in !== this.props.in) {
- this.needsTransition = true;
- }
+ componentDidMount() {
+ this.performNextTransition();
}
- componentDidUpdate() {
- this.processChild();
- }
+ componentWillReceiveProps(nextProps) {
+ const status = this.state.status;
+ if (nextProps.in) {
+ if (status === EXITING) {
+ this.performEnter(nextProps);
+ } else if (this.props.unmountOnExit) {
+ // Perform enter in performNextTransition.
+ if (status === UNMOUNTED) {
+ this.setState({status: EXITED});
+ }
+ } else if (status === EXITED) {
+ this.performEnter(nextProps);
+ }
- componentWillMount() {
- this._mounted = true;
+ // Otherwise we're already entering or entered.
+ } else {
+ if (status === ENTERING || status === ENTERED) {
+ this.performExit(nextProps);
+ }
- if (!this.props.transitionAppear) {
- this.needsTransition = false;
- this.setState({ in: this.props.in });
+ // Otherwise we're already exited or exiting.
}
}
- componentWillUnmount(){
- this._mounted = false;
+ componentDidUpdate() {
+ this.performNextTransition();
}
- componentDidMount() {
- if (this.props.transitionAppear) {
- this.processChild();
- }
+ componentWillUnmount() {
+ this.cancelNextCallback();
}
- processChild(){
- let needsTransition = this.needsTransition;
- let enter = this.props.in;
-
- if (needsTransition) {
- this.needsTransition = false;
- this[enter ? 'performEnter' : 'performLeave']();
+ performNextTransition() {
+ if (this.state.status === EXITED) {
+ if (this.props.in) {
+ // Either because of transitionAppear or unmountOnExit.
+ this.performEnter(this.props);
+ } else if (this.props.unmountOnExit) {
+ this.setState({status: UNMOUNTED});
+ }
}
}
- performEnter() {
- let maybeNode = React.findDOMNode(this);
-
- let enter = node => {
- node = this.props.transitioningNode(node) || node;
-
- this.props.onEnter(node);
+ performEnter(props) {
+ this.cancelNextCallback();
+ const node = React.findDOMNode(this);
- this.safeSetState({ in: true, transitioning: true, needInitialRender: false }, ()=> {
+ // Not this.props, because we might be about to receive new props.
+ props.onEnter(node);
- this.props.onEntering(node);
+ this.safeSetState({status: ENTERING}, () => {
+ this.props.onEntering(node);
- ensureTransitionEnd(node, () => {
- if ( this.state.in ){
- this.safeSetState({
- transitioning: false
- }, () => this.props.onEntered(node));
- }
-
- }, this.props.duration);
+ this.onTransitionEnd(node, () => {
+ this.safeSetState({status: ENTERED}, () => {
+ this.props.onEntered(node);
+ });
});
- };
-
- if (maybeNode) {
- enter(maybeNode);
- }
- else if (this.props.unmountOnExit) {
- this._ensureNode(enter);
- }
+ });
}
- performLeave() {
- let node = React.findDOMNode(this);
-
- node = this.props.transitioningNode(node) || node;
+ performExit(props) {
+ this.cancelNextCallback();
+ const node = React.findDOMNode(this);
- this.props.onExit(node);
+ // Not this.props, because we might be about to receive new props.
+ props.onExit(node);
- this.setState({ in: false, transitioning: true }, () => {
+ this.safeSetState({status: EXITING}, () => {
this.props.onExiting(node);
- ensureTransitionEnd(node, () => {
- if ( !this.state.in ){
- this.safeSetState({ transitioning: false }, ()=> this.props.onExited(node));
- }
- }, this.props.duration);
+ this.onTransitionEnd(node, () => {
+ this.safeSetState({status: EXITED}, () => {
+ this.props.onExited(node);
+ });
+ });
});
}
- _ensureNode(callback) {
-
- this.setState({ needInitialRender: true }, ()=> {
- let node = React.findDOMNode(this);
-
- triggerBrowserReflow(node);
-
- callback(node);
- });
+ cancelNextCallback() {
+ if (this.nextCallback !== null) {
+ this.nextCallback.cancel();
+ this.nextCallback = null;
+ }
}
- safeSetState(newState, cb){
- if (this._mounted) {
- this.setState(newState, cb);
- }
+ safeSetState(nextState, callback) {
+ // This shouldn't be necessary, but there are weird race conditions with
+ // setState callbacks and unmounting in testing, so always make sure that
+ // we can cancel any pending setState callbacks after we unmount.
+ this.setState(nextState, this.setNextCallback(callback));
}
- render() {
- let childProps = omit(this.props, Object.keys(Transition.propTypes).concat('children'));
+ setNextCallback(callback) {
+ let active = true;
- let child = this.props.children;
- let starting = this.state.needInitialRender;
- let out = !this.state.in && !this.state.transitioning;
+ this.nextCallback = (event) => {
+ if (active) {
+ active = false;
+ this.nextCallback = null;
- if ( !child || (this.props.unmountOnExit && out && !starting) ){
- return null;
- }
+ callback(event);
+ }
+ };
- let classes = '';
+ this.nextCallback.cancel = () => {
+ active = false;
+ };
- // using `classnames()` here causes a subtle bug,
- // hence the verbose if/else if sequence.
- if (this.state.in && !this.state.transitioning) {
- classes = this.props.enteredClassName;
- }
+ return this.nextCallback;
+ }
+
+ onTransitionEnd(node, handler) {
+ this.setNextCallback(handler);
- else if (this.state.in && this.state.transitioning) {
- classes = this.props.enteringClassName;
+ if (node) {
+ TransitionEvents.addEndEventListener(node, this.nextCallback);
+ setTimeout(this.nextCallback, this.props.duration);
+ } else {
+ setTimeout(this.nextCallback, 0);
}
+ }
- else if (!this.state.in && !this.state.transitioning) {
- classes = this.props.exitedClassName;
+ render() {
+ const status = this.state.status;
+ if (status === UNMOUNTED) {
+ return null;
}
- else if (!this.state.in && this.state.transitioning) {
- classes = this.props.exitingClassName;
+ const {children, className, style, ...childProps} = this.props;
+ Object.keys(Transition.propTypes).forEach(key => delete childProps[key]);
+
+ let transitionClassName;
+ if (status === EXITED) {
+ transitionClassName = this.props.exitedClassName;
+ } else if (status === ENTERING) {
+ transitionClassName = this.props.enteringClassName;
+ } else if (status === ENTERED) {
+ transitionClassName = this.props.enteredClassName;
+ } else if (status === EXITING) {
+ transitionClassName = this.props.exitingClassName;
}
- return React.cloneElement(child, {
- ...childProps,
- className: classnames(
- child.props.className,
- this.props.className,
- classes)
- });
+ const child = React.Children.only(children);
+ return React.cloneElement(
+ child,
+ {
+ ...childProps,
+ className: classnames(
+ child.props.className,
+ className,
+ transitionClassName
+ ),
+ style: {...child.props.style, ...style}
+ }
+ );
}
}
Transition.propTypes = {
/**
- * Triggers the Enter or Exit animation
+ * Whether the component is entered; triggers the enter or exit animation
*/
- in: React.PropTypes.bool,
+ in: React.PropTypes.bool,
/**
- * Specify whether the transitioning component should be unmounted (removed from the DOM) once the exit animation finishes.
+ * Whether the component should be unmounted (removed from DOM) when exited
*/
- unmountOnExit: React.PropTypes.bool,
+ unmountOnExit: React.PropTypes.bool,
/**
- * Specify whether transitions should run when the Transition component mounts.
+ * Whether transition in should run when the Transition component mounts, if
+ * the component is initially entered
*/
transitionAppear: React.PropTypes.bool,
/**
- * Provide the duration of the animation in milliseconds, used to ensure that finishing callbacks are fired even if the
- * original browser transition end events are canceled.
+ * Duration of the animation in milliseconds, to ensure that finishing
+ * callbacks are fired even if the original browser transition end events are
+ * canceled
*/
- duration: React.PropTypes.number,
+ duration: React.PropTypes.number,
/**
- * A css class or classes applied once the Component has exited.
+ * CSS class or classes applied when the component is exited
*/
- exitedClassName: React.PropTypes.string,
+ exitedClassName: React.PropTypes.string,
/**
- * A css class or classes applied while the Component is exiting.
+ * CSS class or classes applied while the component is exiting
*/
- exitingClassName: React.PropTypes.string,
+ exitingClassName: React.PropTypes.string,
/**
- * A css class or classes applied once the Component has entered.
+ * CSS class or classes applied when the component is entered
*/
- enteredClassName: React.PropTypes.string,
+ enteredClassName: React.PropTypes.string,
/**
- * A css class or classes applied while the Component is entering.
+ * CSS class or classes applied while the component is entering
*/
enteringClassName: React.PropTypes.string,
/**
- * A function that returns the DOM node to animate. This Node will have the transition classes applied to it.
- * When left out, the Component will use its immediate child.
- *
- * @private
- */
- transitioningNode: React.PropTypes.func,
-
- /**
- * A callback fired just before the "entering" classes are applied
+ * Callback fired before the "entering" classes are applied
*/
- onEnter: React.PropTypes.func,
+ onEnter: React.PropTypes.func,
/**
- * A callback fired just after the "entering" classes are applied
+ * Callback fired after the "entering" classes are applied
*/
- onEntering: React.PropTypes.func,
+ onEntering: React.PropTypes.func,
/**
- * A callback fired after "enter" classes are applied
+ * Callback fired after the "enter" classes are applied
*/
- onEntered: React.PropTypes.func,
+ onEntered: React.PropTypes.func,
/**
- * A callback fired after "exiting" classes are applied
+ * Callback fired before the "exiting" classes are applied
*/
- onExit: React.PropTypes.func,
+ onExit: React.PropTypes.func,
/**
- * A callback fired after "exiting" classes are applied
+ * Callback fired after the "exiting" classes are applied
*/
- onExiting: React.PropTypes.func,
+ onExiting: React.PropTypes.func,
/**
- * A callback fired after "exit" classes are applied
+ * Callback fired after the "exited" classes are applied
*/
- onExited: React.PropTypes.func
+ onExited: React.PropTypes.func
};
-// name the function so it is clearer in the documentation
-const noop = ()=>{};
+// Name the function so it is clearer in the documentation
+function noop() {}
Transition.defaultProps = {
- in: false,
+ in: false,
duration: 300,
unmountOnExit: false,
transitionAppear: false,
- transitioningNode: noop,
- onEnter: noop,
+ onEnter: noop,
onEntering: noop,
- onEntered: noop,
+ onEntered: noop,
- onExit: noop,
- onExiting: noop,
- onExited: noop
+ onExit: noop,
+ onExiting: noop,
+ onExited: noop
};
export default Transition;
diff --git a/test/TransitionSpec.js b/test/TransitionSpec.js
index 7945ba8ceb..ced505b537 100644
--- a/test/TransitionSpec.js
+++ b/test/TransitionSpec.js
@@ -1,12 +1,10 @@
import React from 'react';
import ReactTestUtils from 'react/lib/ReactTestUtils';
import { render } from './helpers';
-import Transition from '../src/Transition';
-//import classNames from 'classnames';
+import Transition, {EXITED, ENTERING, ENTERED, EXITING} from
+ '../src/Transition';
describe('Transition', function () {
-
-
it('should not transition on mount', function(){
let instance = render(
{ throw new Error('should not Enter'); }}>
@@ -14,8 +12,7 @@ describe('Transition', function () {
);
- instance.state.in.should.equal(true);
- assert.ok(!instance.state.transitioning);
+ instance.state.status.should.equal(ENTERED);
});
it('should transition on mount with transitionAppear', done =>{
@@ -28,8 +25,7 @@ describe('Transition', function () {
);
- instance.state.in.should.equal(true);
- instance.state.transitioning.should.equal(true);
+ instance.state.status.should.equal(EXITED);
});
describe('entering', ()=> {
@@ -51,10 +47,9 @@ describe('Transition', function () {
let onEnter = sinon.spy();
let onEntering = sinon.spy();
- instance.state.in.should.equal(false);
+ instance.state.status.should.equal(EXITED);
instance = instance.renderWithProps({
-
in: true,
onEnter,
@@ -73,27 +68,23 @@ describe('Transition', function () {
it('should move to each transition state', done => {
let count = 0;
- instance.state.in.should.equal(false);
+ instance.state.status.should.equal(EXITED);
instance = instance.renderWithProps({
-
in: true,
onEnter(){
count++;
- instance.state.in.should.equal(false);
- instance.state.transitioning.should.equal(false);
+ instance.state.status.should.equal(EXITED);
},
onEntering(){
count++;
- instance.state.in.should.equal(true);
- instance.state.transitioning.should.equal(true);
+ instance.state.status.should.equal(ENTERING);
},
onEntered(){
- instance.state.in.should.equal(true);
- instance.state.transitioning.should.equal(false);
+ instance.state.status.should.equal(ENTERED);
assert.ok(count === 2);
done();
}
@@ -103,10 +94,9 @@ describe('Transition', function () {
it('should apply classes at each transition state', done => {
let count = 0;
- instance.state.in.should.equal(false);
+ instance.state.status.should.equal(EXITED);
instance = instance.renderWithProps({
-
in: true,
onEnter(node){
@@ -126,10 +116,8 @@ describe('Transition', function () {
}
});
});
-
});
-
describe('exiting', ()=> {
let instance;
@@ -150,10 +138,9 @@ describe('Transition', function () {
let onExit = sinon.spy();
let onExiting = sinon.spy();
- instance.state.in.should.equal(true);
+ instance.state.status.should.equal(ENTERED);
instance = instance.renderWithProps({
-
in: false,
onExit,
@@ -172,27 +159,23 @@ describe('Transition', function () {
it('should move to each transition state', done => {
let count = 0;
- instance.state.in.should.equal(true);
+ instance.state.status.should.equal(ENTERED);
instance = instance.renderWithProps({
-
in: false,
onExit(){
count++;
- instance.state.in.should.equal(true);
- instance.state.transitioning.should.equal(false);
+ instance.state.status.should.equal(ENTERED);
},
onExiting(){
count++;
- instance.state.in.should.equal(false);
- instance.state.transitioning.should.equal(true);
+ instance.state.status.should.equal(EXITING);
},
onExited(){
- instance.state.in.should.equal(false);
- instance.state.transitioning.should.equal(false);
+ instance.state.status.should.equal(EXITED);
//assert.ok(count === 2);
done();
}
@@ -202,10 +185,9 @@ describe('Transition', function () {
it('should apply classes at each transition state', done => {
let count = 0;
- instance.state.in.should.equal(true);
+ instance.state.status.should.equal(ENTERED);
instance = instance.renderWithProps({
-
in: false,
onExit(node){
@@ -225,7 +207,5 @@ describe('Transition', function () {
}
});
});
-
});
-
});