{"$schema":"https:\/\/ui.particle.academy\/schema\/registry-item.json","name":"color-picker","type":"registry:ui","title":"ColorPicker","description":"ColorPicker from react-fancy","package":"react-fancy","dependencies":[],"registryDependencies":["inputs"],"files":[{"path":"components\/fancy\/color-picker\/ColorPicker.tsx","content":"import { forwardRef, useId, useRef } from \"react\";\r\nimport { cn } from \"..\/..\/utils\/cn\";\r\nimport { useControllableState } from \"..\/..\/hooks\/use-controllable-state\";\r\nimport { useFieldMode } from \"..\/inputs\/mode\/FieldMode.context\";\r\nimport { useInlineEdit } from \"..\/inputs\/mode\/useInlineEdit\";\r\nimport type { ColorPickerProps } from \".\/ColorPicker.types\";\r\n\r\nconst DEFAULT_COLOR = \"#3b82f6\";\r\n\r\nconst SWATCH_SIZES = {\r\n  sm: \"h-6 w-6\",\r\n  md: \"h-8 w-8\",\r\n  lg: \"h-10 w-10\",\r\n} as const;\r\n\r\nconst TEXT_SIZES = {\r\n  sm: \"text-xs\",\r\n  md: \"text-sm\",\r\n  lg: \"text-base\",\r\n} as const;\r\n\r\nexport const ColorPicker = forwardRef<HTMLDivElement, ColorPickerProps>(\r\n  (\r\n    {\r\n      value,\r\n      defaultValue = DEFAULT_COLOR,\r\n      onChange,\r\n      presets,\r\n      size = \"md\",\r\n      variant = \"outline\",\r\n      disabled = false,\r\n      className,\r\n      mode,\r\n    },\r\n    ref,\r\n  ) => {\r\n    const [color, setColor] = useControllableState(\r\n      value,\r\n      defaultValue,\r\n      onChange,\r\n    );\r\n    const resolvedMode = useFieldMode(mode);\r\n    const { showControl, interactive, enterEdit, exitEdit } = useInlineEdit(resolvedMode, disabled);\r\n\r\n    const inputRef = useRef<HTMLInputElement>(null);\r\n    const datalistId = useId();\r\n\r\n    const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\r\n      setColor(e.target.value);\r\n    };\r\n\r\n    const handleSwatchClick = () => {\r\n      if (!disabled) {\r\n        inputRef.current?.click();\r\n      }\r\n    };\r\n\r\n    if (!showControl) {\r\n      return (\r\n        <div\r\n          ref={ref}\r\n          data-react-fancy-color-picker=\"\"\r\n          data-mode=\"view\"\r\n          role={interactive ? \"button\" : undefined}\r\n          tabIndex={interactive ? 0 : undefined}\r\n          title={interactive ? \"Click to edit\" : undefined}\r\n          onClick={interactive ? enterEdit : undefined}\r\n          onKeyDown={\r\n            interactive\r\n              ? (e) => {\r\n                  if (e.key === \"Enter\" || e.key === \" \") {\r\n                    e.preventDefault();\r\n                    enterEdit();\r\n                  }\r\n                }\r\n              : undefined\r\n          }\r\n          className={cn(\r\n            \"inline-flex items-center gap-2\",\r\n            interactive &&\r\n              \"cursor-pointer rounded-md outline-none transition-opacity hover:opacity-80 focus-visible:ring-2 focus-visible:ring-blue-500\/40\",\r\n            className,\r\n          )}\r\n        >\r\n          <span\r\n            className={cn(\r\n              \"shrink-0 rounded-full\",\r\n              SWATCH_SIZES[size],\r\n              variant === \"outline\" && \"ring-1 ring-zinc-300 dark:ring-zinc-600\",\r\n            )}\r\n            style={{ backgroundColor: color }}\r\n            aria-label={`Color: ${color}`}\r\n          \/>\r\n          <span\r\n            className={cn(\r\n              \"select-all font-mono uppercase\",\r\n              TEXT_SIZES[size],\r\n              \"text-zinc-700 dark:text-zinc-300\",\r\n            )}\r\n          >\r\n            {color.toUpperCase()}\r\n          <\/span>\r\n        <\/div>\r\n      );\r\n    }\r\n\r\n    return (\r\n      <div\r\n        ref={ref}\r\n        data-react-fancy-color-picker=\"\"\r\n        className={cn(\"inline-flex items-center gap-2\", className)}\r\n        onBlur={(e) => {\r\n          if (interactive && !e.currentTarget.contains(e.relatedTarget as Node)) exitEdit();\r\n        }}\r\n      >\r\n        <button\r\n          type=\"button\"\r\n          disabled={disabled}\r\n          autoFocus={interactive}\r\n          onClick={handleSwatchClick}\r\n          className={cn(\r\n            \"relative shrink-0 rounded-full transition-shadow\",\r\n            SWATCH_SIZES[size],\r\n            variant === \"outline\" &&\r\n              \"ring-1 ring-zinc-300 dark:ring-zinc-600\",\r\n            disabled\r\n              ? \"cursor-not-allowed opacity-50\"\r\n              : \"cursor-pointer hover:ring-2 hover:ring-zinc-400 dark:hover:ring-zinc-500\",\r\n          )}\r\n          style={{ backgroundColor: color }}\r\n          aria-label={`Selected color: ${color}`}\r\n        >\r\n          <input\r\n            ref={inputRef}\r\n            type=\"color\"\r\n            value={color}\r\n            onChange={handleChange}\r\n            disabled={disabled}\r\n            className=\"absolute inset-0 h-full w-full cursor-pointer opacity-0\"\r\n            tabIndex={-1}\r\n            list={presets ? datalistId : undefined}\r\n          \/>\r\n        <\/button>\r\n\r\n        <span\r\n          className={cn(\r\n            \"select-all font-mono uppercase\",\r\n            TEXT_SIZES[size],\r\n            \"text-zinc-700 dark:text-zinc-300\",\r\n            disabled && \"opacity-50\",\r\n          )}\r\n        >\r\n          {color.toUpperCase()}\r\n        <\/span>\r\n\r\n        {presets && (\r\n          <datalist id={datalistId}>\r\n            {presets.map((preset) => (\r\n              <option key={preset} value={preset} \/>\r\n            ))}\r\n          <\/datalist>\r\n        )}\r\n      <\/div>\r\n    );\r\n  },\r\n);\r\n\r\nColorPicker.displayName = \"ColorPicker\";\r\n","type":"registry:ui","target":"components\/fancy\/color-picker\/ColorPicker.tsx"},{"path":"components\/fancy\/color-picker\/ColorPicker.types.ts","content":"import type { FieldMode } from \"..\/inputs\/inputs.types\";\r\n\r\nexport interface ColorPickerProps {\r\n  value?: string;\r\n  defaultValue?: string;\r\n  onChange?: (color: string) => void;\r\n  presets?: string[];\r\n  size?: \"sm\" | \"md\" | \"lg\";\r\n  variant?: \"outline\" | \"filled\";\r\n  disabled?: boolean;\r\n  className?: string;\r\n  \/** `\"edit\"` (default) renders the control; `\"view\"` renders the value as text. *\/\r\n  mode?: FieldMode;\r\n}\r\n","type":"registry:ui","target":"components\/fancy\/color-picker\/ColorPicker.types.ts"},{"path":"components\/fancy\/color-picker\/index.ts","content":"export { ColorPicker } from \".\/ColorPicker\";\r\nexport type { ColorPickerProps } from \".\/ColorPicker.types\";\r\n","type":"registry:ui","target":"components\/fancy\/color-picker\/index.ts"}]}