{
  "name": "cursor-1",
  "type": "registry:ui",
  "componentName": "cursor-1",
  "description": "Basic cursor effect following pointer movement.",
  "files": [
    {
      "path": "cursor-1.tsx",
      "content": "'use client';\nimport { useRef, useState } from 'react';\nimport { Cursor } from '@/components/core/cursor';\nimport { AnimatePresence, motion } from 'motion/react';\nimport { PlusIcon } from 'lucide-react';\n\nexport function Cursor1() {\n  const [isHovering, setIsHovering] = useState(false);\n  const targetRef = useRef<HTMLDivElement>(null);\n\n  const handlePositionChange = (x: number, y: number) => {\n    if (targetRef.current) {\n      const rect = targetRef.current.getBoundingClientRect();\n      const isInside =\n        x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;\n      setIsHovering(isInside);\n    }\n  };\n\n  return (\n    <div className='flex h-[400px] w-full items-center justify-center'>\n      <Cursor\n        attachToParent\n        variants={{\n          initial: { scale: 0.3, opacity: 0 },\n          animate: { scale: 1, opacity: 1 },\n          exit: { scale: 0.3, opacity: 0 },\n        }}\n        springConfig={{\n          bounce: 0.001,\n        }}\n        transition={{\n          ease: 'easeInOut',\n          duration: 0.15,\n        }}\n        onPositionChange={handlePositionChange}\n      >\n        <motion.div\n          animate={{\n            width: isHovering ? 80 : 16,\n            height: isHovering ? 32 : 16,\n          }}\n          className='flex items-center justify-center rounded-[24px] bg-gray-500/40 backdrop-blur-md dark:bg-gray-300/40'\n        >\n          <AnimatePresence>\n            {isHovering ? (\n              <motion.div\n                initial={{ opacity: 0, scale: 0.6 }}\n                animate={{ opacity: 1, scale: 1 }}\n                exit={{ opacity: 0, scale: 0.6 }}\n                className='inline-flex w-full items-center justify-center'\n              >\n                <div className='inline-flex items-center text-sm text-white dark:text-black'>\n                  More <PlusIcon className='ml-1 h-4 w-4' />\n                </div>\n              </motion.div>\n            ) : null}\n          </AnimatePresence>\n        </motion.div>\n      </Cursor>\n      <div ref={targetRef}>\n        <img\n          src='https://i.pinimg.com/564x/75/3c/3f/753c3f1a9f85871ffa7a7a78bcf49f66.jpg'\n          alt='Olympic logo Paris 2024'\n          className='h-52 w-full max-w-48 rounded-[8px] border border-zinc-100 object-cover'\n        />\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:component"
    },
    {
      "path": "components/core/cursor.tsx",
      "content": "'use client';\nimport React, { useEffect, useState, useRef } from 'react';\nimport {\n  motion,\n  SpringOptions,\n  useMotionValue,\n  useSpring,\n  AnimatePresence,\n  Transition,\n  Variant,\n} from 'motion/react';\nimport { cn } from '@/lib/utils';\n\nexport type CursorProps = {\n  children: React.ReactNode;\n  className?: string;\n  springConfig?: SpringOptions;\n  attachToParent?: boolean;\n  transition?: Transition;\n  variants?: {\n    initial: Variant;\n    animate: Variant;\n    exit: Variant;\n  };\n  onPositionChange?: (x: number, y: number) => void;\n};\n\nexport function Cursor({\n  children,\n  className,\n  springConfig,\n  attachToParent,\n  variants,\n  transition,\n  onPositionChange,\n}: CursorProps) {\n  const cursorX = useMotionValue(0);\n  const cursorY = useMotionValue(0);\n  const cursorRef = useRef<HTMLDivElement>(null);\n  const [isVisible, setIsVisible] = useState(!attachToParent);\n\n  useEffect(() => {\n    if (typeof window !== 'undefined') {\n      cursorX.set(window.innerWidth / 2);\n      cursorY.set(window.innerHeight / 2);\n    }\n  }, [cursorX, cursorY]);\n\n  useEffect(() => {\n    if (!attachToParent) {\n      document.body.style.cursor = 'none';\n    } else {\n      document.body.style.cursor = 'auto';\n    }\n\n    const updatePosition = (e: MouseEvent) => {\n      cursorX.set(e.clientX);\n      cursorY.set(e.clientY);\n      onPositionChange?.(e.clientX, e.clientY);\n    };\n\n    document.addEventListener('mousemove', updatePosition);\n\n    return () => {\n      document.removeEventListener('mousemove', updatePosition);\n      document.body.style.cursor = 'auto';\n    };\n  }, [attachToParent, cursorX, cursorY, onPositionChange]);\n\n  const cursorXSpring = useSpring(cursorX, springConfig || { duration: 0 });\n  const cursorYSpring = useSpring(cursorY, springConfig || { duration: 0 });\n\n  useEffect(() => {\n    const handleVisibilityChange = (visible: boolean) => {\n      setIsVisible(visible);\n    };\n\n    const parent = cursorRef.current?.parentElement;\n\n    if (attachToParent && parent) {\n      const handleMouseEnter = () => {\n        parent.style.cursor = 'none';\n        handleVisibilityChange(true);\n      };\n      const handleMouseLeave = () => {\n        parent.style.cursor = 'auto';\n        handleVisibilityChange(false);\n      };\n\n      parent.addEventListener('mouseenter', handleMouseEnter);\n      parent.addEventListener('mouseleave', handleMouseLeave);\n\n      return () => {\n        parent.removeEventListener('mouseenter', handleMouseEnter);\n        parent.removeEventListener('mouseleave', handleMouseLeave);\n        parent.style.cursor = 'auto';\n      };\n    }\n\n    return undefined;\n  }, [attachToParent]);\n\n  return (\n    <motion.div\n      ref={cursorRef}\n      className={cn('pointer-events-none fixed top-0 left-0 z-50', className)}\n      style={{\n        x: cursorXSpring,\n        y: cursorYSpring,\n        translateX: '-50%',\n        translateY: '-50%',\n      }}\n    >\n      <AnimatePresence>\n        {isVisible && (\n          <motion.div\n            initial='initial'\n            animate='animate'\n            exit='exit'\n            variants={variants}\n            transition={transition}\n          >\n            {children}\n          </motion.div>\n        )}\n      </AnimatePresence>\n    </motion.div>\n  );\n}\n",
      "type": "registry:ui"
    }
  ]
}