mirror of
https://github.com/shadcn-ui/ui.git
synced 2026-06-27 06:34:12 +00:00
fix: handling of apply directive inside utility
This commit is contained in:
@@ -317,7 +317,7 @@ function updateCssPlugin(css: z.infer<typeof registryItemCssSchema>) {
|
||||
postcss.comment({ text: "---break---" })
|
||||
)
|
||||
|
||||
// Add declarations with their values preserved
|
||||
// Add declarations with their values preserved.
|
||||
if (typeof properties === "object") {
|
||||
for (const [prop, value] of Object.entries(properties)) {
|
||||
if (typeof value === "string") {
|
||||
@@ -327,13 +327,38 @@ function updateCssPlugin(css: z.infer<typeof registryItemCssSchema>) {
|
||||
raws: { semicolon: true, before: "\n " },
|
||||
})
|
||||
atRule.append(decl)
|
||||
} else if (
|
||||
prop.startsWith("@") &&
|
||||
typeof value === "object" &&
|
||||
value !== null &&
|
||||
Object.keys(value as Record<string, unknown>).length === 0
|
||||
) {
|
||||
// Handle at-rules with no body (e.g., @apply).
|
||||
const atRuleMatch = prop.match(/@([a-zA-Z-]+)\s*(.*)/)
|
||||
if (atRuleMatch) {
|
||||
const [, atRuleName, atRuleParams] = atRuleMatch
|
||||
const existingAtRule = atRule.nodes?.find(
|
||||
(node): node is AtRule =>
|
||||
node.type === "atrule" &&
|
||||
node.name === atRuleName &&
|
||||
node.params === atRuleParams
|
||||
)
|
||||
if (!existingAtRule) {
|
||||
const newAtRule = postcss.atRule({
|
||||
name: atRuleName,
|
||||
params: atRuleParams,
|
||||
raws: { semicolon: true, before: "\n " },
|
||||
})
|
||||
atRule.append(newAtRule)
|
||||
}
|
||||
}
|
||||
} else if (typeof value === "object") {
|
||||
processRule(atRule, prop, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Update existing utility class
|
||||
// Update existing utility class.
|
||||
if (typeof properties === "object") {
|
||||
for (const [prop, value] of Object.entries(properties)) {
|
||||
if (typeof value === "string") {
|
||||
@@ -351,6 +376,31 @@ function updateCssPlugin(css: z.infer<typeof registryItemCssSchema>) {
|
||||
existingDecl
|
||||
? existingDecl.replaceWith(decl)
|
||||
: utilityAtRule.append(decl)
|
||||
} else if (
|
||||
prop.startsWith("@") &&
|
||||
typeof value === "object" &&
|
||||
value !== null &&
|
||||
Object.keys(value as Record<string, unknown>).length === 0
|
||||
) {
|
||||
// Handle at-rules with no body (e.g., @apply).
|
||||
const atRuleMatch = prop.match(/@([a-zA-Z-]+)\s*(.*)/)
|
||||
if (atRuleMatch) {
|
||||
const [, atRuleName, atRuleParams] = atRuleMatch
|
||||
const existingAtRule = utilityAtRule.nodes?.find(
|
||||
(node): node is AtRule =>
|
||||
node.type === "atrule" &&
|
||||
node.name === atRuleName &&
|
||||
node.params === atRuleParams
|
||||
)
|
||||
if (!existingAtRule) {
|
||||
const newAtRule = postcss.atRule({
|
||||
name: atRuleName,
|
||||
params: atRuleParams,
|
||||
raws: { semicolon: true, before: "\n " },
|
||||
})
|
||||
utilityAtRule.append(newAtRule)
|
||||
}
|
||||
}
|
||||
} else if (typeof value === "object") {
|
||||
processRule(utilityAtRule, prop, value)
|
||||
}
|
||||
|
||||
@@ -929,6 +929,114 @@ describe("transformCss", () => {
|
||||
`)
|
||||
})
|
||||
|
||||
test("should handle @apply inside @utility", async () => {
|
||||
const input = `@import "tailwindcss";`
|
||||
|
||||
const result = await transformCss(input, {
|
||||
"@utility custom-btn": {
|
||||
"@apply px-4 py-2 rounded-md": {},
|
||||
},
|
||||
})
|
||||
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
"@import "tailwindcss";
|
||||
|
||||
@utility custom-btn {
|
||||
@apply px-4 py-2 rounded-md;
|
||||
}"
|
||||
`)
|
||||
})
|
||||
|
||||
test("should handle @apply mixed with declarations inside @utility", async () => {
|
||||
const input = `@import "tailwindcss";`
|
||||
|
||||
const result = await transformCss(input, {
|
||||
"@utility custom-card": {
|
||||
"@apply bg-white shadow-md": {},
|
||||
"border-radius": "0.5rem",
|
||||
},
|
||||
})
|
||||
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
"@import "tailwindcss";
|
||||
|
||||
@utility custom-card {
|
||||
@apply bg-white shadow-md;
|
||||
border-radius: 0.5rem;
|
||||
}"
|
||||
`)
|
||||
})
|
||||
|
||||
test("should handle multiple @apply inside @utility", async () => {
|
||||
const input = `@import "tailwindcss";`
|
||||
|
||||
const result = await transformCss(input, {
|
||||
"@utility custom-input": {
|
||||
"@apply border border-gray-300 rounded-md": {},
|
||||
"@apply focus:ring-2 focus:ring-blue-500": {},
|
||||
padding: "0.5rem",
|
||||
},
|
||||
})
|
||||
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
"@import "tailwindcss";
|
||||
|
||||
@utility custom-input {
|
||||
@apply border border-gray-300 rounded-md;
|
||||
@apply focus:ring-2 focus:ring-blue-500;
|
||||
padding: 0.5rem;
|
||||
}"
|
||||
`)
|
||||
})
|
||||
|
||||
test("should add @apply to existing @utility", async () => {
|
||||
const input = `@import "tailwindcss";
|
||||
|
||||
@utility custom-alert {
|
||||
font-size: 1rem;
|
||||
}`
|
||||
|
||||
const result = await transformCss(input, {
|
||||
"@utility custom-alert": {
|
||||
"@apply font-bold text-red-500": {},
|
||||
},
|
||||
})
|
||||
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
"@import "tailwindcss";
|
||||
|
||||
@utility custom-alert {
|
||||
font-size: 1rem;
|
||||
@apply font-bold text-red-500;
|
||||
}"
|
||||
`)
|
||||
})
|
||||
|
||||
test("should not duplicate @apply inside existing @utility", async () => {
|
||||
const input = `@import "tailwindcss";
|
||||
|
||||
@utility custom-badge {
|
||||
@apply inline-flex items-center;
|
||||
font-size: 0.75rem;
|
||||
}`
|
||||
|
||||
const result = await transformCss(input, {
|
||||
"@utility custom-badge": {
|
||||
"@apply inline-flex items-center": {},
|
||||
"font-size": "0.875rem",
|
||||
},
|
||||
})
|
||||
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
"@import "tailwindcss";
|
||||
|
||||
@utility custom-badge {
|
||||
@apply inline-flex items-center;
|
||||
font-size: 0.875rem;
|
||||
}"
|
||||
`)
|
||||
})
|
||||
|
||||
test("should replace existing keyframes instead of duplicating", async () => {
|
||||
const input = `@import "tailwindcss";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user