From a685f37bcc0e49652c5ee93794384c6382010e12 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Sat, 6 Apr 2024 23:51:00 +0200 Subject: [PATCH 1/2] 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. --- packages/tailwindcss/src/candidate.ts | 29 +++------------------------ 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/packages/tailwindcss/src/candidate.ts b/packages/tailwindcss/src/candidate.ts index 67fcbdbd2..3c2b09a40 100644 --- a/packages/tailwindcss/src/candidate.ts +++ b/packages/tailwindcss/src/candidate.ts @@ -221,34 +221,11 @@ export function parseCandidate(input: string, designSystem: DesignSystem): Candi let parsedCandidateVariants: Variant[] = [] - for (let variant of rawVariants) { - let parsedVariant = designSystem.parseVariant(variant) + for (let i = rawVariants.length - 1; i >= 0; --i) { + let parsedVariant = designSystem.parseVariant(rawVariants[i]) if (parsedVariant === null) return null - // Variants are applied left-to-right meaning that any representing pseudo- - // elements must come first. This is because they cannot have anything - // after them in a selector. The problem with this is that it's common for - // users to write them in the wrong order, for example: - // - // `dark:before:underline` (wrong) - // `before:dark:underline` (right) - // - // Add pseudo-element variants to the front, making both examples above - // function identically which allows users to not care about the order. - switch (variant) { - case 'after': - case 'backdrop': - case 'before': - case 'first-letter': - case 'first-line': - case 'marker': - case 'placeholder': - case 'selection': - parsedCandidateVariants.unshift(parsedVariant) - break - default: - parsedCandidateVariants.push(parsedVariant) - } + parsedCandidateVariants.push(parsedVariant) } let state = { From 7117544d09bbb1ce23eb1854e2c3f60079e063b7 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Sat, 6 Apr 2024 23:53:06 +0200 Subject: [PATCH 2/2] update tests to reflect variant order change --- packages/tailwindcss/src/candidate.test.ts | 12 ++--- packages/tailwindcss/src/index.test.ts | 57 ++++++++++++---------- packages/tailwindcss/src/variants.test.ts | 34 ++++++------- 3 files changed, 53 insertions(+), 50 deletions(-) diff --git a/packages/tailwindcss/src/candidate.test.ts b/packages/tailwindcss/src/candidate.test.ts index 17d1371b6..f9dc65cac 100644 --- a/packages/tailwindcss/src/candidate.test.ts +++ b/packages/tailwindcss/src/candidate.test.ts @@ -120,12 +120,12 @@ it('should parse a simple utility with stacked variants', () => { { "compounds": true, "kind": "static", - "root": "focus", + "root": "hover", }, { "compounds": true, "kind": "static", - "root": "hover", + "root": "focus", }, ], } @@ -1012,12 +1012,12 @@ it('should parse arbitrary properties with stacked variants', () => { { "compounds": true, "kind": "static", - "root": "focus", + "root": "hover", }, { "compounds": true, "kind": "static", - "root": "hover", + "root": "focus", }, ], } @@ -1036,12 +1036,12 @@ it('should parse arbitrary properties that are important and using stacked arbit { "compounds": true, "kind": "arbitrary", - "selector": "@media(width>=123px)", + "selector": "& p", }, { "compounds": true, "kind": "arbitrary", - "selector": "& p", + "selector": "@media(width>=123px)", }, ], } diff --git a/packages/tailwindcss/src/index.test.ts b/packages/tailwindcss/src/index.test.ts index 05e4213c0..b31f6c702 100644 --- a/packages/tailwindcss/src/index.test.ts +++ b/packages/tailwindcss/src/index.test.ts @@ -333,7 +333,7 @@ describe('arbitrary variants', () => { describe('variant stacking', () => { it('should stack simple variants', () => { expect(run(['focus:hover:flex'])).toMatchInlineSnapshot(` - ".focus\\:hover\\:flex:hover:focus { + ".focus\\:hover\\:flex:focus:hover { display: flex; }" `) @@ -341,7 +341,7 @@ describe('variant stacking', () => { it('should stack arbitrary variants and simple variants', () => { expect(run(['[&_p]:hover:flex'])).toMatchInlineSnapshot(` - ".\\[\\&_p\\]\\:hover\\:flex:hover p { + ".\\[\\&_p\\]\\:hover\\:flex p:hover { display: flex; }" `) @@ -359,8 +359,11 @@ describe('variant stacking', () => { it('pseudo element variants are re-ordered', () => { expect(run(['before:hover:flex', 'hover:before:flex'])).toMatchInlineSnapshot(` - ".before\\:hover\\:flex:hover:before { + ".before\\:hover\\:flex:before { content: var(--tw-content); + } + + .before\\:hover\\:flex:before:hover { display: flex; } @@ -592,26 +595,26 @@ describe('sorting', () => { ), ), ).toMatchInlineSnapshot(` - ".flex { - display: flex; - } + ".flex { + display: flex; + } - .hover\\:flex:hover { - display: flex; - } + .hover\\:flex:hover { + display: flex; + } - .focus\\:flex:focus { - display: flex; - } + .focus\\:flex:focus { + display: flex; + } - .hover\\:focus\\:flex:focus:hover { - display: flex; - } + .hover\\:focus\\:flex:hover:focus { + display: flex; + } - .disabled\\:flex:disabled { - display: flex; - }" - `) + .disabled\\:flex:disabled { + display: flex; + }" + `) }) // TODO: Extend this test with user-defined variants to ensure they are sorted @@ -651,19 +654,19 @@ describe('sorting', () => { display: flex; } - .group-hover\\:peer-hover\\:flex:is(:where(.peer):hover ~ *):is(:where(.group):hover *) { + .group-hover\\:peer-hover\\:flex:is(:where(.group):hover *):is(:where(.peer):hover ~ *) { display: flex; } - .peer-hover\\:group-hover\\:flex:is(:where(.group):hover *):is(:where(.peer):hover ~ *) { + .peer-hover\\:group-hover\\:flex:is(:where(.peer):hover ~ *):is(:where(.group):hover *) { display: flex; } - .group-focus\\:peer-hover\\:flex:is(:where(.peer):hover ~ *):is(:where(.group):focus *) { + .group-focus\\:peer-hover\\:flex:is(:where(.group):focus *):is(:where(.peer):hover ~ *) { display: flex; } - .peer-hover\\:group-focus\\:flex:is(:where(.group):focus *):is(:where(.peer):hover ~ *) { + .peer-hover\\:group-focus\\:flex:is(:where(.peer):hover ~ *):is(:where(.group):focus *) { display: flex; } @@ -671,19 +674,19 @@ describe('sorting', () => { display: flex; } - .group-hover\\:peer-focus\\:flex:is(:where(.peer):focus ~ *):is(:where(.group):hover *) { + .group-hover\\:peer-focus\\:flex:is(:where(.group):hover *):is(:where(.peer):focus ~ *) { display: flex; } - .peer-focus\\:group-hover\\:flex:is(:where(.group):hover *):is(:where(.peer):focus ~ *) { + .peer-focus\\:group-hover\\:flex:is(:where(.peer):focus ~ *):is(:where(.group):hover *) { display: flex; } - .group-focus\\:peer-focus\\:flex:is(:where(.peer):focus ~ *):is(:where(.group):focus *) { + .group-focus\\:peer-focus\\:flex:is(:where(.group):focus *):is(:where(.peer):focus ~ *) { display: flex; } - .peer-focus\\:group-focus\\:flex:is(:where(.group):focus *):is(:where(.peer):focus ~ *) { + .peer-focus\\:group-focus\\:flex:is(:where(.peer):focus ~ *):is(:where(.group):focus *) { display: flex; } diff --git a/packages/tailwindcss/src/variants.test.ts b/packages/tailwindcss/src/variants.test.ts index 18ef39eeb..de16fa4ca 100644 --- a/packages/tailwindcss/src/variants.test.ts +++ b/packages/tailwindcss/src/variants.test.ts @@ -651,15 +651,15 @@ test('group-[...]', () => { display: flex; } - .group-\\[\\&\\:hover\\]\\:group-\\[\\&_p\\]\\:flex:is(:where(.group) p *):is(:where(.group):hover *) { + .group-\\[\\&\\:hover\\]\\:group-\\[\\&_p\\]\\:flex:is(:where(.group):hover *):is(:where(.group) p *) { display: flex; } - .group-\\[\\&_p\\]\\:hover\\:flex:hover:is(:where(.group) p *) { + .group-\\[\\&_p\\]\\:hover\\:flex:is(:where(.group) p *):hover { display: flex; } - .hover\\:group-\\[\\&_p\\]\\:flex:is(:where(.group) p *):hover { + .hover\\:group-\\[\\&_p\\]\\:flex:hover:is(:where(.group) p *) { display: flex; } @@ -686,11 +686,11 @@ test('group-*', () => { display: flex; } - .group-focus\\:group-hover\\:flex:is(:where(.group):hover *):is(:where(.group):focus *) { + .group-focus\\:group-hover\\:flex:is(:where(.group):focus *):is(:where(.group):hover *) { display: flex; } - .group-hover\\:group-focus\\:flex:is(:where(.group):focus *):is(:where(.group):hover *) { + .group-hover\\:group-focus\\:flex:is(:where(.group):hover *):is(:where(.group):focus *) { display: flex; }" `) @@ -710,19 +710,19 @@ test('peer-[...]', () => { display: flex; } - .peer-\\[\\&\\:hover\\]\\:peer-\\[\\&_p\\]\\:flex:is(:where(.peer) p ~ *):is(:where(.peer):hover ~ *) { + .peer-\\[\\&\\:hover\\]\\:peer-\\[\\&_p\\]\\:flex:is(:where(.peer):hover ~ *):is(:where(.peer) p ~ *) { display: flex; } - .hover\\:peer-\\[\\&_p\\]\\:flex:is(:where(.peer) p ~ *):hover { + .hover\\:peer-\\[\\&_p\\]\\:flex:hover:is(:where(.peer) p ~ *) { display: flex; } - .peer-\\[\\&_p\\]\\:hover\\:flex:hover:is(:where(.peer) p ~ *) { + .peer-\\[\\&_p\\]\\:hover\\:flex:is(:where(.peer) p ~ *):hover { display: flex; } - .hover\\:peer-\\[\\&_p\\]\\:focus\\:flex:focus:is(:where(.peer) p ~ *):hover { + .hover\\:peer-\\[\\&_p\\]\\:focus\\:flex:hover:is(:where(.peer) p ~ *):focus { display: flex; }" `) @@ -745,11 +745,11 @@ test('peer-*', () => { display: flex; } - .peer-focus\\:peer-hover\\:flex:is(:where(.peer):hover ~ *):is(:where(.peer):focus ~ *) { + .peer-focus\\:peer-hover\\:flex:is(:where(.peer):focus ~ *):is(:where(.peer):hover ~ *) { display: flex; } - .peer-hover\\:peer-focus\\:flex:is(:where(.peer):focus ~ *):is(:where(.peer):hover ~ *) { + .peer-hover\\:peer-focus\\:flex:is(:where(.peer):hover ~ *):is(:where(.peer):focus ~ *) { display: flex; }" `) @@ -1009,24 +1009,24 @@ test('sorting stacked min-* and max-* variants', () => { --breakpoint-xs: 280px; } - @media (width < 1280px) { - @media (width >= 280px) { + @media (width >= 280px) { + @media (width < 1280px) { .min-xs\\:max-xl\\:flex { display: flex; } } } - @media (width < 1280px) { - @media (width >= 640px) { + @media (width >= 640px) { + @media (width < 1280px) { .min-sm\\:max-xl\\:flex { display: flex; } } } - @media (width < 1280px) { - @media (width >= 768px) { + @media (width >= 768px) { + @media (width < 1280px) { .min-md\\:max-xl\\:flex { display: flex; }