From cc696338b12aef1957509d0536ff772168cfa17a Mon Sep 17 00:00:00 2001 From: Brad Cornes Date: Thu, 28 Apr 2022 11:18:51 +0100 Subject: [PATCH] Improve type detection for arbitrary color values (#8201) --- src/util/color.js | 38 ++++++++++++++++++---------------- src/util/dataTypes.js | 2 +- tests/arbitrary-values.test.js | 10 +++++++++ 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/util/color.js b/src/util/color.js index da8ec7bc3a06..8ba94556f958 100644 --- a/src/util/color.js +++ b/src/util/color.js @@ -8,13 +8,15 @@ let ALPHA_SEP = /\s*[,/]\s*/ let CUSTOM_PROPERTY = /var\(--(?:[^ )]*?)\)/ let RGB = new RegExp( - `^rgba?\\(\\s*(${VALUE.source}|${CUSTOM_PROPERTY.source})${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source})${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source})(?:${ALPHA_SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?\\s*\\)$` + `^(rgb)a?\\(\\s*(${VALUE.source}|${CUSTOM_PROPERTY.source})(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${ALPHA_SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?\\s*\\)$` ) let HSL = new RegExp( - `^hsla?\\(\\s*((?:${VALUE.source})(?:deg|rad|grad|turn)?|${CUSTOM_PROPERTY.source})${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source})${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source})(?:${ALPHA_SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?\\s*\\)$` + `^(hsl)a?\\(\\s*((?:${VALUE.source})(?:deg|rad|grad|turn)?|${CUSTOM_PROPERTY.source})(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${ALPHA_SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?\\s*\\)$` ) -export function parseColor(value) { +// In "loose" mode the color may contain fewer than 3 parts, as long as at least +// one of the parts is variable. +export function parseColor(value, { loose = false } = {}) { if (typeof value !== 'string') { return null } @@ -42,27 +44,27 @@ export function parseColor(value) { } } - let rgbMatch = value.match(RGB) + let match = value.match(RGB) ?? value.match(HSL) - if (rgbMatch !== null) { - return { - mode: 'rgb', - color: [rgbMatch[1], rgbMatch[2], rgbMatch[3]].map((v) => v.toString()), - alpha: rgbMatch[4]?.toString?.(), - } + if (match === null) { + return null } - let hslMatch = value.match(HSL) + let color = [match[2], match[3], match[4]].filter(Boolean).map((v) => v.toString()) - if (hslMatch !== null) { - return { - mode: 'hsl', - color: [hslMatch[1], hslMatch[2], hslMatch[3]].map((v) => v.toString()), - alpha: hslMatch[4]?.toString?.(), - } + if (!loose && color.length !== 3) { + return null } - return null + if (color.length < 3 && !color.some((part) => /^var\(.*?\)$/.test(part))) { + return null + } + + return { + mode: match[1], + color, + alpha: match[5]?.toString?.(), + } } export function formatColor({ mode, color, alpha }) { diff --git a/src/util/dataTypes.js b/src/util/dataTypes.js index 61b4ed732695..04a5ee901aa7 100644 --- a/src/util/dataTypes.js +++ b/src/util/dataTypes.js @@ -121,7 +121,7 @@ export function color(value) { part = normalize(part) if (part.startsWith('var(')) return true - if (parseColor(part) !== null) return colors++, true + if (parseColor(part, { loose: true }) !== null) return colors++, true return false }) diff --git a/tests/arbitrary-values.test.js b/tests/arbitrary-values.test.js index ab643ed3159f..baea4ddef9c5 100644 --- a/tests/arbitrary-values.test.js +++ b/tests/arbitrary-values.test.js @@ -68,6 +68,8 @@ it('should support arbitrary values for various background utilities', () => {
+
+
@@ -89,6 +91,14 @@ it('should support arbitrary values for various background utilities', () => { background-color: rgb(255 0 0 / var(--tw-bg-opacity)); } + .bg-\[rgb\(var\(--bg-color\)\)\] { + background-color: rgb(var(--bg-color)); + } + + .bg-\[hsl\(var\(--bg-color\)\)\] { + background-color: hsl(var(--bg-color)); + } + .bg-\[color\:var\(--bg-color\)\] { background-color: var(--bg-color); }