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:

FieldTypeDescription
event.wParamnumber24-bit COLORREF integer (R << 16) | (G << 8) | B
event.detail.hexstringColor 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.

ParameterTypeDescription
WakaColorPickerobjectThe WakaColorPicker plugin object
options.injectCSSbooleanSet 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).

ParameterTypeDescription
hexstring6-char lowercase hex string without '#'
Returns number24-bit integer: (R << 16) | (G << 8) | B

WakaColorPicker.colorRefToHex(colorRef)

Unpacks a 24-bit COLORREF integer into a '#rrggbb' hex string.

ParameterTypeDescription
colorRefnumber24-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.

ParameterTypeDescription
hexstringAny hex color string, with or without '#'
Returns string | null6-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.

ParameterTypeDescription
hexstring6-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 '#'.

ParameterTypeDescription
rnumberRed channel (0–255)
gnumberGreen channel (0–255)
bnumberBlue channel (0–255)
Returns string6-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).

ParameterTypeDescription
rnumberRed channel (0–255)
gnumberGreen channel (0–255)
bnumberBlue 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).

ParameterTypeDescription
hnumberHue (0–360)
snumberSaturation (0–100)
lnumberLightness (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 any wakaPAC() calls so the plugin hooks are in place when components are created.
  • Prefer event.detail.hex over COLORREF arithmetic — the hex string is ready to use and requires no bit manipulation. Use event.wParam only when an integer color representation is specifically needed.
  • Set initial values via the input's value attribute — the widget seeds itself from the input's value on creation. Setting it in HTML is cleaner than calling WakaColorPicker.setColor() after the fact.