ColorWheelPicker
A color picked from a wheel, behind a trigger that shows the color in use. The trigger matches an outlined Select, so it lines up with selects around it.
import { ColorWheelPicker } from '@adecore/ui';import { useState } from 'react';
import { ColorWheelPicker, Select } from '@adecore/ui';
type Tint = 'default' | 'red' | 'orange' | 'amber' | 'lime' | 'green' | 'teal' | 'sky' | 'blue' | 'violet' | 'pink' | 'slate' | 'stone' | 'olive';
const COLORS: Record<Tint, [lighter: string, color: string]> = {
default: ['#d4d4d4', '#737373'],
red: ['#fca5a5', '#ef4444'],
orange: ['#fdba74', '#f97316'],
amber: ['#fcd34d', '#f59e0b'],
lime: ['#bef264', '#84cc16'],
green: ['#86efac', '#22c55e'],
teal: ['#5eead4', '#14b8a6'],
sky: ['#7dd3fc', '#0ea5e9'],
blue: ['#93c5fd', '#3b82f6'],
violet: ['#c4b5fd', '#8b5cf6'],
pink: ['#f9a8d4', '#ec4899'],
slate: ['#cbd5e1', '#64748b'],
stone: ['#d6d3d1', '#78716c'],
olive: ['#d8d8c0', '#7c7c5c']
};
const HUES: Tint[] = ['red', 'orange', 'amber', 'lime', 'green', 'teal', 'sky', 'blue', 'violet', 'pink'];
const NEUTRALS: Tint[] = ['slate', 'stone', 'olive'];
const nameOf = (id: Tint): string => id.charAt(0).toUpperCase() + id.slice(1);
/* Two tones on one swatch: the lighter step under the color, split along the diagonal. */
const swatchOf = (id: Tint): string => `linear-gradient(135deg, ${COLORS[id][0]} 50%, ${COLORS[id][1]} 50%)`;
export default function ColorWheelPickerDemo() {
const [tint, setTint] = useState<Tint>('default');
const [preview, setPreview] = useState<Tint | null>(null);
const [density, setDensity] = useState('comfortable');
const shown = preview ?? tint;
return (
<div className="flex flex-col gap-3">
<div className="flex flex-wrap items-center gap-3">
<ColorWheelPicker<Tint>
label="Tint"
value={tint}
onValueChange={setTint}
onPreviewChange={setPreview}
rings={[HUES, NEUTRALS]}
center="default"
colorOf={swatchOf}
labelOf={nameOf}
/>
<Select
label="Density"
value={density}
onValueChange={setDensity}
items={[
{ value: 'comfortable', label: 'Comfortable' },
{ value: 'compact', label: 'Compact' }
]}
/>
</div>
<div className="h-10 rounded-lg border border-border" style={{ background: COLORS[shown][0] }} />
</div>
);
}The swatches sit on rings, outermost first, each ring in order from the top, with center in the middle. A color is any CSS background, so a swatch can be a gradient.
While the wheel is open, onPreviewChange reports the swatch under the pointer or focus, so the page can preview it. It reports null when the pointer leaves, when the wheel closes, and after a pick (which onValueChange reports first). The wheel opens with focus on the color in use.
The name of the swatch looked at, or of the color in use, shows under the wheel, so swatches have no tooltip. The color in use wears the ring of a picked ColorSwatch. The wheel is a radiogroup and one tab stop: arrow keys walk it, Home and End go to its ends, and only Enter, Space or a click picks and closes it. The trigger is named by label plus the color's name.
Props
ColorWheelPicker is generic over the color's id, a string type.
| Prop | Type | Default | |
|---|---|---|---|
value | Id | Required. | |
onValueChange | (id: Id) => void | Required. | |
onPreviewChange | (id: Id | null) => void | The swatch looked at while the wheel is open, or null. | |
label | string | Required. The accessible name of the trigger and the wheel. | |
rings | readonly (readonly Id[])[] | Required. The rings, outermost first, each in its order from the top. | |
center | Id | The swatch in the middle. | |
colorOf | (id: Id) => string | Required. Any CSS background. | |
labelOf | (id: Id) => string | Required. The name of a color, for its swatch, the trigger and the line under the wheel. | |
disabled | boolean | ||
align | 'start' | 'end' | 'start' | Where the popup lines up with the trigger. |
className | string | ||
ref | Ref<HTMLButtonElement> | The trigger. |
ColorWheelPickerProps is an exported type.