From 20e2fe71f0829c4439680a91cf3d0244a677927c Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Fri, 27 Jan 2023 15:32:10 -0500 Subject: [PATCH 1/2] Parse alpha value from rgba/hsla colors --- src/util/color.js | 19 +++++++++++++++++-- tests/color.test.js | 16 ++++++++++------ tests/opacity.test.js | 23 +++++++++++++++++++++++ 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/src/util/color.js b/src/util/color.js index 8ba94556f958..24b5caadd396 100644 --- a/src/util/color.js +++ b/src/util/color.js @@ -8,10 +8,10 @@ let ALPHA_SEP = /\s*[,/]\s*/ let CUSTOM_PROPERTY = /var\(--(?:[^ )]*?)\)/ let RGB = new RegExp( - `^(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*\\)$` + `^(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*\\)$` ) let HSL = new RegExp( - `^(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*\\)$` + `^(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*\\)$` ) // In "loose" mode the color may contain fewer than 3 parts, as long as at least @@ -52,6 +52,16 @@ export function parseColor(value, { loose = false } = {}) { let color = [match[2], match[3], match[4]].filter(Boolean).map((v) => v.toString()) + // rgba(var(--my-color), 0.1) + // hsla(var(--my-color), 0.1) + if (color.length === 2 && color[0].startsWith('var(')) { + return { + mode: match[1], + color: [color[0]], + alpha: color[1], + } + } + if (!loose && color.length !== 3) { return null } @@ -69,5 +79,10 @@ export function parseColor(value, { loose = false } = {}) { export function formatColor({ mode, color, alpha }) { let hasAlpha = alpha !== undefined + + if (mode === 'rgba' || mode === 'hsla') { + return `${mode}(${color.join(', ')}${hasAlpha ? `, ${alpha}` : ''})` + } + return `${mode}(${color.join(' ')}${hasAlpha ? ` / ${alpha}` : ''})` } diff --git a/tests/color.test.js b/tests/color.test.js index 0c2c7b409a78..be1d85924562 100644 --- a/tests/color.test.js +++ b/tests/color.test.js @@ -11,7 +11,7 @@ crosscheck(() => { ${'#0088cc99'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: '0.6' }} ${'#08c9'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: '0.6' }} ${'rgb(0, 30, 60)'} | ${{ mode: 'rgb', color: ['0', '30', '60'], alpha: undefined }} - ${'rgba(0, 30, 60, 0.5)'} | ${{ mode: 'rgb', color: ['0', '30', '60'], alpha: '0.5' }} + ${'rgba(0, 30, 60, 0.5)'} | ${{ mode: 'rgba', color: ['0', '30', '60'], alpha: '0.5' }} ${'rgb(0 30 60)'} | ${{ mode: 'rgb', color: ['0', '30', '60'], alpha: undefined }} ${'rgb(0 30 60 / 0.5)'} | ${{ mode: 'rgb', color: ['0', '30', '60'], alpha: '0.5' }} ${'rgb(var(--foo), 30, 60)'} | ${{ mode: 'rgb', color: ['var(--foo)', '30', '60'], alpha: undefined }} @@ -31,11 +31,11 @@ crosscheck(() => { ${'hsl(0rad, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0rad', '30%', '60%'], alpha: undefined }} ${'hsl(0grad, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0grad', '30%', '60%'], alpha: undefined }} ${'hsl(0turn, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0turn', '30%', '60%'], alpha: undefined }} - ${'hsla(0, 30%, 60%, 0.5)'} | ${{ mode: 'hsl', color: ['0', '30%', '60%'], alpha: '0.5' }} - ${'hsla(0deg, 30%, 60%, 0.5)'} | ${{ mode: 'hsl', color: ['0deg', '30%', '60%'], alpha: '0.5' }} - ${'hsla(0rad, 30%, 60%, 0.5)'} | ${{ mode: 'hsl', color: ['0rad', '30%', '60%'], alpha: '0.5' }} - ${'hsla(0grad, 30%, 60%, 0.5)'} | ${{ mode: 'hsl', color: ['0grad', '30%', '60%'], alpha: '0.5' }} - ${'hsla(0turn, 30%, 60%, 0.5)'} | ${{ mode: 'hsl', color: ['0turn', '30%', '60%'], alpha: '0.5' }} + ${'hsla(0, 30%, 60%, 0.5)'} | ${{ mode: 'hsla', color: ['0', '30%', '60%'], alpha: '0.5' }} + ${'hsla(0deg, 30%, 60%, 0.5)'} | ${{ mode: 'hsla', color: ['0deg', '30%', '60%'], alpha: '0.5' }} + ${'hsla(0rad, 30%, 60%, 0.5)'} | ${{ mode: 'hsla', color: ['0rad', '30%', '60%'], alpha: '0.5' }} + ${'hsla(0grad, 30%, 60%, 0.5)'} | ${{ mode: 'hsla', color: ['0grad', '30%', '60%'], alpha: '0.5' }} + ${'hsla(0turn, 30%, 60%, 0.5)'} | ${{ mode: 'hsla', color: ['0turn', '30%', '60%'], alpha: '0.5' }} ${'hsl(0 30% 60%)'} | ${{ mode: 'hsl', color: ['0', '30%', '60%'], alpha: undefined }} ${'hsl(0deg 30% 60%)'} | ${{ mode: 'hsl', color: ['0deg', '30%', '60%'], alpha: undefined }} ${'hsl(0rad 30% 60%)'} | ${{ mode: 'hsl', color: ['0rad', '30%', '60%'], alpha: undefined }} @@ -58,6 +58,10 @@ crosscheck(() => { ${'hsl(0 30% var(--foo) / 0.5)'} | ${{ mode: 'hsl', color: ['0', '30%', 'var(--foo)'], alpha: '0.5' }} ${'hsl(var(--foo) 30% var(--bar))'} | ${{ mode: 'hsl', color: ['var(--foo)', '30%', 'var(--bar)'], alpha: undefined }} ${'hsl(var(--foo) var(--bar) var(--baz))'} | ${{ mode: 'hsl', color: ['var(--foo)', 'var(--bar)', 'var(--baz)'], alpha: undefined }} + ${'rgba(var(--foo), 0.1)'} | ${{ mode: 'rgba', color: ['var(--foo)'], alpha: '0.1' }} + ${'rgba(var(--foo), var(--alpha))'} | ${{ mode: 'rgba', color: ['var(--foo)'], alpha: 'var(--alpha)' }} + ${'hsla(var(--foo), 0.1)'} | ${{ mode: 'hsla', color: ['var(--foo)'], alpha: '0.1' }} + ${'hsla(var(--foo), var(--alpha))'} | ${{ mode: 'hsla', color: ['var(--foo)'], alpha: 'var(--alpha)' }} ${'transparent'} | ${{ mode: 'rgb', color: ['0', '0', '0'], alpha: '0' }} `('should parse "$color" to the correct value', ({ color, output }) => { expect(parseColor(color)).toEqual(output) diff --git a/tests/opacity.test.js b/tests/opacity.test.js index f31981a43471..d4e07077a20b 100644 --- a/tests/opacity.test.js +++ b/tests/opacity.test.js @@ -1031,4 +1031,27 @@ crosscheck(() => { `) }) }) + + it('can replace the potential alpha value in rgba/hsla syntax', async () => { + let config = { + content: [{ raw: html`
` }], + theme: { + colors: { + 'primary-rgba': 'rgba(var(--color), 0.1)', + 'primary-hsla': 'hsla(var(--color), 0.1)', + }, + }, + } + + let result = await run('@tailwind utilities', config) + + expect(result.css).toMatchCss(css` + .text-primary-hsla\/50 { + color: hsla(var(--color), 0.5); + } + .text-primary-rgba\/50 { + color: rgba(var(--color), 0.5); + } + `) + }) }) From ea0e21f250888f008bc6b4ef0e70a71b1e0992d3 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 31 Jan 2023 14:29:56 -0500 Subject: [PATCH 2/2] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e338fdc5c6a..cb7edac5086a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Ensure generated CSS is always sorted in the same order for a given set of templates ([#10382](https://github.com/tailwindlabs/tailwindcss/pull/10382)) - Handle variants when the same class appears multiple times in a selector ([#10397](https://github.com/tailwindlabs/tailwindcss/pull/10397)) - Handle group/peer variants with quoted strings ([#10400](https://github.com/tailwindlabs/tailwindcss/pull/10400)) +- Parse alpha value from rgba/hsla colors when using variables ([#10429](https://github.com/tailwindlabs/tailwindcss/pull/10429)) ### Changed