{
	"$schema": "https://ui.shadcn.com/schema/registry-item.json",
	"name": "Stack-JS-TW",
	"title": "Stack",
	"description": "Layered stack with swipe animations, autoplay and smooth transitions.",
	"type": "registry:component",
	"files": [
		{
			"type": "registry:component",
			"path": "Stack/Stack.jsx",
			"content": "import { motion, useMotionValue, useTransform } from 'motion/react';\nimport { useState, useEffect } from 'react';\n\nfunction CardRotate({ children, onSendToBack, sensitivity, disableDrag = false }) {\n  const x = useMotionValue(0);\n  const y = useMotionValue(0);\n  const rotateX = useTransform(y, [-100, 100], [60, -60]);\n  const rotateY = useTransform(x, [-100, 100], [-60, 60]);\n\n  function handleDragEnd(_, info) {\n    if (Math.abs(info.offset.x) > sensitivity || Math.abs(info.offset.y) > sensitivity) {\n      onSendToBack();\n    } else {\n      x.set(0);\n      y.set(0);\n    }\n  }\n\n  if (disableDrag) {\n    return (\n      <motion.div className=\"absolute inset-0 cursor-pointer\" style={{ x: 0, y: 0 }}>\n        {children}\n      </motion.div>\n    );\n  }\n\n  return (\n    <motion.div\n      className=\"absolute inset-0 cursor-grab\"\n      style={{ x, y, rotateX, rotateY }}\n      drag\n      dragConstraints={{ top: 0, right: 0, bottom: 0, left: 0 }}\n      dragElastic={0.6}\n      whileTap={{ cursor: 'grabbing' }}\n      onDragEnd={handleDragEnd}\n    >\n      {children}\n    </motion.div>\n  );\n}\n\nexport default function Stack({\n  randomRotation = false,\n  sensitivity = 200,\n  cards = [],\n  animationConfig = { stiffness: 260, damping: 20 },\n  sendToBackOnClick = false,\n  autoplay = false,\n  autoplayDelay = 3000,\n  pauseOnHover = false,\n  mobileClickOnly = false,\n  mobileBreakpoint = 768\n}) {\n  const [isMobile, setIsMobile] = useState(false);\n  const [isPaused, setIsPaused] = useState(false);\n\n  useEffect(() => {\n    const checkMobile = () => {\n      setIsMobile(window.innerWidth < mobileBreakpoint);\n    };\n\n    checkMobile();\n    window.addEventListener('resize', checkMobile);\n    return () => window.removeEventListener('resize', checkMobile);\n  }, [mobileBreakpoint]);\n\n  const shouldDisableDrag = mobileClickOnly && isMobile;\n  const shouldEnableClick = sendToBackOnClick || shouldDisableDrag;\n\n  const [stack, setStack] = useState(() => {\n    if (cards.length) {\n      return cards.map((content, index) => ({ id: index + 1, content }));\n    } else {\n      return [\n        {\n          id: 1,\n          content: (\n            <img\n              src=\"https://images.unsplash.com/photo-1480074568708-e7b720bb3f09?q=80&w=500&auto=format\"\n              alt=\"card-1\"\n              className=\"w-full h-full object-cover pointer-events-none\"\n            />\n          )\n        },\n        {\n          id: 2,\n          content: (\n            <img\n              src=\"https://images.unsplash.com/photo-1449844908441-8829872d2607?q=80&w=500&auto=format\"\n              alt=\"card-2\"\n              className=\"w-full h-full object-cover pointer-events-none\"\n            />\n          )\n        },\n        {\n          id: 3,\n          content: (\n            <img\n              src=\"https://images.unsplash.com/photo-1452626212852-811d58933cae?q=80&w=500&auto=format\"\n              alt=\"card-3\"\n              className=\"w-full h-full object-cover pointer-events-none\"\n            />\n          )\n        },\n        {\n          id: 4,\n          content: (\n            <img\n              src=\"https://images.unsplash.com/photo-1572120360610-d971b9d7767c?q=80&w=500&auto=format\"\n              alt=\"card-4\"\n              className=\"w-full h-full object-cover pointer-events-none\"\n            />\n          )\n        }\n      ];\n    }\n  });\n\n  useEffect(() => {\n    if (cards.length) {\n      setStack(cards.map((content, index) => ({ id: index + 1, content })));\n    }\n  }, [cards]);\n\n  const sendToBack = id => {\n    setStack(prev => {\n      const newStack = [...prev];\n      const index = newStack.findIndex(card => card.id === id);\n      const [card] = newStack.splice(index, 1);\n      newStack.unshift(card);\n      return newStack;\n    });\n  };\n\n  useEffect(() => {\n    if (autoplay && stack.length > 1 && !isPaused) {\n      const interval = setInterval(() => {\n        const topCardId = stack[stack.length - 1].id;\n        sendToBack(topCardId);\n      }, autoplayDelay);\n\n      return () => clearInterval(interval);\n    }\n  }, [autoplay, autoplayDelay, stack, isPaused]);\n\n  return (\n    <div\n      className=\"relative w-full h-full\"\n      style={{\n        perspective: 600\n      }}\n      onMouseEnter={() => pauseOnHover && setIsPaused(true)}\n      onMouseLeave={() => pauseOnHover && setIsPaused(false)}\n    >\n      {stack.map((card, index) => {\n        const randomRotate = randomRotation ? Math.random() * 10 - 5 : 0;\n        return (\n          <CardRotate\n            key={card.id}\n            onSendToBack={() => sendToBack(card.id)}\n            sensitivity={sensitivity}\n            disableDrag={shouldDisableDrag}\n          >\n            <motion.div\n              className=\"rounded-2xl overflow-hidden w-full h-full\"\n              onClick={() => shouldEnableClick && sendToBack(card.id)}\n              animate={{\n                rotateZ: (stack.length - index - 1) * 4 + randomRotate,\n                scale: 1 + index * 0.06 - stack.length * 0.06,\n                transformOrigin: '90% 90%'\n              }}\n              initial={false}\n              transition={{\n                type: 'spring',\n                stiffness: animationConfig.stiffness,\n                damping: animationConfig.damping\n              }}\n            >\n              {card.content}\n            </motion.div>\n          </CardRotate>\n        );\n      })}\n    </div>\n  );\n}\n"
		}
	],
	"registryDependencies": [],
	"dependencies": [
		"motion@^12.23.12"
	]
}