Skip to content

Commit 1d5aa27

Browse files
authored
Support HSL with hue units in arbitrary values (#6726)
1 parent da7396c commit 1d5aa27

File tree

4 files changed

+59
-22
lines changed

4 files changed

+59
-22
lines changed

src/util/color.js

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@ let SHORT_HEX = /^#([a-f\d])([a-f\d])([a-f\d])([a-f\d])?$/i
55
let VALUE = `(?:\\d+|\\d*\\.\\d+)%?`
66
let SEP = `(?:\\s*,\\s*|\\s+)`
77
let ALPHA_SEP = `\\s*[,/]\\s*`
8-
let RGB_HSL = new RegExp(
9-
`^(rgb|hsl)a?\\(\\s*(${VALUE})${SEP}(${VALUE})${SEP}(${VALUE})(?:${ALPHA_SEP}(${VALUE}))?\\s*\\)$`
8+
let RGB = new RegExp(
9+
`^rgba?\\(\\s*(${VALUE})${SEP}(${VALUE})${SEP}(${VALUE})(?:${ALPHA_SEP}(${VALUE}))?\\s*\\)$`
10+
)
11+
let HSL = new RegExp(
12+
`^hsla?\\(\\s*((?:${VALUE})(?:deg|rad|grad|turn)?)${SEP}(${VALUE})${SEP}(${VALUE})(?:${ALPHA_SEP}(${VALUE}))?\\s*\\)$`
1013
)
1114

1215
export function parseColor(value) {
@@ -37,13 +40,23 @@ export function parseColor(value) {
3740
}
3841
}
3942

40-
let match = value.match(RGB_HSL)
43+
let rgbMatch = value.match(RGB)
44+
45+
if (rgbMatch !== null) {
46+
return {
47+
mode: 'rgb',
48+
color: [rgbMatch[1], rgbMatch[2], rgbMatch[3]].map((v) => v.toString()),
49+
alpha: rgbMatch[4]?.toString?.(),
50+
}
51+
}
52+
53+
let hslMatch = value.match(HSL)
4154

42-
if (match !== null) {
55+
if (hslMatch !== null) {
4356
return {
44-
mode: match[1],
45-
color: [match[2], match[3], match[4]].map((v) => v.toString()),
46-
alpha: match[5]?.toString?.(),
57+
mode: 'hsl',
58+
color: [hslMatch[1], hslMatch[2], hslMatch[3]].map((v) => v.toString()),
59+
alpha: hslMatch[4]?.toString?.(),
4760
}
4861
}
4962

tests/arbitrary-values.test.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,13 @@
603603
.bg-\[hsla\(0\2c 100\%\2c 50\%\2c 0\.3\)\] {
604604
background-color: hsla(0, 100%, 50%, 0.3);
605605
}
606+
.bg-\[hsl\(0rad\2c 100\%\2c 50\%\)\] {
607+
--tw-bg-opacity: 1;
608+
background-color: hsl(0rad 100% 50% / var(--tw-bg-opacity));
609+
}
610+
.bg-\[hsla\(0turn\2c 100\%\2c 50\%\2c 0\.3\)\] {
611+
background-color: hsla(0turn, 100%, 50%, 0.3);
612+
}
606613
.bg-\[\#0f0_var\(--value\)\] {
607614
background-color: #0f0 var(--value);
608615
}

tests/arbitrary-values.test.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@
216216
<div class="bg-[rgb(123,_456,_123)_black]"></div>
217217
<div class="bg-[rgb(123_456_789)]"></div>
218218
<div class="bg-[hsl(0,100%,50%)] bg-[hsla(0,100%,50%,0.3)]"></div>
219+
<div class="bg-[hsl(0rad,100%,50%)] bg-[hsla(0turn,100%,50%,0.3)]"></div>
219220
<div class="bg-[#0f0_var(--value)]"></div>
220221
<div class="bg-[var(--value1)_var(--value2)]"></div>
221222
<div class="bg-[color:var(--value1)_var(--value2)]"></div>

tests/color.test.js

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,37 @@ import { parseColor, formatColor } from '../src/util/color'
22

33
describe('parseColor', () => {
44
it.each`
5-
color | output
6-
${'black'} | ${{ mode: 'rgb', color: ['0', '0', '0'], alpha: undefined }}
7-
${'#0088cc'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: undefined }}
8-
${'#08c'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: undefined }}
9-
${'#0088cc99'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: '0.6' }}
10-
${'#08c9'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: '0.6' }}
11-
${'rgb(0, 30, 60)'} | ${{ mode: 'rgb', color: ['0', '30', '60'], alpha: undefined }}
12-
${'rgba(0, 30, 60, 0.5)'} | ${{ mode: 'rgb', color: ['0', '30', '60'], alpha: '0.5' }}
13-
${'rgb(0 30 60)'} | ${{ mode: 'rgb', color: ['0', '30', '60'], alpha: undefined }}
14-
${'rgb(0 30 60 / 0.5)'} | ${{ mode: 'rgb', color: ['0', '30', '60'], alpha: '0.5' }}
15-
${'hsl(0, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0', '30%', '60%'], alpha: undefined }}
16-
${'hsla(0, 30%, 60%, 0.5)'} | ${{ mode: 'hsl', color: ['0', '30%', '60%'], alpha: '0.5' }}
17-
${'hsl(0 30% 60%)'} | ${{ mode: 'hsl', color: ['0', '30%', '60%'], alpha: undefined }}
18-
${'hsl(0 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0', '30%', '60%'], alpha: '0.5' }}
19-
${'transparent'} | ${{ mode: 'rgb', color: ['0', '0', '0'], alpha: '0' }}
5+
color | output
6+
${'black'} | ${{ mode: 'rgb', color: ['0', '0', '0'], alpha: undefined }}
7+
${'#0088cc'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: undefined }}
8+
${'#08c'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: undefined }}
9+
${'#0088cc99'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: '0.6' }}
10+
${'#08c9'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: '0.6' }}
11+
${'rgb(0, 30, 60)'} | ${{ mode: 'rgb', color: ['0', '30', '60'], alpha: undefined }}
12+
${'rgba(0, 30, 60, 0.5)'} | ${{ mode: 'rgb', color: ['0', '30', '60'], alpha: '0.5' }}
13+
${'rgb(0 30 60)'} | ${{ mode: 'rgb', color: ['0', '30', '60'], alpha: undefined }}
14+
${'rgb(0 30 60 / 0.5)'} | ${{ mode: 'rgb', color: ['0', '30', '60'], alpha: '0.5' }}
15+
${'hsl(0, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0', '30%', '60%'], alpha: undefined }}
16+
${'hsl(0deg, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0deg', '30%', '60%'], alpha: undefined }}
17+
${'hsl(0rad, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0rad', '30%', '60%'], alpha: undefined }}
18+
${'hsl(0grad, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0grad', '30%', '60%'], alpha: undefined }}
19+
${'hsl(0turn, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0turn', '30%', '60%'], alpha: undefined }}
20+
${'hsla(0, 30%, 60%, 0.5)'} | ${{ mode: 'hsl', color: ['0', '30%', '60%'], alpha: '0.5' }}
21+
${'hsla(0deg, 30%, 60%, 0.5)'} | ${{ mode: 'hsl', color: ['0deg', '30%', '60%'], alpha: '0.5' }}
22+
${'hsla(0rad, 30%, 60%, 0.5)'} | ${{ mode: 'hsl', color: ['0rad', '30%', '60%'], alpha: '0.5' }}
23+
${'hsla(0grad, 30%, 60%, 0.5)'} | ${{ mode: 'hsl', color: ['0grad', '30%', '60%'], alpha: '0.5' }}
24+
${'hsla(0turn, 30%, 60%, 0.5)'} | ${{ mode: 'hsl', color: ['0turn', '30%', '60%'], alpha: '0.5' }}
25+
${'hsl(0 30% 60%)'} | ${{ mode: 'hsl', color: ['0', '30%', '60%'], alpha: undefined }}
26+
${'hsl(0deg 30% 60%)'} | ${{ mode: 'hsl', color: ['0deg', '30%', '60%'], alpha: undefined }}
27+
${'hsl(0rad 30% 60%)'} | ${{ mode: 'hsl', color: ['0rad', '30%', '60%'], alpha: undefined }}
28+
${'hsl(0grad 30% 60%)'} | ${{ mode: 'hsl', color: ['0grad', '30%', '60%'], alpha: undefined }}
29+
${'hsl(0turn 30% 60%)'} | ${{ mode: 'hsl', color: ['0turn', '30%', '60%'], alpha: undefined }}
30+
${'hsl(0 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0', '30%', '60%'], alpha: '0.5' }}
31+
${'hsl(0deg 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0deg', '30%', '60%'], alpha: '0.5' }}
32+
${'hsl(0rad 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0rad', '30%', '60%'], alpha: '0.5' }}
33+
${'hsl(0grad 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0grad', '30%', '60%'], alpha: '0.5' }}
34+
${'hsl(0turn 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0turn', '30%', '60%'], alpha: '0.5' }}
35+
${'transparent'} | ${{ mode: 'rgb', color: ['0', '0', '0'], alpha: '0' }}
2036
`('should parse "$color" to the correct value', ({ color, output }) => {
2137
expect(parseColor(color)).toEqual(output)
2238
})

0 commit comments

Comments
 (0)