# ColorPicker

**Maturity:** stable

A single control for choosing one colour — the canonical glass colour well.

## Import

```tsx
import { ColorPicker } from "@liquidify/react/color-picker"
```

## Props

- `className`: `string | undefined`. Optional additional CSS class merged into the glass surface class. The supported per-instance customisation seam: override any `--lq-*` custom property from this class's CSS — the token cascade the engine reads (ADR-0004). No raw inline style is involved, so this stays ADR-0003 clean.
- `defaultValue`: `string | undefined`; default ``"#000000"``. Uncontrolled seed for the internal colour (ignored once {@link ColorPickerProps.value} is supplied).
- `disabled`: `boolean | undefined`; default ``false``. When `true`, the whole control is dimmed, natively disabled, and removed from the tab order; no interaction commits a colour.
- `label`: `ReactNode`. Visible label content — a string/number routes through the shared `Text` primitive (`color="inherit"`, ADR-0028); an element (e.g. `Label(systemImage:)`) passes through unwrapped. Required for an accessible name unless an explicit `aria-label`/`aria-labelledby` is supplied via the inherited props.
- `labelProps`: `LabelProps | undefined`. Per-instance typography override for a string/number {@link label}, forwarded to the internal `Text` (ADR-0028).
- `labelsHidden`: `boolean | undefined`; default ``false``. Removes the visible label text while the accessible name persists (a visually-hidden label / `aria-label`).
- `onChange`: `((next: string) => void) | undefined`. Fires with the next hex string on every colour change inside the OS picker — live, on each drag step. A same-value change emits nothing.
- `ref`: `Ref<HTMLDivElement> | undefined`. Forwarded ref to the rendered element — the outer wrapper `<div>` (charter §4 truthful ref; the documented semantic root, audit §8).
- `supportsOpacity`: `boolean | undefined`; default ``true``. Gates the alpha channel: sets the native control's `alpha` attribute, so the platform picker offers an opacity axis and the committed value carries `#RRGGBBAA`. On an engine that does not yet implement `alpha`, the attribute is ignored and the value degrades to `#RRGGBB` — a platform limitation, not a library behaviour.
- `value`: `string | undefined`. Controlled current colour. Passing this switches ColorPicker to controlled mode: the rendered disc always reflects this value and the consumer owns it via {@link ColorPickerProps.onChange}. Serialised as `#RRGGBB`, or `#RRGGBBAA` when {@link ColorPickerProps.supportsOpacity}. Shorthand (`#RGB` / `#RGBA`) is accepted and expanded; an unparseable string falls back to opaque black.

## SwiftUI mapping

- ``ColorPicker(_ titleKey: LocalizedStringKey, selection:, supportsOpacity: Bool = true)`` → ``label?: ReactNode` + `value?` / `defaultValue?` + `onChange` + `supportsOpacity?`` (direct): `titleKey` → the visible leading label **and** accessible name; a string/number `label` routes through the `Text` primitive (`color="inherit"`, ADR-0028).
- ``ColorPicker(selection:, supportsOpacity:, label: () -> some View)`` → ``label?: ReactNode` (custom content)` (direct): The custom-label overload; an element `label` (e.g. `Label(systemImage:)` → leading glyph + text) passes through unwrapped (ADR-0028).
- ``selection: Binding<Color>`` → ``value?: string` (controlled) / `defaultValue?: string` (uncontrolled seed) / `onChange(next: string)`` (direct): The value triad (ADR-0015); controlled iff `value !== undefined` (audit §8). Colour serialised as a hex string — `#RRGGBB`, or `#RRGGBBAA` when `supportsOpacity`. Fires live during a drag, matching the SwiftUI binding.
- ``Binding<CGColor>` overload` → `(same `value` string)` (renamed): Web has one colour representation — the `CGColor` overload collapses to the hex string (inference).
- ``supportsOpacity: Bool = true`` → ``supportsOpacity?: boolean` (default `true`)` (direct): Sets the native control's `alpha` attribute, gating both the platform picker's opacity axis and the alpha channel in the committed value. Default `true` confirmed by render (the opacity-omitted "Stroke" well offers opacity).
- ``.labelsHidden()`` → ``labelsHidden?: boolean` (default `false`)` (direct): Well-only, no visible label text; the accessible name **still** required (Accessibility). A label-presentation axis, independent of `disabled`.
- ``.disabled(true)`` → ``disabled?: boolean` (default `false`)` (direct): Native `disabled` on the control (genuine inertness + removal from tab order) plus the library-standard dimmed treatment — a deliberate fidelity gap vs iOS's no-dimming.
- ``.font(_:)` / `.foregroundStyle(_:)` on the label` → ``labelProps?: Pick<TextProps, …>`` (direct): Per-instance typography override forwarded to the internal `Text` label; token-backed axes only (ADR-0028). String labels only.
- `picker presentation (no SwiftUI counterpart — UIKit owns it)` → `—` (direct): No presentation triad: the platform owns the picker surface and reports neither its open state nor its dismissal (see Out of scope).
- ``.controlSize(_:)`` → `—` (direct): No size axis (see Sizes).
- ``.tint(_:)`` → `—` (direct): No tint axis; the rainbow rim is fixed system chrome, theme-invariant (see Out of scope).
