{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "coffee-02",
  "title": "coffee-02",
  "description": "Animated coffee icon",
  "dependencies": [
    "motion"
  ],
  "files": [
    {
      "path": "icons/coffee-02.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 Coffee02IconHandle {\n  startAnimation: () => void;\n  stopAnimation: () => void;\n}\n\ninterface Coffee02IconProps extends HTMLAttributes<HTMLDivElement> {\n  size?: number;\n}\n\ninterface SteamMotion {\n  duration: number;\n  delay: number;\n}\n\nconst createSteamVariants = ({\n  duration,\n  delay,\n}: SteamMotion): Variants => ({\n  normal: {\n    visibility: 'visible',\n    pathLength: 1,\n    pathOffset: 0,\n    transform: 'translateY(0px)',\n    transition: { duration: 0.14, ease: [0.23, 1, 0.32, 1] },\n  },\n  animate: {\n    pathLength: [1, 0.58, 0.22, 0, 0.14, 0.14, 0.34, 0.6, 1],\n    pathOffset: [0, 0, 0, 0, 0.86, 0.86, 0.54, 0.2, 0],\n    visibility: ['visible', 'visible', 'visible', 'hidden', 'hidden', 'visible', 'visible', 'visible', 'visible'],\n    transform: [\n      'translateY(0px)',\n      'translateY(-0.35px)',\n      'translateY(-0.9px)',\n      'translateY(-1.4px)',\n      'translateY(0px)',\n      'translateY(0px)',\n      'translateY(0px)',\n      'translateY(0px)',\n      'translateY(0px)',\n    ],\n    transition: {\n      duration,\n      delay,\n      ease: 'linear',\n      times: [0, 0.18, 0.32, 0.42, 0.48, 0.54, 0.68, 0.82, 1],\n      repeat: Infinity,\n    },\n  },\n});\n\n// rest-parity: split-source-path\n// The original combined Hugeicons steam path is split into its three exact\n// subpaths so each full resting stroke can rise and taper toward the top,\n// evaporate, reappear small at the cup, and grow into the full stroke again.\nconst leftSteamVariants = createSteamVariants({\n  duration: 1.08,\n  delay: 0,\n});\n\nconst centerSteamVariants = createSteamVariants({\n  duration: 1.2,\n  delay: 0.08,\n});\n\nconst rightSteamVariants = createSteamVariants({\n  duration: 1.12,\n  delay: 0.16,\n});\n\nconst Coffee02Icon = forwardRef<Coffee02IconHandle, Coffee02IconProps>(\n  ({ onMouseEnter, onMouseLeave, className, size = 28, ...props }, ref) => {\n    const controls = useAnimation();\n    const { handleMouseEnter, handleMouseLeave } = useIconAnimation({\n      controls,\n      loops: true,\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          <path\n            d=\"M18.2505 10.5H19.6403C21.4918 10.5 22.0421 10.7655 21.9975 12.0838C21.9237 14.2674 20.939 16.8047 17 17.5\"\n            stroke=\"currentColor\"\n            strokeLinecap=\"round\"\n            strokeWidth=\"1.5\"\n          />\n          <path\n            d=\"M5.94627 20.6145C2.57185 18.02 2.07468 14.3401 2.00143 10.5001C1.96979 8.8413 2.45126 8.5 4.65919 8.5H15.3408C17.5487 8.5 18.0302 8.8413 17.9986 10.5001C17.9253 14.3401 17.4281 18.02 14.0537 20.6145C13.0934 21.3528 12.2831 21.5 10.9194 21.5H9.08064C7.71686 21.5 6.90658 21.3528 5.94627 20.6145Z\"\n            stroke=\"currentColor\"\n            strokeLinecap=\"round\"\n            strokeWidth=\"1.5\"\n          />\n          <motion.path\n            d=\"M7.53971 4C7.53971 4 7.47974 4.05556 7.39979 4.16667C7.31983 4.27778 7.21988 4.44444 7.13992 4.66667C7.05997 4.88889 7 5.16667 7 5.5\"\n            stroke=\"currentColor\"\n            strokeLinecap=\"round\"\n            strokeLinejoin=\"round\"\n            strokeWidth=\"1.5\"\n            variants={leftSteamVariants}\n            animate={controls}\n            initial=\"normal\"\n          />\n          <motion.path\n            d=\"M11.3089 2.5C11.12667 2.61287 10.92062 2.81716 10.72689 3.09494C10.53316 3.37272 10.35173 3.72398 10.21874 4.1308C10.08576 4.53762 10.0012 5 10.0012 5.5\"\n            stroke=\"currentColor\"\n            strokeLinecap=\"round\"\n            strokeLinejoin=\"round\"\n            strokeWidth=\"1.5\"\n            variants={centerSteamVariants}\n            animate={controls}\n            initial=\"normal\"\n          />\n          <motion.path\n            d=\"M14.0012 4C13.9101 4.05643 13.82404 4.18636 13.74979 4.35302C13.67554 4.51969 13.61309 4.7231 13.56921 4.92651C13.52532 5.12992 13.5 5.33333 13.5 5.5\"\n            stroke=\"currentColor\"\n            strokeLinecap=\"round\"\n            strokeLinejoin=\"round\"\n            strokeWidth=\"1.5\"\n            variants={rightSteamVariants}\n            animate={controls}\n            initial=\"normal\"\n          />\n        </svg>\n      </div>\n    );\n  }\n);\n\nCoffee02Icon.displayName = 'Coffee02Icon';\n\nexport { Coffee02Icon };\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"
}