{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "icon-picker-custom-color",
  "title": "Icon Picker Custom Color",
  "description": "A simple icon picker component with custom color.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "input",
    "scroll-area",
    "button",
    "radio-group",
    "popover"
  ],
  "files": [
    {
      "path": "registry/icon-picker/icon-picker-custom-color.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { icons, PaletteIcon } from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\nimport { useDebounce } from \"@/hooks/use-debounce\";\n\nimport { Input } from \"@/components/ui/input\";\nimport { ScrollArea } from \"@/components/ui/scroll-area\";\nimport {\n  Popover,\n  PopoverContent,\n  PopoverTrigger,\n} from \"@/components/ui/popover\";\nimport { Button } from \"@/components/ui/button\";\nimport { RadioGroup, RadioGroupItem } from \"@/components/ui/radio-group\";\n\nconst IconItem = React.memo(\n  ({\n    iconName,\n    setSelectedIcon,\n    selectedIcon,\n  }: {\n    iconName: string;\n    setSelectedIcon?: (iconName: string) => void;\n    selectedIcon?: string | null;\n  }) => {\n    const Icon = icons[iconName as keyof typeof icons];\n\n    const handleClick = React.useCallback(() => {\n      setSelectedIcon?.(iconName);\n    }, [iconName, setSelectedIcon]);\n\n    return (\n      <button\n        className={cn(\n          \"flex items-center justify-center size-7 rounded-md cursor-pointer text-popover-foreground/70 hover:bg-muted hover:text-popover-foreground transition-colors\",\n          selectedIcon === iconName &&\n            \"bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground\",\n        )}\n        onClick={handleClick}\n        title={iconName}\n        aria-label={`Select ${iconName} icon`}\n        aria-pressed={selectedIcon === iconName}\n      >\n        <Icon size={16} />\n      </button>\n    );\n  },\n);\n\nIconItem.displayName = \"IconItem\";\n\nconst IconPicker = React.memo(\n  ({\n    setSelectedIcon,\n    selectedIcon,\n    setSelectedColor,\n    selectedColor,\n    className,\n    ...props\n  }: {\n    setSelectedIcon?: (iconName: string) => void;\n    selectedIcon?: string | null;\n    selectedColor?: string;\n    setSelectedColor?: (color: string) => void;\n  } & React.ComponentProps<\"div\">) => {\n    const [searchQuery, setSearchQuery] = React.useState(\"\");\n    const debouncedSearchQuery = useDebounce(searchQuery, 200);\n\n    const iconsMap = React.useMemo(() => Object.keys(icons), []);\n\n    const filteredIcons = React.useMemo(() => {\n      if (!debouncedSearchQuery.trim()) return iconsMap;\n      return iconsMap.filter((iconName) =>\n        iconName.toLowerCase().includes(debouncedSearchQuery.toLowerCase()),\n      );\n    }, [iconsMap, debouncedSearchQuery]);\n\n    const handleSearchChange = React.useCallback(\n      (e: React.ChangeEvent<HTMLInputElement>) => {\n        setSearchQuery(e.target.value);\n      },\n      [],\n    );\n\n    return (\n      <div\n        className={cn(\n          \"max-w-72 bg-popover rounded-lg border shadow-md\",\n          className,\n        )}\n        aria-label=\"Icon picker\"\n        {...props}\n      >\n        <div className=\"mt-1.5 mx-1.5 flex items-center gap-1.5 min-w-0 md:min-w-[252px]\">\n          <Input\n            autoComplete=\"off\"\n            autoCorrect=\"off\"\n            autoCapitalize=\"off\"\n            spellCheck={false}\n            className=\"border-none focus-visible:ring-2 font-semibold px-2.5 py-2 w-full\"\n            placeholder=\"Search...\"\n            type=\"text\"\n            value={searchQuery}\n            onChange={handleSearchChange}\n            aria-label=\"Search icons\"\n          />\n          {selectedIcon && (\n            <Popover>\n              <PopoverTrigger\n                render={\n                  <Button\n                    variant=\"outline\"\n                    size=\"icon\"\n                    className=\"border-none focus-visible:ring-2 relative\"\n                    style={{ backgroundColor: selectedColor }}\n                  />\n                }\n              >\n                <PaletteIcon size={16} />\n              </PopoverTrigger>\n              <PopoverContent className=\"w-min\">\n                <RadioGroup\n                  className=\"flex gap-1.5\"\n                  value={selectedColor}\n                  onValueChange={setSelectedColor}\n                >\n                  <RadioGroupItem\n                    value=\"oklch(62.3% 0.214 259.815)\"\n                    aria-label=\"blue\"\n                    className=\"size-6 !border-blue-500 !bg-blue-500 shadow-none data-[state=checked]:border-blue-500 data-[state=checked]:bg-blue-500\"\n                  />\n                  <RadioGroupItem\n                    value=\"oklch(58.5% 0.233 277.117)\"\n                    aria-label=\"indigo\"\n                    className=\"size-6 !border-indigo-500 !bg-indigo-500 shadow-none data-[state=checked]:border-indigo-500 data-[state=checked]:bg-indigo-500\"\n                  />\n                  <RadioGroupItem\n                    value=\"oklch(65.6% 0.241 354.308)\"\n                    aria-label=\"pink\"\n                    className=\"size-6 !border-pink-500 !bg-pink-500 shadow-none data-[state=checked]:border-pink-500 data-[state=checked]:bg-pink-500\"\n                  />\n                  <RadioGroupItem\n                    value=\"oklch(63.7% 0.237 25.331)\"\n                    aria-label=\"red\"\n                    className=\"size-6 !border-red-500 !bg-red-500 shadow-none data-[state=checked]:border-red-500 data-[state=checked]:bg-red-500\"\n                  />\n                  <RadioGroupItem\n                    value=\"oklch(70.5% 0.213 47.604)\"\n                    aria-label=\"orange\"\n                    className=\"size-6 !border-orange-500 !bg-orange-500 shadow-none data-[state=checked]:border-orange-500 data-[state=checked]:bg-orange-500\"\n                  />\n                  <RadioGroupItem\n                    value=\"oklch(76.9% 0.188 70.08)\"\n                    aria-label=\"amber\"\n                    className=\"size-6 !border-amber-500 !bg-amber-500 shadow-none data-[state=checked]:border-amber-500 data-[state=checked]:bg-amber-500\"\n                  />\n                  <RadioGroupItem\n                    value=\"oklch(69.6% 0.17 162.48)\"\n                    aria-label=\"emerald\"\n                    className=\"size-6 !border-emerald-500 !bg-emerald-500 shadow-none data-[state=checked]:border-emerald-500 data-[state=checked]:bg-emerald-500\"\n                  />\n                  <RadioGroupItem\n                    value=\"oklch(71.48% 0.1257 215.22)\"\n                    aria-label=\"teal\"\n                    className=\"size-6 !border-teal-500 !bg-teal-500 shadow-none data-[state=checked]:border-teal-500 data-[state=checked]:bg-teal-500\"\n                  />\n                </RadioGroup>\n              </PopoverContent>\n            </Popover>\n          )}\n        </div>\n        <ScrollArea className=\"h-60 md:h-80 p-1.5\">\n          <div\n            className=\"grid grid-cols-7 md:grid-cols-9\"\n            aria-label=\"Available icons\"\n          >\n            {filteredIcons.map((iconName) => (\n              <IconItem\n                key={iconName}\n                iconName={iconName}\n                setSelectedIcon={setSelectedIcon}\n                selectedIcon={selectedIcon}\n              />\n            ))}\n          </div>\n        </ScrollArea>\n      </div>\n    );\n  },\n);\n\nIconPicker.displayName = \"IconPicker\";\n\nexport default IconPicker;\n",
      "type": "registry:component"
    },
    {
      "path": "hooks/use-debounce.ts",
      "content": "import * as React from \"react\";\n\nexport function useDebounce<T>(value: T, delay?: number): T {\n  const [debouncedValue, setDebouncedValue] = React.useState<T>(value);\n\n  React.useEffect(() => {\n    const timer = setTimeout(() => {\n      setDebouncedValue(value);\n    }, delay || 500);\n\n    return () => {\n      clearTimeout(timer);\n    };\n  }, [value, delay]);\n\n  return debouncedValue;\n}\n",
      "type": "registry:hook"
    }
  ],
  "type": "registry:block"
}