WakaColorPicker
WakaColorPicker is a color picker plugin for wakaPAC. It replaces a plain <input> element with an inline widget showing a 10-stop Tailwind-style color gradient and a hex text field backed by the native browser color picker. Selecting a color from the text field or native picker regenerates the gradient row. Clicking a swatch selects it without regenerating.
Getting Started
Include the script after wakaPAC and register the plugin:
<script src="https://cdn.jsdelivr.net/gh/quellabs/wakapac@main/wakapac.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/quellabs/wakapac@main/plugins/wakacolorpicker.min.js"></script>
<script>
wakaPAC.use(WakaColorPicker); // must be called before any wakaPAC() calls
</script>
The plugin activates automatically for components whose root element is either a <waka-colorpicker> custom element, or an <input> carrying a data-wcp attribute.
Custom element
Use <waka-colorpicker> as the container element. The plugin detects the tag name and activates automatically — no extra attribute is needed. Add a name attribute to participate in form submission and a value attribute to set the initial color:
<waka-colorpicker id="brandColor" name="brand_color" value="#3b82f6"></waka-colorpicker>
<script>
wakaPAC('#brandColor', {});
</script>
Attribute-based (classic)
Mark the input element with data-wcp to opt it in, then register it as a wakaPAC component:
<input id="brandColor" name="brand_color" value="#3b82f6" data-wcp>
<script>
wakaPAC('#brandColor', {});
</script>
The plugin hides the original <input> and inserts the widget immediately after it. The hidden input retains its name and value attributes so it continues to participate in form submission normally.
Usage
Gradient Palette
The 10-stop gradient is generated from the current color using the Tailwind CSS palette algorithm. For colors that match one of the 23 hand-crafted Tailwind palettes (red, blue, slate, etc.) the preset is used directly. For all other colors a synthetic gradient is computed via HSL lightness distribution. The gradient is regenerated whenever the color changes via the text field or native picker. Clicking a swatch selects it without regenerating — the palette remains stable while browsing stops.
Receiving Color Changes
When the user picks a color the plugin sends MSG_COLOR_CHANGED to the component. The message carries the color in two forms:
| Field | Type | Description |
|---|---|---|
event.wParam | number | 24-bit COLORREF integer (R << 16) | (G << 8) | B |
event.detail.hex | string | Color as a '#rrggbb' string |
The component abstraction also exposes a value property that always holds the current color as a '#rrggbb' string. It is kept in sync with the widget and can be read via this.value inside msgProc:
wakaPAC('#brandColor', {
msgProc(event) {
switch (event.message) {
case WakaColorPicker.MSG_COLOR_CHANGED: {
// As hex string from the message
const hex = event.detail.hex;
// As individual channels via COLORREF
const r = (event.wParam >> 16) & 0xFF;
const g = (event.wParam >> 8) & 0xFF;
const b = event.wParam & 0xFF;
// Or read the reactive property directly
console.log(this.value); // '#3b82f6'
break;
}
}
}
});
To update the widget programmatically from outside the component, use WakaColorPicker.setColor(). This updates the widget, regenerates the gradient row, and syncs the text field and native picker:
WakaColorPicker.setColor('brandColor', '#ef4444');
CSS Injection
By default the plugin injects its stylesheet into <head> the first time wakaPAC.use() is called. To manage styles yourself, pass injectCSS: false:
wakaPAC.use(WakaColorPicker, { injectCSS: false });
All plugin classes are prefixed with wcp-. The relevant selectors are .wcp-widget, .wcp-swatches, .wcp-cell, .wcp-cell.wcp-selected, .wcp-text-input, and .wcp-color-trigger.
API
wakaPAC.use(WakaColorPicker, options?)
Registers the WakaColorPicker plugin with the wakaPAC runtime. Must be called before any wakaPAC() calls.
| Parameter | Type | Description |
|---|---|---|
WakaColorPicker | object | The WakaColorPicker plugin object |
options.injectCSS | boolean | Set to false to skip automatic stylesheet injection. Default: true |
Returns void | ||
WakaColorPicker.hexToColorRef(hex)
Packs a hex color string into a 24-bit COLORREF integer (0x00RRGGBB).
| Parameter | Type | Description |
|---|---|---|
hex | string | 6-char lowercase hex string without '#' |
Returns number | 24-bit integer: (R << 16) | (G << 8) | B | |
WakaColorPicker.colorRefToHex(colorRef)
Unpacks a 24-bit COLORREF integer into a '#rrggbb' hex string.
| Parameter | Type | Description |
|---|---|---|
colorRef | number | 24-bit integer: (R << 16) | (G << 8) | B |
Returns string | '#rrggbb' hex color string | |
WakaColorPicker.normalizeHex(hex)
Normalizes any valid hex color string to a 6-character lowercase string without '#'. Accepts 3-character shorthand. Returns null for invalid input.
| Parameter | Type | Description |
|---|---|---|
hex | string | Any hex color string, with or without '#' |
Returns string | null | 6-char lowercase hex without '#', or null if invalid | |
WakaColorPicker.hexToRgb(hex)
Converts a normalized 6-character hex string to an RGB object. Assumes input is already validated.
| Parameter | Type | Description |
|---|---|---|
hex | string | 6-char lowercase hex string without '#' |
Returns { r, g, b } | Integer channel values in range 0–255 | |
WakaColorPicker.rgbToHex(r, g, b)
Converts integer RGB channel values to a 6-character lowercase hex string without '#'.
| Parameter | Type | Description |
|---|---|---|
r | number | Red channel (0–255) |
g | number | Green channel (0–255) |
b | number | Blue channel (0–255) |
Returns string | 6-char lowercase hex without '#' | |
WakaColorPicker.rgbToHsl(r, g, b)
Converts RGB (0–255) to HSL. H is in degrees (0–360), S and L are percentages (0–100).
| Parameter | Type | Description |
|---|---|---|
r | number | Red channel (0–255) |
g | number | Green channel (0–255) |
b | number | Blue channel (0–255) |
Returns { H, S, L } | H in degrees (0–360), S and L as percentages (0–100) | |
WakaColorPicker.hslToRgb(h, s, l)
Converts HSL to RGB (0–255). H is in degrees (0–360), S and L are percentages (0–100).
| Parameter | Type | Description |
|---|---|---|
h | number | Hue (0–360) |
s | number | Saturation (0–100) |
l | number | Lightness (0–100) |
Returns { r, g, b } | Integer channel values in range 0–255 | |
Messages
WakaColorPicker delivers one message type to msgProc. Only components that carry data-wcp receive it.
Color Changed (MSG_COLOR_CHANGED)
Sent to the component whenever the user picks a color via the text field, native picker, or a swatch. Equal to MSG_PLUGIN + 1.
Message Parameters
| Parameter | Type | Description |
|---|---|---|
wParam |
number | The selected color as a 24-bit COLORREF integer (R << 16) | (G << 8) | B. |
lParam |
number | Always 0. |
Detail Properties
| Property | Type | Description |
|---|---|---|
detail.hex |
string | The selected color as a '#rrggbb' string. |
Notes
The plugin activates on <waka-colorpicker> custom elements and on <input> elements carrying data-wcp. Other element types are silently ignored. When using the custom element, the plugin creates a hidden <input> inside it to carry the name and value attributes for form submission.
The data-wcp attribute is the opt-in marker for the classic input pattern. Elements without it are left untouched even when the plugin is registered globally. This allows wakaPAC.use(WakaColorPicker) to be called once at application startup without affecting unrelated input fields.
The hidden input's value is kept in sync with the active color at all times. The input's original type is restored if the component is destroyed.
The Tailwind preset lookup runs in O(1) via a pre-built flat map. Each of the 23 palettes covers 10 stops, giving 230 entries. Any color that matches a stop in a preset uses the entire preset row — the other 9 stops are taken from the same palette regardless of which stop matched.
Best Practices
- Register before creating components — call
wakaPAC.use(WakaColorPicker)before anywakaPAC()calls so the plugin hooks are in place when components are created. - Prefer
event.detail.hexover COLORREF arithmetic — the hex string is ready to use and requires no bit manipulation. Useevent.wParamonly when an integer color representation is specifically needed. - Set initial values via the input's
valueattribute — the widget seeds itself from the input's value on creation. Setting it in HTML is cleaner than callingWakaColorPicker.setColor()after the fact.