Improve canonicalization for & > :pseudo and & :pseudo arbitrary variants (#19178)

This improves canonicalization of arbitrary variants that use pseudo
classes a bit.

Before this we would see `[&_:first-child]:flex` and leave it be when it
can instead be written as `**:first:flex`. Likewise, for pseudo classes
that don't have a variant, we can still simplify things a bit as
`[&_:--custom]` can be written `**:[:--custom]`.
This commit is contained in:
Jordan Pittman 2025-10-22 08:29:08 -04:00 • committed by GitHub
parent 0113b88fbd
commit a41add9fab
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 24 additions and 3 deletions

View file

@ -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))

View file

@ -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'],

View file

@ -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}`