All files / animations/generators keyframes.ts

100% Statements 26/26
83.33% Branches 15/18
100% Functions 10/10
100% Lines 21/21

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67            57x       23x 23x 52x         46x       20x 20x 20x 20x 20x           20x         20x         20x           23x         20x   20x   187x 187x 187x     3x 3x        
import { Animation, AnimationState, KeyframeOptions } from "../types"
import { interpolate } from "../../utils/interpolate"
import { Easing } from "../../easing/types"
import { easeInOut } from "../../easing"
 
export function defaultEasing(values: any[], easing?: Easing): Easing[] {
    return values.map(() => easing || easeInOut).splice(0, values.length - 1)
}
 
export function defaultOffset(values: any[]): number[] {
    const numValues = values.length
    return values.map((_value: number, i: number): number =>
        i !== 0 ? i / (numValues - 1) : 0
    )
}
 
export function convertOffsetToTimes(offset: number[], duration: number) {
    return offset.map((o) => o * duration)
}
 
export function keyframes<V>({
    from = 0,
    to = 1,
    ease,
    offset,
    duration = 300,
}: KeyframeOptions): Animation<number | string> {
    /**
     * This is the Iterator-spec return value. We ensure it's mutable rather than using a generator
     * to reduce GC during animation.
     */
    const state: AnimationState<typeof from> = { done: false, value: from }
 
    /**
     * Convert values to an array if they've been given as from/to options
     */
    const values = Array.isArray(to) ? to : [from, to]
 
    /**
     * Create a times array based on the provided 0-1 offsets
     */
    const times = convertOffsetToTimes(
        offset ?? defaultOffset(values),
        duration
    )
 
    function createInterpolator() {
        return interpolate(times, values, {
            ease: Array.isArray(ease) ? ease : defaultEasing(values, ease),
        })
    }
 
    let interpolator = createInterpolator()
 
    return {
        next: (t: number) => {
            state.value = interpolator(t)
            state.done = t >= duration
            return state
        },
        flipTarget: () => {
            values.reverse()
            interpolator = createInterpolator()
        },
    }
}