Repository: tailwindlabs/tailwindcss (ts)

Issue:
Dark mode `class` strategy not compatible with complex variants like `group-hover`
Using the dark mode stuff in `class` mode with `group-hover` enabled generates selectors like this:

```
.dark .dark\:group:hover .dark .dark\:group-hover\:bg-white 
```

...which seems pretty wrong.

I think the correct output should be this:

```
.dark .group:hover .dark\:group-hover\:bg-white 
```

Pull request description:
Fix issue where dark variant in 'class' mode was incompatible with 'group-hover' variant
Fixes #2336.

Long term I need to consider the whole "make it possible for variants to control which class is the 'variant target'" concept but this is good enough for now.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index be2feccb..dfd3610f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 - Fix [issue](https://github.com/tailwindlabs/tailwindcss/issues/2258) where inserting extra PurgeCSS control comments could break integrated PurgeCSS support
 - Rename `font-hairline` and `font-thin` to `font-thin` and `font-extralight` behind `standardFontWeights` flag ([#2333](https://github.com/tailwindlabs/tailwindcss/pull/2333))
+- Fix issue where dark variant in 'class' mode was incompatible with 'group-hover' variant ([#2337](https://github.com/tailwindlabs/tailwindcss/pull/2337))
 
 ## [1.8.3] - 2020-09-05
 
diff --git a/src/flagged/darkModeVariant.js b/src/flagged/darkModeVariant.js
index 725e845d..65803114 100644
--- a/src/flagged/darkModeVariant.js
+++ b/src/flagged/darkModeVariant.js
@@ -1,4 +1,3 @@
-import selectorParser from 'postcss-selector-parser'
 import buildSelectorVariant from '../util/buildSelectorVariant'
 import defaultConfig from '../../defaultConfig'
 
@@ -31,13 +30,19 @@ export default {
         }
 
         if (config('dark') === 'class') {
-          const parser = selectorParser(selectors => {
-            selectors.walkClasses(sel => {
-              sel.value = `dark${separator}${sel.value}`
-              sel.parent.insertBefore(sel, selectorParser().astSync(prefix('.dark ')))
+          const modified = modifySelectors(({ selector }) => {
+            return buildSelectorVariant(selector, 'dark', separator, message => {
+              throw container.error(message)
             })
           })
-          return modifySelectors(({ selector }) => parser.processSync(selector))
+
+          modified.walkRules(rule => {
+            rule.selectors = rule.selectors.map(selector => {
+              return `${prefix('.dark ')} ${selector}`
+            })
+          })
+
+          return modified
         }
 
         throw new Error("The `dark` config option must be either 'media' or 'class'.")


Test patch:
diff --git a/__tests__/darkMode.test.js b/__tests__/darkMode.test.js
index f96b9035..477c6d80 100644
--- a/__tests__/darkMode.test.js
+++ b/__tests__/darkMode.test.js
@@ -189,7 +189,7 @@ test('dark mode variants stack with other variants', () => {
 
 test('dark mode variants stack with other variants when using the class strategy', () => {
   const input = `
-    @variants responsive, dark, hover, focus {
+    @variants responsive, dark, group-hover, hover, focus {
       .text-red {
         color: red;
       }
@@ -200,6 +200,9 @@ test('dark mode variants stack with other variants when using the class strategy
     .text-red {
       color: red;
     }
+    .group:hover .group-hover\\:text-red {
+      color: red;
+    }
     .hover\\:text-red:hover {
       color: red;
     }
@@ -209,6 +212,9 @@ test('dark mode variants stack with other variants when using the class strategy
     .dark .dark\\:text-red {
       color: red;
     }
+    .dark .group:hover .dark\\:group-hover\\:text-red {
+      color: red;
+    }
     .dark .dark\\:hover\\:text-red:hover {
       color: red;
     }
@@ -219,6 +225,9 @@ test('dark mode variants stack with other variants when using the class strategy
       .sm\\:text-red {
         color: red;
       }
+      .group:hover .sm\\:group-hover\\:text-red {
+        color: red;
+      }
       .sm\\:hover\\:text-red:hover {
         color: red;
       }
@@ -228,6 +237,9 @@ test('dark mode variants stack with other variants when using the class strategy
       .dark .sm\\:dark\\:text-red {
         color: red;
       }
+      .dark .group:hover .sm\\:dark\\:group-hover\\:text-red {
+        color: red;
+      }
       .dark .sm\\:dark\\:hover\\:text-red:hover {
         color: red;
       }
@@ -239,6 +251,9 @@ test('dark mode variants stack with other variants when using the class strategy
       .lg\\:text-red {
         color: red;
       }
+      .group:hover .lg\\:group-hover\\:text-red {
+        color: red;
+      }
       .lg\\:hover\\:text-red:hover {
         color: red;
       }
@@ -248,6 +263,9 @@ test('dark mode variants stack with other variants when using the class strategy
       .dark .lg\\:dark\\:text-red {
         color: red;
       }
+      .dark .group:hover .lg\\:dark\\:group-hover\\:text-red {
+        color: red;
+      }
       .dark .lg\\:dark\\:hover\\:text-red:hover {
         color: red;
       }