{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "dropdown-disclosure",
  "type": "registry:component",
  "title": "Dropdown Disclosure",
  "description": "A sophisticated dropdown menu with shared layout transitions and spring-driven animations for item selection.",
  "dependencies": [
    "@hugeicons/core-free-icons",
    "@hugeicons/react",
    "lucide-react",
    "motion",
    "react-icons",
    "react-use-measure"
  ],
  "files": [
    {
      "path": "components/watermelon/dropdown-disclosure.tsx",
      "type": "registry:component",
      "content": "'use client';\n\nimport { useRef, useEffect, type ReactNode, type FC } from 'react';\nimport { motion, AnimatePresence, MotionConfig } from 'motion/react';\nimport { ChevronDown, X, ArrowUpRight, Check } from 'lucide-react';\nimport { FaMeta } from 'react-icons/fa6';\nimport { HugeiconsIcon } from '@hugeicons/react';\nimport { GoogleGeminiIcon, QwenFreeIcons } from '@hugeicons/core-free-icons';\nimport { SiClaude } from 'react-icons/si';\nimport useMeasure from 'react-use-measure';\n\n\nexport interface Model {\n  id: string;\n  name: string;\n  description: string;\n  icon: ReactNode;\n  hasUpgrade?: boolean;\n}\n\ninterface DropdownDisclosureProps {\n  models?: Model[];\n  isOpen: boolean;\n  onOpenChange: (isOpen: boolean) => void;\n  selectedModelId: string;\n  onModelChange: (model: Model) => void;\n}\n\nconst DEFAULT_MODELS: Model[] = [\n  {\n    id: 'sonnet',\n    name: 'Sonnet 3.5',\n    description: 'Advanced reasoning',\n    icon: <SiClaude size={22} />,\n    hasUpgrade: true,\n  },\n  {\n    id: 'llama',\n    name: 'Llama 3.2',\n    description: 'Versatile problem-solving',\n    icon: <FaMeta size={22} />,\n  },\n  {\n    id: 'qwen',\n    name: 'Qwen 2.5',\n    description: 'Rapid text generation',\n    icon: (\n      <HugeiconsIcon\n        icon={QwenFreeIcons}\n        size={24}\n        color=\"#7c7b82\"\n        strokeWidth={1.5}\n      />\n    ),\n  },\n  {\n    id: 'gemma',\n    name: 'Gemma 2',\n    description: 'Efficient task completion',\n    icon: (\n      <HugeiconsIcon\n        icon={GoogleGeminiIcon}\n        size={24}\n        color=\"#7c7b82\"\n        strokeWidth={1.5}\n      />\n    ),\n  },\n];\n\nexport const DropdownDisclosure: FC<DropdownDisclosureProps> = ({\n  models = DEFAULT_MODELS,\n  isOpen,\n  onOpenChange,\n  selectedModelId,\n  onModelChange,\n}) => {\n  const modelList = models;\n  const selected =\n    modelList.find((m) => m.id === selectedModelId) || modelList[0];\n\n  const [ref, bounds] = useMeasure({ offsetSize: true });\n  const containerRef = useRef<HTMLDivElement | null>(null);\n\n  useEffect(() => {\n    function handleClickOutside(e: MouseEvent) {\n      if (!containerRef.current) return;\n      if (!containerRef.current.contains(e.target as Node)) {\n        onOpenChange(false);\n      }\n    }\n\n    if (isOpen) {\n      document.addEventListener('mousedown', handleClickOutside);\n    }\n\n    return () => {\n      document.removeEventListener('mousedown', handleClickOutside);\n    };\n  }, [isOpen, onOpenChange]);\n\n  return (\n    <MotionConfig\n      transition={{\n        type: 'spring',\n        stiffness: 200,\n        damping: 25,\n        mass: 1,\n      }}\n    >\n      <motion.div\n        ref={containerRef}\n        animate={{\n          width: bounds.width > 0 ? bounds.width : 'auto',\n          height: bounds.height > 0 ? bounds.height : 'auto',\n        }}\n        className=\"relative flex items-center justify-center overflow-hidden border border-black/10 bg-neutral-50 dark:border-white/20 dark:bg-neutral-900\"\n        style={{\n          borderRadius: 16,\n        }}\n      >\n        <div ref={ref} className=\"shrink-0 p-2\">\n          <AnimatePresence mode=\"popLayout\" initial={false}>\n            {!isOpen ? (\n              <motion.button\n                key=\"trigger\"\n                onClick={() => onOpenChange(true)}\n                exit={{\n                  opacity: 0,\n                  transition: {\n                    duration: 0,\n                  },\n                }}\n                className=\"flex cursor-pointer items-center gap-2\"\n              >\n                <motion.div\n                  layoutId={`model-icon-${selected.id}`}\n                  //   layout=\"position\"\n                  className=\"flex shrink-0 items-center justify-center rounded-full border border-neutral-200 text-neutral-500 dark:border-neutral-700 dark:text-neutral-400\"\n                  style={{\n                    width: 40,\n                    height: 40,\n                  }}\n                >\n                  {selected.icon}\n                </motion.div>\n\n                <motion.span\n                  layoutId={`model-name-${selected.id}`}\n                  layout=\"position\"\n                  className=\"truncate text-base font-bold text-neutral-600 dark:text-neutral-200\"\n                >\n                  {selected.name}\n                </motion.span>\n\n                <motion.div\n                  //   layoutId=\"toggle\"\n                  className=\"ml-4\"\n                >\n                  <ChevronDown className=\"h-6 w-6 text-neutral-800 dark:text-neutral-400\" />\n                </motion.div>\n              </motion.button>\n            ) : (\n              <motion.div\n                key=\"expanded\"\n                exit={{ opacity: 0, transition: { duration: 0.2 } }}\n                className=\"flex flex-col items-center gap-3 pt-2\"\n              >\n                <motion.div\n                  role=\"dialog\"\n                  aria-label=\"Model Selection Menu\"\n                  className=\"\"\n                >\n                  <div className=\"mb-3 flex items-center justify-between px-2\">\n                    <motion.span\n                      layoutId=\"title\"\n                      className=\"text-lg font-bold text-neutral-500 dark:text-neutral-500\"\n                    >\n                      Choose Model\n                    </motion.span>\n\n                    <button\n                      onClick={() => onOpenChange(false)}\n                      aria-label=\"Close menu\"\n                      title=\"Close menu\"\n                      className=\"flex h-7 w-7 items-center justify-center rounded-full bg-neutral-400 transition-opacity hover:opacity-80 dark:bg-neutral-700\"\n                    >\n                      <X className=\"h-5 w-5 text-white\" />\n                    </button>\n                  </div>\n\n                  <div className=\"flex flex-col gap-1\">\n                    {modelList.map((m) => {\n                      const active = m.id === selected.id;\n\n                      return (\n                        <motion.button\n                          key={m.id}\n                          onClick={() => {\n                            onModelChange?.(m);\n                            onOpenChange?.(false);\n                          }}\n                          whileTap={{ scale: 0.97 }}\n                          className=\"group flex items-center justify-between gap-4 rounded-xl px-2 py-3 transition-colors hover:bg-neutral-100 sm:px-3 dark:hover:bg-neutral-800\"\n                        >\n                          <div className=\"flex min-w-0 flex-1 items-center gap-3 sm:gap-5\">\n                            <motion.div\n                              layoutId={`model-icon-${m.id}`}\n                              layout=\"position\"\n                              className=\"flex shrink-0 items-center justify-center rounded-full border border-neutral-200 text-neutral-500 dark:border-neutral-700 dark:text-neutral-400\"\n                              style={{\n                                width: 40,\n                                height: 40,\n                              }}\n                            >\n                              {m.icon}\n                            </motion.div>\n\n                            <div className=\"min-w-0 flex-1 text-left\">\n                              <motion.div\n                                layoutId={`model-name-${m.id}`}\n                                layout=\"position\"\n                                className=\"truncate text-base font-bold text-neutral-600 dark:text-neutral-200\"\n                                style={{\n                                  fontSize: 14,\n                                }}\n                              >\n                                {m.name}\n                              </motion.div>\n                              <div className=\"truncate text-sm text-neutral-400 dark:text-neutral-500\">\n                                {m.description}\n                              </div>\n                            </div>\n                          </div>\n\n                          <div className=\"flex items-center gap-3\">\n                            {m.hasUpgrade && (\n                              <div className=\"flex items-center overflow-hidden rounded-lg border border-neutral-300 text-sm font-semibold text-neutral-800 dark:border-neutral-600 dark:text-neutral-300\">\n                                <div className=\"border-r border-neutral-300 px-2 py-1 dark:border-neutral-600\">\n                                  <ArrowUpRight className=\"h-4 w-4 rounded-sm border-2 border-neutral-800 dark:border-neutral-300\" />\n                                </div>\n                                <div className=\"px-2 py-1\">Upgrade</div>\n                              </div>\n                            )}\n\n                            {!m.hasUpgrade && (\n                              <div\n                                className={`flex h-6 w-6 items-center justify-center rounded-full border-2 transition-all ${\n                                  active\n                                    ? 'border-neutral-900 bg-neutral-900 dark:border-neutral-100 dark:bg-neutral-100'\n                                    : 'border-neutral-200 dark:border-neutral-700'\n                                }`}\n                              >\n                                <AnimatePresence\n                                  mode=\"popLayout\"\n                                  initial={false}\n                                >\n                                  {active && (\n                                    <motion.div\n                                      initial={{ scale: 0, opacity: 0 }}\n                                      animate={{ scale: 1, opacity: 1 }}\n                                      exit={{ scale: 0, opacity: 0 }}\n                                      transition={{ duration: 0.2 }}\n                                    >\n                                      <Check className=\"h-4 w-4 stroke-[3.5px] text-white dark:text-neutral-900\" />\n                                    </motion.div>\n                                  )}\n                                </AnimatePresence>\n                              </div>\n                            )}\n                          </div>\n                        </motion.button>\n                      );\n                    })}\n                  </div>\n                </motion.div>\n              </motion.div>\n            )}\n          </AnimatePresence>\n        </div>\n      </motion.div>\n    </MotionConfig>\n  );\n};\n"
    }
  ]
}
