diff --git a/CHANGELOG.md b/CHANGELOG.md index 36966fdfd681..fc3c27c14c83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - _Experimental_: Add `@container-size` utility ([#18901](https://github.com/tailwindlabs/tailwindcss/pull/18901)) +### Changed + +- Improve canonicalization for `& > :pseudo` and `& :pseudo` arbitrary variants ([#19178](https://github.com/tailwindlabs/tailwindcss/pull/19178)) + ### Fixed - Discard candidates with an empty data type ([#19172](https://github.com/tailwindlabs/tailwindcss/pull/19172)) diff --git a/packages/tailwindcss/src/canonicalize-candidates.test.ts b/packages/tailwindcss/src/canonicalize-candidates.test.ts index bcf992a886ea..c5599d181c09 100644 --- a/packages/tailwindcss/src/canonicalize-candidates.test.ts +++ b/packages/tailwindcss/src/canonicalize-candidates.test.ts @@ -857,6 +857,11 @@ describe.each([['default'], ['with-variant'], ['important'], ['prefix']])('%s', ['[&:first-child]:flex', 'first:flex'], ['[&:not(:first-child)]:flex', 'not-first:flex'], + ['[&_:first-child]:flex', '**:first:flex'], + ['[&_>_:first-child]:flex', '*:first:flex'], + ['[&_:--custom]:flex', '**:[:--custom]:flex'], + ['[&_>_:--custom]:flex', '*:[:--custom]:flex'], + // in-* variants ['[p_&]:flex', 'in-[p]:flex'], ['[.foo_&]:flex', 'in-[.foo]:flex'], diff --git a/packages/tailwindcss/src/canonicalize-candidates.ts b/packages/tailwindcss/src/canonicalize-candidates.ts index fd8b862490cf..13c3bc257a91 100644 --- a/packages/tailwindcss/src/canonicalize-candidates.ts +++ b/packages/tailwindcss/src/canonicalize-candidates.ts @@ -1610,7 +1610,7 @@ function modernizeArbitraryValuesVariant( ast[1].kind === 'combinator' && ast[1].value.trim() === '>' && ast[2].kind === 'selector' && - isAttributeSelector(ast[2]) + (isAttributeSelector(ast[2]) || ast[2].value[0] === ':') ) { ast = [ast[2]] prefixedVariant = designSystem.parseVariant('*') @@ -1628,7 +1628,7 @@ function modernizeArbitraryValuesVariant( ast[1].kind === 'combinator' && ast[1].value.trim() === '' && // space, but trimmed because there could be multiple spaces ast[2].kind === 'selector' && - isAttributeSelector(ast[2]) + (isAttributeSelector(ast[2]) || ast[2].value[0] === ':') ) { ast = [ast[2]] prefixedVariant = designSystem.parseVariant('**') @@ -1742,7 +1742,19 @@ function modernizeArbitraryValuesVariant( return null })(targetNode.value) - if (newVariant === null) continue + if (newVariant === null) { + if (prefixedVariant) { + replaceObject(variant, { + kind: 'arbitrary', + selector: target.value, + relative: false, + } satisfies Variant) + + return [prefixedVariant, variant] + } + + continue + } // Add `not-` prefix if (compoundNot) newVariant = `not-${newVariant}`