Expand description
Internal state for ColorPicker.
ColorComponents is constructed once in the picker’s build() and
holds derived Signals for each RGB / HSV channel plus typed
setters that recompose the bound Signal<Color> when a single
channel changes. Centralizing the conversions here keeps every
subwidget (HSV canvas, hue strip, alpha strip, RGB/HSV spinners,
preview) reading from clean per-channel signals without duplicating
the conversion logic.
§Hue preservation across grays
When saturation drops to 0 or value drops to 0, the underlying
sRGB representation has no hue (gray / black). A naive
value.map(|c| c.to_hsv().0) would clamp the visible hue back to
0° — which makes the HSV canvas snap from “red” back to “red at the
top-left” the moment the user drags down to white. We avoid this by
caching the last non-degenerate hue in ColorComponents and
returning it whenever the bound color’s saturation/value collapses.