Projeto Framer animations

Projeto Framer animations

Projeto Framer animations

Number counter

Number counter

Copie o código e siga as instruções da aula.
import React, { useState, useEffect } from "react"
import { motion } from "framer-motion"
import { addPropertyControls, ControlType } from "framer"

const NumberCounterStyles = {
    display: "flex",
    justifyContent: "left",
    alignItems: "left",
}

export function NumberCounter(props) {
    const {
        startNumber,
        endNumber,
        speed,
        prefix,
        suffix,
        loop,
        decimalSeparator,
        fontSize,
        font,
        fontColor, // Add fontColor property
    } = props

    const [count, setCount] = useState(startNumber)
    const [isVisible, setIsVisible] = useState(false)
    const ref = React.useRef(null)

    useEffect(() => {
        const observer = new IntersectionObserver((entries) => {
            const entry = entries[0]
            setIsVisible(entry.isIntersecting)
        })

        if (ref.current) {
            observer.observe(ref.current)
        }

        return () => {
            if (ref.current) {
                observer.unobserve(ref.current)
            }
        }
    }, [])

    useEffect(() => {
        if (isVisible && startNumber !== endNumber) {
            const intervalId = setInterval(() => {
                if (count < endNumber) {
                    setCount((prevCount) => prevCount + 1)
                } else if (loop) {
                    setCount(startNumber)
                }
            }, speed)

            return () => {
                clearInterval(intervalId)
            }
        }
    }, [count, startNumber, endNumber, loop, isVisible])

    const formatCount = (number) => {
        if (decimalSeparator === "comma") {
            return number.toLocaleString("en-US")
        } else if (decimalSeparator === "period") {
            return number.toLocaleString("en-US").replace(/,/g, ".")
        } else {
            return number.toFixed(0)
        }
    }

    return (
        <motion.div
            ref={ref}
            style={{
                ...NumberCounterStyles,
                gap: `${fontSize / 2}px`, // Adjust gap size based on font size
                flexDirection: "row",
                alignItems: "left",
                fontSize: `${fontSize}px`,
                fontFamily: font.fontFamily, // Use the selected font family
                fontWeight: font.fontWeight, // Use the selected font weight
                color: fontColor, // Apply the selected font color
            }}
        >
            {prefix}
            {formatCount(count)}
            {suffix}
        </motion.div>
    )
}

NumberCounter.defaultProps = {
    startNumber: 0,
    endNumber: 10,
    speed: 100,
    prefix: "",
    suffix: "",
    loop: false,
    decimalSeparator: "comma",
    fontSize: 16,
    font: {
        fontFamily: "Arial",
        fontWeight: 400,
        systemFont: true,
    }, // Default font
    fontColor: "#707070", // Default font color
}

addPropertyControls(NumberCounter, {
    font: {
        title: "Font",
        type: ControlType.Font,
        defaultValue: {
            fontFamily: "Arial",
            fontWeight: 400,
            systemFont: true,
        }, // Set default font family and weight
    },
    fontSize: {
        title: "Font Size",
        type: ControlType.Number,
        min: 8,
        max: 200,
        step: 1,
    },
    fontColor: {
        type: ControlType.Color, // Add font color property
        title: "Font Color",
    },
    startNumber: {
        type: ControlType.Number,
        title: "Start Number",
        defaultValue: 0,
        displayStepper: true,
    },
    endNumber: {
        type: ControlType.Number,
        title: "End Number",
        defaultValue: 0,
        displayStepper: true,
    },
    decimalSeparator: {
        type: ControlType.Enum,
        title: "Decimal Separator",
        defaultValue: "comma",
        options: ["comma", "period", "none"],
        optionTitles: ["Comma (1,000)", "Period (1.000)", "None"],
    },
    speed: {
        type: ControlType.Number,
        title: "Speed (ms)",
        defaultValue: 120,
        min: 0,
        max: 1000,
        step: 10,
    },
    prefix: {
        type: ControlType.String,
        title: "Prefix",
        defaultValue: "",
    },
    suffix: {
        type: ControlType.String,
        title: "Suffix",
        defaultValue: "",
    },
    loop: {
        type: ControlType.Boolean,
        title: "Loop Animation",
        defaultValue: false,
        enabledTitle: "On",
        disabledTitle: "Off",
    },
})

Curso de Framer • Lucas Marte UX
©2025 • Todos os direitos reservados

Curso de Framer • Lucas Marte UX
©2025 • Todos os direitos reservados

Curso de Framer • Lucas Marte UX
©2025 • Todos os direitos reservados