{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "statscount",
  "type": "registry:ui",
  "title": "StatsCount",
  "description": "Animated statistics counter with responsive layout and scroll triggers.",
  "author": "Ahdeetai <https://aditya.is-cool.dev>",
  "registryDependencies": [],
  "dependencies": ["motion", "clsx", "tailwind-merge"],
  "files": [
    {
      "type": "registry:ui",
      "path": "components/ui/statscount.tsx",
      "content": "'use client';\n\nimport { useEffect, useRef, useState } from 'react';\nimport {\n  motion,\n  useMotionValue,\n  useSpring,\n  useTransform,\n  useInView,\n} from 'motion/react';\nimport { cn } from '@/lib/utils';\n\ninterface StatItem {\n  value: number;\n  suffix?: string;\n  label: string;\n  duration?: number;\n}\n\ninterface StatsCountProps {\n  stats?: StatItem[];\n  title?: string;\n  showDividers?: boolean;\n  className?: string;\n}\n\nconst defaultStats: StatItem[] = [\n  {\n    value: 50,\n    suffix: '+',\n    label: 'Handcrafted animated components',\n    duration: 5,\n  },\n  {\n    value: 12,\n    suffix: 'K+',\n    label: 'Developers building with ScrollX-UI',\n    duration: 6,\n  },\n  {\n    value: 99,\n    suffix: '%',\n    label: 'Performance optimized for web',\n    duration: 5.5,\n  },\n];\n\nconst defaultTitle = 'CREATE STUNNING INTERFACES WITH SCROLLX-UI COMPONENTS';\n\nfunction AnimatedCounter({\n  value,\n  suffix = '',\n  duration = 1,\n  delay = 0,\n  label,\n}: {\n  value: number;\n  suffix?: string;\n  duration?: number;\n  delay?: number;\n  label: string;\n}) {\n  const ref = useRef<HTMLDivElement>(null);\n  const isInView = useInView(ref, { margin: '-50px' });\n\n  const motionValue = useMotionValue(0);\n  const springValue = useSpring(motionValue, {\n    damping: 20,\n    stiffness: 50,\n    mass: 1,\n  });\n\n  const rounded = useTransform(springValue, (latest) =>\n    Number(latest.toFixed(value % 1 === 0 ? 0 : 1)),\n  );\n\n  const [displayValue, setDisplayValue] = useState(0);\n\n  useEffect(() => {\n    const unsubscribe = rounded.on('change', (latest) => {\n      setDisplayValue(latest);\n    });\n    return () => unsubscribe();\n  }, [rounded]);\n\n  useEffect(() => {\n    let timeout: NodeJS.Timeout;\n    if (isInView) {\n      motionValue.set(0);\n      timeout = setTimeout(() => {\n        motionValue.set(value);\n      }, delay * 300);\n    } else {\n      motionValue.set(0);\n    }\n    return () => clearTimeout(timeout);\n  }, [isInView, value, motionValue, delay]);\n\n  return (\n    <motion.div\n      ref={ref}\n      initial={{ opacity: 0, y: 30 }}\n      animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 30 }}\n      transition={{\n        duration: 0.8,\n        delay: delay * 0.2,\n        type: 'spring',\n        stiffness: 80,\n      }}\n      className={cn(\n        'text-center flex-1 min-w-0 flex flex-col justify-center h-full',\n      )}\n    >\n      <motion.div\n        className={cn(\n          'text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold mb-2 sm:mb-4 whitespace-nowrap',\n        )}\n        initial={{ scale: 0.8 }}\n        animate={isInView ? { scale: 1 } : { scale: 0.8 }}\n        transition={{\n          duration: 0.6,\n          delay: delay * 0.2 + 0.3,\n          type: 'spring',\n          stiffness: 100,\n        }}\n      >\n        {displayValue}\n        {suffix}\n      </motion.div>\n      <motion.p\n        className={cn(\n          'text-gray-600 dark:text-gray-400 text-xs sm:text-sm leading-relaxed px-1 sm:px-2 hyphens-auto wrap-break-word',\n        )}\n        style={{ wordBreak: 'break-word', overflowWrap: 'break-word' }}\n        initial={{ opacity: 0 }}\n        animate={isInView ? { opacity: 1 } : { opacity: 0 }}\n        transition={{ delay: delay * 0.2 + 0.6, duration: 0.6 }}\n      >\n        {label}\n      </motion.p>\n    </motion.div>\n  );\n}\n\nexport default function StatsCount({\n  stats = defaultStats,\n  title = defaultTitle,\n  showDividers = true,\n  className = '',\n}: StatsCountProps) {\n  const containerRef = useRef<HTMLElement>(null);\n  const isInView = useInView(containerRef, { margin: '-100px' });\n\n  return (\n    <motion.section\n      ref={containerRef}\n      className={cn(\n        'py-8 sm:py-12 lg:py-20 px-2 sm:px-4 md:px-8 w-full overflow-hidden',\n        className,\n      )}\n      initial={{ opacity: 0 }}\n      animate={isInView ? { opacity: 1 } : { opacity: 0 }}\n      transition={{ duration: 0.8 }}\n    >\n      <motion.div\n        className={cn('text-center mb-8 sm:mb-12 lg:mb-16')}\n        initial={{ opacity: 0, y: -20 }}\n        animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: -20 }}\n        transition={{ duration: 0.8, delay: 0.2 }}\n      >\n        <h2\n          className={cn(\n            'text-sm sm:text-base md:text-lg lg:text-xl font-medium tracking-wide px-4',\n          )}\n        >\n          <span className='hidden sm:inline'>\n            {title.includes('WITH') ? (\n              <>\n                {title.split('WITH')[0]}WITH{' '}\n                <span\n                  className={cn(\n                    'text-blue-600 dark:text-blue-400 font-semibold',\n                  )}\n                >\n                  {title.split('WITH')[1]}\n                </span>\n              </>\n            ) : (\n              title\n            )}\n          </span>\n          <div\n            className={cn('flex flex-col items-center leading-tight sm:hidden')}\n          >\n            {title.includes('WITH') ? (\n              <>\n                <span>{title.split('WITH')[0].trim()}</span>\n                <span className={cn('text-center')}>WITH</span>\n                <span\n                  className={cn(\n                    'text-blue-600 dark:text-blue-400 font-semibold',\n                  )}\n                >\n                  {title.split('WITH')[1].trim()}\n                </span>\n              </>\n            ) : (\n              <span>{title}</span>\n            )}\n          </div>\n        </h2>\n      </motion.div>\n\n      <div className={cn('w-full max-w-6xl mx-auto')}>\n        <div\n          className={cn(\n            'flex flex-row items-stretch justify-between gap-2 sm:gap-4 lg:gap-8 w-full min-h-30 sm:min-h-35',\n          )}\n        >\n          {stats.map((stat, index) => (\n            <div\n              key={index}\n              className={cn(\n                'relative flex-1 min-w-0 flex flex-col justify-center h-full',\n              )}\n            >\n              <AnimatedCounter\n                value={stat.value}\n                suffix={stat.suffix}\n                duration={stat.duration}\n                delay={index}\n                label={stat.label}\n              />\n              {index < stats.length - 1 && showDividers && (\n                <motion.div\n                  className={cn(\n                    'absolute -right-1 sm:-right-2 lg:-right-4 top-1/2 transform -translate-y-1/2 h-12 sm:h-16 lg:h-20 w-px bg-gray-200 dark:bg-gray-700',\n                  )}\n                  initial={{ opacity: 0, scaleY: 0 }}\n                  animate={\n                    isInView\n                      ? { opacity: 1, scaleY: 1 }\n                      : { opacity: 0, scaleY: 0 }\n                  }\n                  transition={{ delay: 1.5 + index * 0.2, duration: 0.6 }}\n                />\n              )}\n            </div>\n          ))}\n        </div>\n      </div>\n    </motion.section>\n  );\n}\n"
    },
    {
      "type": "registry:lib",
      "path": "lib/utils.ts",
      "content": "import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}"
    }
  ]
}
