Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only sort pseudo elements after classes when using @apply and variants #9765

Merged
merged 2 commits into from Nov 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Fixed use of `raw` content in the CLI ([#9773](https://github.com/tailwindlabs/tailwindcss/pull/9773))
- Pick up changes from files that are both context and content deps ([#9787](https://github.com/tailwindlabs/tailwindcss/pull/9787))
- Sort pseudo-elements ONLY after classes when using variants and `@apply` ([#9765](https://github.com/tailwindlabs/tailwindcss/pull/9765))

## [3.2.2] - 2022-11-04

Expand Down
4 changes: 2 additions & 2 deletions src/lib/expandApplyAtRules.js
Expand Up @@ -370,9 +370,9 @@ function processApply(root, context, localCache) {
return -1
} else if (a.type === 'class' && b.type === 'tag') {
return 1
} else if (a.type === 'class' && b.type === 'pseudo') {
} else if (a.type === 'class' && b.type === 'pseudo' && b.value.startsWith('::')) {
return -1
} else if (a.type === 'pseudo' && b.type === 'class') {
} else if (a.type === 'pseudo' && a.value.startsWith('::') && b.type === 'class') {
return 1
}

Expand Down
4 changes: 2 additions & 2 deletions src/util/formatVariantSelector.js
Expand Up @@ -69,9 +69,9 @@ function resortSelector(sel) {
return -1
} else if (a.type === 'class' && b.type === 'tag') {
return 1
} else if (a.type === 'class' && b.type === 'pseudo' && b.value !== ':merge') {
} else if (a.type === 'class' && b.type === 'pseudo' && b.value.startsWith('::')) {
return -1
} else if (a.type === 'pseudo' && a.value !== ':merge' && b.type === 'class') {
} else if (a.type === 'pseudo' && a.value.startsWith('::') && b.type === 'class') {
return 1
}

Expand Down
19 changes: 11 additions & 8 deletions tests/apply.test.js
Expand Up @@ -1601,6 +1601,9 @@ it('can apply joined classes when using elements', async () => {
header:nth-of-type(odd) {
@apply foo;
}
header::after {
@apply foo;
}
main {
@apply foo bar;
}
Expand All @@ -1618,7 +1621,13 @@ it('can apply joined classes when using elements', async () => {
.bar.foo {
color: green;
}
header:nth-of-type(odd).bar {
color: red;
}
header.bar:nth-of-type(odd) {
color: green;
}
header.bar::after {
color: red;
color: green;
}
Expand Down Expand Up @@ -1721,21 +1730,15 @@ it('should maintain the correct selector when applying other utilities', () => {

return run(input, config).then((result) => {
expect(result.css).toMatchFormattedCss(css`
.foo.bar:hover .baz {
.foo:hover.bar .baz {
--tw-bg-opacity: 1;
background-color: rgb(0 0 0 / var(--tw-bg-opacity));
}
.foo:hover.bar .baz {
color: red;
}
.foo.bar:hover > .baz {
.foo:hover.bar > .baz {
--tw-bg-opacity: 1;
background-color: rgb(0 0 0 / var(--tw-bg-opacity));
}
.foo:hover.bar > .baz {
color: red;
}
`)
Expand Down
40 changes: 35 additions & 5 deletions tests/variants.test.js
Expand Up @@ -861,12 +861,12 @@ test('multi-class utilities handle selector-mutating variants correctly', () =>
content: [
{
raw: html`<div
class="hover:foo hover:bar hover:baz group-hover:foo group-hover:bar group-hover:baz peer-checked:foo peer-checked:bar peer-checked:baz"
class="after:foo after:bar after:baz hover:foo hover:bar hover:baz group-hover:foo group-hover:bar group-hover:baz peer-checked:foo peer-checked:bar peer-checked:baz"
></div>`,
},
{
raw: html`<div
class="hover:foo1 hover:bar1 hover:baz1 group-hover:foo1 group-hover:bar1 group-hover:baz1 peer-checked:foo1 peer-checked:bar1 peer-checked:baz1"
class="after:foo1 after:bar1 after:baz1 hover:foo1 hover:bar1 hover:baz1 group-hover:foo1 group-hover:bar1 group-hover:baz1 peer-checked:foo1 peer-checked:bar1 peer-checked:baz1"
></div>`,
},
],
Expand All @@ -885,15 +885,45 @@ test('multi-class utilities handle selector-mutating variants correctly', () =>
}
`

// The second set of ::after cases (w/ descendant selectors)
// are clearly "wrong" BUT you can't have a descendant of a
// pseudo - element so the utilities `after:foo1` and
// `after:bar1` are non-sensical so this is still
// perfectly fine behavior

return run(input, config).then((result) => {
expect(result.css).toMatchFormattedCss(css`
.hover\:foo.bar.baz:hover {
.after\:foo.bar.baz::after {
content: var(--tw-content);
color: red;
}
.after\:bar.foo.baz::after {
content: var(--tw-content);
color: red;
}
.after\:baz.foo.bar::after {
content: var(--tw-content);
color: red;
}
.after\:foo1 .bar1 .baz1::after {
content: var(--tw-content);
color: red;
}
.foo1 .after\:bar1 .baz1::after {
content: var(--tw-content);
color: red;
}
.foo1 .bar1 .after\:baz1::after {
content: var(--tw-content);
color: red;
}
.hover\:foo:hover.bar.baz {
color: red;
}
.hover\:bar.foo.baz:hover {
.hover\:bar:hover.foo.baz {
color: red;
}
.hover\:baz.foo.bar:hover {
.hover\:baz:hover.foo.bar {
color: red;
}
.hover\:foo1:hover .bar1 .baz1 {
Expand Down