UNPKG

react-animated-numbers

Version:

Library showing animation of number changes in react.js

113 lines (112 loc) 5.82 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); const react_1 = __importStar(require("react")); const react_2 = require("motion/react"); const generateRandomSequence = (target, length = 40) => { const base = Array.from({ length: length - 1 }, () => Math.floor(Math.random() * 10)); return [...base, target]; }; const AnimatedNumber = ({ className, animateToNumber, fontStyle, transitions, useThousandsSeparator = false, locale = "en-US", }) => { const wrapperRef = (0, react_1.useRef)(null); const numberRef = (0, react_1.useRef)(null); const isInView = (0, react_2.useInView)(wrapperRef, { once: false }); const controls = (0, react_2.useAnimation)(); const [numberHeight, setNumberHeight] = (0, react_1.useState)(0); const [numberWidth, setNumberWidth] = (0, react_1.useState)(0); const [randomSequences, setRandomSequences] = (0, react_1.useState)([]); const animateNumberStr = useThousandsSeparator ? Math.abs(animateToNumber).toLocaleString(locale) : String(Math.abs(animateToNumber)); (0, react_1.useEffect)(() => { const animateDigits = Array.from(animateNumberStr).map((char) => /\d/.test(char) ? Number(char) : char); const newSeq = animateDigits.map((digit) => typeof digit === "number" ? generateRandomSequence(digit) : digit); setRandomSequences(newSeq); }, [animateNumberStr]); (0, react_1.useEffect)(() => { if (!numberRef.current) return; const observer = new ResizeObserver((entries) => { for (const entry of entries) { const { height, width } = entry.contentRect; setNumberHeight(height); setNumberWidth(width); } }); observer.observe(numberRef.current); return () => observer.disconnect(); }, [fontStyle]); (0, react_1.useEffect)(() => { if (isInView) { controls.start("visible"); } }, [controls, isInView, randomSequences]); return (react_1.default.createElement("span", { ref: wrapperRef, style: { position: "relative", display: "inline-block" } }, numberHeight > 0 && (react_1.default.createElement("div", { className: className, style: { display: "flex", overflow: "hidden", flexDirection: "row", position: "relative", } }, randomSequences.map((seq, index) => { var _a; if (typeof seq === "string") { return (react_1.default.createElement("div", { key: `static-${index}`, style: Object.assign(Object.assign({}, fontStyle), { fontVariantNumeric: "tabular-nums", width: numberWidth, textAlign: "center" }) }, seq)); } return (react_1.default.createElement(react_2.motion.div, { key: `motion-${index}-${animateToNumber}`, initial: { y: 0 }, animate: { y: -1 * numberHeight * (seq.length - 1) }, transition: (_a = transitions === null || transitions === void 0 ? void 0 : transitions(index)) !== null && _a !== void 0 ? _a : { duration: 1.8 + index * 0.1, ease: [0.25, 0.1, 0.25, 1], }, style: { height: numberHeight, width: numberWidth, position: "relative", } }, seq.map((num, i) => { const isTarget = i === seq.length - 1; return (react_1.default.createElement(react_2.motion.div, { key: `digit-${index}-${i}`, style: Object.assign(Object.assign({}, fontStyle), { fontVariantNumeric: "tabular-nums", height: numberHeight, textAlign: "center", opacity: isTarget ? 1 : 0.2, scale: isTarget ? 1 : 0.9 }), animate: isTarget ? { scale: [1.2, 1], opacity: [0.6, 1], } : {}, transition: isTarget ? { duration: 0.4, delay: 1.8 + index * 0.1, ease: "easeOut", } : {} }, num)); }))); }))), react_1.default.createElement("div", { ref: numberRef, style: Object.assign(Object.assign({ position: "absolute", top: -9999, visibility: "hidden" }, fontStyle), { fontVariantNumeric: "tabular-nums" }) }, "0"))); }; exports.default = AnimatedNumber;