Repository: tailwindlabs/tailwindcss

Problem statement:
Using @apply with variants doesn't work properly with group selectors
Loving the new features in 1.7 so far, thank you!

Came across what seems to be an issue with the new `applyComplexClasses` feature, in that when a variant class (e.g. `hover:bg-red-400`) is applied to a rule for a group selector, the variant modifier only works for the last selector in the group.

For example, if we have the following in the CSS:
```css
.class1,
.class2 {
  @apply hover:bg-red-400;
}
```

Then I would expect the following output:
```css
.class1:hover, .class2:hover {
  --bg-opacity: 1;
  background-color: #f98080;
  background-color: rgba(249, 128, 128, var(--bg-opacity));
}
```

But this is what I am actually getting (note that the `:hover` modifier is only applied to `.class2`):

<img width="411" alt="Screenshot 2020-08-19 at 15 37 02@2x" src="https://user-images.githubusercontent.com/4648467/90597037-a1900080-e233-11ea-990a-ce2bbf6f71d1.png">


For reference I am using v.1.7.1



Hints:
Same issue here.
![image](https://user-images.githubusercontent.com/12186284/90762103-bd9faa80-e2e4-11ea-8bd9-f11dee3ad1d5.png)

A related issue I think is this strange behavior when applying a selector when chaining selectors:

```
.foo, .selector {
  color: red;
}

.custom {
  @apply selector;
}
```

`@apply selector;` doesn't seems to produce anything.


Instead this

```
.foo, .selector {
  color: red;
}

.custom {
  @apply foo;
}
```

results in another strange result:

```
.custom, .selector {
    color: red;
}
```

Patch:
diff --git a/src/flagged/applyComplexClasses.js b/src/flagged/applyComplexClasses.js
--- a/src/flagged/applyComplexClasses.js
+++ b/src/flagged/applyComplexClasses.js
@@ -39,7 +39,7 @@ const tailwindApplyPlaceholder = selectorParser.attribute({
   attribute: '__TAILWIND-APPLY-PLACEHOLDER__',
 })
 
-function generateRulesFromApply({ rule, utilityName: className, classPosition }, replaceWith) {
+function generateRulesFromApply({ rule, utilityName: className, classPosition }, replaceWiths) {
   const parser = selectorParser(selectors => {
     let i = 0
     selectors.walkClasses(c => {
@@ -49,11 +49,13 @@ function generateRulesFromApply({ rule, utilityName: className, classPosition },
     })
   })
 
-  const processedSelectors = rule.selectors.map(selector => {
+  const processedSelectors = _.flatMap(rule.selectors, selector => {
     // You could argue we should make this replacement at the AST level, but if we believe
     // the placeholder string is safe from collisions then it is safe to do this is a simple
     // string replacement, and much, much faster.
-    return parser.processSync(selector).replace('[__TAILWIND-APPLY-PLACEHOLDER__]', replaceWith)
+    return replaceWiths.map(replaceWith =>
+      parser.processSync(selector).replace('[__TAILWIND-APPLY-PLACEHOLDER__]', replaceWith)
+    )
   })
 
   const cloned = rule.clone()
@@ -242,7 +244,7 @@ function processApplyAtRules(css, lookupTree, config) {
         // Get new rules with the utility portion of the selector replaced with the new selector
         const rulesToInsert = [
           ...applys.map(applyUtility => {
-            return generateRulesFromApply(applyUtility, rule.selector)
+            return generateRulesFromApply(applyUtility, rule.selectors)
           }),
           afterRule,
         ]


Test patch:
diff --git a/__tests__/applyComplexClasses.test.js b/__tests__/applyComplexClasses.test.js
--- a/__tests__/applyComplexClasses.test.js
+++ b/__tests__/applyComplexClasses.test.js
@@ -848,3 +848,35 @@ test('you can apply utility classes when a selector is used for the important op
     expect(result.warnings().length).toBe(0)
   })
 })
+
+test('you can apply classes to a rule with multiple selectors', () => {
+  const input = `
+    @supports (display: grid) {
+      .foo, h1 > .bar * {
+        @apply float-left opacity-50 hover:opacity-100 md:float-right;
+      }
+    }
+    `
+
+  const expected = `
+    @supports (display: grid) {
+      .foo, h1 > .bar * {
+        float: left;
+        opacity: 0.5;
+      }
+      .foo:hover, h1 > .bar *:hover {
+        opacity: 1;
+      }
+      @media (min-width: 768px) {
+        .foo, h1 > .bar * {
+          float: right;
+        }
+      }
+    }
+  `
+
+  return run(input).then(result => {
+    expect(result.css).toMatchCss(expected)
+    expect(result.warnings().length).toBe(0)
+  })
+})