'use client'; import { useState, useRef, useEffect } from 'react'; import { hexToRgb, rgbToHsv, hsvToRgb, rgbToHex, isValidHex, normalizeHex } from '@/lib/color-utils'; interface ColorPickerProps { color: string; onChange: (color: string) => void; } export function ColorPicker({ color, onChange }: ColorPickerProps) { const svPickerRef = useRef(null); const huePickerRef = useRef(null); const rgb = hexToRgb(color); const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b); const [hue, setHue] = useState(hsv.h); const [saturation, setSaturation] = useState(hsv.s); const [value, setValue] = useState(hsv.v); const [hexInput, setHexInput] = useState(color); const [isDraggingSV, setIsDraggingSV] = useState(false); const [isDraggingHue, setIsDraggingHue] = useState(false); useEffect(() => { const rgb = hexToRgb(color); const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b); setHue(hsv.h); setSaturation(hsv.s); setValue(hsv.v); setHexInput(color); }, [color]); const updateColor = (h: number, s: number, v: number) => { const rgb = hsvToRgb(h, s, v); const hex = rgbToHex(rgb.r, rgb.g, rgb.b); onChange(hex); }; const handleSVPointerDown = (e: React.PointerEvent) => { setIsDraggingSV(true); handleSVMove(e); }; const handleSVMove = (e: React.PointerEvent) => { if (!svPickerRef.current) return; const rect = svPickerRef.current.getBoundingClientRect(); const x = Math.max(0, Math.min(e.clientX - rect.left, rect.width)); const y = Math.max(0, Math.min(e.clientY - rect.top, rect.height)); const newS = (x / rect.width) * 100; const newV = 100 - (y / rect.height) * 100; setSaturation(newS); setValue(newV); updateColor(hue, newS, newV); }; const handleHuePointerDown = (e: React.PointerEvent) => { setIsDraggingHue(true); handleHueMove(e); }; const handleHueMove = (e: React.PointerEvent) => { if (!huePickerRef.current) return; const rect = huePickerRef.current.getBoundingClientRect(); const y = Math.max(0, Math.min(e.clientY - rect.top, rect.height)); const newH = (y / rect.height) * 360; setHue(newH); updateColor(newH, saturation, value); }; const handlePointerMove = (e: React.PointerEvent) => { if (isDraggingSV) handleSVMove(e); if (isDraggingHue) handleHueMove(e); }; const handlePointerUp = () => { setIsDraggingSV(false); setIsDraggingHue(false); }; const handleHexChange = (e: React.ChangeEvent) => { const value = e.target.value; setHexInput(value); if (isValidHex(value)) { const normalized = normalizeHex(value); const rgb = hexToRgb(normalized); const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b); setHue(hsv.h); setSaturation(hsv.s); setValue(hsv.v); onChange(normalized); } }; const hueBackground = `linear-gradient(to bottom, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%)`; const hueColor = hsvToRgb(hue, 100, 100); const hueHex = rgbToHex(hueColor.r, hueColor.g, hueColor.b); return (
{/* Saturation/Value picker */}
{/* Hue picker */}
{/* Hex input */}
{/* RGB display */}
R:{' '} {rgb.r}
G:{' '} {rgb.g}
B:{' '} {rgb.b}
); }