# ColorPicker

> Un campo que abre un selector de color, con paleta, espectro, valores y los últimos colores usados. Trabaja en OKLCH.

```tsx
import { ColorPicker } from "sebs7n-ui/color-picker"
```

## Ejemplos

### Con recientes

El componente muestra la lista, no la guarda. Acá se suma el color al cerrar el panel: elegí uno, cerrá, y volvé a abrir.

```tsx
import { ColorPicker } from "sebs7n-ui/color-picker"
import { Label } from "sebs7n-ui/label"
import { hexOfOklch, type Oklch } from "sebs7n-ui/lib/contrast"
import { useId, useState } from "react"

function Recientes() {
  const id = useId()
  const [color, setColor] = useState<Oklch>([0.573, 0.214, 258])
  const [recientes, setRecientes] = useState<Oklch[]>([
    [0.55, 0.16, 35],
    [0.515, 0.099, 183],
    [0.53, 0.13, 162],
  ])
  return (
    <div className="flex w-full max-w-xs flex-col gap-2">
      <Label htmlFor={id}>Color de la etiqueta</Label>
      <ColorPicker
        id={id}
        onOpenChange={(abierto) => {
          if (abierto) return
          // El más nuevo adelante, sin repetidos, y ocho como mucho.
          setRecientes((lista) => [color, ...lista.filter((otro) => hexOfOklch(otro) !== hexOfOklch(color))].slice(0, 8))
        }}
        onValueChange={setColor}
        recent={recientes}
        value={color}
      />
    </div>
  )
}
```

### Básico

Sin `recent`, la sección no aparece. Con `name`, el color viaja en el formulario como hexadecimal.

```tsx
import { ColorPicker } from "sebs7n-ui/color-picker"
import { Label } from "sebs7n-ui/label"
import { useId } from "react"

function Basico() {
  const id = useId()
  return (
    <div className="flex w-full max-w-xs flex-col gap-2">
      <Label htmlFor={id}>Color</Label>
      <ColorPicker defaultValue={[0.55, 0.16, 35]} id={id} name="color" />
    </div>
  )
}
```

### Tamaños y pie

Las mismas tres alturas que `Input`. `footer` recibe el color actual: sirve para una vista previa.

```tsx
import { ColorPicker } from "sebs7n-ui/color-picker"
import { hexOfOklch } from "sebs7n-ui/lib/contrast"

function TamanosYPie() {
  return (
    <div className="flex w-full max-w-xs flex-col gap-3">
      <ColorPicker aria-label="Chico" defaultValue={[0.515, 0.099, 183]} size="sm" />
      <ColorPicker
        aria-label="Con vista previa"
        defaultValue={[0.53, 0.13, 162]}
        footer={(color) => (
          <div
            className="flex h-10 items-center justify-center rounded-full text-callout font-medium text-white"
            style={{ backgroundColor: hexOfOklch(color) }}
          >
            Vista previa
          </div>
        )}
      />
      <ColorPicker aria-label="Grande" defaultValue={[0.55, 0.16, 35]} size="lg" />
      <ColorPicker aria-label="Deshabilitado" disabled />
    </div>
  )
}
```

## Props

### ColorPicker

Hereda las props de `<button>`.

| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
| `defaultValue` | `Oklch` | `DEFAULT` | El color con el que arranca, sin controlar. |
| `disabled` | `boolean` | — | Apaga la interacción y lo marca con `data-disabled`, que es el atributo del que cuelgan los estilos de apagado. |
| `footer` | `React.ReactNode \| ((color: Oklch) => React.ReactNode)` | — | Lo que va abajo del panel: una vista previa, un aviso de contraste. Recibe el color actual. |
| `labels` | `Partial<ColorPickerLabels>` | — | Los textos del panel. |
| `locale` | `string` | `"es-AR"` | El idioma de los números de la pestaña Valores, como lo entiende `Intl`. Por defecto, `es-AR`. |
| `name` | `string` | — | El nombre con el que el color viaja en un formulario, como `#0070f3`. |
| `onOpenChange` | `(open: boolean) => void` | — | Avisa cuando se abre o se cierra. Es el momento para guardar el color en los recientes. |
| `onValueChange` | `(color: Oklch) => void` | — | Avisa el color en cada cambio, también mientras se arrastra. |
| `open` | `boolean` | — | El panel abierto o cerrado, controlado. |
| `popupClassName` | `string` | — | Clases del panel. |
| `recent` | `readonly Oklch[]` | — | Los últimos colores usados, del más nuevo al más viejo. Se muestran arriba de la paleta; sin lista, la sección no aparece. El componente los **muestra**, no los guarda: qué cuenta como «usado» y dónde vive la lista —un estado, `localStorage`, la base— lo decide la app. Lo más común es sumar el color al cerrar el panel, con `onOpenChange`. |
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | Las mismas tres alturas que `Input`. |
| `value` | `Oklch` | — | El color elegido, controlado. En OKLCH, como se escribe en CSS: `[0.573, 0.214, 258]`. |
| `className` | `string` | — | Se fusiona con las clases del componente vía `cn()` (tailwind-merge): lo que pongas gana. |

## Teclado

| Tecla | Qué hace |
|---|---|
| Enter · Espacio | Abre el panel. |
| Escape | Cierra y devuelve el foco al campo. |
| Tab | Recorre las pestañas, las muestras y los controles. |
| ← → ↑ ↓ | En el espectro, croma y luminosidad. Con Shift, de a pasos más grandes. |

## Accesibilidad

- El campo es un botón: necesita `aria-label`, `aria-labelledby` o un `<Label htmlFor>` apuntando a su `id`.
- Cada muestra se llama por su hexadecimal y anuncia si es la elegida con `aria-pressed`.
- El espectro es un `role="slider"` de dos ejes que se maneja con las flechas; la tira de matices es un `<input type="range">` de verdad.
- **El componente no opina sobre el contraste del color elegido.** Si el color va a llevar texto encima, medilo con `sebs7n-ui/lib/contrast` y mostralo en `footer`.

## Reglas de uso

- En una pantalla angosta (< 640 px) el panel se abre en la hoja de abajo, como el `Popover`.
- Para elegir un color libre: una etiqueta, una categoría, el color de marca. Si las opciones son cinco y fijas, es un `RadioGroup` o un `ToggleGroup`.
- `recent` muestra los últimos colores usados. El componente no los guarda: la app decide qué cuenta como «usado» y dónde vive la lista. Lo más común es sumar el color al cerrar, con `onOpenChange`.
- El valor es OKLCH (`[0.573, 0.214, 258]`). Para guardar o mostrar un hexadecimal están `hexOfOklch` y `oklchOfHex`; con `name`, el formulario lo recibe ya como `#0070f3`.
- Reemplaza a `<input type="color">`, cuyo panel es del sistema operativo.

## Relacionados

[date-picker](/docs/components/date-picker.md) · [popover](/docs/components/popover.md) · [slider](/docs/components/slider.md) · [tabs](/docs/components/tabs.md)
