{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "folder-animation-carbon",
  "type": "registry:component",
  "title": "Folder Animation",
  "description": "Animated folder card with motion blur effect, perfect for showcasing file operations or loading states.",
  "dependencies": [
    "framer-motion",
    "react"
  ],
  "files": [
    {
      "path": "@uitripled/react-carbon/src/components/native/folder-animation-carbon.tsx",
      "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\nimport {\n  motion,\n  useAnimationControls,\n  useReducedMotion,\n} from \"framer-motion\";\nimport { type ReactNode, useState, useCallback, useEffect, useRef } from \"react\";\n\ninterface FolderAnimationProps {\n  /**\n   * Duration of the animation cycle in seconds.\n   * Default: 3\n   */\n  animationDuration?: number;\n  /**\n   * Custom folder icon to display. If not provided, a default folder icon is rendered.\n   */\n  folderIcon?: ReactNode;\n  /**\n   * Content to display in the card footer.\n   */\n  children?: ReactNode;\n  /**\n   * Additional CSS classes for the container.\n   */\n  className?: string;\n  /**\n   * Accessible label for the animation area.\n   */\n  ariaLabel?: string;\n}\n\nexport function FolderAnimation({\n  animationDuration = 3,\n  folderIcon,\n  children,\n  className,\n  ariaLabel = \"Animated folder illustration\",\n}: FolderAnimationProps) {\n  const [isHovered, setIsHovered] = useState(false);\n  const prefersReducedMotion = useReducedMotion();\n  const controls = useAnimationControls();\n  const blurControls = useAnimationControls();\n  const isAnimatingRef = useRef(false);\n  const shouldStopRef = useRef(false);\n\n  const handleMouseEnter = useCallback(() => setIsHovered(true), []);\n  const handleMouseLeave = useCallback(() => setIsHovered(false), []);\n  const handleFocus = useCallback(() => setIsHovered(true), []);\n  const handleBlur = useCallback(() => setIsHovered(false), []);\n\n  // Animation sequence: center → right → (wrap to left) → center → repeat\n  const runAnimation = useCallback(async () => {\n    if (prefersReducedMotion) return;\n\n    isAnimatingRef.current = true;\n    shouldStopRef.current = false;\n\n    while (!shouldStopRef.current) {\n      // Phase 1: Center to right (exit right with blur)\n      await Promise.all([\n        controls.start({\n          x: \"150%\",\n          opacity: [1, 1, 0],\n          transition: {\n            duration: animationDuration / 2,\n            ease: \"easeIn\",\n            times: [0, 0.7, 1],\n          },\n        }),\n        blurControls.start({\n          filter: [\"blur(0px)\", \"blur(0px)\", \"blur(8px)\", \"blur(16px)\"],\n          transition: {\n            duration: animationDuration / 2,\n            ease: \"easeIn\",\n            times: [0, 0.5, 0.75, 1],\n          },\n        }),\n      ]);\n\n      if (shouldStopRef.current) break;\n\n      // Instantly move to left (off-screen)\n      await controls.set({ x: \"-150%\", opacity: 0 });\n      await blurControls.set({ filter: \"blur(16px)\" });\n\n      if (shouldStopRef.current) break;\n\n      // Phase 2: Left to center (enter from left, deblur)\n      await Promise.all([\n        controls.start({\n          x: \"0%\",\n          opacity: [0, 1, 1],\n          transition: {\n            duration: animationDuration / 2,\n            ease: \"easeOut\",\n            times: [0, 0.3, 1],\n          },\n        }),\n        blurControls.start({\n          filter: [\"blur(16px)\", \"blur(8px)\", \"blur(0px)\", \"blur(0px)\"],\n          transition: {\n            duration: animationDuration / 2,\n            ease: \"easeOut\",\n            times: [0, 0.25, 0.5, 1],\n          },\n        }),\n      ]);\n\n      if (shouldStopRef.current) break;\n\n      // Brief pause at center\n      await new Promise((resolve) => setTimeout(resolve, 400));\n    }\n\n    isAnimatingRef.current = false;\n  }, [controls, blurControls, animationDuration, prefersReducedMotion]);\n\n  // Return to center smoothly\n  const returnToCenter = useCallback(async () => {\n    shouldStopRef.current = true;\n\n    await Promise.all([\n      controls.start({\n        x: \"0%\",\n        opacity: 1,\n        transition: {\n          duration: 0.5,\n          ease: [0.25, 0.1, 0.25, 1], // cubic-bezier for smooth deceleration\n        },\n      }),\n      blurControls.start({\n        filter: \"blur(0px)\",\n        transition: {\n          duration: 0.3,\n          ease: \"easeOut\",\n        },\n      }),\n    ]);\n\n    isAnimatingRef.current = false;\n  }, [controls, blurControls]);\n\n  useEffect(() => {\n    if (isHovered && !prefersReducedMotion) {\n      runAnimation();\n    } else {\n      returnToCenter();\n    }\n  }, [isHovered, prefersReducedMotion, runAnimation, returnToCenter]);\n\n  // Set initial position\n  useEffect(() => {\n    controls.set({ x: \"0%\", opacity: 1 });\n    blurControls.set({ filter: \"blur(0px)\" });\n  }, [controls, blurControls]);\n\n  return (\n    <div className={cn(className)}>\n      {/* Card Container */}\n      <div className=\"bg-card p-2 rounded-lg overflow-hidden w-full border border-border\">\n        {/* Animation Area */}\n        <div\n          className=\"relative w-full h-64 bg-muted overflow-hidden flex items-center justify-center rounded-lg cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n          onMouseEnter={handleMouseEnter}\n          onMouseLeave={handleMouseLeave}\n          onFocus={handleFocus}\n          onBlur={handleBlur}\n          tabIndex={0}\n          role=\"img\"\n          aria-label={ariaLabel}\n        >\n          {/* Animated Icon/Folder */}\n          <motion.div\n            animate={controls}\n            className=\"absolute\"\n            style={{ willChange: \"transform, opacity\" }}\n          >\n            <motion.div\n              animate={blurControls}\n              className=\"relative\"\n              style={{ willChange: \"filter\" }}\n            >\n              {folderIcon ? (\n                <div className=\"flex items-center justify-center\">{folderIcon}</div>\n              ) : (\n                <div className=\"relative w-28 h-24\">\n                  {/* Folder Back */}\n                  <div className=\"absolute inset-0 bg-primary/10 rounded-lg border border-primary/20\">\n                    {/* Tab */}\n                  </div>\n\n                  {/* Files inside */}\n                  <div className=\"absolute bottom-2 left-2 right-2 h-20 bg-background border border-border rounded shadow-sm transform -rotate-3 origin-bottom-left flex flex-col p-2 gap-1.5\">\n                    <div className=\"w-8 h-1 bg-muted rounded-full\" />\n                    <div className=\"w-full h-1 bg-muted/50 rounded-full\" />\n                    <div className=\"w-16 h-1 bg-muted/50 rounded-full\" />\n                  </div>\n\n                  <div className=\"absolute bottom-2 left-2 right-2 h-20 bg-background border border-border rounded shadow-sm transform rotate-3 origin-bottom-right z-10 flex flex-col p-2 gap-1.5\">\n                    <div className=\"flex gap-2 items-center mb-1\">\n                      <div className=\"w-4 h-4 bg-primary/10 rounded-full\" />\n                      <div className=\"w-10 h-1 bg-muted rounded-full\" />\n                    </div>\n                    <div className=\"w-full h-1 bg-muted/50 rounded-full\" />\n                    <div className=\"w-3/4 h-1 bg-muted/50 rounded-full\" />\n                  </div>\n\n                  {/* Folder Front */}\n                  <div className=\"absolute bottom-0 inset-x-0 h-14 bg-gradient-to-br from-primary/20 to-primary/5 backdrop-blur-md rounded-lg border-t border-white/20 border-x border-primary/10 shadow-lg z-20 flex items-center justify-center\">\n                    <div className=\"w-8 h-1 bg-primary/20 rounded-full\" />\n                  </div>\n                </div>\n              )}\n            </motion.div>\n          </motion.div>\n        </div>\n\n        {/* Card Footer */}\n        {children && <div className=\"p-3 mt-5\">{children}</div>}\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/uitripled/folder-animation-carbon.tsx"
    }
  ]
}