{ "name": "sliding-number", "type": "registry:ui", "registryDependencies": [], "dependencies": [ "motion", "react-use-measure" ], "devDependencies": [], "tailwind": {}, "cssVars": { "light": {}, "dark": {} }, "files": [ { "path": "sliding-number.tsx", "content": "'use client';\nimport { useEffect, useId } from 'react';\nimport {\n MotionValue,\n motion,\n useSpring,\n useTransform,\n motionValue,\n} from 'motion/react';\nimport useMeasure from 'react-use-measure';\n\nconst TRANSITION = {\n type: 'spring',\n stiffness: 280,\n damping: 18,\n mass: 0.3,\n};\n\nfunction Digit({ value, place }: { value: number; place: number }) {\n const valueRoundedToPlace = Math.floor(value / place) % 10;\n const initial = motionValue(valueRoundedToPlace);\n const animatedValue = useSpring(initial, TRANSITION);\n\n useEffect(() => {\n animatedValue.set(valueRoundedToPlace);\n }, [animatedValue, valueRoundedToPlace]);\n\n return (\n
\n
0
\n {Array.from({ length: 10 }, (_, i) => (\n \n ))}\n
\n );\n}\n\nfunction Number({ mv, number }: { mv: MotionValue; number: number }) {\n const uniqueId = useId();\n const [ref, bounds] = useMeasure();\n\n const y = useTransform(mv, (latest) => {\n if (!bounds.height) return 0;\n const placeValue = latest % 10;\n const offset = (10 + number - placeValue) % 10;\n let memo = offset * bounds.height;\n\n if (offset > 5) {\n memo -= 10 * bounds.height;\n }\n\n return memo;\n });\n\n // don't render the animated number until we know the height\n if (!bounds.height) {\n return (\n \n {number}\n \n );\n }\n\n return (\n \n {number}\n \n );\n}\n\ntype SlidingNumberProps = {\n value: number;\n padStart?: boolean;\n decimalSeparator?: string;\n};\n\nexport function SlidingNumber({\n value,\n padStart = false,\n decimalSeparator = '.',\n}: SlidingNumberProps) {\n const absValue = Math.abs(value);\n const [integerPart, decimalPart] = absValue.toString().split('.');\n const integerValue = parseInt(integerPart, 10);\n const paddedInteger =\n padStart && integerValue < 10 ? `0${integerPart}` : integerPart;\n const integerDigits = paddedInteger.split('');\n const integerPlaces = integerDigits.map((_, i) =>\n Math.pow(10, integerDigits.length - i - 1)\n );\n\n return (\n
\n {value < 0 && '-'}\n {integerDigits.map((_, index) => (\n \n ))}\n {decimalPart && (\n <>\n {decimalSeparator}\n {decimalPart.split('').map((_, index) => (\n \n ))}\n \n )}\n
\n );\n}\n", "type": "registry:ui" } ] }