{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "clipboard-paste",
  "title": "clipboard-paste",
  "description": "Animated clipboard paste icon",
  "dependencies": [
    "motion"
  ],
  "files": [
    {
      "path": "icons/clipboard-paste.tsx",
      "content": "'use client';\n\nimport type { Variants } from 'motion/react';\nimport { motion, useAnimation } from 'motion/react';\nimport type { HTMLAttributes } from 'react';\nimport { forwardRef } from 'react';\nimport { useIconAnimation } from '@/lib/use-icon-animation';\nimport { cn } from '@/lib/utils';\n\n/** Imperative controls for the Clipboard Paste icon animation. */\nexport interface ClipboardPasteIconHandle {\n  startAnimation: () => void;\n  stopAnimation: () => void;\n}\n\ninterface ClipboardPasteIconProps extends HTMLAttributes<HTMLDivElement> {\n  size?: number;\n}\n\n// The arrow pulls back and releases while the complete clipboard absorbs it.\nconst pasteVariants: Variants = {\n  normal: {\n    x: 0,\n    scaleX: 1,\n    transition: { type: 'spring', duration: 0.3, bounce: 0 },\n  },\n  animate: {\n    x: [0, -1.4, -1.4, 1.6, -0.35, 0],\n    scaleX: [1, 0.9, 0.9, 1.04, 0.99, 1],\n    transition: {\n      duration: 0.68,\n      ease: 'easeInOut',\n      times: [0, 0.16, 0.28, 0.6, 0.82, 1],\n    },\n  },\n};\n\nconst boardVariants: Variants = {\n  normal: {\n    x: 0,\n    scale: 1,\n    rotate: 0,\n    transition: { type: 'spring', duration: 0.3, bounce: 0 },\n  },\n  animate: {\n    x: [0, 0, 0, -0.5, 0.22, 0],\n    scale: [1, 1, 1, 0.985, 1.012, 1],\n    rotate: [0, 0, 0, -0.6, 0.25, 0],\n    transition: {\n      duration: 0.68,\n      ease: 'easeInOut',\n      times: [0, 0.16, 0.34, 0.6, 0.82, 1],\n    },\n  },\n};\n\n/** Animated Clipboard Paste icon with imperative hover controls. */\nconst ClipboardPasteIcon = forwardRef<ClipboardPasteIconHandle, ClipboardPasteIconProps>(\n  ({ onMouseEnter, onMouseLeave, className, size = 28, ...props }, ref) => {\n    const controls = useAnimation();\n    const { handleMouseEnter, handleMouseLeave } = useIconAnimation({\n      controls,\n      loops: false,\n      onMouseEnter,\n      onMouseLeave,\n      ref,\n    });\n\n    return (\n      <div\n        className={cn(className)}\n        onMouseEnter={handleMouseEnter}\n        onMouseLeave={handleMouseLeave}\n        {...props}\n      >\n        <svg\n          xmlns=\"http://www.w3.org/2000/svg\"\n          width={size}\n          height={size}\n          viewBox=\"0 0 24 24\"\n          fill=\"none\"\n          overflow=\"visible\"\n        >\n          <motion.g\n            variants={pasteVariants}\n            animate={controls}\n            initial=\"normal\"\n            style={{ transformOrigin: '15px 13px' }}\n          >\n            <path\n              d=\"M19.502 13.0005H10.502\"\n              stroke=\"currentColor\"\n              strokeLinecap=\"round\"\n              strokeLinejoin=\"round\"\n              strokeWidth=\"1.5\"\n            />\n            <path\n              d=\"M17.502 10.0005C17.502 10.0005 20.5019 12.21 20.502 13.0005C20.502 13.7911 17.502 16.0005 17.502 16.0005\"\n              stroke=\"currentColor\"\n              strokeLinecap=\"round\"\n              strokeLinejoin=\"round\"\n              strokeWidth=\"1.5\"\n            />\n          </motion.g>\n          <motion.g\n            variants={boardVariants}\n            animate={controls}\n            initial=\"normal\"\n            style={{ transformOrigin: '11.5px 12px' }}\n          >\n            <path\n              d=\"M13.998 2.00049H8.99805C8.16962 2.00049 7.49805 2.67206 7.49805 3.50049C7.49805 4.32892 8.16962 5.00049 8.99805 5.00049H13.998C14.8265 5.00049 15.498 4.32892 15.498 3.50049C15.498 2.67206 14.8265 2.00049 13.998 2.00049Z\"\n              stroke=\"currentColor\"\n              strokeLinecap=\"round\"\n              strokeLinejoin=\"round\"\n              strokeWidth=\"1.5\"\n            />\n            <path\n              d=\"M15.4981 3.50049C17.0515 3.5473 17.9781 3.72056 18.6194 4.36185C19.1913 4.93377 19.391 5.73255 19.4607 7.00049M7.49795 3.50049C5.94456 3.5473 5.01802 3.72056 4.37673 4.36184C3.49805 5.24053 3.49805 6.65474 3.49806 9.48318L3.49805 16C3.49805 18.8284 3.49806 20.2426 4.37674 21.1213C5.25541 22 6.66963 22 9.49805 22L13.498 22C16.3265 22 17.7407 22 18.6194 21.1213C19.1092 20.6315 19.3259 19.9753 19.4219 19.0005\"\n              stroke=\"currentColor\"\n              strokeLinecap=\"round\"\n              strokeLinejoin=\"round\"\n              strokeWidth=\"1.5\"\n            />\n          </motion.g>\n        </svg>\n      </div>\n    );\n  }\n);\n\nClipboardPasteIcon.displayName = 'ClipboardPasteIcon';\n\nexport { ClipboardPasteIcon };\n",
      "type": "registry:ui"
    },
    {
      "path": "lib/use-icon-animation.ts",
      "content": "'use client';\n\nimport type { LegacyAnimationControls } from 'motion/react';\nimport { useReducedMotion } from 'motion/react';\nimport type {\n  ForwardedRef,\n  MouseEventHandler,\n} from 'react';\nimport { useCallback, useImperativeHandle, useRef } from 'react';\n\nexport interface AnimatedIconHandle {\n  startAnimation: () => void;\n  stopAnimation: () => void;\n}\n\ninterface UseIconAnimationOptions {\n  controls: LegacyAnimationControls;\n  loops?: boolean;\n  onMouseEnter?: MouseEventHandler<HTMLDivElement>;\n  onMouseLeave?: MouseEventHandler<HTMLDivElement>;\n  ref: ForwardedRef<AnimatedIconHandle>;\n}\n\nexport function useIconAnimation({\n  controls,\n  loops = false,\n  onMouseEnter,\n  onMouseLeave,\n  ref,\n}: UseIconAnimationOptions) {\n  const shouldReduceMotion = useReducedMotion();\n  const isControlledRef = useRef(false);\n  const isPlayingRef = useRef(false);\n  const runRef = useRef(0);\n\n  const startAnimation = useCallback(() => {\n    if (shouldReduceMotion || isPlayingRef.current) return;\n\n    isPlayingRef.current = true;\n    const run = ++runRef.current;\n    controls.set('normal');\n    void controls.start('animate').then(() => {\n      if (runRef.current === run) isPlayingRef.current = false;\n    });\n  }, [controls, shouldReduceMotion]);\n\n  const stopAnimation = useCallback(() => {\n    if (!loops) return;\n\n    runRef.current++;\n    isPlayingRef.current = false;\n    void controls.start('normal');\n  }, [controls, loops]);\n\n  useImperativeHandle(\n    ref,\n    () => {\n      isControlledRef.current = true;\n      return { startAnimation, stopAnimation };\n    },\n    [startAnimation, stopAnimation]\n  );\n\n  const handleMouseEnter = useCallback<MouseEventHandler<HTMLDivElement>>(\n    (event) => {\n      onMouseEnter?.(event);\n      if (!isControlledRef.current) startAnimation();\n    },\n    [onMouseEnter, startAnimation]\n  );\n\n  const handleMouseLeave = useCallback<MouseEventHandler<HTMLDivElement>>(\n    (event) => {\n      onMouseLeave?.(event);\n      if (!isControlledRef.current) stopAnimation();\n    },\n    [onMouseLeave, stopAnimation]\n  );\n\n  return { handleMouseEnter, handleMouseLeave };\n}\n",
      "type": "registry:lib"
    }
  ],
  "type": "registry:ui"
}