From 1124d1d3c72cc8d203010f243ad2ddcaac589a00 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Mon, 3 Jun 2024 11:41:01 -0400 Subject: [PATCH] Add `nth-*` variants (#13661) * Add `nth-*` variants * Update changelog * Update snapshots * Update * update older `toMatchInlineSnapshot` to `toEqual` --------- Co-authored-by: Robin Malfait --- CHANGELOG.md | 4 ++ .../__snapshots__/intellisense.test.ts.snap | 40 ++++++++++++ packages/tailwindcss/src/utilities.test.ts | 2 +- packages/tailwindcss/src/variants.test.ts | 61 +++++++++++++++++++ packages/tailwindcss/src/variants.ts | 36 +++++++++++ 5 files changed, 142 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b40b12bde..af8b6466f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Use `length` data type for `background-size` instead of `background-position` ([#13771](https://github.com/tailwindlabs/tailwindcss/pull/13771)) - Support negative values for `{col,row}-{start,end}` utilities ([#13780](https://github.com/tailwindlabs/tailwindcss/pull/13780)) +### Added + +- Add `nth-*` variants ([#13661](https://github.com/tailwindlabs/tailwindcss/pull/13661)) + ## [4.0.0-alpha.15] - 2024-05-08 ### Fixed diff --git a/packages/tailwindcss/src/__snapshots__/intellisense.test.ts.snap b/packages/tailwindcss/src/__snapshots__/intellisense.test.ts.snap index 4148944de..9ec67647f 100644 --- a/packages/tailwindcss/src/__snapshots__/intellisense.test.ts.snap +++ b/packages/tailwindcss/src/__snapshots__/intellisense.test.ts.snap @@ -1933,6 +1933,10 @@ exports[`getVariants 1`] = ` "has", "aria", "data", + "nth", + "nth-last", + "nth-of-type", + "nth-last-of-type", "ltr", "rtl", ], @@ -1980,6 +1984,10 @@ exports[`getVariants 1`] = ` "has", "aria", "data", + "nth", + "nth-last", + "nth-of-type", + "nth-last-of-type", "ltr", "rtl", ], @@ -2307,6 +2315,10 @@ exports[`getVariants 1`] = ` "has", "aria", "data", + "nth", + "nth-last", + "nth-of-type", + "nth-last-of-type", "ltr", "rtl", ], @@ -2335,6 +2347,34 @@ exports[`getVariants 1`] = ` "selectors": [Function], "values": [], }, + { + "hasDash": true, + "isArbitrary": true, + "name": "nth", + "selectors": [Function], + "values": [], + }, + { + "hasDash": true, + "isArbitrary": true, + "name": "nth-last", + "selectors": [Function], + "values": [], + }, + { + "hasDash": true, + "isArbitrary": true, + "name": "nth-of-type", + "selectors": [Function], + "values": [], + }, + { + "hasDash": true, + "isArbitrary": true, + "name": "nth-last-of-type", + "selectors": [Function], + "values": [], + }, { "hasDash": true, "isArbitrary": true, diff --git a/packages/tailwindcss/src/utilities.test.ts b/packages/tailwindcss/src/utilities.test.ts index 4df5a0273..c44f9a852 100644 --- a/packages/tailwindcss/src/utilities.test.ts +++ b/packages/tailwindcss/src/utilities.test.ts @@ -6253,7 +6253,7 @@ test('divide-color', () => { '-divide-[#0088cc]/[0.5]', '-divide-[#0088cc]/[50%]', ]), - ).toMatchInlineSnapshot(`""`) + ).toEqual('') }) test('place-self', () => { diff --git a/packages/tailwindcss/src/variants.test.ts b/packages/tailwindcss/src/variants.test.ts index e93980440..c5a510bb5 100644 --- a/packages/tailwindcss/src/variants.test.ts +++ b/packages/tailwindcss/src/variants.test.ts @@ -1594,6 +1594,67 @@ test('forced-colors', () => { `) }) +test('nth', () => { + expect( + run([ + 'nth-3:flex', + 'nth-[2n+1]:flex', + 'nth-[2n+1_of_.foo]:flex', + 'nth-last-3:flex', + 'nth-last-[2n+1]:flex', + 'nth-last-[2n+1_of_.foo]:flex', + 'nth-of-type-3:flex', + 'nth-of-type-[2n+1]:flex', + 'nth-last-of-type-3:flex', + 'nth-last-of-type-[2n+1]:flex', + ]), + ).toMatchInlineSnapshot(` + ".nth-3\\:flex:nth-child(3) { + display: flex; + } + + .nth-\\[2n\\+1\\]\\:flex:nth-child(odd) { + display: flex; + } + + .nth-\\[2n\\+1_of_\\.foo\\]\\:flex:nth-child(odd of .foo) { + display: flex; + } + + .nth-last-3\\:flex:nth-last-child(3) { + display: flex; + } + + .nth-last-\\[2n\\+1\\]\\:flex:nth-last-child(odd) { + display: flex; + } + + .nth-last-\\[2n\\+1_of_\\.foo\\]\\:flex:nth-last-child(odd of .foo) { + display: flex; + } + + .nth-of-type-3\\:flex:nth-of-type(3) { + display: flex; + } + + .nth-of-type-\\[2n\\+1\\]\\:flex:nth-of-type(odd) { + display: flex; + } + + .nth-last-of-type-3\\:flex:nth-last-of-type(3) { + display: flex; + } + + .nth-last-of-type-\\[2n\\+1\\]\\:flex:nth-last-of-type(odd) { + display: flex; + }" + `) + + expect( + run(['nth-foo:flex', 'nth-of-type-foo:flex', 'nth-last-foo:flex', 'nth-last-of-type-foo:flex']), + ).toEqual('') +}) + test('container queries', () => { expect( compileCss( diff --git a/packages/tailwindcss/src/variants.ts b/packages/tailwindcss/src/variants.ts index 4738d6d64..8c76c237c 100644 --- a/packages/tailwindcss/src/variants.ts +++ b/packages/tailwindcss/src/variants.ts @@ -373,6 +373,42 @@ export function createVariants(theme: Theme): Variants { ruleNode.nodes = [rule(`&[data-${variant.value.value}]`, ruleNode.nodes)] }) + variants.functional('nth', (ruleNode, variant) => { + if (variant.value === null) return null + + // Only numeric bare values are allowed + if (variant.value.kind === 'named' && Number.isNaN(Number(variant.value.value))) return null + + ruleNode.nodes = [rule(`&:nth-child(${variant.value.value})`, ruleNode.nodes)] + }) + + variants.functional('nth-last', (ruleNode, variant) => { + if (variant.value === null) return null + + // Only numeric bare values are allowed + if (variant.value.kind === 'named' && Number.isNaN(Number(variant.value.value))) return null + + ruleNode.nodes = [rule(`&:nth-last-child(${variant.value.value})`, ruleNode.nodes)] + }) + + variants.functional('nth-of-type', (ruleNode, variant) => { + if (variant.value === null) return null + + // Only numeric bare values are allowed + if (variant.value.kind === 'named' && Number.isNaN(Number(variant.value.value))) return null + + ruleNode.nodes = [rule(`&:nth-of-type(${variant.value.value})`, ruleNode.nodes)] + }) + + variants.functional('nth-last-of-type', (ruleNode, variant) => { + if (variant.value === null) return null + + // Only numeric bare values are allowed + if (variant.value.kind === 'named' && Number.isNaN(Number(variant.value.value))) return null + + ruleNode.nodes = [rule(`&:nth-last-of-type(${variant.value.value})`, ruleNode.nodes)] + }) + variants.functional( 'supports', (ruleNode, variant) => {