Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
RobinMalfait committed Mar 25, 2024
1 parent 19c8fe3 commit dfd601f
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 2 deletions.
41 changes: 41 additions & 0 deletions packages/tailwindcss/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,47 @@ describe('@apply', () => {
}"
`)
})

it('should be possible to apply user-defined CSS', () => {
expect(
compileCss(css`
@theme {
--spacing-2: 0.5rem;
--spacing-3: 0.75rem;
--color-red-600: #e53e3e;
}
.btn {
@apply py-2 px-3;
}
.btn-red {
@apply btn bg-red-600;
}
`),
).toMatchInlineSnapshot(`
":root {
--spacing-2: .5rem;
--spacing-3: .75rem;
--color-red-600: #e53e3e;
}
.btn {
padding-top: var(--spacing-2, .5rem);
padding-bottom: var(--spacing-2, .5rem);
padding-left: var(--spacing-3, .75rem);
padding-right: var(--spacing-3, .75rem);
}
.btn-red {
padding-top: var(--spacing-2, .5rem);
padding-bottom: var(--spacing-2, .5rem);
padding-left: var(--spacing-3, .75rem);
padding-right: var(--spacing-3, .75rem);
background-color: var(--color-red-600, #e53e3e);
}"
`)
})
})

describe('arbitrary variants', () => {
Expand Down
34 changes: 32 additions & 2 deletions packages/tailwindcss/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ export function compile(css: string): {
invalidCandidates.add(candidate)
}

// Track `@apply` information
let isApplyUsed = css.includes('@apply')
let applyables = new Map<string, AstNode[]>()

// Find all `@theme` declarations
let theme = new Theme()
let firstThemeRule: Rule | null = null
Expand All @@ -28,6 +32,14 @@ export function compile(css: string): {
walk(ast, (node, { replaceWith }) => {
if (node.kind !== 'rule') return

// Track all user-defined classes for `@apply` support
if (isApplyUsed && node.selector[0] === '.' && !node.selector.includes(' ')) {
let candidate = node.selector.slice(1)
let existing = applyables.get(candidate) ?? []
existing.push(node)
applyables.set(candidate, existing)
}

// Drop instances of `@media reference`
//
// We support `@import "tailwindcss/theme" reference` as a way to import an external theme file
Expand Down Expand Up @@ -143,7 +155,7 @@ export function compile(css: string): {
})

// Replace `@apply` rules with the actual utility classes.
if (css.includes('@apply')) {
if (isApplyUsed) {
walk(ast, (node, { replaceWith }) => {
if (node.kind === 'rule' && node.selector[0] === '@' && node.selector.startsWith('@apply')) {
let candidates = node.selector
Expand All @@ -153,6 +165,25 @@ export function compile(css: string): {

// Replace the `@apply` rule with the actual utility classes
{
let newNodes: AstNode[] = []
for (let candidate of candidates.splice(0)) {
if (applyables.has(candidate)) {
for (let candidateNode of applyables.get(candidate) ?? []) {
candidateNode = structuredClone(candidateNode)

if (candidateNode.kind === 'rule' && candidateNode.selector[0] !== '@') {
for (let child of candidateNode.nodes) {
newNodes.push(child)
}
} else {
newNodes.push(candidateNode)
}
}
} else {
candidates.push(candidate)
}
}

// Parse the candidates to an AST that we can replace the `@apply` rule with.
let candidateAst = compileCandidates(candidates, designSystem, {
onInvalidCandidate: (candidate) => {
Expand All @@ -163,7 +194,6 @@ export function compile(css: string): {
// Collect the nodes to insert in place of the `@apply` rule. When a
// rule was used, we want to insert its children instead of the rule
// because we don't want the wrapping selector.
let newNodes: AstNode[] = []
for (let candidateNode of candidateAst) {
if (candidateNode.kind === 'rule' && candidateNode.selector[0] !== '@') {
for (let child of candidateNode.nodes) {
Expand Down

0 comments on commit dfd601f

Please sign in to comment.