{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "inline-disclosure-menu",
  "type": "registry:component",
  "title": "Inline Disclosure Menu",
  "description": "An animated inline action menu with contextul Options and a two-step delete confirmation flow.",
  "dependencies": [
    "@hugeicons/core-free-icons",
    "@hugeicons/react",
    "lucide-react",
    "motion"
  ],
  "files": [
    {
      "path": "components/watermelon/inline-disclosure-menu.tsx",
      "type": "registry:component",
      "content": "'use client';\n\nimport * as React from 'react';\nimport { MoreVertical } from 'lucide-react';\nimport { HugeiconsIcon } from '@hugeicons/react';\nimport {\n  Copy01Icon,\n  Delete02Icon,\n  FavouriteIcon,\n  PencilEdit02Icon,\n  Share01Icon,\n} from '@hugeicons/core-free-icons';\nimport {\n  AnimatePresence,\n  LayoutGroup,\n  motion,\n  type Transition,\n  type Variants,\n} from 'motion/react';\n\nexport interface MenuItemProps {\n  icon: React.ReactNode;\n  label: string;\n  onClick?: () => void;\n  className?: string;\n}\n\nexport interface InlineDisclosureMenuProps {\n  menuItems?: MenuItemProps[];\n  showDelete?: boolean;\n  onDelete?: () => void;\n}\n\nconst spring: Transition = {\n  type: 'spring',\n  bounce: 0,\n  duration: 0.4,\n};\n\nconst menuVariants: Variants = {\n  hidden: { opacity: 0, scale: 0.94 },\n  visible: { opacity: 1, scale: 1, transition: spring },\n};\n\nconst deleteVariants: Variants = {\n  initial: (confirm: boolean) => ({\n    y: confirm ? 60 : -60,\n  }),\n  animate: {\n    y: 0,\n    transition: spring,\n  },\n  exit: (confirm: boolean) => ({\n    y: confirm ? -60 : 60,\n    transition: spring,\n  }),\n};\n\nconst confirmVariants: Variants = {\n  initial: (confirm: boolean) => ({\n    y: confirm ? 60 : -60,\n  }),\n  animate: {\n    y: 0,\n    transition: spring,\n  },\n  exit: (confirm: boolean) => ({\n    y: confirm ? -60 : 60,\n    transition: spring,\n  }),\n};\n\nconst MenuItem: React.FC<MenuItemProps> = ({\n  icon,\n  label,\n  onClick,\n  className = '',\n}) => (\n  <button\n    onClick={onClick}\n    className={`flex w-full items-center gap-3 rounded-xl px-3 py-2 text-left text-[#363538] transition-colors hover:bg-[#F6F5FA] sm:gap-4 dark:text-zinc-200 dark:hover:bg-zinc-800 ${className}`}\n  >\n    <span className=\"text-gray-500 dark:text-zinc-400\">{icon}</span>\n    <span className=\"text-base font-medium tracking-tight sm:text-[18px]\">\n      {label}\n    </span>\n  </button>\n);\n\nexport function InlineDisclosureMenu({\n  menuItems = [\n    {\n      icon: <HugeiconsIcon icon={PencilEdit02Icon} size={24} />,\n      label: 'Edit',\n    },\n    { icon: <HugeiconsIcon icon={Copy01Icon} size={24} />, label: 'Duplicate' },\n    {\n      icon: <HugeiconsIcon icon={FavouriteIcon} size={24} />,\n      label: 'Favourite',\n    },\n    { icon: <HugeiconsIcon icon={Share01Icon} size={24} />, label: 'Share' },\n  ],\n  showDelete = true,\n  onDelete,\n}: InlineDisclosureMenuProps) {\n  const [open, setOpen] = React.useState(false);\n  const [confirm, setConfirm] = React.useState(false);\n  const ref = React.useRef<HTMLDivElement>(null);\n\n  React.useEffect(() => {\n    const handler = (e: MouseEvent) => {\n      if (ref.current && !ref.current.contains(e.target as Node)) {\n        setOpen(false);\n        setConfirm(false);\n      }\n    };\n    document.addEventListener('mousedown', handler);\n    return () => document.removeEventListener('mousedown', handler);\n  }, []);\n\n  return (\n    <div className=\"relative flex w-full justify-center\">\n      <div ref={ref} className=\"relative\">\n        <motion.button\n          whileTap={{ scale: 0.95 }}\n          onClick={() => setOpen((v) => !v)}\n          className=\"flex h-12 w-12 items-center justify-center rounded-2xl border-2 border-[#EEEEF2] bg-white text-gray-500 sm:h-14 sm:w-14 dark:border-zinc-800 dark:bg-zinc-900 dark:text-zinc-400\"\n        >\n          <MoreVertical className=\"h-5 w-5 sm:h-6 sm:w-6\" />\n        </motion.button>\n\n        <AnimatePresence>\n          {open && (\n            <motion.div\n              variants={menuVariants}\n              initial=\"hidden\"\n              animate=\"visible\"\n              exit=\"hidden\"\n              className=\"absolute top-1/2 left-1/2 z-50 w-[260px] -translate-x-1/2 -translate-y-1/2 overflow-hidden rounded-2xl border-2 border-[#EEEEF2] bg-white shadow-xl sm:w-[304px] dark:border-zinc-800 dark:bg-zinc-900\"\n            >\n              <div className=\"border-b-2 border-[#EEEEF2] bg-[#FAFAFC] px-4 py-2 sm:px-6 dark:border-zinc-800 dark:bg-zinc-800/50\">\n                <span className=\"text-sm font-medium text-[#828287] sm:text-[16px] dark:text-zinc-500\">\n                  More Options\n                </span>\n              </div>\n\n              <LayoutGroup>\n                <div className=\"flex flex-col gap-2 px-2 py-2\">\n                  {menuItems.map((item, i) => (\n                    <MenuItem key={i} {...item} />\n                  ))}\n                </div>\n\n                {showDelete && (\n                  <div className=\"relative h-[56px] overflow-hidden border-t-2 border-[#EEEEF2] dark:border-zinc-800\">\n                    <AnimatePresence\n                      custom={confirm}\n                      mode=\"popLayout\"\n                      initial={false}\n                    >\n                      {!confirm ? (\n                        <motion.div\n                          key=\"delete\"\n                          custom={confirm}\n                          variants={deleteVariants}\n                          initial=\"initial\"\n                          animate=\"animate\"\n                          exit=\"exit\"\n                          className=\"absolute inset-0 flex items-center px-2\"\n                        >\n                          <MenuItem\n                            icon={\n                              <HugeiconsIcon\n                                icon={Delete02Icon}\n                                size={24}\n                                color=\"#e94447\"\n                              />\n                            }\n                            label=\"Delete\"\n                            className=\"cursor-pointer text-[#e94447]\"\n                            onClick={() => setConfirm(true)}\n                          />\n                        </motion.div>\n                      ) : (\n                        <motion.div\n                          key=\"confirm\"\n                          custom={confirm}\n                          variants={confirmVariants}\n                          initial=\"initial\"\n                          animate=\"animate\"\n                          exit=\"exit\"\n                          className=\"absolute inset-0 flex items-center gap-2 px-2\"\n                        >\n                          <button\n                            onClick={onDelete}\n                            className=\"h-10 flex-1 cursor-pointer rounded-xl bg-[#F24140] font-semibold text-white\"\n                          >\n                            Yes, Delete\n                          </button>\n\n                          <button\n                            onClick={() => setConfirm(false)}\n                            className=\"h-10 flex-1 cursor-pointer rounded-xl border border-gray-200 text-gray-600 dark:border-zinc-700 dark:text-zinc-300\"\n                          >\n                            Cancel\n                          </button>\n                        </motion.div>\n                      )}\n                    </AnimatePresence>\n                  </div>\n                )}\n              </LayoutGroup>\n            </motion.div>\n          )}\n        </AnimatePresence>\n      </div>\n    </div>\n  );\n}\n"
    }
  ]
}
