Skip to content

Commit 6a155a6

Browse files
committed
Allow variants to request outer wrapper nodes
1 parent e5cce25 commit 6a155a6

File tree

4 files changed

+58
-12
lines changed

4 files changed

+58
-12
lines changed

packages/tailwindcss/src/ast.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -325,16 +325,6 @@ export function optimizeAst(
325325

326326

327327

328-
if (
329-
nodes.length === 1 &&
330-
nodes[0].kind === 'at-rule' &&
331-
(nodes[0].name === '@media' || nodes[0].name === '@supports' || nodes[0].name === '@container' || nodes[0].name === '@scope')
332-
) {
333-
let at = nodes[0]
334-
parent.push(atRule(at.name, at.params, [styleRule(node.selector, at.nodes)]))
335-
return
336-
}
337-
338328
// Rules with `&` as the selector should be flattened
339329
if (node.selector === '&') {
340330
parent.push(...nodes)

packages/tailwindcss/src/compat/plugin-api.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,18 @@ export function buildPluginApi({
145145
designSystem.variants.static(
146146
name,
147147
(r) => {
148-
r.nodes = parseVariantValue(variant, r.nodes)
148+
let body = parseVariantValue(variant, r.nodes)
149+
150+
const isBlock =
151+
typeof variant === 'string'
152+
? variant.trim().endsWith('}')
153+
: variant.some((v) => v.trim().endsWith('}'))
154+
155+
if (isBlock && body.length === 1 && body[0].kind === 'at-rule') {
156+
return body[0]
157+
}
158+
159+
r.nodes = body
149160
},
150161
{
151162
compounds: compoundsForSelectors(typeof variant === 'string' ? [variant] : variant),

packages/tailwindcss/src/compile.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,10 @@ export function applyVariant(
197197
// not hitting this code path.
198198
let { applyFn } = variants.get(variant.root)!
199199

200+
201+
202+
let originalSelector = node.kind === 'rule' ? (node as StyleRule).selector : undefined
203+
200204
if (variant.kind === 'compound') {
201205
// Some variants traverse the AST to mutate the nodes. E.g.: `group-*` wants
202206
// to prefix every selector of the variant it's compounding with `.group`.
@@ -255,6 +259,47 @@ export function applyVariant(
255259
// All other variants
256260
let result = applyFn(node, variant)
257261
if (result === null) return null
262+
263+
264+
265+
266+
267+
268+
if (result && typeof result === 'object' && 'kind' in (result as any)) {
269+
const newNode = result as AstNode
270+
if (newNode.kind === 'at-rule' && originalSelector) {
271+
let replaced = false
272+
walk(newNode.nodes, (child) => {
273+
if (child.kind === 'rule' && child.selector === '&') {
274+
child.selector = originalSelector!
275+
replaced = true
276+
}
277+
})
278+
279+
if (!replaced) {
280+
newNode.nodes = [rule(originalSelector!, newNode.nodes)]
281+
}
282+
}
283+
284+
285+
if (newNode.kind === 'at-rule') {
286+
;(node as any).kind = 'at-rule'
287+
;(node as any).name = newNode.name
288+
;(node as any).params = newNode.params
289+
;(node as any).nodes = newNode.nodes
290+
291+
delete (node as any).selector
292+
} else if (newNode.kind === 'rule') {
293+
;(node as any).kind = 'rule'
294+
;(node as any).selector = newNode.selector
295+
;(node as any).nodes = newNode.nodes
296+
delete (node as any).name
297+
delete (node as any).params
298+
} else {
299+
300+
;(node as any).nodes = (newNode as any).nodes ?? []
301+
}
302+
}
258303
}
259304

260305
function isFallbackUtility(utility: Utility) {

packages/tailwindcss/src/variants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export const IS_VALID_VARIANT_NAME = /^@?[a-z0-9][a-zA-Z0-9_-]*(?<![_-])$/
2626
type VariantFn<T extends Variant['kind']> = (
2727
rule: Rule,
2828
variant: Extract<Variant, { kind: T }>,
29-
) => null | void
29+
) => null | void | AstNode
3030

3131
type CompareFn = (a: Variant, z: Variant) => number
3232

0 commit comments

Comments
 (0)