{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "native-follow-cursor-carbon",
  "type": "registry:component",
  "title": "Native Follow Cursor",
  "description": "Label that smoothly follows the cursor with spring physics and customizable variants.",
  "dependencies": [
    "framer-motion",
    "react"
  ],
  "files": [
    {
      "path": "@uitripled/react-carbon/src/components/native/native-follow-cursor-carbon.tsx",
      "content": "\"use client\";\n\nimport type React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\nimport {\n  AnimatePresence,\n  motion,\n  useMotionValue,\n  useSpring,\n} from \"framer-motion\";\nimport { useEffect, useRef, useState } from \"react\";\n\nexport interface NativeFollowCursorProps {\n  /**\n   * Name or text to display that follows the cursor\n   * @deprecated Use children prop instead for custom content\n   */\n  name?: string;\n  /**\n   * Custom content to display (can be React nodes)\n   */\n  children?: React.ReactNode;\n  /**\n   * Size variant of the label\n   * Default: \"md\"\n   */\n  size?: \"sm\" | \"md\" | \"lg\";\n  /**\n   * Visual variant\n   * Default: \"default\"\n   */\n  variant?: \"default\" | \"glass\" | \"solid\" | \"minimal\";\n  /**\n   * Offset from cursor in pixels\n   * Default: { x: 12, y: 12 }\n   */\n  offset?: { x: number; y: number };\n  /**\n   * Spring stiffness for smooth following\n   * Default: 150\n   */\n  stiffness?: number;\n  /**\n   * Spring damping for smooth following\n   * Default: 20\n   */\n  damping?: number;\n  /**\n   * Additional class names for the label\n   */\n  className?: string;\n  /**\n   * Show decorative dot indicator\n   * Default: true (false when using custom children)\n   */\n  showDot?: boolean;\n}\n\nexport interface NativeFollowCursorAreaProps {\n  /**\n   * Content area to track cursor within\n   */\n  children: React.ReactNode;\n  /**\n   * Content that follows the cursor\n   */\n  cursorContent: React.ReactNode;\n  /**\n   * Size variant of the cursor label\n   * Default: \"md\"\n   */\n  size?: \"sm\" | \"md\" | \"lg\";\n  /**\n   * Visual variant\n   * Default: \"default\"\n   */\n  variant?: \"default\" | \"glass\" | \"solid\" | \"minimal\";\n  /**\n   * Offset from cursor in pixels\n   * Default: { x: 12, y: 12 }\n   */\n  offset?: { x: number; y: number };\n  /**\n   * Spring stiffness for smooth following\n   * Default: 150\n   */\n  stiffness?: number;\n  /**\n   * Spring damping for smooth following\n   * Default: 20\n   */\n  damping?: number;\n  /**\n   * Additional class names for the area wrapper\n   */\n  className?: string;\n  /**\n   * Additional class names for the cursor label\n   */\n  cursorClassName?: string;\n  /**\n   * Show decorative dot indicator\n   * Default: false\n   */\n  showDot?: boolean;\n}\n\nconst sizeVariants = {\n  sm: \"text-xs px-2 py-1\",\n  md: \"text-sm px-3 py-1.5\",\n  lg: \"text-base px-4 py-2\",\n};\n\nconst dotSizeVariants = {\n  sm: \"h-1.5 w-1.5\",\n  md: \"h-2 w-2\",\n  lg: \"h-2.5 w-2.5\",\n};\n\nexport function NativeFollowCursor({\n  name,\n  children,\n  size = \"md\",\n  variant = \"default\",\n  offset = { x: 12, y: 12 },\n  stiffness = 150,\n  damping = 20,\n  className,\n  showDot,\n}: NativeFollowCursorProps) {\n  const shouldShowDot = showDot ?? (children ? false : true);\n  const content = children || name;\n\n  const cursorX = useMotionValue(0);\n  const cursorY = useMotionValue(0);\n\n  const springConfig = { stiffness, damping };\n  const x = useSpring(cursorX, springConfig);\n  const y = useSpring(cursorY, springConfig);\n\n  useEffect(() => {\n    const handleMouseMove = (e: MouseEvent) => {\n      cursorX.set(e.clientX + offset.x);\n      cursorY.set(e.clientY + offset.y);\n    };\n\n    document.addEventListener(\"mousemove\", handleMouseMove);\n\n    return () => {\n      document.removeEventListener(\"mousemove\", handleMouseMove);\n    };\n  }, [cursorX, cursorY, offset]);\n\n  const getVariantStyles = () => {\n    switch (variant) {\n      case \"glass\":\n        return \"bg-background/80 backdrop-blur-md border border-border/50 shadow-lg\";\n      case \"solid\":\n        return \"bg-primary text-primary-foreground shadow-md\";\n      case \"minimal\":\n        return \"bg-background/95 border border-border shadow-sm\";\n      case \"default\":\n      default:\n        return \"bg-popover text-popover-foreground border border-border shadow-lg\";\n    }\n  };\n\n  return (\n    <motion.div\n      initial={{ opacity: 0, scale: 0.8, filter: \"blur(4px)\" }}\n      animate={{ opacity: 1, scale: 1, filter: \"blur(0px)\" }}\n      style={{\n        x,\n        y,\n      }}\n      transition={{\n        opacity: { duration: 0.2 },\n        scale: { duration: 0.2 },\n        filter: { duration: 0.2 },\n      }}\n      className={cn(\n        \"fixed top-0 left-0 z-50 pointer-events-none select-none\",\n        \"rounded-full flex items-center gap-2\",\n        sizeVariants[size],\n        getVariantStyles(),\n        className\n      )}\n    >\n      {shouldShowDot && (\n        <motion.div\n          animate={{\n            scale: [1, 1.2, 1],\n            opacity: [0.7, 1, 0.7],\n          }}\n          transition={{\n            duration: 2,\n            repeat: Number.POSITIVE_INFINITY,\n            ease: \"easeInOut\",\n          }}\n          className={cn(\n            \"rounded-full shrink-0\",\n            dotSizeVariants[size],\n            variant === \"solid\" ? \"bg-primary-foreground\" : \"bg-primary\"\n          )}\n        />\n      )}\n      <span className=\"font-medium whitespace-nowrap\">{content}</span>\n    </motion.div>\n  );\n}\n\nexport function NativeFollowCursorArea({\n  children,\n  cursorContent,\n  size = \"md\",\n  variant = \"default\",\n  offset = { x: 12, y: 12 },\n  stiffness = 150,\n  damping = 20,\n  className,\n  cursorClassName,\n  showDot = false,\n}: NativeFollowCursorAreaProps) {\n  const [isVisible, setIsVisible] = useState(false);\n  const containerRef = useRef<HTMLDivElement>(null);\n  const cursorX = useMotionValue(0);\n  const cursorY = useMotionValue(0);\n\n  const springConfig = { stiffness, damping };\n  const x = useSpring(cursorX, springConfig);\n  const y = useSpring(cursorY, springConfig);\n\n  useEffect(() => {\n    const container = containerRef.current;\n    if (!container) return;\n\n    const handleMouseMove = (e: MouseEvent) => {\n      const rect = container.getBoundingClientRect();\n      const isInside =\n        e.clientX >= rect.left &&\n        e.clientX <= rect.right &&\n        e.clientY >= rect.top &&\n        e.clientY <= rect.bottom;\n\n      setIsVisible(isInside);\n\n      if (isInside) {\n        cursorX.set(e.clientX + offset.x);\n        cursorY.set(e.clientY + offset.y);\n      }\n    };\n\n    const handleMouseLeave = () => {\n      setIsVisible(false);\n    };\n\n    document.addEventListener(\"mousemove\", handleMouseMove);\n    container.addEventListener(\"mouseleave\", handleMouseLeave);\n\n    return () => {\n      document.removeEventListener(\"mousemove\", handleMouseMove);\n      container.removeEventListener(\"mouseleave\", handleMouseLeave);\n    };\n  }, [cursorX, cursorY, offset]);\n\n  const getVariantStyles = () => {\n    switch (variant) {\n      case \"glass\":\n        return \"bg-background/80 backdrop-blur-md border border-border/50 shadow-lg\";\n      case \"solid\":\n        return \"bg-primary text-primary-foreground shadow-md\";\n      case \"minimal\":\n        return \"bg-background/95 border border-border shadow-sm\";\n      case \"default\":\n      default:\n        return \"bg-popover text-popover-foreground border border-border shadow-lg\";\n    }\n  };\n\n  return (\n    <div ref={containerRef} className={cn(\"relative\", className)}>\n      {children}\n      <AnimatePresence>\n        {isVisible && (\n          <motion.div\n            initial={{ opacity: 0, scale: 0.8, filter: \"blur(4px)\" }}\n            animate={{ opacity: 1, scale: 1, filter: \"blur(0px)\" }}\n            exit={{ opacity: 0, scale: 0.8, filter: \"blur(4px)\" }}\n            style={{\n              x,\n              y,\n            }}\n            transition={{\n              opacity: { duration: 0.2 },\n              scale: { duration: 0.2 },\n              filter: { duration: 0.2 },\n            }}\n            className={cn(\n              \"fixed top-0 left-0 z-50 pointer-events-none select-none\",\n              \"rounded-full flex items-center gap-2\",\n              sizeVariants[size],\n              getVariantStyles(),\n              cursorClassName\n            )}\n          >\n            {showDot && (\n              <motion.div\n                animate={{\n                  scale: [1, 1.2, 1],\n                  opacity: [0.7, 1, 0.7],\n                }}\n                transition={{\n                  duration: 2,\n                  repeat: Number.POSITIVE_INFINITY,\n                  ease: \"easeInOut\",\n                }}\n                className={cn(\n                  \"rounded-full shrink-0\",\n                  dotSizeVariants[size],\n                  variant === \"solid\" ? \"bg-primary-foreground\" : \"bg-primary\"\n                )}\n              />\n            )}\n            <div className=\"font-medium\">{cursorContent}</div>\n          </motion.div>\n        )}\n      </AnimatePresence>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/uitripled/native-follow-cursor-carbon.tsx"
    }
  ]
}