{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "discover-button",
  "type": "registry:block",
  "title": "Discover button",
  "description": "Discover button",
  "files": [
    {
      "path": "components/usages/discoverbuttonusage.tsx",
      "content": "import DiscoverButton from \"@/registry/open-source/discover-button\";\n\nexport default function DiscoverButtonUsage() {\n    return (\n        <div>\n            <DiscoverButton />\n        </div>\n    );\n}",
      "type": "registry:block",
      "target": "~/example.tsx"
    },
    {
      "path": "components/usages/discoverbuttonusage.tsx",
      "content": "import DiscoverButton from \"@/registry/open-source/discover-button\";\n\nexport default function DiscoverButtonUsage() {\n    return (\n        <div>\n            <DiscoverButton />\n        </div>\n    );\n}",
      "type": "registry:ui"
    },
    {
      "path": "registry/open-source/discover-button.tsx",
      "content": "\"use client\";\n\nimport { useState } from \"react\";\nimport { motion } from \"motion/react\";\n\n\nimport { SearchIcon } from \"./icons/search\";\nimport { HeartIcon } from \"./icons/heart\";\nimport { FlameIcon } from \"./icons/flame\";\nimport { XIcon } from \"./icons/x\";\n\n// Credit:\n// https://uselayouts.com/docs/components/discover-button\n\n// Change Here\nconst TABS = [\n    {\n        id: \"popular\",\n        label: \"Popular\",\n        Icon: FlameIcon,\n        color: \"text-red-500\",\n        fill: \"fill-red-500\",\n        bg: \"bg-red-50\",\n    },\n    {\n        id: \"favorites\",\n        label: \"Favorites\",\n        Icon: HeartIcon,\n        color: \"text-gray-900\",\n        fill: \"fill-gray-900\",\n        bg: \"bg-gray-100\",\n    },\n] as const;\n\nexport default function DiscoverButton() {\n    const [activeTab, setActiveTab] = useState<(typeof TABS)[number][\"id\"]>(\n        TABS[0].id\n    );\n    const [isSearchExpanded, setIsSearchExpanded] = useState(false);\n\n    return (\n        <div className=\"flex items-center gap-3 p-2 h-full \">\n            {/* Search Button / Input */}\n            <motion.div\n                layout\n                transition={{\n                    type: \"spring\",\n                    damping: 20,\n                    stiffness: 230,\n                    mass: 1.2,\n                }}\n                onClick={() => !isSearchExpanded && setIsSearchExpanded(true)}\n                className={`flex items-center bg-white rounded-[3rem] shadow-lg cursor-pointer h-[60px] overflow-hidden relative px-[1.125rem]     ${isSearchExpanded ? \"flex-1\" : \"\"\n                    }`}\n            >\n                <div className=\"shrink-0\">\n                    <SearchIcon />\n                </div>\n\n                <motion.div\n                    initial={false}\n                    animate={{\n                        width: isSearchExpanded ? \"auto\" : \"0px\",\n                        opacity: isSearchExpanded ? 1 : 0,\n                        filter: isSearchExpanded ? \"blur(0px)\" : \"blur(4px)\",\n                        marginLeft: isSearchExpanded ? \"12px\" : \"0px\",\n                    }}\n                    transition={{\n                        type: \"spring\",\n                        damping: 20,\n                        stiffness: 230,\n                        mass: 1.2,\n                    }}\n                    className=\"overflow-hidden -mb-0.5 flex items-center\"\n                >\n                    <input\n                        type=\"text\"\n                        placeholder=\"Search\"\n                        className=\"border-0 outline-none bg-transparent text-lg focus-visible:ring-0 focus-visible:ring-offset-0 w-full\"\n                        onClick={(e) => e.stopPropagation()}\n                    />\n                </motion.div>\n            </motion.div>\n\n            {/* Tab Container / Close Button */}\n            <motion.div\n                layout\n                transition={{\n                    type: \"spring\",\n                    damping: 20,\n                    stiffness: 230,\n                    mass: 1.2,\n                }}\n                className={`flex items-center bg-white rounded-[3rem] shadow-lg h-[60px] overflow-hidden relative `}\n            >\n                {/* Wrapper to control clipping - clips from right side */}\n                <motion.div\n                    initial={false}\n                    animate={{\n                        width: isSearchExpanded ? \"60px\" : \"auto\",\n                    }}\n                    transition={{\n                        type: \"spring\",\n                        damping: 20,\n                        stiffness: 230,\n                        mass: 1.2,\n                    }}\n                    className=\"overflow-hidden relative h-full flex items-center\"\n                >\n                    {/* Tabs Group - stays in place, gets clipped */}\n                    <motion.div\n                        initial={false}\n                        animate={{\n                            opacity: isSearchExpanded ? 0 : 1,\n                            filter: isSearchExpanded ? \"blur(4px)\" : \"blur(0px)\",\n                            width: \"auto\",\n                        }}\n                        transition={{\n                            duration: 0.2,\n                        }}\n                        className={`flex items-center  whitespace-nowrap `}\n                    >\n                        <div className=\"flex items-center gap-2 px-[6px]\">\n                            {TABS.map((tab) => (\n                                <button\n                                    key={tab.id}\n                                    onClick={() => setActiveTab(tab.id)}\n                                    className={`flex items-center gap-2 px-6 py-3 rounded-[3rem] transition-colors relative ${activeTab === tab.id ? tab.color : \"text-gray-700\"\n                                        }`}\n                                >\n                                    {activeTab === tab.id && (\n                                        <motion.span\n                                            layoutId=\"bubble\"\n                                            className={`absolute inset-0 z-0 ${tab.bg}`}\n                                            style={{ borderRadius: 9999 }}\n                                            transition={{\n                                                type: \"spring\",\n                                                bounce: 0.19,\n                                                duration: 0.4,\n                                            }}\n                                        />\n                                    )}\n                                    <tab.Icon />\n                                    <span className=\"font-semibold font-mono uppercase relative z-10\">\n                                        {tab.label}\n                                    </span>\n                                </button>\n                            ))}\n                        </div>\n                    </motion.div>\n\n                    {/* Close Button - positioned absolutely on top */}\n                    <motion.div\n                        initial={false}\n                        animate={{\n                            opacity: isSearchExpanded ? 1 : 0,\n                            filter: isSearchExpanded ? \"blur(0px)\" : \"blur(4px)\",\n                        }}\n                        transition={{\n                            duration: 0.2,\n                        }}\n                        className=\"absolute inset-0 flex items-center justify-center\"\n                        style={{ pointerEvents: isSearchExpanded ? \"auto\" : \"none\" }}\n                    >\n                        <button\n                            onClick={() => setIsSearchExpanded(false)}\n                            className=\"shrink-0 cursor-pointer\"\n                        >\n                            <XIcon />\n                        </button>\n                    </motion.div>\n                </motion.div>\n            </motion.div>\n        </div>\n    );\n}\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/open-source/icons/search.tsx",
      "content": "\"use client\";\n\nimport type { HTMLAttributes } from \"react\";\nimport { forwardRef, useCallback, useImperativeHandle, useRef } from \"react\";\n\nimport { cn } from \"@/registry/utilities/cn\";\nimport { motion, useAnimation } from \"motion/react\";\n\nexport interface SearchIconHandle {\n\tstartAnimation: () => void;\n\tstopAnimation: () => void;\n}\n\ninterface SearchIconProps extends HTMLAttributes<HTMLDivElement> {\n\tsize?: number;\n}\n\nconst SearchIcon = forwardRef<SearchIconHandle, SearchIconProps>(\n\t({ onMouseEnter, onMouseLeave, className, size = 28, ...props }, ref) => {\n\t\tconst controls = useAnimation();\n\t\tconst isControlledRef = useRef(false);\n\n\t\tuseImperativeHandle(ref, () => {\n\t\t\tisControlledRef.current = true;\n\n\t\t\treturn {\n\t\t\t\tstartAnimation: () => controls.start(\"animate\"),\n\t\t\t\tstopAnimation: () => controls.start(\"normal\"),\n\t\t\t};\n\t\t});\n\n\t\tconst handleMouseEnter = useCallback(\n\t\t\t(e: React.MouseEvent<HTMLDivElement>) => {\n\t\t\t\tif (!isControlledRef.current) {\n\t\t\t\t\tcontrols.start(\"animate\");\n\t\t\t\t} else {\n\t\t\t\t\tonMouseEnter?.(e);\n\t\t\t\t}\n\t\t\t},\n\t\t\t[controls, onMouseEnter]\n\t\t);\n\n\t\tconst handleMouseLeave = useCallback(\n\t\t\t(e: React.MouseEvent<HTMLDivElement>) => {\n\t\t\t\tif (!isControlledRef.current) {\n\t\t\t\t\tcontrols.start(\"normal\");\n\t\t\t\t} else {\n\t\t\t\t\tonMouseLeave?.(e);\n\t\t\t\t}\n\t\t\t},\n\t\t\t[controls, onMouseLeave]\n\t\t);\n\n\t\treturn (\n\t\t\t<div\n\t\t\t\tclassName={cn(\n\t\t\t\t\t`cursor-pointer select-none p-2 hover:bg-accent rounded-md transition-colors duration-200 flex items-center justify-center`,\n\t\t\t\t\tclassName\n\t\t\t\t)}\n\t\t\t\tonMouseEnter={handleMouseEnter}\n\t\t\t\tonMouseLeave={handleMouseLeave}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t<motion.svg\n\t\t\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t\t\twidth={size}\n\t\t\t\t\theight={size}\n\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\tfill=\"none\"\n\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\tstrokeWidth=\"2\"\n\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\tvariants={{\n\t\t\t\t\t\tnormal: { x: 0, y: 0 },\n\t\t\t\t\t\tanimate: {\n\t\t\t\t\t\t\tx: [0, 0, -3, 0],\n\t\t\t\t\t\t\ty: [0, -4, 0, 0],\n\t\t\t\t\t\t},\n\t\t\t\t\t}}\n\t\t\t\t\ttransition={{\n\t\t\t\t\t\tduration: 1,\n\t\t\t\t\t\tbounce: 0.3,\n\t\t\t\t\t}}\n\t\t\t\t\tanimate={controls}\n\t\t\t\t>\n\t\t\t\t\t<circle cx=\"11\" cy=\"11\" r=\"8\" />\n\t\t\t\t\t<path d=\"m21 21-4.3-4.3\" />\n\t\t\t\t</motion.svg>\n\t\t\t</div>\n\t\t);\n\t}\n);\n\nSearchIcon.displayName = \"SearchIcon\";\n\nexport { SearchIcon };\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/utilities/cn.ts",
      "content": "import { ClassValue, clsx } from \"clsx\";\r\nimport { twMerge } from \"tailwind-merge\";\r\n\r\nexport function cn(...inputs: ClassValue[]) {\r\n\treturn twMerge(clsx(inputs));\r\n}\r\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/open-source/icons/heart.tsx",
      "content": "\"use client\";\n\nimport { motion, useAnimation } from \"motion/react\";\nimport type { HTMLAttributes } from \"react\";\nimport { forwardRef, useCallback, useImperativeHandle, useRef } from \"react\";\n\nimport { cn } from \"@/registry/utilities/cn\";\n\nexport interface HeartIconHandle {\n    startAnimation: () => void;\n    stopAnimation: () => void;\n}\n\ninterface HeartIconProps extends HTMLAttributes<HTMLDivElement> {\n    size?: number;\n}\n\nconst HeartIcon = forwardRef<HeartIconHandle, HeartIconProps>(\n    ({ onMouseEnter, onMouseLeave, className, size = 28, ...props }, ref) => {\n        const controls = useAnimation();\n        const isControlledRef = useRef(false);\n\n        useImperativeHandle(ref, () => {\n            isControlledRef.current = true;\n\n            return {\n                startAnimation: () => controls.start(\"animate\"),\n                stopAnimation: () => controls.start(\"normal\"),\n            };\n        });\n\n        const handleMouseEnter = useCallback(\n            (e: React.MouseEvent<HTMLDivElement>) => {\n                if (isControlledRef.current) {\n                    onMouseEnter?.(e);\n                } else {\n                    controls.start(\"animate\");\n                }\n            },\n            [controls, onMouseEnter]\n        );\n\n        const handleMouseLeave = useCallback(\n            (e: React.MouseEvent<HTMLDivElement>) => {\n                if (isControlledRef.current) {\n                    onMouseLeave?.(e);\n                } else {\n                    controls.start(\"normal\");\n                }\n            },\n            [controls, onMouseLeave]\n        );\n\n        return (\n            <div\n                className={cn(className)}\n                onMouseEnter={handleMouseEnter}\n                onMouseLeave={handleMouseLeave}\n                {...props}\n            >\n                <motion.svg\n                    animate={controls}\n                    fill=\"none\"\n                    height={size}\n                    stroke=\"currentColor\"\n                    strokeLinecap=\"round\"\n                    strokeLinejoin=\"round\"\n                    strokeWidth=\"2\"\n                    transition={{\n                        duration: 0.45,\n                        repeat: 2,\n                    }}\n                    variants={{\n                        normal: { scale: 1 },\n                        animate: { scale: [1, 1.08, 1] },\n                    }}\n                    viewBox=\"0 0 24 24\"\n                    width={size}\n                    xmlns=\"http://www.w3.org/2000/svg\"\n                >\n                    <path d=\"M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z\" />\n                </motion.svg>\n            </div>\n        );\n    }\n);\n\nHeartIcon.displayName = \"HeartIcon\";\n\nexport { HeartIcon };\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/open-source/icons/flame.tsx",
      "content": "\"use client\";\r\n\r\nimport type { HTMLAttributes } from \"react\";\r\nimport { forwardRef, useCallback, useImperativeHandle, useRef } from \"react\";\r\n\r\nimport { cn } from \"@/registry/utilities/cn\";\r\nimport type { Variants } from \"motion/react\";\r\nimport { motion, useAnimation } from \"motion/react\";\r\n\r\nexport interface FlameIconHandle {\r\n\tstartAnimation: () => void;\r\n\tstopAnimation: () => void;\r\n}\r\n\r\ninterface FlameIconProps extends HTMLAttributes<HTMLDivElement> {\r\n\tsize?: number;\r\n}\r\n\r\nconst pathVariants: Variants = {\r\n\tnormal: {\r\n\t\tpathLength: 1,\r\n\t\topacity: 1,\r\n\t\tpathOffset: 0,\r\n\t},\r\n\tanimate: {\r\n\t\topacity: [0, 1],\r\n\t\tpathLength: [0, 1],\r\n\t\ttransition: {\r\n\t\t\tdelay: 0.1,\r\n\t\t\tduration: 0.4,\r\n\t\t\topacity: { duration: 0.1, delay: 0.1 },\r\n\t\t},\r\n\t},\r\n};\r\n\r\nconst FlameIcon = forwardRef<FlameIconHandle, FlameIconProps>(\r\n\t({ onMouseEnter, onMouseLeave, className, size = 28, ...props }, ref) => {\r\n\t\tconst controls = useAnimation();\r\n\t\tconst isControlledRef = useRef(false);\r\n\r\n\t\tuseImperativeHandle(ref, () => {\r\n\t\t\tisControlledRef.current = true;\r\n\r\n\t\t\treturn {\r\n\t\t\t\tstartAnimation: () => controls.start(\"animate\"),\r\n\t\t\t\tstopAnimation: () => controls.start(\"normal\"),\r\n\t\t\t};\r\n\t\t});\r\n\r\n\t\tconst handleMouseEnter = useCallback(\r\n\t\t\t(e: React.MouseEvent<HTMLDivElement>) => {\r\n\t\t\t\tif (!isControlledRef.current) {\r\n\t\t\t\t\tcontrols.start(\"animate\");\r\n\t\t\t\t} else {\r\n\t\t\t\t\tonMouseEnter?.(e);\r\n\t\t\t\t}\r\n\t\t\t},\r\n\t\t\t[controls, onMouseEnter]\r\n\t\t);\r\n\r\n\t\tconst handleMouseLeave = useCallback(\r\n\t\t\t(e: React.MouseEvent<HTMLDivElement>) => {\r\n\t\t\t\tif (!isControlledRef.current) {\r\n\t\t\t\t\tcontrols.start(\"normal\");\r\n\t\t\t\t} else {\r\n\t\t\t\t\tonMouseLeave?.(e);\r\n\t\t\t\t}\r\n\t\t\t},\r\n\t\t\t[controls, onMouseLeave]\r\n\t\t);\r\n\r\n\t\treturn (\r\n\t\t\t<div\r\n\t\t\t\tclassName={cn(\r\n\t\t\t\t\t`cursor-pointer select-none p-2 hover:bg-accent rounded-md transition-colors duration-200 flex items-center justify-center`,\r\n\t\t\t\t\tclassName\r\n\t\t\t\t)}\r\n\t\t\t\tonMouseEnter={handleMouseEnter}\r\n\t\t\t\tonMouseLeave={handleMouseLeave}\r\n\t\t\t\t{...props}\r\n\t\t\t>\r\n\t\t\t\t<svg\r\n\t\t\t\t\txmlns=\"http://www.w3.org/2000/svg\"\r\n\t\t\t\t\twidth={size}\r\n\t\t\t\t\theight={size}\r\n\t\t\t\t\tviewBox=\"0 0 24 24\"\r\n\t\t\t\t\tfill=\"none\"\r\n\t\t\t\t\tstroke=\"currentColor\"\r\n\t\t\t\t\tstrokeWidth=\"2\"\r\n\t\t\t\t\tstrokeLinecap=\"round\"\r\n\t\t\t\t\tstrokeLinejoin=\"round\"\r\n\t\t\t\t>\r\n\t\t\t\t\t<motion.path\r\n\t\t\t\t\t\tvariants={pathVariants}\r\n\t\t\t\t\t\tinitial=\"normal\"\r\n\t\t\t\t\t\tanimate={controls}\r\n\t\t\t\t\t\tfill=\"none\"\r\n\t\t\t\t\t\td=\"M8.9 14.5A2.5 2.5 0 0 0 11 12c0-1.38-.5-2-1-3-1.072-2.143-.224-4.054 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 1 1-14 0c0-1.153.433-2.294 1-3a2.5 2.5 0 0 0 2.5 2.5z\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</svg>\r\n\t\t\t</div>\r\n\t\t);\r\n\t}\r\n);\r\n\r\nFlameIcon.displayName = \"FlameIcon\";\r\n\r\nexport { FlameIcon };\r\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/open-source/icons/x.tsx",
      "content": "\"use client\";\r\n\r\nimport type { HTMLAttributes } from \"react\";\r\nimport { forwardRef, useCallback, useImperativeHandle, useRef } from \"react\";\r\n\r\nimport { cn } from \"@/registry/utilities/cn\";\r\nimport type { Variants } from \"motion/react\";\r\nimport { motion, useAnimation } from \"motion/react\";\r\n\r\nexport interface XIconHandle {\r\n\tstartAnimation: () => void;\r\n\tstopAnimation: () => void;\r\n}\r\n\r\ninterface XIconProps extends HTMLAttributes<HTMLDivElement> {\r\n\tsize?: number;\r\n}\r\n\r\nconst pathVariants: Variants = {\r\n\tnormal: {\r\n\t\topacity: 1,\r\n\t\tpathLength: 1,\r\n\t},\r\n\tanimate: {\r\n\t\topacity: [0, 1],\r\n\t\tpathLength: [0, 1],\r\n\t},\r\n};\r\n\r\nconst XIcon = forwardRef<XIconHandle, XIconProps>(\r\n\t({ onMouseEnter, onMouseLeave, className, size = 28, ...props }, ref) => {\r\n\t\tconst controls = useAnimation();\r\n\t\tconst isControlledRef = useRef(false);\r\n\r\n\t\tuseImperativeHandle(ref, () => {\r\n\t\t\tisControlledRef.current = true;\r\n\r\n\t\t\treturn {\r\n\t\t\t\tstartAnimation: () => controls.start(\"animate\"),\r\n\t\t\t\tstopAnimation: () => controls.start(\"normal\"),\r\n\t\t\t};\r\n\t\t});\r\n\r\n\t\tconst handleMouseEnter = useCallback(\r\n\t\t\t(e: React.MouseEvent<HTMLDivElement>) => {\r\n\t\t\t\tif (!isControlledRef.current) {\r\n\t\t\t\t\tcontrols.start(\"animate\");\r\n\t\t\t\t} else {\r\n\t\t\t\t\tonMouseEnter?.(e);\r\n\t\t\t\t}\r\n\t\t\t},\r\n\t\t\t[controls, onMouseEnter]\r\n\t\t);\r\n\r\n\t\tconst handleMouseLeave = useCallback(\r\n\t\t\t(e: React.MouseEvent<HTMLDivElement>) => {\r\n\t\t\t\tif (!isControlledRef.current) {\r\n\t\t\t\t\tcontrols.start(\"normal\");\r\n\t\t\t\t} else {\r\n\t\t\t\t\tonMouseLeave?.(e);\r\n\t\t\t\t}\r\n\t\t\t},\r\n\t\t\t[controls, onMouseLeave]\r\n\t\t);\r\n\t\treturn (\r\n\t\t\t<div\r\n\t\t\t\tclassName={cn(\r\n\t\t\t\t\t`cursor-pointer select-none p-2 hover:bg-accent rounded-md transition-colors duration-200 flex items-center justify-center`,\r\n\t\t\t\t\tclassName\r\n\t\t\t\t)}\r\n\t\t\t\tonMouseEnter={handleMouseEnter}\r\n\t\t\t\tonMouseLeave={handleMouseLeave}\r\n\t\t\t\t{...props}\r\n\t\t\t>\r\n\t\t\t\t<svg\r\n\t\t\t\t\txmlns=\"http://www.w3.org/2000/svg\"\r\n\t\t\t\t\twidth={size}\r\n\t\t\t\t\theight={size}\r\n\t\t\t\t\tviewBox=\"0 0 24 24\"\r\n\t\t\t\t\tfill=\"none\"\r\n\t\t\t\t\tstroke=\"currentColor\"\r\n\t\t\t\t\tstrokeWidth=\"2\"\r\n\t\t\t\t\tstrokeLinecap=\"round\"\r\n\t\t\t\t\tstrokeLinejoin=\"round\"\r\n\t\t\t\t>\r\n\t\t\t\t\t<motion.path\r\n\t\t\t\t\t\tvariants={pathVariants}\r\n\t\t\t\t\t\tanimate={controls}\r\n\t\t\t\t\t\td=\"M18 6 6 18\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t\t<motion.path\r\n\t\t\t\t\t\ttransition={{ delay: 0.2 }}\r\n\t\t\t\t\t\tvariants={pathVariants}\r\n\t\t\t\t\t\tanimate={controls}\r\n\t\t\t\t\t\td=\"m6 6 12 12\"\r\n\t\t\t\t\t/>\r\n\t\t\t\t</svg>\r\n\t\t\t</div>\r\n\t\t);\r\n\t}\r\n);\r\n\r\nXIcon.displayName = \"XIcon\";\r\n\r\nexport { XIcon };\r\n",
      "type": "registry:ui"
    }
  ]
}