Skip to content

Commit

Permalink
Make custom @at-root private API (#14618)
Browse files Browse the repository at this point in the history
This PR makes the internal `@at-root` API private. Before this PR you
could use `@at-root` in your own CSS, which means that it was part of
the public API. If you (accidentally) used it in variants, you could
generate CSS that was completely broken.

This now introduces a new private `AtRoot` node (similar to the recently
introduced `Context` node) and can only be constructed within the
framework.
  • Loading branch information
RobinMalfait authored Oct 8, 2024
1 parent 7be5346 commit 68c32d1
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 33 deletions.
30 changes: 21 additions & 9 deletions packages/tailwindcss/src/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -56,6 +61,13 @@ export function context(context: Record<string, string>, nodes: AstNode[]): Cont
}
}

export function atRoot(nodes: AstNode[]): AtRoot {
return {
kind: 'at-root',
nodes,
}
}

export enum WalkAction {
/** Continue walking, which is the default */
Continue,
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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`
Expand Down
8 changes: 2 additions & 6 deletions packages/tailwindcss/src/compile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -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)
}
Expand Down
10 changes: 4 additions & 6 deletions packages/tailwindcss/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { version } from '../package.json'
import { substituteAtApply } from './apply'
import {
atRoot,
comment,
context,
decl,
Expand Down Expand Up @@ -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)])),
)
}
}
Expand Down
6 changes: 1 addition & 5 deletions packages/tailwindcss/src/utilities.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -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}"` : `"*"`),
Expand Down
11 changes: 4 additions & 7 deletions packages/tailwindcss/src/variants.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -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', '""'),
Expand Down Expand Up @@ -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
}
})
Expand Down

0 comments on commit 68c32d1

Please sign in to comment.