diff --git a/packages/tailwindcss/src/ast.ts b/packages/tailwindcss/src/ast.ts index c34a3d5af..e9d1ce48c 100644 --- a/packages/tailwindcss/src/ast.ts +++ b/packages/tailwindcss/src/ast.ts @@ -22,7 +22,12 @@ export type Context = { nodes: AstNode[] } -export type AstNode = Rule | Declaration | Comment | Context +export type AtRoot = { + kind: 'at-root' + nodes: AstNode[] +} + +export type AstNode = Rule | Declaration | Comment | Context | AtRoot export function rule(selector: string, nodes: AstNode[]): Rule { return { @@ -56,6 +61,13 @@ export function context(context: Record, nodes: AstNode[]): Cont } } +export function atRoot(nodes: AstNode[]): AtRoot { + return { + kind: 'at-root', + nodes, + } +} + export enum WalkAction { /** Continue walking, which is the default */ Continue, @@ -128,14 +140,6 @@ export function toCss(ast: AstNode[]) { // Rule if (node.kind === 'rule') { - // Pull out `@at-root` rules to append later - if (node.selector === '@at-root') { - for (let child of node.nodes) { - atRoots += stringify(child, 0) - } - return css - } - if (node.selector === '@tailwind utilities') { for (let child of node.nodes) { css += stringify(child, depth) @@ -204,6 +208,14 @@ export function toCss(ast: AstNode[]) { } } + // AtRoot Node + else if (node.kind === 'at-root') { + for (let child of node.nodes) { + atRoots += stringify(child, 0) + } + return css + } + // Declaration else if (node.property !== '--tw-sort' && node.value !== undefined && node.value !== null) { css += `${indent}${node.property}: ${node.value}${node.important ? ' !important' : ''};\n` diff --git a/packages/tailwindcss/src/compile.ts b/packages/tailwindcss/src/compile.ts index f7d9c5125..87b5133da 100644 --- a/packages/tailwindcss/src/compile.ts +++ b/packages/tailwindcss/src/compile.ts @@ -293,9 +293,9 @@ function compileBaseUtility(candidate: Candidate, designSystem: DesignSystem) { function applyImportant(ast: AstNode[]): void { for (let node of ast) { - // Skip any `@at-root` rules — we don't want to make the contents of things + // Skip any `AtRoot` nodes — we don't want to make the contents of things // like `@keyframes` or `@property` important. - if (node.kind === 'rule' && node.selector === '@at-root') { + if (node.kind === 'at-root') { continue } @@ -328,10 +328,6 @@ function getPropertySort(nodes: AstNode[]) { let idx = GLOBAL_PROPERTY_ORDER.indexOf(node.property) if (idx !== -1) propertySort.add(idx) } else if (node.kind === 'rule') { - // Don't consider properties within `@at-root` when determining the sort - // order for a rule. - if (node.selector === '@at-root') continue - for (let child of node.nodes) { q.push(child) } diff --git a/packages/tailwindcss/src/index.ts b/packages/tailwindcss/src/index.ts index 2d247b3aa..742f459cc 100644 --- a/packages/tailwindcss/src/index.ts +++ b/packages/tailwindcss/src/index.ts @@ -1,6 +1,7 @@ import { version } from '../package.json' import { substituteAtApply } from './apply' import { + atRoot, comment, context, decl, @@ -361,13 +362,10 @@ async function parseCss( continue } - // Wrap `@keyframes` in `@at-root` so they are hoisted out of `:root` - // when printing. + // Wrap `@keyframes` in `AtRoot` so they are hoisted out of `:root` when + // printing. nodes.push( - Object.assign(keyframesRule, { - selector: '@at-root', - nodes: [rule(keyframesRule.selector, keyframesRule.nodes)], - }), + Object.assign(keyframesRule, atRoot([rule(keyframesRule.selector, keyframesRule.nodes)])), ) } } diff --git a/packages/tailwindcss/src/utilities.ts b/packages/tailwindcss/src/utilities.ts index e6e064b0e..a308b49c3 100644 --- a/packages/tailwindcss/src/utilities.ts +++ b/packages/tailwindcss/src/utilities.ts @@ -1,4 +1,4 @@ -import { decl, rule, type AstNode, type Rule } from './ast' +import { atRoot, decl, rule, type AstNode } from './ast' import type { Candidate, CandidateModifier, NamedUtilityValue } from './candidate' import type { Theme, ThemeKey } from './theme' import { DefaultMap } from './utils/default-map' @@ -84,10 +84,6 @@ export class Utilities { } } -function atRoot(rules: Rule[]) { - return rule('@at-root', rules) -} - function property(ident: string, initialValue?: string, syntax?: string) { return rule(`@property ${ident}`, [ decl('syntax', syntax ? `"${syntax}"` : `"*"`), diff --git a/packages/tailwindcss/src/variants.ts b/packages/tailwindcss/src/variants.ts index 968f8d7a1..693222860 100644 --- a/packages/tailwindcss/src/variants.ts +++ b/packages/tailwindcss/src/variants.ts @@ -1,4 +1,4 @@ -import { WalkAction, decl, rule, walk, type AstNode, type Rule } from './ast' +import { WalkAction, atRoot, decl, rule, walk, type AstNode, type Rule } from './ast' import { type Variant } from './candidate' import type { Theme } from './theme' import { DefaultMap } from './utils/default-map' @@ -380,7 +380,7 @@ export function createVariants(theme: Theme): Variants { { function contentProperties() { - return rule('@at-root', [ + return atRoot([ rule('@property --tw-content', [ decl('syntax', '"*"'), decl('initial-value', '""'), @@ -933,16 +933,13 @@ export function substituteAtSlot(ast: AstNode[], nodes: AstNode[]) { replaceWith(nodes) } - // Wrap `@keyframes` and `@property` in `@at-root` + // Wrap `@keyframes` and `@property` in `AtRoot` nodes else if ( node.kind === 'rule' && node.selector[0] === '@' && (node.selector.startsWith('@keyframes ') || node.selector.startsWith('@property ')) ) { - Object.assign(node, { - selector: '@at-root', - nodes: [rule(node.selector, node.nodes)], - }) + Object.assign(node, atRoot([rule(node.selector, node.nodes)])) return WalkAction.Skip } })