From 96053db5101d3894d5b8015c64fb8cbede3949c0 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 24 Mar 2022 12:27:02 +0100 Subject: [PATCH 1/3] allow for custom properties in `rgb`, `rgba`, `hsl` and `hsla` colors --- src/util/color.js | 12 +++--- tests/color-opacity-modifiers.test.js | 59 +++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/src/util/color.js b/src/util/color.js index aa21d6685d7c..da8ec7bc3a06 100644 --- a/src/util/color.js +++ b/src/util/color.js @@ -2,14 +2,16 @@ import namedColors from 'color-name' let HEX = /^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i let SHORT_HEX = /^#([a-f\d])([a-f\d])([a-f\d])([a-f\d])?$/i -let VALUE = `(?:\\d+|\\d*\\.\\d+)%?` -let SEP = `(?:\\s*,\\s*|\\s+)` -let ALPHA_SEP = `\\s*[,/]\\s*` +let VALUE = /(?:\d+|\d*\.\d+)%?/ +let SEP = /(?:\s*,\s*|\s+)/ +let ALPHA_SEP = /\s*[,/]\s*/ +let CUSTOM_PROPERTY = /var\(--(?:[^ )]*?)\)/ + let RGB = new RegExp( - `^rgba?\\(\\s*(${VALUE})${SEP}(${VALUE})${SEP}(${VALUE})(?:${ALPHA_SEP}(${VALUE}))?\\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( - `^hsla?\\(\\s*((?:${VALUE})(?:deg|rad|grad|turn)?)${SEP}(${VALUE})${SEP}(${VALUE})(?:${ALPHA_SEP}(${VALUE}))?\\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*\\)$` ) export function parseColor(value) { diff --git a/tests/color-opacity-modifiers.test.js b/tests/color-opacity-modifiers.test.js index fa881ff9543e..3c3954a35c50 100644 --- a/tests/color-opacity-modifiers.test.js +++ b/tests/color-opacity-modifiers.test.js @@ -178,3 +178,62 @@ test('utilities that support any type are supported', async () => { `) }) }) + +test('opacity modifier in combination with partial custom properties', async () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-\[hsl\(var\(--foo\)\2c 50\%\2c 50\%\)\] { + --tw-bg-opacity: 1; + background-color: hsl(var(--foo) 50% 50% / var(--tw-bg-opacity)); + } + + .bg-\[hsl\(123\2c var\(--foo\)\2c 50\%\)\] { + --tw-bg-opacity: 1; + background-color: hsl(123 var(--foo) 50% / var(--tw-bg-opacity)); + } + + .bg-\[hsl\(123\2c 50\%\2c var\(--foo\)\)\] { + --tw-bg-opacity: 1; + background-color: hsl(123 50% var(--foo) / var(--tw-bg-opacity)); + } + + .bg-\[hsl\(var\(--foo\)\2c 50\%\2c 50\%\)\]\/50 { + background-color: hsl(var(--foo) 50% 50% / 0.5); + } + + .bg-\[hsl\(123\2c var\(--foo\)\2c 50\%\)\]\/50 { + background-color: hsl(123 var(--foo) 50% / 0.5); + } + + .bg-\[hsl\(123\2c 50\%\2c var\(--foo\)\)\]\/50 { + background-color: hsl(123 50% var(--foo) / 0.5); + } + + .bg-\[hsl\(var\(--foo\)\2c var\(--bar\)\2c var\(--baz\)\)\]\/50 { + background-color: hsl(var(--foo) var(--bar) var(--baz) / 0.5); + } + `) + }) +}) From 8b1cc217c6300f3205db24c4b539baabb50cf36a Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 24 Mar 2022 12:31:07 +0100 Subject: [PATCH 2/3] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c43a94d6ee9..8a181ef8c073 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix extraction from template literal/function with array ([#7481](https://github.com/tailwindlabs/tailwindcss/pull/7481)) - Don't output unparsable arbitrary values ([#7789](https://github.com/tailwindlabs/tailwindcss/pull/7789)) - Fix generation of `div:not(.foo)` if `.foo` is never defined ([#7815](https://github.com/tailwindlabs/tailwindcss/pull/7815)) +- Allow for custom properties in `rgb`, `rgba`, `hsl` and `hsla` colors ([#7933](https://github.com/tailwindlabs/tailwindcss/pull/7933)) ### Changed From 01b5ce878cc51667a21f83202c0525e326f78615 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 24 Mar 2022 12:37:57 +0100 Subject: [PATCH 3/3] add more `parseColor` test cases --- tests/color.test.js | 86 +++++++++++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 31 deletions(-) diff --git a/tests/color.test.js b/tests/color.test.js index a01b9d7e1d80..8d4f611c055f 100644 --- a/tests/color.test.js +++ b/tests/color.test.js @@ -2,37 +2,61 @@ import { parseColor, formatColor } from '../src/util/color' describe('parseColor', () => { it.each` - color | output - ${'black'} | ${{ mode: 'rgb', color: ['0', '0', '0'], alpha: undefined }} - ${'#0088cc'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: undefined }} - ${'#08c'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: undefined }} - ${'#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' }} - ${'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' }} - ${'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 }} - ${'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' }} - ${'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 }} - ${'hsl(0grad 30% 60%)'} | ${{ mode: 'hsl', color: ['0grad', '30%', '60%'], alpha: undefined }} - ${'hsl(0turn 30% 60%)'} | ${{ mode: 'hsl', color: ['0turn', '30%', '60%'], alpha: undefined }} - ${'hsl(0 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0', '30%', '60%'], alpha: '0.5' }} - ${'hsl(0deg 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0deg', '30%', '60%'], alpha: '0.5' }} - ${'hsl(0rad 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0rad', '30%', '60%'], alpha: '0.5' }} - ${'hsl(0grad 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0grad', '30%', '60%'], alpha: '0.5' }} - ${'hsl(0turn 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0turn', '30%', '60%'], alpha: '0.5' }} - ${'transparent'} | ${{ mode: 'rgb', color: ['0', '0', '0'], alpha: '0' }} + color | output + ${'black'} | ${{ mode: 'rgb', color: ['0', '0', '0'], alpha: undefined }} + ${'#0088cc'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: undefined }} + ${'#08c'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: undefined }} + ${'#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' }} + ${'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 }} + ${'rgb(0, var(--foo), 60)'} | ${{ mode: 'rgb', color: ['0', 'var(--foo)', '60'], alpha: undefined }} + ${'rgb(0, 30, var(--foo))'} | ${{ mode: 'rgb', color: ['0', '30', 'var(--foo)'], alpha: undefined }} + ${'rgb(0, 30, var(--foo), 0.5)'} | ${{ mode: 'rgb', color: ['0', '30', 'var(--foo)'], alpha: '0.5' }} + ${'rgb(var(--foo), 30, var(--bar))'} | ${{ mode: 'rgb', color: ['var(--foo)', '30', 'var(--bar)'], alpha: undefined }} + ${'rgb(var(--foo), var(--bar), var(--baz))'} | ${{ mode: 'rgb', color: ['var(--foo)', 'var(--bar)', 'var(--baz)'], alpha: undefined }} + ${'rgb(var(--foo) 30 60)'} | ${{ mode: 'rgb', color: ['var(--foo)', '30', '60'], alpha: undefined }} + ${'rgb(0 var(--foo) 60)'} | ${{ mode: 'rgb', color: ['0', 'var(--foo)', '60'], alpha: undefined }} + ${'rgb(0 30 var(--foo))'} | ${{ mode: 'rgb', color: ['0', '30', 'var(--foo)'], alpha: undefined }} + ${'rgb(0 30 var(--foo) / 0.5)'} | ${{ mode: 'rgb', color: ['0', '30', 'var(--foo)'], alpha: '0.5' }} + ${'rgb(var(--foo) 30 var(--bar))'} | ${{ mode: 'rgb', color: ['var(--foo)', '30', 'var(--bar)'], alpha: undefined }} + ${'rgb(var(--foo) var(--bar) var(--baz))'} | ${{ mode: 'rgb', color: ['var(--foo)', 'var(--bar)', 'var(--baz)'], alpha: undefined }} + ${'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 }} + ${'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' }} + ${'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 }} + ${'hsl(0grad 30% 60%)'} | ${{ mode: 'hsl', color: ['0grad', '30%', '60%'], alpha: undefined }} + ${'hsl(0turn 30% 60%)'} | ${{ mode: 'hsl', color: ['0turn', '30%', '60%'], alpha: undefined }} + ${'hsl(0 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0', '30%', '60%'], alpha: '0.5' }} + ${'hsl(0deg 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0deg', '30%', '60%'], alpha: '0.5' }} + ${'hsl(0rad 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0rad', '30%', '60%'], alpha: '0.5' }} + ${'hsl(0grad 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0grad', '30%', '60%'], alpha: '0.5' }} + ${'hsl(0turn 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0turn', '30%', '60%'], alpha: '0.5' }} + ${'hsl(var(--foo), 30%, 60%)'} | ${{ mode: 'hsl', color: ['var(--foo)', '30%', '60%'], alpha: undefined }} + ${'hsl(0, var(--foo), 60%)'} | ${{ mode: 'hsl', color: ['0', 'var(--foo)', '60%'], alpha: undefined }} + ${'hsl(0, 30%, var(--foo))'} | ${{ mode: 'hsl', color: ['0', '30%', 'var(--foo)'], alpha: undefined }} + ${'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 }} + ${'hsl(var(--foo) 30% 60%)'} | ${{ mode: 'hsl', color: ['var(--foo)', '30%', '60%'], alpha: undefined }} + ${'hsl(0 var(--foo) 60%)'} | ${{ mode: 'hsl', color: ['0', 'var(--foo)', '60%'], alpha: undefined }} + ${'hsl(0 30% var(--foo))'} | ${{ mode: 'hsl', color: ['0', '30%', 'var(--foo)'], alpha: undefined }} + ${'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 }} + ${'transparent'} | ${{ mode: 'rgb', color: ['0', '0', '0'], alpha: '0' }} `('should parse "$color" to the correct value', ({ color, output }) => { expect(parseColor(color)).toEqual(output) })