{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "cursor",
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "src/components/watermelon-ui/cursor.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\nimport {\n  motion,\n  useMotionValue,\n  useSpring,\n  AnimatePresence,\n  isMotionComponent,\n  type HTMLMotionProps,\n  type SpringOptions,\n} from 'motion/react';\nimport { cn } from '@/lib/utils';\n\n/* =============================================================================\n * Utility Types\n * ========================================================================== */\ntype AnyProps = Record<string, unknown>;\n\ntype DOMMotionProps<T extends HTMLElement = HTMLElement> = Omit<\n  HTMLMotionProps<keyof HTMLElementTagNameMap>,\n  'ref'\n> & { ref?: React.Ref<T> };\n\ntype WithAsChild<Base extends object> =\n  | (Base & { asChild: true; children: React.ReactElement })\n  | (Base & { asChild?: false | undefined });\n\n/* =============================================================================\n * Strict Context\n * ========================================================================== */\nfunction getStrictContext<T>(\n  name?: string,\n): readonly [\n  ({\n    value,\n    children,\n  }: {\n    value: T;\n    children?: React.ReactNode;\n  }) => React.JSX.Element,\n  () => T,\n] {\n  const Context = React.createContext<T | undefined>(undefined);\n\n  const Provider = ({\n    value,\n    children,\n  }: {\n    value: T;\n    children?: React.ReactNode;\n  }) => <Context.Provider value={value}>{children}</Context.Provider>;\n\n  const useSafeContext = () => {\n    const ctx = React.useContext(Context);\n    if (ctx === undefined) {\n      throw new Error(`useContext must be used within ${name ?? 'a Provider'}`);\n    }\n    return ctx;\n  };\n\n  return [Provider, useSafeContext] as const;\n}\n\n/* =============================================================================\n * Slot Component\n * ========================================================================== */\ntype SlotProps<T extends HTMLElement = HTMLElement> = {\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  children?: any;\n} & DOMMotionProps<T>;\n\nfunction mergeRefs<T>(\n  ...refs: (React.Ref<T> | undefined)[]\n): React.RefCallback<T> {\n  return (node) => {\n    refs.forEach((ref) => {\n      if (!ref) return;\n      if (typeof ref === 'function') {\n        ref(node);\n      } else {\n        (ref as React.RefObject<T | null>).current = node;\n      }\n    });\n  };\n}\n\nfunction mergeProps<T extends HTMLElement>(\n  childProps: AnyProps,\n  slotProps: DOMMotionProps<T>,\n): AnyProps {\n  const merged: AnyProps = { ...childProps, ...slotProps };\n\n  if (childProps.className || slotProps.className) {\n    merged.className = cn(\n      childProps.className as string,\n      slotProps.className as string,\n    );\n  }\n\n  if (childProps.style || slotProps.style) {\n    merged.style = {\n      ...(childProps.style as React.CSSProperties),\n      ...(slotProps.style as React.CSSProperties),\n    };\n  }\n\n  return merged;\n}\n\nfunction Slot<T extends HTMLElement = HTMLElement>({\n  children,\n  ref,\n  ...props\n}: SlotProps<T>) {\n  const isAlreadyMotion =\n    typeof children.type === 'object' &&\n    children.type !== null &&\n    isMotionComponent(children.type);\n\n  const Base = React.useMemo(\n    () =>\n      isAlreadyMotion\n        ? (children.type as React.ElementType)\n        : motion.create(children.type as React.ElementType),\n    [isAlreadyMotion, children.type],\n  );\n\n  if (!React.isValidElement(children)) return null;\n\n  const { ref: childRef, ...childProps } = children.props as AnyProps;\n\n  const mergedProps = mergeProps(childProps, props);\n\n  return (\n    // eslint-disable-next-line react-hooks/static-components\n    <Base {...mergedProps} ref={mergeRefs(childRef as React.Ref<T>, ref)} />\n  );\n}\n\n/* =============================================================================\n * Cursor Context\n * ========================================================================== */\ntype CursorContextType = {\n  cursorPos: { x: number; y: number };\n  active: boolean;\n  global: boolean;\n  containerRef: React.RefObject<HTMLDivElement | null>;\n  cursorRef: React.RefObject<HTMLDivElement | null>;\n};\n\nconst [LocalCursorProvider, useCursor] =\n  getStrictContext<CursorContextType>('CursorContext');\n\n/* =============================================================================\n * Cursor Provider Primitive\n * ========================================================================== */\ntype CursorProviderPropsPrimitive = {\n  children: React.ReactNode;\n  global?: boolean;\n};\n\nfunction CursorProviderPrimitive({\n  children,\n  global = false,\n}: CursorProviderPropsPrimitive) {\n  const [cursorPos, setCursorPos] = React.useState({ x: 0, y: 0 });\n  const [active, setActive] = React.useState(false);\n\n  const containerRef = React.useRef<HTMLDivElement>(null);\n  const cursorRef = React.useRef<HTMLDivElement>(null);\n\n  React.useEffect(() => {\n    const id = '__cursor_none_style__';\n    if (document.getElementById(id)) return;\n\n    const style = document.createElement('style');\n    style.id = id;\n    style.textContent = `\n      .animate-ui-cursor-none, .animate-ui-cursor-none * { cursor: none !important; }\n    `;\n    document.head.appendChild(style);\n  }, []);\n\n  React.useEffect(() => {\n    let removeListeners: (() => void) | undefined;\n\n    if (global) {\n      const handlePointerMove = (e: PointerEvent) => {\n        setCursorPos({ x: e.clientX, y: e.clientY });\n        setActive(true);\n      };\n\n      const handlePointerOut = (e: PointerEvent | MouseEvent) => {\n        if (e instanceof PointerEvent && e.relatedTarget === null) {\n          setActive(false);\n        }\n      };\n\n      const handleVisibilityChange = () => {\n        if (document.visibilityState === 'hidden') setActive(false);\n      };\n\n      window.addEventListener('pointermove', handlePointerMove, {\n        passive: true,\n      });\n      window.addEventListener('pointerout', handlePointerOut, {\n        passive: true,\n      });\n      window.addEventListener('mouseout', handlePointerOut, { passive: true });\n      document.addEventListener('visibilitychange', handleVisibilityChange);\n\n      removeListeners = () => {\n        window.removeEventListener('pointermove', handlePointerMove);\n        window.removeEventListener('pointerout', handlePointerOut);\n        window.removeEventListener('mouseout', handlePointerOut);\n        document.removeEventListener(\n          'visibilitychange',\n          handleVisibilityChange,\n        );\n      };\n    } else {\n      if (!containerRef.current) return;\n\n      const parent = containerRef.current.parentElement;\n      if (!parent) return;\n\n      if (getComputedStyle(parent).position === 'static') {\n        parent.style.position = 'relative';\n      }\n\n      const handlePointerMove = (e: PointerEvent) => {\n        const rect = parent.getBoundingClientRect();\n        setCursorPos({ x: e.clientX - rect.left, y: e.clientY - rect.top });\n        setActive(true);\n      };\n\n      const handlePointerOut = (e: PointerEvent | MouseEvent) => {\n        if (\n          e.relatedTarget === null ||\n          !(parent as Node).contains(e.relatedTarget as Node)\n        ) {\n          setActive(false);\n        }\n      };\n\n      parent.addEventListener('pointermove', handlePointerMove, {\n        passive: true,\n      });\n      parent.addEventListener('pointerout', handlePointerOut, {\n        passive: true,\n      });\n      parent.addEventListener('mouseout', handlePointerOut, { passive: true });\n\n      removeListeners = () => {\n        parent.removeEventListener('pointermove', handlePointerMove);\n        parent.removeEventListener('pointerout', handlePointerOut);\n        parent.removeEventListener('mouseout', handlePointerOut);\n      };\n    }\n\n    return removeListeners;\n  }, [global]);\n\n  return (\n    <LocalCursorProvider\n      value={{ cursorPos, active, global, containerRef, cursorRef }}\n    >\n      {children}\n    </LocalCursorProvider>\n  );\n}\n\n/* =============================================================================\n * Cursor Container Primitive\n * ========================================================================== */\ntype CursorContainerPropsPrimitive = WithAsChild<HTMLMotionProps<'div'>>;\n\nfunction CursorContainerPrimitive({\n  ref,\n  asChild = false,\n  ...props\n}: CursorContainerPropsPrimitive) {\n  const { containerRef, global, active } = useCursor();\n  React.useImperativeHandle(ref, () => containerRef.current as HTMLDivElement);\n\n  const Component = asChild ? Slot : motion.div;\n\n  return (\n    <Component\n      ref={containerRef}\n      data-slot=\"cursor-container\"\n      data-global={global}\n      data-active={active}\n      {...props}\n    />\n  );\n}\n\n/* =============================================================================\n * Cursor Primitive\n * ========================================================================== */\ntype CursorPropsPrimitive = WithAsChild<\n  HTMLMotionProps<'div'> & {\n    children?: React.ReactNode;\n  }\n>;\n\nfunction CursorPrimitive({\n  ref,\n  asChild = false,\n  style,\n  children,\n  ...props\n}: CursorPropsPrimitive) {\n  const { cursorPos, active, containerRef, cursorRef, global } = useCursor();\n  React.useImperativeHandle(ref, () => cursorRef.current as HTMLDivElement);\n\n  const x = useMotionValue(0);\n  const y = useMotionValue(0);\n\n  React.useEffect(() => {\n    const target = global\n      ? document.documentElement\n      : containerRef.current?.parentElement;\n\n    if (!target) return;\n\n    if (active) {\n      target.classList.add('animate-ui-cursor-none');\n    } else {\n      target.classList.remove('animate-ui-cursor-none');\n    }\n\n    return () => {\n      target.classList.remove('animate-ui-cursor-none');\n    };\n  }, [active, global, containerRef]);\n\n  React.useEffect(() => {\n    x.set(cursorPos.x);\n    y.set(cursorPos.y);\n  }, [cursorPos, x, y]);\n\n  const Component = asChild ? Slot : motion.div;\n\n  return (\n    <AnimatePresence>\n      {active && (\n        <Component\n          ref={cursorRef}\n          data-slot=\"cursor\"\n          data-global={global}\n          data-active={active}\n          style={{\n            transform: 'translate(-50%,-50%)',\n            pointerEvents: 'none',\n            zIndex: 9999,\n            position: global ? 'fixed' : 'absolute',\n            top: y,\n            left: x,\n            ...style,\n          }}\n          initial={{ scale: 0, opacity: 0 }}\n          animate={{ scale: 1, opacity: 1 }}\n          exit={{ scale: 0, opacity: 0 }}\n          {...props}\n        >\n          {children}\n        </Component>\n      )}\n    </AnimatePresence>\n  );\n}\n\n/* =============================================================================\n * Cursor Follow Primitive\n * ========================================================================== */\ntype CursorFollowSide = 'top' | 'right' | 'bottom' | 'left';\ntype CursorFollowAlign = 'start' | 'center' | 'end';\n\ntype CursorFollowPropsPrimitive = WithAsChild<\n  Omit<HTMLMotionProps<'div'>, 'transition'> & {\n    side?: CursorFollowSide;\n    sideOffset?: number;\n    align?: CursorFollowAlign;\n    alignOffset?: number;\n    transition?: SpringOptions;\n    children?: React.ReactNode;\n  }\n>;\n\nfunction CursorFollowPrimitive({\n  ref,\n  asChild = false,\n  side = 'bottom',\n  sideOffset = 0,\n  align = 'end',\n  alignOffset = 0,\n  style,\n  transition = { stiffness: 500, damping: 50, bounce: 0 },\n  children,\n  ...props\n}: CursorFollowPropsPrimitive) {\n  const { cursorPos, active, cursorRef, global } = useCursor();\n  const cursorFollowRef = React.useRef<HTMLDivElement>(null);\n  React.useImperativeHandle(\n    ref,\n    () => cursorFollowRef.current as HTMLDivElement,\n  );\n\n  const x = useMotionValue(0);\n  const y = useMotionValue(0);\n\n  const springX = useSpring(x, transition);\n  const springY = useSpring(y, transition);\n\n  const calculateOffset = React.useCallback(() => {\n    const rect = cursorFollowRef.current?.getBoundingClientRect();\n    const width = rect?.width ?? 0;\n    const height = rect?.height ?? 0;\n\n    let offsetX = 0;\n    let offsetY = 0;\n\n    switch (side) {\n      case 'top':\n        offsetY = height + sideOffset;\n        switch (align) {\n          case 'start':\n            offsetX = width + alignOffset;\n            break;\n          case 'center':\n            offsetX = width / 2;\n            break;\n          case 'end':\n            offsetX = -alignOffset;\n            break;\n        }\n        break;\n\n      case 'bottom':\n        offsetY = -sideOffset;\n        switch (align) {\n          case 'start':\n            offsetX = width + alignOffset;\n            break;\n          case 'center':\n            offsetX = width / 2;\n            break;\n          case 'end':\n            offsetX = -alignOffset;\n            break;\n        }\n        break;\n\n      case 'left':\n        offsetX = width + sideOffset;\n        switch (align) {\n          case 'start':\n            offsetY = height + alignOffset;\n            break;\n          case 'center':\n            offsetY = height / 2;\n            break;\n          case 'end':\n            offsetY = -alignOffset;\n            break;\n        }\n        break;\n\n      case 'right':\n        offsetX = -sideOffset;\n        switch (align) {\n          case 'start':\n            offsetY = height + alignOffset;\n            break;\n          case 'center':\n            offsetY = height / 2;\n            break;\n          case 'end':\n            offsetY = -alignOffset;\n            break;\n        }\n        break;\n    }\n\n    return { x: offsetX, y: offsetY };\n  }, [side, align, sideOffset, alignOffset]);\n\n  React.useEffect(() => {\n    const offset = calculateOffset();\n    const cursorRect = cursorRef.current?.getBoundingClientRect();\n    const cursorWidth = cursorRect?.width ?? 20;\n    const cursorHeight = cursorRect?.height ?? 20;\n\n    x.set(cursorPos.x - offset.x + cursorWidth / 2);\n    y.set(cursorPos.y - offset.y + cursorHeight / 2);\n  }, [calculateOffset, cursorPos, cursorRef, x, y]);\n\n  const Component = asChild ? Slot : motion.div;\n\n  return (\n    <AnimatePresence>\n      {active && (\n        <Component\n          ref={cursorFollowRef}\n          data-slot=\"cursor-follow\"\n          data-global={global}\n          data-active={active}\n          style={{\n            transform: 'translate(-50%,-50%)',\n            pointerEvents: 'none',\n            zIndex: 9998,\n            position: global ? 'fixed' : 'absolute',\n            top: springY,\n            left: springX,\n            ...style,\n          }}\n          initial={{ scale: 0, opacity: 0 }}\n          animate={{ scale: 1, opacity: 1 }}\n          exit={{ scale: 0, opacity: 0 }}\n          {...props}\n        >\n          {children}\n        </Component>\n      )}\n    </AnimatePresence>\n  );\n}\n\n/* =============================================================================\n * Public API (what you import)\n * ========================================================================== */\ntype CursorProviderProps = Omit<CursorProviderPropsPrimitive, 'children'> &\n  CursorContainerPropsPrimitive;\n\nfunction CursorProvider({ global, ...props }: CursorProviderProps) {\n  return (\n    <CursorProviderPrimitive global={global}>\n      <CursorContainerPrimitive {...props} />\n    </CursorProviderPrimitive>\n  );\n}\n\ntype CursorProps = Omit<CursorPropsPrimitive, 'children' | 'asChild'>;\n\nfunction Cursor({ className, ...props }: CursorProps) {\n  return (\n    <CursorPrimitive asChild {...props}>\n      <svg\n        className={cn('size-6 text-foreground', className)}\n        xmlns=\"http://www.w3.org/2000/svg\"\n        viewBox=\"0 0 40 40\"\n      >\n        <path\n          fill=\"currentColor\"\n          d=\"M1.8 4.4 7 36.2c.3 1.8 2.6 2.3 3.6.8l3.9-5.7c1.7-2.5 4.5-4.1 7.5-4.3l6.9-.5c1.8-.1 2.5-2.4 1.1-3.5L5 2.5c-1.4-1.1-3.5 0-3.3 1.9Z\"\n        />\n      </svg>\n    </CursorPrimitive>\n  );\n}\n\ntype CursorFollowProps = Omit<CursorFollowPropsPrimitive, 'asChild'>;\n\nfunction CursorFollow({\n  className,\n  children,\n  sideOffset = 15,\n  alignOffset = 5,\n  ...props\n}: CursorFollowProps) {\n  return (\n    <CursorFollowPrimitive\n      sideOffset={sideOffset}\n      alignOffset={alignOffset}\n      asChild\n      {...props}\n    >\n      <div\n        className={cn(\n          'bg-foreground rounded-md text-background px-2 py-1 text-sm',\n          className,\n        )}\n      >\n        {children}\n      </div>\n    </CursorFollowPrimitive>\n  );\n}\n\nexport {\n  CursorProvider,\n  Cursor,\n  CursorFollow,\n  useCursor,\n  type CursorProviderProps,\n  type CursorProps,\n  type CursorFollowProps,\n};\n",
      "type": "registry:ui",
      "target": "components/ui/cursor.tsx"
    }
  ],
  "type": "registry:ui"
}
