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 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 function Switch(Component): ComponentType {
    return (props) => {
        const [current, cycle] = useCycle("off", "on")

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

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

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

Leave a Reply