{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "morphing-discovery-bar",
  "type": "registry:component",
  "title": "Morphing Discovery Bar",
  "description": "A category tab bar that morphs into a search field, with a sliding active indicator and smooth layout animations.",
  "dependencies": [
    "lucide-react",
    "motion"
  ],
  "files": [
    {
      "path": "components/watermelon/morphing-discovery-bar.tsx",
      "type": "registry:component",
      "content": "'use client';\n\nimport React, { useState, useRef, useEffect } from 'react';\nimport { motion, AnimatePresence, LayoutGroup } from 'motion/react';\nimport { Search, X } from 'lucide-react';\n\n/* ---------- Types ---------- */\nexport interface Category {\n  id: string;\n  label: string;\n  icon: React.ReactNode;\n  activeColor: string;\n  activeTextColor: string;\n}\n\nexport interface MorphingDiscoveryBarProps {\n  categories: Category[];\n  className?: string;\n}\n\n/* ---------- Motion Settings ---------- */\nconst transition = {\n  type: 'spring',\n  bounce: 0.3,\n  duration: 0.7,\n} as const;\n\nexport const MorphingDiscoveryBar: React.FC<MorphingDiscoveryBarProps> = ({\n  categories,\n  className = '',\n}) => {\n  const [isSearching, setIsSearching] = useState(false);\n  const [activeTab, setActiveTab] = useState(categories[0]?.id);\n  const [searchValue, setSearchValue] = useState('');\n  const inputRef = useRef<HTMLInputElement>(null);\n\n  useEffect(() => {\n    if (isSearching) {\n      const timer = setTimeout(() => inputRef.current?.focus(), 100);\n      return () => clearTimeout(timer);\n    }\n  }, [isSearching]);\n\n  return (\n    <div\n      className={`flex w-full flex-col items-center justify-center bg-transparent p-2 transition-colors duration-500 sm:p-4 ${className}`}\n    >\n      {/* Container height adjusted for mobile flow */}\n      <div className=\"flex h-20 w-full max-w-full items-center justify-center\">\n        <LayoutGroup>\n          <motion.div\n            layout\n            transition={transition}\n            className=\"flex max-w-full items-center gap-1.5 rounded-[32px] p-1.5 backdrop-blur-md sm:gap-3 sm:p-2\"\n          >\n            {/* SEARCH COMPONENT */}\n            <motion.div\n              layout\n              style={{ borderRadius: 28 }}\n              transition={transition}\n              className={`relative flex items-center overflow-hidden border shadow-sm transition-colors ${\n                isSearching\n                  ? 'xs:w-64 h-12 w-[calc(100vw-80px)] sm:h-14 sm:w-80'\n                  : 'h-12 w-12 sm:h-14 sm:w-14'\n              } border-neutral-100 bg-white dark:border-neutral-800 dark:bg-neutral-900`}\n            >\n              <div className=\"flex h-full w-full items-center justify-center px-3 sm:px-4\">\n                <motion.div layout=\"position\" transition={transition}>\n                  <Search\n                    size={18}\n                    strokeWidth={3}\n                    className=\"shrink-0 text-neutral-900 transition-colors dark:text-neutral-400\"\n                  />\n                </motion.div>\n\n                <AnimatePresence mode=\"wait\">\n                  {isSearching && (\n                    <motion.input\n                      key=\"search-input\"\n                      ref={inputRef}\n                      initial={{\n                        opacity: 0,\n                        scaleX: 0.6,\n                        scaleY: 0.8,\n                        filter: 'blur(4px)',\n                        transformOrigin: 'left center',\n                      }}\n                      animate={{\n                        opacity: 1,\n                        scaleX: 1,\n                        scaleY: 1,\n                        filter: 'blur(0px)',\n                      }}\n                      exit={{\n                        opacity: 0,\n                        scaleX: 0.6,\n                        scaleY: 0.8,\n                        filter: 'blur(4px)',\n                      }}\n                      transition={{ duration: 0.15 }}\n                      placeholder=\"Search\"\n                      className=\"ml-2 w-full border-none bg-transparent text-sm font-medium text-neutral-900 outline-none placeholder:text-neutral-400 sm:text-base dark:text-white dark:placeholder:text-neutral-600\"\n                      value={searchValue}\n                      onChange={(e) => setSearchValue(e.target.value)}\n                    />\n                  )}\n                </AnimatePresence>\n\n                {!isSearching && (\n                  <motion.button\n                    layoutId=\"search-click-overlay\"\n                    className=\"absolute inset-0 z-10 h-full w-full\"\n                    onClick={() => setIsSearching(true)}\n                  />\n                )}\n              </div>\n            </motion.div>\n\n            {/* CATEGORIES */}\n            <AnimatePresence mode=\"popLayout\">\n              {!isSearching ? (\n                <motion.div\n                  key=\"categories-list\"\n                  layout\n                  initial={{ opacity: 0, scale: 0.9, filter: 'blur(10px)' }}\n                  animate={{ opacity: 1, scale: 1, filter: 'blur(0px)' }}\n                  exit={{ opacity: 0, scale: 0.9, filter: 'blur(10px)' }}\n                  transition={transition}\n                  className=\"flex items-center gap-1 overflow-hidden rounded-full border border-[#F0F0F0] bg-[#ffffff] p-1 dark:border-neutral-800 dark:bg-neutral-900\"\n                >\n                  {categories.map((cat) => {\n                    const isActive = activeTab === cat.id;\n\n                    return (\n                      <motion.button\n                        key={cat.id}\n                        layout\n                        onClick={() => setActiveTab(cat.id)}\n                        className={`relative z-0 flex items-center gap-1.5 rounded-full px-3 py-2 text-xs font-bold tracking-tight whitespace-nowrap transition-colors sm:gap-2 sm:px-6 sm:py-3 sm:text-lg`}\n                        style={{\n                          color: isActive ? cat.activeTextColor : undefined,\n                        }}\n                      >\n                        {!isActive && (\n                          <span className=\"absolute inset-0 flex items-center justify-center text-neutral-600 dark:text-neutral-400\" />\n                        )}\n\n                        {isActive && (\n                          <motion.div\n                            layoutId=\"pill-bg\"\n                            className=\"absolute inset-0 z-[-1] rounded-full bg-[(--active-bg)] shadow-sm dark:border dark:border-neutral-700 dark:bg-neutral-800\"\n                            style={\n                              {\n                                // @ts-ignore\n                                '--active-bg': cat.activeColor,\n                              } as React.CSSProperties\n                            }\n                            transition={transition}\n                          />\n                        )}\n                        <span className=\"relative z-10 scale-90 sm:scale-100\">\n                          {cat.icon}\n                        </span>\n                        <span\n                          className={`relative z-10 ${!isActive ? 'text-neutral-600 dark:text-neutral-400' : ''}`}\n                        >\n                          {cat.label}\n                        </span>\n                      </motion.button>\n                    );\n                  })}\n                </motion.div>\n              ) : (\n                <motion.button\n                  key=\"close-action\"\n                  layout\n                  initial={{\n                    width: 120,\n                    x: -80,\n                    scaleX: 1.5,\n                    scaleY: 0.8,\n                    opacity: 0,\n                    filter: 'blur(8px)',\n                    transformOrigin: 'left center',\n                  }}\n                  animate={{\n                    width: 56,\n                    x: 0,\n                    scaleX: 1,\n                    scaleY: 1,\n                    opacity: 1,\n                    filter: 'blur(0px)',\n                  }}\n                  exit={{\n                    width: 120,\n                    x: -80,\n                    scaleX: 1.5,\n                    scaleY: 0.8,\n                    opacity: 0,\n                    filter: 'blur(8px)',\n                  }}\n                  transition={transition}\n                  whileTap={{ scale: 0.9 }}\n                  onClick={() => {\n                    setIsSearching(false);\n                    setSearchValue('');\n                  }}\n                  className=\"flex h-12 w-12 shrink-0 items-center justify-center rounded-full border border-neutral-100 bg-white text-neutral-900 shadow-sm transition-colors sm:h-14 sm:w-14 dark:border-neutral-800 dark:bg-neutral-900 dark:text-white\"\n                >\n                  <X size={18} strokeWidth={2.5} />\n                </motion.button>\n              )}\n            </AnimatePresence>\n          </motion.div>\n        </LayoutGroup>\n      </div>\n    </div>\n  );\n};\n"
    }
  ]
}
