From 2257c91b193c17a14e3045133eb853424c71d74c Mon Sep 17 00:00:00 2001 From: BenjaminJ Date: Thu, 7 Nov 2024 09:59:50 +0100 Subject: [PATCH] feat: Add support for rgb values with % --- src/lib/colors/strategies/hsl-strategy.ts | 1 + src/lib/colors/strategies/rgb-strategy.ts | 43 ++++++++++++++----- .../rgb-extrator.test.ts | 12 +++++- 3 files changed, 43 insertions(+), 13 deletions(-) diff --git a/src/lib/colors/strategies/hsl-strategy.ts b/src/lib/colors/strategies/hsl-strategy.ts index 99336c52..130118ac 100644 --- a/src/lib/colors/strategies/hsl-strategy.ts +++ b/src/lib/colors/strategies/hsl-strategy.ts @@ -36,6 +36,7 @@ function extractHSLValue(value: string) { .replace(/\)/, '') .replace(/%/g, '') .replace(/deg/, '') + .replace('/', ' ') .replaceAll(',', ' ') .split(/\s+/) .map((c) => parseFloat(c)); diff --git a/src/lib/colors/strategies/rgb-strategy.ts b/src/lib/colors/strategies/rgb-strategy.ts index cebb82d5..6b7727c6 100644 --- a/src/lib/colors/strategies/rgb-strategy.ts +++ b/src/lib/colors/strategies/rgb-strategy.ts @@ -7,7 +7,7 @@ const R_RED = `(?:\\d{1,3}${DOT_VALUE}?|${DOT_VALUE})`; const R_GREEN = R_RED; const R_BLUE = R_RED; -const RGB_NEW_SYNTAX = `rgba?\\(\\s*${R_RED}\\s*${R_GREEN}\\s*${R_BLUE}(?:\\s*\\/\\s*(?:\\d{1,3}${DOT_VALUE}?|${ALPHA})?%?)?\\)`; +const RGB_NEW_SYNTAX = `rgba?\\(\\s*${R_RED}%?\\s*${R_GREEN}%?\\s*${R_BLUE}%?(?:\\s*\\/\\s*(?:\\d{1,3}${DOT_VALUE}?|${ALPHA})?%?)?\\)`; const RGB_LEGACY_SYNTAX = `rgb\\(\\s*${R_RED}\\s*,\\s*${R_GREEN}\\s*,\\s*${R_BLUE}\\s*\\)`; const RGBA_LEGACY_SYNTAX = `rgba\\(\\s*${R_RED}\\s*,\\s*${R_GREEN}\\s*,\\s*${R_BLUE}\\s*,\\s*${ALPHA}\\s*\\)`; @@ -24,24 +24,45 @@ function extractRGBA(value: string): number[] { const rgba_string = value .replace(/rgb(a){0,1}\(/, '') .replace(/\)/, '') - .replace(/%/g, '') .replace('/', ' ') .replaceAll(',', ' '); - return rgba_string.split(/\s+/).map((c) => parseFloat(c)); + const values = rgba_string.split(/\s+/); + + const [r, g, b] = values.slice(0, 3).map((v) => { + const value = parseFloat(v); + + if (v.includes('%')) { + const percentage = value > 100 ? 100 : value; + + return (255 * percentage) / 100; + } + + return value; + }); + + const isRelativeAlpha = /%/.test(values[3]); + + let a = parseFloat(values[3] ?? 1); + + if (!isRelativeAlpha && a > 1) { + a = 1; + } + + if (isRelativeAlpha && a > 100) { + a = 1; + } + + if (a > 1) { + a = a / 100; + } + return [r, g, b, a]; } function getColor(match: RegExpExecArray) { const value = match[1]; const rgba = extractRGBA(value); - let alpha = rgba[3] ?? 1; - if (alpha > 100) { - alpha = 1; - } - - if (alpha > 1) { - alpha = alpha / 100; - } + const alpha = rgba[3] ?? 1; const rgb = rgba.slice(0, 3) as [number, number, number]; // Check if it's a valid rgb(a) color diff --git a/test/unit/color-extractor-strategies/rgb-extrator.test.ts b/test/unit/color-extractor-strategies/rgb-extrator.test.ts index 8eb7c5e5..a4b83611 100644 --- a/test/unit/color-extractor-strategies/rgb-extrator.test.ts +++ b/test/unit/color-extractor-strategies/rgb-extrator.test.ts @@ -9,6 +9,7 @@ import Color from '../../../src/lib/colors/color'; describe('Test rgb(a) color Regex', () => { it('Should match the new syntax', function () { assert.equal(regex_exec('rgb(255 255 255)', REGEXP)[1], 'rgb(255 255 255)'); + assert.equal(regex_exec('rgb(2% 13% 255)', REGEXP)[1], 'rgb(2% 13% 255)'); assert.equal( regex_exec('rgb(255 255 255 / 50%)', REGEXP)[1], 'rgb(255 255 255 / 50%)', @@ -192,14 +193,21 @@ describe('Extract color', () => { input: 'rgba(0 255 255 / 50)', expected: { rgb: [0, 255, 255], - alpha: 0.5, + alpha: 1, }, }, { input: 'rgba(.1 25.5 2.55 / 50)', expected: { rgb: [0.1, 25.5, 2.55], - alpha: 0.5, + alpha: 1, + }, + }, + { + input: 'rgb(2% 13% 255)', + expected: { + rgb: [5.1, 33.15, 255], + alpha: 1, }, }, {