Repository: tailwindlabs/tailwindcss (TypeScript)

Issue:
HSL no longer works in JIT
**What version of Tailwind CSS are you using?**

v3.0.7

**What build tool (or framework if it abstracts the build tool) are you using?**

Next 12.0.7, VSCode 1.63.2, latest version of Tailwind IntelliSense plugin

**What version of Node.js are you using?**

v16.13.0

**What browser are you using?**

N/A

**What operating system are you using?**

macOS

**Reproduction URL**

The `bg-[hsl(202deg,96%,16%)]` class name.

**Describe your issue**

This used to work in previous Tailwind 2.x versions but `bg-[hsl(202deg,96%,16%)]` but no longer works.


Hints:
Thanks! Looks like we need to account for the unit on the first value in our parser, because using `rad`, `grad`, or `turn` also doesn't work.

One temporary workaround is to add a type hint:

```
bg-[color:hsl(202deg,96%,16%)]
```

...or remove the `deg`:

```
bg-[hsl(202,96%,16%)]
```

Will leave this open until we get a chance to fix though 👍🏻 


Patch:
diff --git a/src/util/color.js b/src/util/color.js
--- a/src/util/color.js
+++ b/src/util/color.js
@@ -5,8 +5,11 @@ 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 RGB_HSL = new RegExp(
-  `^(rgb|hsl)a?\\(\\s*(${VALUE})${SEP}(${VALUE})${SEP}(${VALUE})(?:${ALPHA_SEP}(${VALUE}))?\\s*\\)$`
+let RGB = new RegExp(
+  `^rgba?\\(\\s*(${VALUE})${SEP}(${VALUE})${SEP}(${VALUE})(?:${ALPHA_SEP}(${VALUE}))?\\s*\\)$`
+)
+let HSL = new RegExp(
+  `^hsla?\\(\\s*((?:${VALUE})(?:deg|rad|grad|turn)?)${SEP}(${VALUE})${SEP}(${VALUE})(?:${ALPHA_SEP}(${VALUE}))?\\s*\\)$`
 )
 
 export function parseColor(value) {
@@ -37,13 +40,23 @@ export function parseColor(value) {
     }
   }
 
-  let match = value.match(RGB_HSL)
+  let rgbMatch = value.match(RGB)
+
+  if (rgbMatch !== null) {
+    return {
+      mode: 'rgb',
+      color: [rgbMatch[1], rgbMatch[2], rgbMatch[3]].map((v) => v.toString()),
+      alpha: rgbMatch[4]?.toString?.(),
+    }
+  }
+
+  let hslMatch = value.match(HSL)
 
-  if (match !== null) {
+  if (hslMatch !== null) {
     return {
-      mode: match[1],
-      color: [match[2], match[3], match[4]].map((v) => v.toString()),
-      alpha: match[5]?.toString?.(),
+      mode: 'hsl',
+      color: [hslMatch[1], hslMatch[2], hslMatch[3]].map((v) => v.toString()),
+      alpha: hslMatch[4]?.toString?.(),
     }
   }
 


Test patch:
diff --git a/tests/arbitrary-values.test.css b/tests/arbitrary-values.test.css
--- a/tests/arbitrary-values.test.css
+++ b/tests/arbitrary-values.test.css
@@ -603,6 +603,13 @@
 .bg-\[hsla\(0\2c 100\%\2c 50\%\2c 0\.3\)\] {
   background-color: hsla(0, 100%, 50%, 0.3);
 }
+.bg-\[hsl\(0rad\2c 100\%\2c 50\%\)\] {
+  --tw-bg-opacity: 1;
+  background-color: hsl(0rad 100% 50% / var(--tw-bg-opacity));
+}
+.bg-\[hsla\(0turn\2c 100\%\2c 50\%\2c 0\.3\)\] {
+  background-color: hsla(0turn, 100%, 50%, 0.3);
+}
 .bg-\[\#0f0_var\(--value\)\] {
   background-color: #0f0 var(--value);
 }
diff --git a/tests/arbitrary-values.test.html b/tests/arbitrary-values.test.html
--- a/tests/arbitrary-values.test.html
+++ b/tests/arbitrary-values.test.html
@@ -216,6 +216,7 @@
     <div class="bg-[rgb(123,_456,_123)_black]"></div>
     <div class="bg-[rgb(123_456_789)]"></div>
     <div class="bg-[hsl(0,100%,50%)] bg-[hsla(0,100%,50%,0.3)]"></div>
+    <div class="bg-[hsl(0rad,100%,50%)] bg-[hsla(0turn,100%,50%,0.3)]"></div>
     <div class="bg-[#0f0_var(--value)]"></div>
     <div class="bg-[var(--value1)_var(--value2)]"></div>
     <div class="bg-[color:var(--value1)_var(--value2)]"></div>
diff --git a/tests/color.test.js b/tests/color.test.js
--- a/tests/color.test.js
+++ b/tests/color.test.js
@@ -2,21 +2,37 @@ 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 }}
-    ${'hsla(0, 30%, 60%, 0.5)'} | ${{ mode: 'hsl', color: ['0', '30%', '60%'], alpha: '0.5' }}
-    ${'hsl(0 30% 60%)'}         | ${{ mode: 'hsl', color: ['0', '30%', '60%'], alpha: undefined }}
-    ${'hsl(0 30% 60% / 0.5)'}   | ${{ mode: 'hsl', color: ['0', '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' }}
+    ${'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' }}
   `('should parse "$color" to the correct value', ({ color, output }) => {
     expect(parseColor(color)).toEqual(output)
   })