ColorWheelPicker
A color picked from a wheel, behind a trigger that holds the color in use. The trigger is the one of an outlined Select, the same height, radius, border and type, so a row with a picker lines up with the rows of 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 stand on rings, a ring at a time from the outside in, each in its own order from the top and evenly spread, with center in the middle if there is one. The outer ring grows when its swatches would not keep a gap between them otherwise. A color is any CSS background, so a swatch can be a gradient of two tones, as above.
While the wheel is open, onPreviewChange reports the swatch under the pointer or the focus, so the page can show it before it is picked: the band under the demo does. It reports null once nothing is looked at: when the pointer leaves the wheel, when the wheel closes without a pick, and after a pick, which onValueChange reports first. The wheel opens with the focus on the color in use, never on the first swatch, since a swatch with the focus is a preview.
The name of the swatch looked at, or else of the color in use, stands under the wheel, so a swatch carries no tooltip, only its aria-label. The color in use wears the ring of a picked ColorSwatch and no tick, which reads as a glitch on a swatch of two tones. The wheel is a radiogroup and one tab stop: the arrow keys walk it in its order, Home and End go to its ends, and only Enter, Space or a click picks and closes it. The trigger is named by label and the name of the color in use.
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; the row above usually carries the visible one. | |
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.