{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "folder-01",
  "title": "folder-01",
  "description": "Animated folder icon",
  "dependencies": [
    "motion"
  ],
  "files": [
    {
      "path": "icons/folder-01.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 Folder01IconHandle {\n  startAnimation: () => void;\n  stopAnimation: () => void;\n}\n\ninterface Folder01IconProps extends HTMLAttributes<HTMLDivElement> {\n  size?: number;\n}\n\n// match the compact lift, lean, and weighted settle of the sibling folders\nconst folderVariants: Variants = {\n  normal: { transform: 'translateY(0px) rotate(0deg)' },\n  animate: {\n    transform: [\n      'translateY(0px) rotate(0deg)',\n      'translateY(-1.7px) rotate(-2deg)',\n      'translateY(0.4px) rotate(0.7deg)',\n      'translateY(0px) rotate(0deg)',\n    ],\n    transition: {\n      duration: 0.56,\n      ease: [0.23, 1, 0.32, 1],\n    },\n  },\n};\n\nconst Folder01Icon = forwardRef<Folder01IconHandle, Folder01IconProps>(\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.path\n            d=\"M8 7H16.75C18.8567 7 19.91 7 20.6667 7.50559C20.9943 7.72447 21.2755 8.00572 21.4944 8.33329C22 9.08996 22 10.1433 22 12.25C22 15.7612 22 17.5167 21.1573 18.7779C20.7926 19.3238 20.3238 19.7926 19.7779 20.1573C18.5167 21 16.7612 21 13.25 21H12C7.28595 21 4.92893 21 3.46447 19.5355C2 18.0711 2 15.714 2 11V7.94427C2 6.1278 2 5.21956 2.38032 4.53806C2.65142 4.05227 3.05227 3.65142 3.53806 3.38032C4.21956 3 5.1278 3 6.94427 3C8.10802 3 8.6899 3 9.19926 3.19101C10.3622 3.62712 10.8418 4.68358 11.3666 5.73313L12 7\"\n            stroke=\"currentColor\"\n            strokeLinecap=\"round\"\n            strokeWidth=\"1.5\"\n            variants={folderVariants}\n            animate={controls}\n            initial=\"normal\"\n            style={{ transformOrigin: '12px 18px' }}\n          />\n        </svg>\n      </div>\n    );\n  }\n);\n\nFolder01Icon.displayName = 'Folder01Icon';\n\nexport { Folder01Icon };\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"
}