|
var ReactTransitionGroup = React.addons.TransitionGroup; |
|
|
|
var AnimationItem = React.createClass({ |
|
componentWillEnter: function(done) { |
|
this.el = this.getDOMNode(); |
|
this.$el = $(this.el); |
|
// Before state applied immediately |
|
this.$el.addClass(this.props.prefix+"-enter-before"); |
|
// Ensure parent class changes propagate in time |
|
requestAnimationFrame(function() { |
|
this.$el |
|
.removeClass(this.props.prefix+"-enter-before") |
|
.addClass(this.props.prefix+"-enter"); |
|
|
|
requestAnimationFrame(function() { |
|
getComputedStyle(this.el); |
|
this.$el.addClass(this.props.prefix+"-enter-active"); |
|
Arrival.complete(this.$el, done); |
|
}.bind(this)); |
|
}.bind(this)); |
|
}, |
|
componentDidEnter: function() { |
|
this.$el |
|
.removeClass(this.props.prefix+"-enter") |
|
.removeClass(this.props.prefix+"-enter-active"); |
|
}, |
|
componentWillLeave: function(done) { |
|
this.el = this.getDOMNode(); |
|
this.$el = $(this.el); |
|
// Before state applied immediately |
|
this.$el.addClass(this.props.prefix+"-leave-before"); |
|
requestAnimationFrame(function() { |
|
this.$el |
|
.removeClass(this.props.prefix+"-leave-before") |
|
.addClass(this.props.prefix+"-leave"); |
|
requestAnimationFrame(function() { |
|
this.$el.addClass(this.props.prefix+"-leave-active"); |
|
Arrival.complete(this.$el, done); |
|
}.bind(this)); |
|
}.bind(this)); |
|
}, |
|
componentDidLeave: function() { |
|
this.$el |
|
.removeClass(this.props.prefix+"-leave") |
|
.removeClass(this.props.prefix+"-leave-active"); |
|
}, |
|
render: function() { |
|
return ( |
|
React.DOM.div( |
|
{className: "animation-item", key: this.props.key}, |
|
this.props.children |
|
) |
|
) |
|
} |
|
}); |
|
|
|
|
|
var TodoList = React.createClass({ |
|
getInitialState: function() { |
|
return {items: ['Hello', 'World', 'Click', 'Me']}; |
|
}, |
|
handleAdd: function() { |
|
var newItems = |
|
this.state.items.concat([prompt('Enter some text')]); |
|
this.setState({items: newItems}); |
|
}, |
|
handleRemove: function(i) { |
|
var newItems = this.state.items; |
|
newItems.splice(i, 1); |
|
this.setState({items: newItems}); |
|
}, |
|
render: function() { |
|
var items = this.state.items.map(function(item, i) { |
|
var element = React.DOM.div( |
|
{ key: item, className: "item", onClick: this.handleRemove.bind(this, i) }, |
|
item |
|
); |
|
return ( |
|
AnimationItem({key: "example-"+item, prefix: "example"}, element) |
|
); |
|
}.bind(this)); |
|
return ( |
|
React.DOM.div( |
|
null, |
|
React.DOM.div( |
|
null, |
|
React.DOM.button({onClick: this.handleAdd}, "Add item") |
|
), |
|
ReactTransitionGroup( |
|
null, |
|
items |
|
) |
|
) |
|
); |
|
} |
|
}); |
|
|
|
React.renderComponent( |
|
TodoList(), |
|
document.getElementById('list') |
|
); |
|
|
|
|
|
|
|
|
|
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/ |
|
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating |
|
|
|
// requestAnimationFrame polyfill by Erik Möller |
|
// fixes from Paul Irish and Tino Zijdel |
|
|
|
(function() { |
|
var lastTime = 0; |
|
var vendors = ['ms', 'moz', 'webkit', 'o']; |
|
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { |
|
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; |
|
window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] |
|
|| window[vendors[x]+'CancelRequestAnimationFrame']; |
|
} |
|
|
|
if (!window.requestAnimationFrame) |
|
window.requestAnimationFrame = function(callback, element) { |
|
var currTime = new Date().getTime(); |
|
var timeToCall = Math.max(0, 16 - (currTime - lastTime)); |
|
var id = window.setTimeout(function() { callback(currTime + timeToCall); }, |
|
timeToCall); |
|
lastTime = currTime + timeToCall; |
|
return id; |
|
}; |
|
|
|
if (!window.cancelAnimationFrame) |
|
window.cancelAnimationFrame = function(id) { |
|
clearTimeout(id); |
|
}; |
|
}()); |