This commit is contained in:
Jordan Pittman 2024-07-19 13:27:00 -04:00
parent a609809ce0
commit 8023be68ce
2 changed files with 52 additions and 46 deletions

View file

@ -705,23 +705,23 @@ test('group-[...]', () => {
'group-[&:hover]:group-[&_p]:flex',
]),
).toMatchInlineSnapshot(`
".group-\\[\\&_p\\]\\:flex:is(:where(.group) p *) {
".group-\\[\\&_p\\]\\:flex:is(:where(.group):is(* p) *) {
display: flex;
}
.group-\\[\\&\\:hover\\]\\:group-\\[\\&_p\\]\\:flex:is(:where(.group):hover *):is(:where(.group) p *) {
.group-\\[\\&\\:hover\\]\\:group-\\[\\&_p\\]\\:flex:is(:where(.group):hover *):is(:where(.group):is(* p) *) {
display: flex;
}
.group-\\[\\&_p\\]\\:hover\\:flex:is(:where(.group) p *):hover {
.group-\\[\\&_p\\]\\:hover\\:flex:is(:where(.group):is(* p) *):hover {
display: flex;
}
.hover\\:group-\\[\\&_p\\]\\:flex:hover:is(:where(.group) p *) {
.hover\\:group-\\[\\&_p\\]\\:flex:hover:is(:where(.group):is(* p) *) {
display: flex;
}
.hover\\:group-\\[\\&_p\\]\\:hover\\:flex:hover:is(:where(.group) p *):hover {
.hover\\:group-\\[\\&_p\\]\\:hover\\:flex:hover:is(:where(.group):is(* p) *):hover {
display: flex;
}"
`)
@ -746,6 +746,13 @@ test('group-*', () => {
@slot;
}
}
@variant nested-selectors {
&:hover {
&:focus {
@slot;
}
}
}
@tailwind utilities;
`,
[
@ -755,6 +762,8 @@ test('group-*', () => {
'group-hover:group-focus:flex',
'group-focus:group-hover:flex',
'group-nested-selectors:flex',
],
),
).toMatchInlineSnapshot(`
@ -774,7 +783,11 @@ test('group-*', () => {
display: flex;
}
.group-hocus\\:flex:is(:is(:where(.group):hover, :where(.group):focus) *) {
.group-hocus\\:flex:is(:where(.group):is(:hover, :focus) *) {
display: flex;
}
.group-nested-selectors\\:flex:is(:where(.group):focus:hover *) {
display: flex;
}"
`)
@ -783,16 +796,9 @@ test('group-*', () => {
compileCss(
css`
@variant custom-at-rule (@media foo);
@variant nested-selectors {
&:hover {
&:focus {
@slot;
}
}
}
@tailwind utilities;
`,
['group-custom-at-rule:flex', 'group-nested-selectors:flex'],
['group-custom-at-rule:flex'],
),
).toEqual('')
})

View file

@ -239,9 +239,7 @@ export function createVariants(theme: Theme): Variants {
return null
}
console.log({ groups })
ruleNode.selector = '&' + groups.join('')
ruleNode.selector = `&:is(${groups.join('')})`
ruleNode.nodes = []
})
@ -252,50 +250,52 @@ export function createVariants(theme: Theme): Variants {
? `:where(.group\\/${variant.modifier.value})`
: ':where(.group)'
let didApply = false
let groups: string[] = []
walk([ruleNode], (node) => {
walk([ruleNode], (node, { path }) => {
if (node.kind !== 'rule') return WalkAction.Continue
// Skip past at-rules, and continue traversing the children of the at-rule
if (node.selector[0] === '@') return WalkAction.Continue
// Throw out any candidates with variants using nested selectors
if (didApply) {
walk([node], (childNode) => {
if (childNode.kind !== 'rule' || childNode.selector[0] === '@') return WalkAction.Continue
// 1. Walk the tree until we find `@slot`
if (node.nodes.length !== 0) return WalkAction.Continue
didApply = false
return WalkAction.Stop
})
let selectors = []
return didApply ? WalkAction.Skip : WalkAction.Stop
// 2. Collect the selectors of the parents
for (let ancestor of path) {
if (ancestor.kind !== 'rule') continue
// Skip past at-rules, and continue traversing the children of the at-rule
if (ancestor.selector[0] === '@') continue
// Skip over the "root" node
if (ancestor.selector === '&') continue
// For most variants we rely entirely on CSS nesting to build-up the final
// selector, but there is no way to use CSS nesting to make `&` refer to
// just the `.group` class the way we'd need to for these variants, so we
// need to replace it in the selector ourselves.
let selector = ancestor.selector.replaceAll('&', '*')
// When the selector is a selector _list_ we need to wrap it in `:is`
// to make sure the matching behavior is consistent with the original
// variant / selector.
selectors.push(`:is(${selector})`)
}
// For most variants we rely entirely on CSS nesting to build-up the final
// selector, but there is no way to use CSS nesting to make `&` refer to
// just the `.group` class the way we'd need to for these variants, so we
// need to replace it in the selector ourselves.
node.selector = node.selector.replaceAll('&', groupSelector)
if (selectors.length === 0) return
// When the selector is a selector _list_ we need to wrap it in `:is`
// to make sure the matching behavior is consistent with the original
// variant / selector.
if (segment(node.selector, ',').length > 1) {
node.selector = `:is(${node.selector})`
}
node.selector = `&:is(${node.selector} *)`
// Track that the variant was actually applied
didApply = true
groups.push(selectors.join(''))
})
// If the node wasn't modified, this variant is not compatible with
// `group-*` so discard the candidate.
if (!didApply) {
if (groups.length === 0) {
return null
}
ruleNode.selector = `&:is(${groupSelector}:is(${groups.join(',')}) *)`
ruleNode.nodes = []
})
variants.suggest('group', () => {