ldx-widgets
Version:
widgets
117 lines (84 loc) • 4.06 kB
text/coffeescript
Animation = require 'ainojs-animation'
easing = require 'ainojs-easing'
_ = require 'lodash'
###
Purpose: Easily add Enter and Leave animations to a React Component (that is a child of React's TransitionGroup)
The react component must have these properties for an Enter Animation
initialState: object - Only required when there are additional states to those being animated
The initial state of the component, which will have animated properties mixed in
Note: getInitialState on your component is overwritten by this mixin
ENTER ANIMATION PROPS
enterDuration: number (millisecoinds), defaults to 300
enterStateStart: object, required, no default
enterStateEnd: object, required, no default
enterEasing: string, defaults to 'linear' (ainojs-easing function name: https://github.com/aino/ainojs-easing)
LEAVE ANIMATION PROPS
leaveDuration: number (millisecoinds), defaults to 300
leaveStateStart: object, required, no default
leaveStateEnd: object, required, no default
leaveEasing: string, defaults to 'linear' (ainojs-easing function name: https://github.com/aino/ainojs-easing)
finaally, the @state properties must be applied as inline styles in the component's render method
###
module.exports =
getInitialState: ->
enterStateStart = @enterStateStart?() or @enterStateStart
leaveStateStart = @leaveStateStart?() or @leaveStateStart
_.extend(@initialState or {}, enterStateStart or leaveStateStart or {})
componentWillEnter: (done) ->
unless @enterStateStart? and @enterStateEnd?
done()
return
@animation = new Animation {
duration: @enterDuration or 300
easing: easing(@enterEasing or 'linear')
}
enterStateStart = @enterStateStart?() or @enterStateStart
enterStateEnd = @enterStateEnd?() or @enterStateEnd
# Note: need to clone here so animate class does not alter initial values
stateStart = _.clone(enterStateStart)
# Note: Not feeding init @state directly, because that will clobber @state properties not being animated
@animation.init stateStart
@animation.on('frame', @onFrame)
@animation.on('complete', done)
@animation.animateTo enterStateEnd
componentWillLeave: (done) ->
unless @leaveStateEnd?
done()
return
@animation = new Animation {
duration: @leaveDuration or 300
easing: easing(@leaveEasing or 'linear')
}
leaveStateStart = @leaveStateStart?() or @leaveStateStart
leaveStateEnd = @leaveStateEnd?() or @leaveStateEnd
if not leaveStateStart?
leaveStateStart = {}
leaveStateStart[k] = @state[k] for k,v of leaveStateEnd
# Note: need to clone here so animate class does not alter initial values
stateStart = _.clone(leaveStateStart)
# Note: Not feeding init method @state directly because that will clobber @state properties not being animated
@animation.init stateStart
@animation.on('frame', @onFrame)
@animation.on('complete', done)
@animation.animateTo leaveStateEnd
componentWillUnmount: -> if @animation?.isAnimating() then @animation.destroy()
# For us with the transition_out mixin, allows for navigation to be delyated until animation completes
#componentDidLeave: ->
# @props.completeNavigation?()
# @completeNavigation?()
onFrame: (e) ->
if @isMounted() then @setState e.values
animateStateTo: (options) ->
{newState, duration, easingType, cb} = options
@animation = new Animation
duration: duration or @enterDuration or 300
easing: easing(easingType or @enterEasing or 'linear')
# Pull the values to animate out of state to get the starting position
stateStart = {}
for k,v of newState
return console?.warn "State: #{k} must be in component state to be animated" unless @state[k]?
stateStart[k] = @state[k]
@animation.init stateStart
@animation.on 'frame', @onFrame
@animation.on 'complete', -> cb?()
@animation.animateTo newState