{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "cloud",
  "title": "cloud",
  "description": "Animated cloud icon",
  "dependencies": [
    "motion"
  ],
  "files": [
    {
      "path": "icons/cloud.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\nexport interface CloudIconHandle {\n  startAnimation: () => void;\n  stopAnimation: () => void;\n}\n\ninterface CloudIconProps extends HTMLAttributes<HTMLDivElement> {\n  size?: number;\n}\n\n// A soft swell rolls through the cloud from left to right while its baseline\n// stays planted, so the icon feels alive without becoming weather-like.\nconst CLOUD_REST =\n  'M17.4776 10.0001C17.485 10 17.4925 10 17.5 10C19.9853 10 22 12.0147 22 14.5C22 16.9853 19.9853 19 17.5 19H7C4.23858 19 2 16.7614 2 14C2 11.4003 3.98398 9.26407 6.52042 9.0227M17.4776 10.0001C17.4924 9.83536 17.5 9.66856 17.5 9.5C17.5 6.46243 15.0376 4 12 4C9.12324 4 6.76233 6.20862 6.52042 9.0227M17.4776 10.0001C17.3753 11.1345 16.9286 12.1696 16.2428 13M6.52042 9.0227C6.67826 9.00768 6.83823 9 7 9C8.12582 9 9.16474 9.37209 10.0005 10';\nconst CLOUD_LEFT_SWELL =\n  'M17.3 10.2C17.32 10.18 17.35 10.17 17.4 10.17C20.08 10.17 22.2 12 22.2 14.5C22.2 16.9853 19.9853 19 17.5 19H7C3.85 19 1.15 16.7614 1.15 14C1.15 10.75 3.8 8.25 7.1 8.15M17.3 10.2C17.33 9.96 17.35 9.72 17.35 9.48C17.35 6.28 14.95 3.7 12 3.7C8.95 3.7 7.25 5.8 7.1 8.15M17.3 10.2C17.18 11.28 16.75 12.22 16.08 13M7.1 8.15C7.3 8.12 7.5 8.13 7.7 8.17C8.78 8.38 9.58 9.05 10.1 10.1';\nconst CLOUD_CROWN_SWELL =\n  'M17.75 9.65C17.78 9.63 17.82 9.62 17.86 9.62C20.55 9.62 22.7 11.78 22.7 14.5C22.7 16.9853 19.9853 19 17.5 19H7C4 19 1.45 16.7614 1.45 14C1.45 10.98 3.88 8.58 6.85 8.45M17.75 9.65C17.82 9.35 17.85 9.05 17.85 8.75C17.85 5.2 15.25 2.35 12 2.35C8.85 2.35 7 5.2 6.85 8.45M17.75 9.65C17.62 10.98 17.08 12.13 16.23 13M6.85 8.45C7.03 8.42 7.2 8.42 7.38 8.45C8.5 8.62 9.4 9.17 10.05 10.05';\nconst CLOUD_RIGHT_SWELL =\n  'M18.1 9.15C18.14 9.13 18.18 9.12 18.23 9.12C21.15 9.12 23.05 11.55 23.05 14.5C23.05 16.9853 19.9853 19 17.5 19H7C4.35 19 2.1 16.7614 2.1 14C2.1 11.55 4 9.5 6.45 9.12M18.1 9.15C18.12 8.98 18.13 8.8 18.13 8.62C18.13 5.68 15.28 3.45 12.08 3.45C9.2 3.45 6.72 6.08 6.45 9.12M18.1 9.15C17.98 10.68 17.32 11.98 16.3 13M6.45 9.12C6.62 9.08 6.8 9.06 6.98 9.06C8.12 9.06 9.18 9.4 10.02 10';\n\nconst svgVariants: Variants = {\n  normal: { transform: 'translate(0px, 0px)' },\n  animate: {\n    transform: [\n      'translate(0px, 0px)',\n      'translate(-0.8px, -0.35px)',\n      'translate(0px, -1.1px)',\n      'translate(0.9px, -0.3px)',\n      'translate(0px, 0px)',\n    ],\n    transition: {\n      duration: 1.05,\n      ease: 'easeInOut',\n      times: [0, 0.2, 0.45, 0.7, 1],\n    },\n  },\n};\n\nconst cloudShapeVariants: Variants = {\n  normal: { d: CLOUD_REST },\n  animate: {\n    d: [\n      CLOUD_REST,\n      CLOUD_LEFT_SWELL,\n      CLOUD_CROWN_SWELL,\n      CLOUD_RIGHT_SWELL,\n      CLOUD_REST,\n    ],\n    transition: {\n      duration: 1.05,\n      ease: 'easeInOut',\n      times: [0, 0.2, 0.45, 0.7, 1],\n    },\n  },\n};\n\nconst CloudIcon = forwardRef<CloudIconHandle, CloudIconProps>(\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        <motion.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          variants={svgVariants}\n          animate={controls}\n          initial=\"normal\"\n        >\n          <motion.path\n            d=\"M17.4776 10.0001C17.485 10 17.4925 10 17.5 10C19.9853 10 22 12.0147 22 14.5C22 16.9853 19.9853 19 17.5 19H7C4.23858 19 2 16.7614 2 14C2 11.4003 3.98398 9.26407 6.52042 9.0227M17.4776 10.0001C17.4924 9.83536 17.5 9.66856 17.5 9.5C17.5 6.46243 15.0376 4 12 4C9.12324 4 6.76233 6.20862 6.52042 9.0227M17.4776 10.0001C17.3753 11.1345 16.9286 12.1696 16.2428 13M6.52042 9.0227C6.67826 9.00768 6.83823 9 7 9C8.12582 9 9.16474 9.37209 10.0005 10\"\n            stroke=\"currentColor\"\n            strokeLinecap=\"round\"\n            strokeLinejoin=\"round\"\n            strokeWidth=\"1.5\"\n            variants={cloudShapeVariants}\n            animate={controls}\n            initial=\"normal\"\n          />\n        </motion.svg>\n      </div>\n    );\n  }\n);\n\nCloudIcon.displayName = 'CloudIcon';\n\nexport { CloudIcon };\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"
}