react-addons
Version:
Simple packaging of react addons to avoid fiddly 'react/addons' npm module.
139 lines (111 loc) • 3.83 kB
JavaScript
/**
* Copyright 2013-2014 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @typechecks
* @providesModule ReactCSSTransitionGroupChild
*/
"use strict";
var React = require("react");
var CSSCore = require("./CSSCore");
var ReactTransitionEvents = require("./ReactTransitionEvents");
var onlyChild = require("./onlyChild");
// We don't remove the element from the DOM until we receive an animationend or
// transitionend event. If the user screws up and forgets to add an animation
// their node will be stuck in the DOM forever, so we detect if an animation
// does not start and if it doesn't, we just call the end listener immediately.
var TICK = 17;
var NO_EVENT_TIMEOUT = 5000;
var noEventListener = null;
if ("production" !== process.env.NODE_ENV) {
noEventListener = function() {
console.warn(
'transition(): tried to perform an animation without ' +
'an animationend or transitionend event after timeout (' +
NO_EVENT_TIMEOUT + 'ms). You should either disable this ' +
'transition in JS or add a CSS animation/transition.'
);
};
}
var ReactCSSTransitionGroupChild = React.createClass({
transition: function(animationType, finishCallback) {
var node = this.getDOMNode();
var className = this.props.name + '-' + animationType;
var activeClassName = className + '-active';
var noEventTimeout = null;
var endListener = function() {
if ("production" !== process.env.NODE_ENV) {
clearTimeout(noEventTimeout);
}
CSSCore.removeClass(node, className);
CSSCore.removeClass(node, activeClassName);
ReactTransitionEvents.removeEndEventListener(node, endListener);
// Usually this optional callback is used for informing an owner of
// a leave animation and telling it to remove the child.
finishCallback && finishCallback();
};
ReactTransitionEvents.addEndEventListener(node, endListener);
CSSCore.addClass(node, className);
// Need to do this to actually trigger a transition.
this.queueClass(activeClassName);
if ("production" !== process.env.NODE_ENV) {
noEventTimeout = setTimeout(noEventListener, NO_EVENT_TIMEOUT);
}
},
queueClass: function(className) {
this.classNameQueue.push(className);
if (this.props.runNextTick) {
this.props.runNextTick(this.flushClassNameQueue);
return;
}
if (!this.timeout) {
this.timeout = setTimeout(this.flushClassNameQueue, TICK);
}
},
flushClassNameQueue: function() {
if (this.isMounted()) {
this.classNameQueue.forEach(
CSSCore.addClass.bind(CSSCore, this.getDOMNode())
);
}
this.classNameQueue.length = 0;
this.timeout = null;
},
componentWillMount: function() {
this.classNameQueue = [];
},
componentWillUnmount: function() {
if (this.timeout) {
clearTimeout(this.timeout);
}
},
componentWillEnter: function(done) {
if (this.props.enter) {
this.transition('enter', done);
} else {
done();
}
},
componentWillLeave: function(done) {
if (this.props.leave) {
this.transition('leave', done);
} else {
done();
}
},
render: function() {
return onlyChild(this.props.children);
}
});
module.exports = ReactCSSTransitionGroupChild;