v1
- by pramilk 5/28/202300
Setup HTML - click to add setup HTML
disable setup JavaScript
Setup JavaScript
function parseHex(hex){
    return parseInt(hex.padEnd(2, hex), 16) / 255;
}
function clamp(n, min, max){
    return Math.min(Math.max(min, n), max);
}
function parseAlpha(a, asPercentage) {
    return clamp(asPercentage ? (a / 100) : a, 0, 1);
}
function validateNumbers(array){
    return !array.some(Number.isNaN);
}

function constrainAngle(angle) {
    angle = angle % 360;
    if (angle < 0) {
        angle += 360;
    }
    return angle;
}


function hslToRgb([h, s, l, alpha]) {
    h = constrainAngle(h);
    s /= 100;
    l /= 100;

    function f(n) {
        const k = (n + h / 30) % 12;
        const a = s * Math.min(l, 1 - l);
        return l - a * Math.max(-1, Math.min(k - 3, 9 - k, 1));
    }

    return [f(0), f(8), f(4), alpha];
}
delete caserun single casemove downdrag and drop case


ready



const input = "#ff00ccf1";
let result;
const hexRegexp = /^#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/;
        if (hexRegexp.test(input)) {
            const step = input.length < 6 ? 1 : 2;
            let i = 1;
            result = [
                parseHex(input.slice(i, i += step)),
                parseHex(input.slice(i, i += step)),
                parseHex(input.slice(i, i += step)),
                parseHex(input.slice(i, i + step) || 'ff'),
            ];
        }
delete caserun single casemove upmove downdrag and drop case


ready



const input = "rgb(128, 0, 0)";
let result;
const rgbRegExp = /^rgba?\(\s*([\de.+-]+)(%)?(?:\s+|\s*(,)\s*)([\de.+-]+)(%)?(?:\s+|\s*(,)\s*)([\de.+-]+)(%)?(?:\s*([,\/])\s*([\de.+-]+)(%)?)?\s*\)$/;
        const rgbMatch = input.match(rgbRegExp);
        if (rgbMatch) {
            const [
                _,  // eslint-disable-line @typescript-eslint/no-unused-vars
                r,  // <numeric>
                rp, // %         (optional)
                f1, // ,         (optional)
                g,  // <numeric>
                gp, // %         (optional)
                f2, // ,         (optional)
                b,  // <numeric>
                bp, // %         (optional)
                f3, // ,|/       (optional)
                a,  // <numeric> (optional)
                ap, // %         (optional)
            ] = rgbMatch;

            const argFormat = [f1 || ' ', f2 || ' ', f3].join('');
            if (
                argFormat === '  ' ||
                argFormat === '  /' ||
                argFormat === ',,' ||
                argFormat === ',,,'
            ) {
                const valFormat = [rp, gp, bp].join('');
                const maxValue =
                    (valFormat === '%%%') ? 100 :
                        (valFormat === '') ? 255 : 0;
                if (maxValue) {
                    const rgba = [
                        clamp(+r / maxValue, 0, 1),
                        clamp(+g / maxValue, 0, 1),
                        clamp(+b / maxValue, 0, 1),
                        a ? parseAlpha(+a, ap) : 1,
                    ];
                    if (validateNumbers(rgba)) {
                        result = rgba;
                    }           
                }           
            }           
        }
delete caserun single casemove upmove downdrag and drop case


ready



const input = "rgba(128, 0, 0, 1)";
let result;
const rgbRegExp = /^rgba?\(\s*([\de.+-]+)(%)?(?:\s+|\s*(,)\s*)([\de.+-]+)(%)?(?:\s+|\s*(,)\s*)([\de.+-]+)(%)?(?:\s*([,\/])\s*([\de.+-]+)(%)?)?\s*\)$/;
        const rgbMatch = input.match(rgbRegExp);
        if (rgbMatch) {
            const [
                _,  // eslint-disable-line @typescript-eslint/no-unused-vars
                r,  // <numeric>
                rp, // %         (optional)
                f1, // ,         (optional)
                g,  // <numeric>
                gp, // %         (optional)
                f2, // ,         (optional)
                b,  // <numeric>
                bp, // %         (optional)
                f3, // ,|/       (optional)
                a,  // <numeric> (optional)
                ap, // %         (optional)
            ] = rgbMatch;

            const argFormat = [f1 || ' ', f2 || ' ', f3].join('');
            if (
                argFormat === '  ' ||
                argFormat === '  /' ||
                argFormat === ',,' ||
                argFormat === ',,,'
            ) {
                const valFormat = [rp, gp, bp].join('');
                const maxValue =
                    (valFormat === '%%%') ? 100 :
                        (valFormat === '') ? 255 : 0;
                if (maxValue) {
                    const rgba = [
                        clamp(+r / maxValue, 0, 1),
                        clamp(+g / maxValue, 0, 1),
                        clamp(+b / maxValue, 0, 1),
                        a ? parseAlpha(+a, ap) : 1,
                    ];
                    if (validateNumbers(rgba)) {
                        result = rgba;
                    }           
                }           
            }           
        }
delete caserun single casemove upmove downdrag and drop case


ready



const input = "hsl(120 50% 80%)";
let result;
const hslRegExp = /^hsla?\(\s*([\de.+-]+)(?:deg)?(?:\s+|\s*(,)\s*)([\de.+-]+)%(?:\s+|\s*(,)\s*)([\de.+-]+)%(?:\s*([,\/])\s*([\de.+-]+)(%)?)?\s*\)$/;
    const hslMatch = input.match(hslRegExp);
    if (hslMatch) {
        const [
            _,  // eslint-disable-line @typescript-eslint/no-unused-vars
            h,  // <numeric>
            f1, // ,         (optional)
            s,  // <numeric>
            f2, // ,         (optional)
            l,  // <numeric>
            f3, // ,|/       (optional)
            a,  // <numeric> (optional)
            ap, // %         (optional)
        ] = hslMatch;

        const argFormat = [f1 || ' ', f2 || ' ', f3].join('');
        if (
            argFormat === '  ' ||
            argFormat === '  /' ||
            argFormat === ',,' ||
            argFormat === ',,,'
        ) {
            const hsla = [
                +h,
                clamp(+s, 0, 100),
                clamp(+l, 0, 100),
                a ? parseAlpha(+a, ap) : 1,
            ];
            if (validateNumbers(hsla)) {
                result = hslToRgb(hsla);
            }
            // invalid numbers
        }
        // comma optional syntax requires no commas at all
    }
delete caserun single casemove updrag and drop case


ready



const input = "[128, 0, 0, 1]";
try {
        const [r, g, b, a] = JSON.parse(input);
        if (!isNaN(r + g + b)) {
            return [
                clamp(+r / 255, 0, 1),
                clamp(+g / 255, 0, 1),
                clamp(+b / 255, 0, 1),
                clamp(isNaN(a) ? 1 : +a, 0, 1)];
        }
    } catch(ex) {
        // Invalid JSON
    }
Test Case - click to add another test case
Teardown JS - click to add teardown JavaScript
Output (DOM) - click to monitor output (DOM) while test is running
RUN