Skip to content

Commit

Permalink
Improve type detection for arbitrary color values (#8201)
Browse files Browse the repository at this point in the history
  • Loading branch information
bradlc committed Apr 28, 2022
1 parent 89bf2ed commit cc69633
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 19 deletions.
38 changes: 20 additions & 18 deletions src/util/color.js
Expand Up @@ -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
}
Expand Down Expand Up @@ -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 }) {
Expand Down
2 changes: 1 addition & 1 deletion src/util/dataTypes.js
Expand Up @@ -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
})
Expand Down
10 changes: 10 additions & 0 deletions tests/arbitrary-values.test.js
Expand Up @@ -68,6 +68,8 @@ it('should support arbitrary values for various background utilities', () => {
<!-- By implicit type -->
<div class="bg-[url('/image-1-0.png')]"></div>
<div class="bg-[#ff0000]"></div>
<div class="bg-[rgb(var(--bg-color))]"></div>
<div class="bg-[hsl(var(--bg-color))]"></div>
<!-- By explicit type -->
<div class="bg-[url:var(--image-url)]"></div>
Expand All @@ -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);
}
Expand Down

0 comments on commit cc69633

Please sign in to comment.