Animation » Example Animations » 29. Cycling parent and child variants

29. Cycling parent and child variants

Another example of automatic animation propagation with variants, here in combination with an useCycle().

Code component

export default function CC_29_Cycling_parent_and_child_variants(props) {
    const [current, cycle] = useCycle("off", "on")

    return (
        <motion.div
            style={{
                width: 51,
                height: 31,
                borderRadius: 16,
                backgroundColor: "rgba(120,120,128,.16)",
                position: "relative",
                cursor: "pointer",
            }}
            animate={current}
            initial={false}
            onTapStart={cycle}
        >
            <motion.div
                style={{
                    width: "100%",
                    height: "100%",
                    borderRadius: 16,
                    backgroundColor: "#34C759",
                }}
                variants={{ off: { scale: 0 }, on: { scale: 1 } }}
                transition={{ ease: "easeInOut" }}
            />
            <motion.div
                style={{
                    width: 27,
                    height: 27,
                    borderRadius: 16,
                    backgroundColor: "white",
                    boxShadow: `0 0 0 0.5px rgba(0,0,0,.04), 
                         0 3px 8px 0 rgba(0,0,0,.15), 
                         0 3px 1px 0 rgba(0,0,0,.06)`,
                    position: "absolute",
                    top: 2,
                    left: 2,
                }}
                variants={{ off: { x: 0 }, on: { x: 20 } }}
                transition={{ ease: "easeInOut" }}
            />
        </motion.div>
    )
}

Code overrides

When you tap the Switch(), it does a cycle() to the next variant label. And the children (Background() and Knob() overrides) will follow along, just because they have the same variant labels: "off" and "on".

Note that the override for the parent frame, Switch(), doesn’t even have an animation.

By the way, I used the onTapStart() event, so that the animation already starts when you press down.

export const Switch = (Component): ComponentType => {
    return (props) => {
        const [current, cycle] = useCycle("off", "on")

        return (
            <Component
                {...props}
                initial={false}
                animate={current}
                onTapStart={cycle}
            />
        )
    }
}

export const Background = (Component): ComponentType => {
    return (props) => {
        return (
            <Component
                {...props}
                variants={{ off: { scale: 0 }, on: { scale: 1 } }}
                transition={{ ease: "easeInOut" }}
            />
        )
    }
}

export const Knob = (Component): ComponentType => {
    return (props) => {
        return (
            <Component
                {...props}
                variants={{ off: { x: 0 }, on: { x: 20 } }}
                transition={{ ease: "easeInOut" }}
            />
        )
    }
}

Leave a Reply