diff --git a/src/lib/expandApplyAtRules.js b/src/lib/expandApplyAtRules.js index 97f97a98d3e0..6d23b88112e2 100644 --- a/src/lib/expandApplyAtRules.js +++ b/src/lib/expandApplyAtRules.js @@ -332,6 +332,24 @@ function processApply(root, context, localCache) { }) }) + // Sort tag names before class names + // This happens when replacing `.bar` in `.foo.bar` with a tag like `section` + for (const sel of replaced) { + sel.sort((a, b) => { + if (a.type === 'tag' && b.type === 'class') { + return -1 + } else if (a.type === 'class' && b.type === 'tag') { + return 1 + } else if (a.type === 'class' && b.type === 'pseudo') { + return -1 + } else if (a.type === 'pseudo' && b.type === 'class') { + return 1 + } + + return sel.index(a) - sel.index(b) + }) + } + sel.replaceWith(...replaced) }) diff --git a/tests/apply.test.js b/tests/apply.test.js index ee7d567bb659..300aa8a8c7a2 100644 --- a/tests/apply.test.js +++ b/tests/apply.test.js @@ -1585,6 +1585,62 @@ it('can apply user utilities that start with a dash', async () => { `) }) +it('can apply joined classes when using elements', async () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + .foo.bar { + color: red; + } + .bar.foo { + color: green; + } + header:nth-of-type(odd) { + @apply foo; + } + main { + @apply foo bar; + } + footer { + @apply bar; + } + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .foo.bar { + color: red; + } + .bar.foo { + color: green; + } + header.bar:nth-of-type(odd) { + color: red; + color: green; + } + main.bar { + color: red; + } + main.foo { + color: red; + } + main.bar { + color: green; + } + main.foo { + color: green; + } + footer.foo { + color: red; + color: green; + } + `) +}) + it('can produce selectors that replace multiple instances of the same class', async () => { let config = { content: [{ raw: html`
` }],