ColorSlider
A slider for one channel of a color.
The color is hsl(210, 80%, 50%).
<script>
import { $bind, $signal } from 'brumate/signals';
import ColorSlider from '@brumate/ui/ColorSlider.brm';
import ColorThumb from '@brumate/ui/ColorThumb.brm';
import Label from '@brumate/ui/Label.brm';
import SliderOutput from '@brumate/ui/SliderOutput.brm';
import SliderTrack from '@brumate/ui/SliderTrack.brm';
let color = $signal('hsl(210, 80%, 50%)');
</script>
<div class="ui-stack">
<ColorSlider class="ui-color-slider" channel="hue" value=$bind(color)>
<Label>Hue</Label>
<SliderOutput />
<SliderTrack class="ui-color-track">
<ColorThumb class="ui-color-thumb" />
</SliderTrack>
</ColorSlider>
<ColorSlider class="ui-color-slider" channel="alpha" value=$bind(color)>
<Label>Opacity</Label>
<SliderOutput />
<SliderTrack class="ui-color-track">
<ColorThumb class="ui-color-thumb" />
</SliderTrack>
</ColorSlider>
</div>
<p>The color is {color}.</p>
<ColorSlider channel="hue" value=$bind(color)>
<Label>Hue</Label>
<SliderOutput />
<SliderTrack>
<ColorThumb />
</SliderTrack>
</ColorSlider>
- A
ColorSliderholds aLabel, aSliderOutput, and aSliderTrackwith aColorThumb. The Label, the SliderOutput and the SliderTrack are those of Slider. channelis the channel that it adjusts:hue,saturation,lightness,brightness,red,green,blueoralpha.colorSpaceis the space that it reads the channel in,rgb,hslorhsb. A color of another space moves to it. Without it, the color keeps its own space, and moves to one that has the channel when its own does not.valueis a color of CSS, such as#e2445a. It starts its own state, or binds with$bind. See State.onChangegets each change.onChangeEndgets the color once a drag or a key ends.- The color keeps the format it was given: hex stays hex, and
hsl()stayshsl(). - The slider edits a color at full precision, and gives back the format of the caller. Hex cannot hold the hue of a gray, so the thumb of a hue keeps where the user put it.
valueandonChangechange only when an edit makes another color, and then the string of the caller stays as it was. Whenvaluechanges from outside, such as from a reset of the form, the color follows it. orientationishorizontalorvertical.isDisabledkeeps it still.namesends the value of the channel with a form, also before the code of the page loads.- The ColorSlider is a group that its Label names. Without a Label, the name of the channel names it, such as
Hue. It showsdata-orientationanddata-disabled. - A reset of the form gives back the first color.
Channel
- The arrows move a step, and a page with Shift, as in React Aria. Up raises the value and Down lowers it. Left and Right do the same on a slider of either orientation, and right to left they are mirrored. Home and End go to the ends. A key with Ctrl, Meta or Alt moves nothing.
- The range, the step and the page of PageUp and PageDown are those of the channel: hue goes to 360 in steps of 1 and pages of 15, and alpha goes to 1 in steps of 0.01 and pages of 0.1.
- The SliderOutput shows the channel in the format of the locale, such as
210°,50%or128. Alpha shows as a percent. - A screen reader hears the value and a name of the color it makes, such as
210°, blue. The color is named without its alpha.
Track
- The element of the ColorSlider has the custom property
--track-background, the gradient of the channel with the other channels as they are. Give it to the track:background: var(--track-background). The gradient follows the orientation and the direction of the locale. - The track of alpha is the gradient over a checkerboard.
- A press on the track moves the thumb there, and a drag moves it on.
- The track is
position: relative. Give it a size.
ColorThumb
A ColorThumb has no page of its own, since it works only inside a ColorSlider, a ColorArea or a ColorWheel, which give it its state.
- It has
--color, the color it shows, and a background of that color over a checkerboard. On a ColorSlider, a hue shows at full saturation, and a channel shows without its alpha. - It is placed in the middle of its position on the parent with
position: absolute. Give it a size, and a border if you like. - It holds a hidden
<input type="range">for each axis it moves, one for a slider and two for an area. A screen reader reads them, and the keys move them: the part takes all the keys of the input. - A press with Alt, Ctrl or Meta does not start a drag.
- A drag moves it from where the pointer took it, so it does not jump to the pointer.
- It shows
data-dragging,data-focused,data-focus-visibleanddata-disabled.
Building on ColorThumb
A part that has a thumb of color provides a ColorThumbState in ColorThumbContext, from @brumate/ui/color-thumb.ts:
coloris the color to show, as a color of CSS.leftandtopare the position of the center of the thumb, in percents of its parent. The part computes them, and flips them for a track that grows upward or right to left.inputslists the hidden inputs as data:id,name,min,max,step,value,valueText,label,labelledBy,orientation,roleDescription,tabIndexandhidden.isDragging,isFocused,isFocusVisibleandisDisabledare the states.onInputChange(index, value)gets a value that a screen reader sets on an input.onInputKey(index, key, shiftKey)gets the arrows, PageUp, PageDown, Home and End, and the range input does not move by itself. A ColorArea needs it, since Up on the input of x moves y.onPress(event)gets the press on the thumb, to start a drag.onFocusChange(focused, focusVisible, index)andonChangeEnd()follow the focus and the end of a change.- The functions are declared in the part and not inside the lists, since the state of the page can hold a function only where the compiler can name it.