{
    "name": "ai-token-counter",
    "title": "Modal Ability Selector",
    "description": "Compact selector for toggling abilities with icons and custom styles",
    "type": "registry:ui",
    "dependencies": ["gsap", "@gsap/react"],
    "files": [
        {
            "path": "components/gsap/ai-token-counter.tsx",
            "type": "registry:ui",
            "target": "~/components/gsap/ai-token-counter.tsx",
            "content": "\"use client\";\n\nimport { useRef, useState } from \"react\";\n\nimport { useGSAP } from \"@gsap/react\";\nimport gsap from \"gsap\";\nimport { MotionPathPlugin } from \"gsap/MotionPathPlugin\";\n\nimport { cn } from \"@/lib/utils\";\n\ngsap.registerPlugin(MotionPathPlugin);\n\nexport const AiTokenCounter = ({ sourceRef, token, className, flyingClassName, ...props }: any) => {\n    const [displayCount, setDisplayCount] = useState(token);\n    const lastToken = useRef(token);\n    const counterRef = useRef<HTMLParagraphElement>(null);\n    const flyingRef = useRef<HTMLParagraphElement>(null);\n\n    useGSAP(\n        () => {\n            const diff = token - lastToken.current;\n            if (diff === 0 || !sourceRef.current || !counterRef.current || !flyingRef.current) return;\n\n            const startValue = lastToken.current;\n            lastToken.current = token;\n\n            const [src, dest, fly] = [\n                sourceRef.current.getBoundingClientRect(),\n                counterRef.current.getBoundingClientRect(),\n                flyingRef.current.getBoundingClientRect(),\n            ];\n\n            const flyEl = flyingRef.current;\n            flyEl.innerText = `${diff > 0 ? \"+\" : \"\"}${diff}`;\n\n            // Relative Math\n            const start = {\n                x: src.left + src.width / 2 - fly.left - fly.width / 2 - 15,\n                y: src.top + src.height / 2 - fly.top - fly.height / 2,\n            };\n            const end = {\n                x: dest.left + dest.width / 2 - fly.left - fly.width / 2,\n                y: dest.top + dest.height / 2 - fly.top - fly.height / 2,\n            };\n\n            const tl = gsap.timeline();\n            tl.set(flyEl, { ...start, scale: 0.5, opacity: 0, visibility: \"visible\" })\n                .to(flyEl, {\n                    duration: 0.6,\n                    ease: \"power2.out\",\n                    motionPath: { path: [start, { x: (start.x + end.x) / 2, y: Math.min(start.y, end.y) - 20 }, end] },\n                    opacity: 1,\n                    scale: 1,\n                })\n                .to(flyEl, { opacity: 0, scale: 0.5, duration: 0.2 }, \"-=0.1\")\n                .to(\n                    { val: startValue },\n                    {\n                        val: token,\n                        duration: 0.4,\n                        onUpdate: function () {\n                            setDisplayCount(Math.floor(this.targets()[0].val));\n                        },\n                        onComplete: () => setDisplayCount(token),\n                    },\n                    \"<\",\n                );\n        },\n        { dependencies: [token] },\n    );\n\n    return (\n        <div className=\"flex items-center\">\n            <p ref={counterRef} className={className} {...props}>\n                {displayCount}\n            </p>\n            <div className=\"relative h-0 w-0\">\n                <p ref={flyingRef} className={cn(\"invisible absolute font-bold\", flyingClassName)}>\n                    +0\n                </p>\n            </div>\n        </div>\n    );\n};\n"
        }
    ]
}
