{
    "name": "mouse-wave-text",
    "title": "Mouse Wave Text",
    "description": "Creates a wave-like bounce effect on text as the mouse moves across",
    "type": "registry:ui",
    "dependencies": ["gsap", "@gsap/react"],
    "files": [
        {
            "path": "components/gsap/mouse-wave-text.tsx",
            "type": "registry:ui",
            "target": "~/components/gsap/mouse-wave-text.tsx",
            "content": "\"use client\";\n\nimport { ComponentProps, ReactNode, useRef } from \"react\";\n\nimport { useGSAP } from \"@gsap/react\";\nimport gsap from \"gsap\";\n\nimport { cn } from \"@/lib/utils\";\n\ntype MouseWaveTextProps = {\n    children: ReactNode;\n    className?: string;\n    shadowClassName?: string;\n    textClassName?: string;\n    wrapperTweenVars?: gsap.TweenVars;\n} & ComponentProps<\"div\">;\n\nexport const MouseWaveText = ({\n    children,\n    textClassName,\n    className,\n    shadowClassName,\n    wrapperTweenVars,\n    ...props\n}: MouseWaveTextProps) => {\n    const wrapperRef = useRef<HTMLDivElement | null>(null);\n    const textRef = useRef<HTMLParagraphElement | null>(null);\n    const shadowRef = useRef<HTMLParagraphElement | null>(null);\n\n    useGSAP(\n        () => {\n            if (!wrapperRef.current || !shadowRef.current || !textRef.current) return;\n            const textContent = shadowRef.current.textContent;\n            const bb = shadowRef.current.getBoundingClientRect();\n\n            for (let i = 0; i <= bb.width * 0.55; i++) {\n                const div = document.createElement(\"div\");\n                textRef.current.append(div);\n                gsap.set(div, {\n                    position: \"absolute\",\n                    width: 4,\n                    height: bb.height,\n                    x: i * 2,\n                    y: -bb.height,\n                    textIndent: -i * 2,\n                    overflow: \"hidden\",\n                    textContent: textContent,\n                });\n            }\n\n            if (wrapperTweenVars) gsap.set(wrapperRef.current, wrapperTweenVars);\n\n            const tl = gsap\n                .timeline({\n                    paused: true,\n                    defaults: { duration: 0.25, ease: \"power3.inOut\", yoyoEase: \"sine.inOut\" },\n                })\n                .to(textRef.current.children, {\n                    y: \"-=30\",\n                    stagger: {\n                        amount: 1,\n                        yoyo: true,\n                        repeat: 1,\n                        ease: \"none\",\n                    },\n                });\n\n            gsap.timeline()\n                .fromTo(tl, { progress: 0.9 }, { duration: 1.5, progress: 0.1, ease: \"power2.inOut\" })\n                .to(tl, { duration: 4, progress: 0.4, ease: \"elastic.out(0.8)\" });\n\n            const onMove = (e: MouseEvent) => {\n                const xp = e.x / window.innerWidth;\n                gsap.to(tl, { progress: xp, overwrite: true });\n                gsap.to(wrapperRef.current, {\n                    x: gsap.utils.mapRange(0, 1, 15, -15, xp),\n                    y: gsap.utils.mapRange(0, 1, -15, 15, xp),\n                });\n            };\n\n            const onMouseDown = () => {\n                gsap.timeline({ defaults: { duration: 0.2, overwrite: \"auto\" } })\n                    .to(textRef.current, {\n                        y: -25,\n                    })\n                    .to(\n                        shadowRef.current,\n                        {\n                            filter: \"blur(2px)\",\n                            opacity: 0.85,\n                            scale: 0.96,\n                            transformOrigin: \"45px 99px\",\n                        },\n                        0,\n                    );\n            };\n\n            const onMouseUp = () => {\n                gsap.timeline({ defaults: { ease: \"bounce\" } })\n                    .to(textRef.current, { y: 0 })\n                    .to(\n                        shadowRef.current,\n                        {\n                            filter: \"blur(0px)\",\n                            opacity: 1,\n                            scale: 1,\n                        },\n                        0,\n                    );\n            };\n\n            window.addEventListener(\"pointermove\", onMove);\n            window.addEventListener(\"mousedown\", onMouseDown);\n            window.addEventListener(\"mouseup\", onMouseUp);\n\n            return () => {\n                window.removeEventListener(\"pointermove\", onMove);\n                window.removeEventListener(\"mousedown\", onMouseDown);\n                window.removeEventListener(\"mouseup\", onMouseUp);\n            };\n        },\n        { scope: wrapperRef },\n    );\n\n    return (\n        <div {...props} ref={wrapperRef} className={cn(\"whitespace-nowrap\", className)}>\n            <p ref={shadowRef} className={shadowClassName}>\n                {children}\n            </p>\n            <p ref={textRef} aria-disabled=\"true\" className={textClassName} />\n        </div>\n    );\n};\n"
        }
    ]
}
