{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "share-sheet",
  "type": "registry:component",
  "title": "share sheet",
  "description": "An animated share sheet widget that smoothly expands to reveal a list of users for quick link sharing.",
  "dependencies": [
    "motion",
    "react-icons"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "components/watermelon/share-sheet.tsx",
      "type": "registry:component",
      "content": "'use client';\n\nimport { useState } from 'react';\nimport { motion, AnimatePresence } from 'motion/react';\nimport { FiShare } from 'react-icons/fi';\nimport { cn } from '@/lib/utils';\n\ninterface User {\n  id: string;\n  name: string;\n  avatar: string;\n}\n\ninterface ShareSheetProps {\n  users: User[];\n  onShareComplete?: (user: User) => void;\n}\n\nconst springTransition = {\n  type: 'spring',\n  stiffness: 240,\n  damping: 20,\n  mass: 1,\n} as const;\n\nexport const ShareSheet = ({ users, onShareComplete }: ShareSheetProps) => {\n  const [status, setStatus] = useState<'idle' | 'open' | 'sending' | 'success'>(\n    'idle',\n  );\n  const [selectedUser, setSelectedUser] = useState<User | null>(null);\n  const [hoveredId, setHoveredId] = useState<string | null>(null);\n\n  const radius = 22;\n  const circumference = 2 * Math.PI * radius;\n\n  const handleSelectUser = (user: User) => {\n    setSelectedUser(user);\n    setStatus('sending');\n\n    setTimeout(() => {\n      setStatus('success');\n\n      setTimeout(() => {\n        setStatus('idle');\n        setSelectedUser(null);\n        onShareComplete?.(user);\n      }, 800);\n    }, 1800);\n  };\n\n  return (\n    <div className=\"relative flex items-center justify-center\">\n      <motion.button\n        onClick={() => status === 'idle' && setStatus('open')}\n        className=\"relative flex h-14 w-14 items-center justify-center overflow-hidden rounded-[17px] bg-neutral-900 text-neutral-50 shadow-sm dark:bg-neutral-100 dark:text-neutral-900\"\n        initial={{ opacity: 0, scale: 0.8 }}\n        animate={{ opacity: 1, scale: 1 }}\n        transition={springTransition}\n      >\n        <AnimatePresence mode=\"popLayout\" initial={false}>\n          {status === 'idle' && (\n            <motion.div\n              key=\"share-icon\"\n              initial={{ opacity: 0, y: 40 }}\n              animate={{ opacity: 1, y: 0 }}\n              exit={{ opacity: 0, y: -40 }}\n            >\n              <FiShare size={26} strokeWidth={2} />\n            </motion.div>\n          )}\n\n          {(status === 'sending' || status === 'success') && (\n            <motion.div\n              key=\"sending-container\"\n              initial={{ opacity: 0, y: 40 }}\n              animate={{ opacity: 1, y: 0 }}\n              exit={{ opacity: 0, y: -40 }}\n              transition={{\n                type: 'spring',\n                stiffness: 400,\n                damping: 25,\n              }}\n              className=\"flex h-14 w-14 items-center justify-center overflow-hidden rounded-[17px] bg-neutral-900 text-neutral-50 shadow-sm dark:bg-neutral-100 dark:text-neutral-900\"\n            >\n              <div className=\"relative flex h-full w-full items-center justify-center overflow-hidden p-2\">\n                <svg className=\"pointer-events-none absolute inset-0 h-full w-full -rotate-90\">\n                  <circle\n                    cx=\"28\"\n                    cy=\"28\"\n                    r=\"22\"\n                    stroke=\"currentColor\"\n                    strokeOpacity=\"0.15\"\n                    strokeWidth=\"3\"\n                    fill=\"transparent\"\n                  />\n\n                  <motion.circle\n                    cx=\"28\"\n                    cy=\"28\"\n                    r=\"22\"\n                    stroke=\"currentColor\"\n                    strokeWidth=\"3\"\n                    fill=\"transparent\"\n                    strokeDasharray={circumference}\n                    initial={{ strokeDashoffset: circumference }}\n                    animate={{ strokeDashoffset: 0 }}\n                    transition={{ duration: 1.8, ease: 'easeInOut' }}\n                  />\n                </svg>\n\n                <motion.img\n                  key=\"sending-avatar\"\n                  layoutId=\"avatar-morph\"\n                  src={selectedUser?.avatar}\n                  className=\"absolute inset-0 m-auto size-10 rounded-full object-cover\"\n                  exit={{ opacity: 0, scale: 0.6 }}\n                  transition={{ duration: 0.3 }}\n                />\n\n                <AnimatePresence mode=\"wait\">\n                  {status === 'success' && (\n                    <motion.div\n                      key=\"success-check\"\n                      initial={{ scale: 0, opacity: 0 }}\n                      animate={{ scale: 1, opacity: 1 }}\n                      exit={{ scale: 0, opacity: 0 }}\n                      transition={{\n                        type: 'spring',\n                        stiffness: 400,\n                        damping: 20,\n                      }}\n                      className=\"flex h-9 w-9 items-center justify-center\"\n                    >\n                      <svg\n                        width=\"24\"\n                        height=\"24\"\n                        viewBox=\"0 0 24 24\"\n                        fill=\"none\"\n                        stroke=\"currentColor\"\n                        strokeWidth=\"3.5\"\n                        strokeLinecap=\"round\"\n                        strokeLinejoin=\"round\"\n                      >\n                        <polyline points=\"20 6 9 17 4 12\" />\n                      </svg>\n                    </motion.div>\n                  )}\n                </AnimatePresence>\n              </div>\n            </motion.div>\n          )}\n        </AnimatePresence>\n      </motion.button>\n      <AnimatePresence mode=\"popLayout\" initial={false}>\n        {status === 'open' && (\n          <motion.div\n            className=\"absolute w-[340px] rounded-[38px] bg-neutral-100 p-3 py-5 shadow-md transition-colors duration-300 dark:bg-neutral-900\"\n            initial={{ opacity: 0, scale: 0 }}\n            animate={{ opacity: 1, scale: 1 }}\n            exit={{ opacity: 0, scale: 0 }}\n            transition={springTransition}\n          >\n            <div className=\"relative flex flex-col\">\n              {users.map((user) => (\n                <motion.div\n                  layout\n                  key={user.id}\n                  onHoverStart={() => setHoveredId(user.id)}\n                  onHoverEnd={() => setHoveredId(null)}\n                  onClick={() => handleSelectUser(user)}\n                  className={cn(\n                    'group relative z-10 flex cursor-pointer items-center gap-3 p-2',\n                    hoveredId === user.id && 'px-0',\n                  )}\n                  animate={{\n                    x: hoveredId === user.id ? -10 : 0,\n                  }}\n                >\n                  {hoveredId === user.id && (\n                    <motion.div\n                      layoutId=\"hover-bg\"\n                      className=\"absolute inset-y-0 -right-6 -left-6 -z-10 rounded-[14px] border border-neutral-200 bg-white shadow-sm dark:border-neutral-800 dark:bg-neutral-800\"\n                      transition={springTransition}\n                    />\n                  )}\n\n                  <motion.div\n                    layout\n                    className=\"relative h-11 w-11 overflow-hidden\"\n                    animate={{\n                      borderRadius: hoveredId === user.id ? '12px' : '28px',\n                    }}\n                    transition={springTransition}\n                  >\n                    <motion.img\n                      layout\n                      layoutId={\n                        selectedUser?.id === user.id\n                          ? 'avatar-morph'\n                          : `img-${user.id}`\n                      }\n                      src={user.avatar}\n                      className=\"h-full w-full object-cover\"\n                    />\n                  </motion.div>\n\n                  <motion.span\n                    layout\n                    className=\"text-[17px] font-medium tracking-tight text-neutral-800 dark:text-neutral-200\"\n                  >\n                    {user.name}\n                  </motion.span>\n                </motion.div>\n              ))}\n            </div>\n          </motion.div>\n        )}\n      </AnimatePresence>\n    </div>\n  );\n};\n"
    }
  ]
}
