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