Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A component for doing child transitions using Velocity.js
// Velocity Animate
// ================
//
// Inspired by https://gist.github.com/tkafka/0d94c6ec94297bb67091.
//
// Extend so it supports:
//
// 1) A transition object in the same format as the ones in the library below,
// directly to the component. Example:
//
// let customTransition = {
// duration: 1500,
// enter: {
// scale: [ 0.5, 1 ],
// opacity: [0, 1 ]
// },
// leave: {
// scale: [ 1, 1.25 ],
// opacity: [ 1, 0 ]
// }
// }
// …
// return <VelocityTransitionGroup transition={customTransition}>…
//
// 2) Transition objects accept queued transforms. Example:
//
// let customTransition = {
// duration: 1500,
// enter: [ { scale: [ 0.5, 1 ] }, { opacity: [ 0, 1 ] } ],
// leave: [ { scale: [ 1, 0.5 ] }, { opacity: [ 1, 0 ] } ]
// }
//
// Note that for queued transitions, the duration parameter will be split among
// the queue, so that means the total duration of all transitions.
import React from 'react'
import Velocity from 'velocity-animate'
import Animate from 'rc-animate'
const transitions = {
'slide-forward': {
duration: 500,
enter: {
translateX: [ '0%', '100%' ]
},
leave: {
translateX: [ '-100%', '0%' ]
}
},
'slide-back': {
duration: 500,
enter: {
translateX: [ '0%', '-100%' ]
},
leave: {
translateX: [ '100%', '0%' ]
}
},
'slideover-forward': {
duration: 500,
enter: {
translateX: [ '0%', '100%' ],
zIndex: [ 1, 1 ]
},
leave: {
zIndex: [ 0, 0 ]
}
},
'slideover-back': {
duration: 500,
enter: {
zIndex: [ 0, 0 ]
},
leave: {
translateX: [ '100%', '0%' ],
zIndex: [ 1, 1 ]
}
},
'default': {
duration: 2000,
enter: {
opacity: [ 1, 0 ]
},
leave: {
opacity: [ 0, 1 ]
}
}
}
let resolveTransition = function(transition) {
if (typeof transition !== 'string') return transition
return transitions[transition]
}
let validateTransition = function(transition) {
if (typeof transition === 'string' && !transitions[transition]) {
throw new Error(
`VelocityAnimate: Transition ${transition} not found in library`
)
}
if (
typeof transition === 'object' &&
(!transition.duration || !transition.enter || !transition.leave)
) {
throw new Error(
'VelocityAnimate: object missing duration, enter, or leave key'
)
}
}
export default class VelocityAnimate extends React.Component {
getTransition() {
validateTransition(this.props.transition)
return resolveTransition(this.props.transition)
}
render() {
return <Animate
component={this.props.component}
exclusive={this.props.exclusive}
className={this.props.className}
animation={{
enter: this.animateEnter.bind(this),
leave: this.animateLeave.bind(this)
}}>
{this.props.children}
</Animate>
}
animateEnter(node, callback) {
let transition = this.getTransition()
if (!Array.isArray(transition.enter)) transition.enter = [transition.enter]
transition.enter.forEach((transform, index) => {
let options = { duration: transition.duration / transition.enter.length, queue: false }
if (index === transition.enter.length - 1) options.complete = callback
Velocity(node, transform, options)
})
return { stop: () => { Velocity(node, 'stop') }}
}
animateLeave(node, callback) {
let transition = this.getTransition()
if (!Array.isArray(transition.leave)) transition.leave = [transition.leave]
transition.leave.forEach((transform, index) => {
let options = { duration: transition.duration / transition.leave.length, queue: false }
if (index === transition.leave.length - 1) options.complete = callback
Velocity(node, transform, options)
})
return { stop: () => { Velocity(node, 'stop') }}
}
}
VelocityAnimate.propTypes = {
component: React.PropTypes.string,
className: React.PropTypes.string,
exclusive: React.PropTypes.bool,
transition: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.object
])
}
VelocityAnimate.defaultProps = {
component: 'div',
exclusive: false,
transition: 'default'
}
@yiminghe
Copy link

yiminghe commented Jul 29, 2015

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment