Skip to content

Commit d1eedb2

Browse files
Invert variant order application (#13478)
* reverse order of variants This way variants work similar to how you would write them in CSS itself. This also allows us to remove the special "fixup" code that fixes the position of some variants because they have to be in a specific order (the end). Since the order wasn't intuitive we had to solve this with a fixup. This commit should allow us to remove this entirely, because now it is intuitive. * update tests to reflect variant order change * Update changelog --------- Co-authored-by: Adam Wathan <[email protected]>
1 parent 4a25bc1 commit d1eedb2

File tree

5 files changed

+60
-76
lines changed

5 files changed

+60
-76
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- Ensure deterministic SSR builds in `@tailwindcss/vite` ([#13457](https://github.com/tailwindlabs/tailwindcss/pull/13457))
1313

14+
### Changed
15+
16+
- Apply variants from left to right instead of inside-out ([#13478](https://github.com/tailwindlabs/tailwindcss/pull/13478))
17+
1418
## [4.0.0-alpha.13] - 2024-04-04
1519

1620
### Fixed

packages/tailwindcss/src/candidate.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,12 @@ it('should parse a simple utility with stacked variants', () => {
120120
{
121121
"compounds": true,
122122
"kind": "static",
123-
"root": "focus",
123+
"root": "hover",
124124
},
125125
{
126126
"compounds": true,
127127
"kind": "static",
128-
"root": "hover",
128+
"root": "focus",
129129
},
130130
],
131131
}
@@ -1012,12 +1012,12 @@ it('should parse arbitrary properties with stacked variants', () => {
10121012
{
10131013
"compounds": true,
10141014
"kind": "static",
1015-
"root": "focus",
1015+
"root": "hover",
10161016
},
10171017
{
10181018
"compounds": true,
10191019
"kind": "static",
1020-
"root": "hover",
1020+
"root": "focus",
10211021
},
10221022
],
10231023
}
@@ -1036,12 +1036,12 @@ it('should parse arbitrary properties that are important and using stacked arbit
10361036
{
10371037
"compounds": true,
10381038
"kind": "arbitrary",
1039-
"selector": "@media(width>=123px)",
1039+
"selector": "& p",
10401040
},
10411041
{
10421042
"compounds": true,
10431043
"kind": "arbitrary",
1044-
"selector": "& p",
1044+
"selector": "@media(width>=123px)",
10451045
},
10461046
],
10471047
}

packages/tailwindcss/src/candidate.ts

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -221,34 +221,11 @@ export function parseCandidate(input: string, designSystem: DesignSystem): Candi
221221

222222
let parsedCandidateVariants: Variant[] = []
223223

224-
for (let variant of rawVariants) {
225-
let parsedVariant = designSystem.parseVariant(variant)
224+
for (let i = rawVariants.length - 1; i >= 0; --i) {
225+
let parsedVariant = designSystem.parseVariant(rawVariants[i])
226226
if (parsedVariant === null) return null
227227

228-
// Variants are applied left-to-right meaning that any representing pseudo-
229-
// elements must come first. This is because they cannot have anything
230-
// after them in a selector. The problem with this is that it's common for
231-
// users to write them in the wrong order, for example:
232-
//
233-
// `dark:before:underline` (wrong)
234-
// `before:dark:underline` (right)
235-
//
236-
// Add pseudo-element variants to the front, making both examples above
237-
// function identically which allows users to not care about the order.
238-
switch (variant) {
239-
case 'after':
240-
case 'backdrop':
241-
case 'before':
242-
case 'first-letter':
243-
case 'first-line':
244-
case 'marker':
245-
case 'placeholder':
246-
case 'selection':
247-
parsedCandidateVariants.unshift(parsedVariant)
248-
break
249-
default:
250-
parsedCandidateVariants.push(parsedVariant)
251-
}
228+
parsedCandidateVariants.push(parsedVariant)
252229
}
253230

254231
let state = {

packages/tailwindcss/src/index.test.ts

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -333,15 +333,15 @@ describe('arbitrary variants', () => {
333333
describe('variant stacking', () => {
334334
it('should stack simple variants', () => {
335335
expect(run(['focus:hover:flex'])).toMatchInlineSnapshot(`
336-
".focus\\:hover\\:flex:hover:focus {
336+
".focus\\:hover\\:flex:focus:hover {
337337
display: flex;
338338
}"
339339
`)
340340
})
341341

342342
it('should stack arbitrary variants and simple variants', () => {
343343
expect(run(['[&_p]:hover:flex'])).toMatchInlineSnapshot(`
344-
".\\[\\&_p\\]\\:hover\\:flex:hover p {
344+
".\\[\\&_p\\]\\:hover\\:flex p:hover {
345345
display: flex;
346346
}"
347347
`)
@@ -359,8 +359,11 @@ describe('variant stacking', () => {
359359

360360
it('pseudo element variants are re-ordered', () => {
361361
expect(run(['before:hover:flex', 'hover:before:flex'])).toMatchInlineSnapshot(`
362-
".before\\:hover\\:flex:hover:before {
362+
".before\\:hover\\:flex:before {
363363
content: var(--tw-content);
364+
}
365+
366+
.before\\:hover\\:flex:before:hover {
364367
display: flex;
365368
}
366369
@@ -592,26 +595,26 @@ describe('sorting', () => {
592595
),
593596
),
594597
).toMatchInlineSnapshot(`
595-
".flex {
596-
display: flex;
597-
}
598+
".flex {
599+
display: flex;
600+
}
598601
599-
.hover\\:flex:hover {
600-
display: flex;
601-
}
602+
.hover\\:flex:hover {
603+
display: flex;
604+
}
602605
603-
.focus\\:flex:focus {
604-
display: flex;
605-
}
606+
.focus\\:flex:focus {
607+
display: flex;
608+
}
606609
607-
.hover\\:focus\\:flex:focus:hover {
608-
display: flex;
609-
}
610+
.hover\\:focus\\:flex:hover:focus {
611+
display: flex;
612+
}
610613
611-
.disabled\\:flex:disabled {
612-
display: flex;
613-
}"
614-
`)
614+
.disabled\\:flex:disabled {
615+
display: flex;
616+
}"
617+
`)
615618
})
616619

617620
// TODO: Extend this test with user-defined variants to ensure they are sorted
@@ -651,39 +654,39 @@ describe('sorting', () => {
651654
display: flex;
652655
}
653656
654-
.group-hover\\:peer-hover\\:flex:is(:where(.peer):hover ~ *):is(:where(.group):hover *) {
657+
.group-hover\\:peer-hover\\:flex:is(:where(.group):hover *):is(:where(.peer):hover ~ *) {
655658
display: flex;
656659
}
657660
658-
.peer-hover\\:group-hover\\:flex:is(:where(.group):hover *):is(:where(.peer):hover ~ *) {
661+
.peer-hover\\:group-hover\\:flex:is(:where(.peer):hover ~ *):is(:where(.group):hover *) {
659662
display: flex;
660663
}
661664
662-
.group-focus\\:peer-hover\\:flex:is(:where(.peer):hover ~ *):is(:where(.group):focus *) {
665+
.group-focus\\:peer-hover\\:flex:is(:where(.group):focus *):is(:where(.peer):hover ~ *) {
663666
display: flex;
664667
}
665668
666-
.peer-hover\\:group-focus\\:flex:is(:where(.group):focus *):is(:where(.peer):hover ~ *) {
669+
.peer-hover\\:group-focus\\:flex:is(:where(.peer):hover ~ *):is(:where(.group):focus *) {
667670
display: flex;
668671
}
669672
670673
.peer-focus\\:flex:is(:where(.peer):focus ~ *) {
671674
display: flex;
672675
}
673676
674-
.group-hover\\:peer-focus\\:flex:is(:where(.peer):focus ~ *):is(:where(.group):hover *) {
677+
.group-hover\\:peer-focus\\:flex:is(:where(.group):hover *):is(:where(.peer):focus ~ *) {
675678
display: flex;
676679
}
677680
678-
.peer-focus\\:group-hover\\:flex:is(:where(.group):hover *):is(:where(.peer):focus ~ *) {
681+
.peer-focus\\:group-hover\\:flex:is(:where(.peer):focus ~ *):is(:where(.group):hover *) {
679682
display: flex;
680683
}
681684
682-
.group-focus\\:peer-focus\\:flex:is(:where(.peer):focus ~ *):is(:where(.group):focus *) {
685+
.group-focus\\:peer-focus\\:flex:is(:where(.group):focus *):is(:where(.peer):focus ~ *) {
683686
display: flex;
684687
}
685688
686-
.peer-focus\\:group-focus\\:flex:is(:where(.group):focus *):is(:where(.peer):focus ~ *) {
689+
.peer-focus\\:group-focus\\:flex:is(:where(.peer):focus ~ *):is(:where(.group):focus *) {
687690
display: flex;
688691
}
689692

packages/tailwindcss/src/variants.test.ts

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -651,15 +651,15 @@ test('group-[...]', () => {
651651
display: flex;
652652
}
653653
654-
.group-\\[\\&\\:hover\\]\\:group-\\[\\&_p\\]\\:flex:is(:where(.group) p *):is(:where(.group):hover *) {
654+
.group-\\[\\&\\:hover\\]\\:group-\\[\\&_p\\]\\:flex:is(:where(.group):hover *):is(:where(.group) p *) {
655655
display: flex;
656656
}
657657
658-
.group-\\[\\&_p\\]\\:hover\\:flex:hover:is(:where(.group) p *) {
658+
.group-\\[\\&_p\\]\\:hover\\:flex:is(:where(.group) p *):hover {
659659
display: flex;
660660
}
661661
662-
.hover\\:group-\\[\\&_p\\]\\:flex:is(:where(.group) p *):hover {
662+
.hover\\:group-\\[\\&_p\\]\\:flex:hover:is(:where(.group) p *) {
663663
display: flex;
664664
}
665665
@@ -686,11 +686,11 @@ test('group-*', () => {
686686
display: flex;
687687
}
688688
689-
.group-focus\\:group-hover\\:flex:is(:where(.group):hover *):is(:where(.group):focus *) {
689+
.group-focus\\:group-hover\\:flex:is(:where(.group):focus *):is(:where(.group):hover *) {
690690
display: flex;
691691
}
692692
693-
.group-hover\\:group-focus\\:flex:is(:where(.group):focus *):is(:where(.group):hover *) {
693+
.group-hover\\:group-focus\\:flex:is(:where(.group):hover *):is(:where(.group):focus *) {
694694
display: flex;
695695
}"
696696
`)
@@ -710,19 +710,19 @@ test('peer-[...]', () => {
710710
display: flex;
711711
}
712712
713-
.peer-\\[\\&\\:hover\\]\\:peer-\\[\\&_p\\]\\:flex:is(:where(.peer) p ~ *):is(:where(.peer):hover ~ *) {
713+
.peer-\\[\\&\\:hover\\]\\:peer-\\[\\&_p\\]\\:flex:is(:where(.peer):hover ~ *):is(:where(.peer) p ~ *) {
714714
display: flex;
715715
}
716716
717-
.hover\\:peer-\\[\\&_p\\]\\:flex:is(:where(.peer) p ~ *):hover {
717+
.hover\\:peer-\\[\\&_p\\]\\:flex:hover:is(:where(.peer) p ~ *) {
718718
display: flex;
719719
}
720720
721-
.peer-\\[\\&_p\\]\\:hover\\:flex:hover:is(:where(.peer) p ~ *) {
721+
.peer-\\[\\&_p\\]\\:hover\\:flex:is(:where(.peer) p ~ *):hover {
722722
display: flex;
723723
}
724724
725-
.hover\\:peer-\\[\\&_p\\]\\:focus\\:flex:focus:is(:where(.peer) p ~ *):hover {
725+
.hover\\:peer-\\[\\&_p\\]\\:focus\\:flex:hover:is(:where(.peer) p ~ *):focus {
726726
display: flex;
727727
}"
728728
`)
@@ -745,11 +745,11 @@ test('peer-*', () => {
745745
display: flex;
746746
}
747747
748-
.peer-focus\\:peer-hover\\:flex:is(:where(.peer):hover ~ *):is(:where(.peer):focus ~ *) {
748+
.peer-focus\\:peer-hover\\:flex:is(:where(.peer):focus ~ *):is(:where(.peer):hover ~ *) {
749749
display: flex;
750750
}
751751
752-
.peer-hover\\:peer-focus\\:flex:is(:where(.peer):focus ~ *):is(:where(.peer):hover ~ *) {
752+
.peer-hover\\:peer-focus\\:flex:is(:where(.peer):hover ~ *):is(:where(.peer):focus ~ *) {
753753
display: flex;
754754
}"
755755
`)
@@ -1009,24 +1009,24 @@ test('sorting stacked min-* and max-* variants', () => {
10091009
--breakpoint-xs: 280px;
10101010
}
10111011
1012-
@media (width < 1280px) {
1013-
@media (width >= 280px) {
1012+
@media (width >= 280px) {
1013+
@media (width < 1280px) {
10141014
.min-xs\\:max-xl\\:flex {
10151015
display: flex;
10161016
}
10171017
}
10181018
}
10191019
1020-
@media (width < 1280px) {
1021-
@media (width >= 640px) {
1020+
@media (width >= 640px) {
1021+
@media (width < 1280px) {
10221022
.min-sm\\:max-xl\\:flex {
10231023
display: flex;
10241024
}
10251025
}
10261026
}
10271027
1028-
@media (width < 1280px) {
1029-
@media (width >= 768px) {
1028+
@media (width >= 768px) {
1029+
@media (width < 1280px) {
10301030
.min-md\\:max-xl\\:flex {
10311031
display: flex;
10321032
}

0 commit comments

Comments
 (0)