Skip to content

Commit

Permalink
feat(shadcn): add animation vars
Browse files Browse the repository at this point in the history
  • Loading branch information
shadcn committed Jan 29, 2025
1 parent 2504d23 commit 3ff0dfa
Show file tree
Hide file tree
Showing 2 changed files with 260 additions and 8 deletions.
56 changes: 52 additions & 4 deletions packages/shadcn/src/utils/updaters/update-css-vars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export async function transformCssVars(

if (options.tailwindConfig) {
plugins.push(updateTailwindConfigPlugin(options.tailwindConfig))
plugins.push(updateTailwindConfigAnimationPlugin(options.tailwindConfig))
plugins.push(updateTailwindConfigKeyframesPlugin(options.tailwindConfig))
}
}
Expand Down Expand Up @@ -513,7 +514,7 @@ function updateTailwindConfigKeyframesPlugin(
}

const themeNode = upsertThemeNode(root)
const keyframesNode = themeNode.nodes?.find(
const existingKeyFrameNodes = themeNode.nodes?.filter(
(node): node is AtRule =>
node.type === "atrule" && node.name === "keyframes"
)
Expand All @@ -537,11 +538,14 @@ function updateTailwindConfigKeyframesPlugin(
}

if (
keyframesNode?.nodes?.find(
(node): node is postcss.Declaration =>
node.type === "decl" && node.prop === keyframeName
existingKeyFrameNodes?.find(
(node): node is postcss.AtRule =>
node.type === "atrule" &&
node.name === "keyframes" &&
node.params === keyframeName
)
) {
console.log("Keyframe already present", keyframeName)
continue
}

Expand Down Expand Up @@ -573,6 +577,50 @@ function updateTailwindConfigKeyframesPlugin(
}
}

function updateTailwindConfigAnimationPlugin(
tailwindConfig: z.infer<typeof registryItemTailwindSchema>["config"]
) {
return {
postcssPlugin: "update-tailwind-config-animation",
Once(root: Root) {
if (!tailwindConfig?.theme?.extend?.animation) {
return
}

const themeNode = upsertThemeNode(root)
const existingAnimationNodes = themeNode.nodes?.filter(
(node): node is postcss.Declaration =>
node.type === "decl" && node.prop.startsWith("--animation-")
)

const parsedAnimationValue = z
.record(z.string(), z.string())
.safeParse(tailwindConfig.theme.extend.animation)
if (!parsedAnimationValue.success) {
return
}

for (const [key, value] of Object.entries(parsedAnimationValue.data)) {
const prop = `--animation-${key}`
if (
existingAnimationNodes?.find(
(node): node is postcss.Declaration => node.prop === prop
)
) {
continue
}

const animationNode = postcss.decl({
prop,
value,
raws: { semicolon: true, between: ": ", before: "\n " },
})
themeNode.append(animationNode)
}
},
}
}

function getQuoteType(root: Root): "single" | "double" {
const firstNode = root.nodes[0]
const raw = firstNode.toString()
Expand Down
212 changes: 208 additions & 4 deletions packages/shadcn/test/utils/updaters/update-css-vars.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -668,10 +668,6 @@ describe("transformCssVarsV4", () => {
to: { height: "0" },
},
},
animation: {
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
},
},
},
},
Expand Down Expand Up @@ -709,4 +705,212 @@ describe("transformCssVarsV4", () => {
"
`)
})

test("should NOT add @keyframes if already present", async () => {
expect(
await transformCssVars(
`@import "tailwindcss";
@theme inline {
@keyframes accordion-down {
from {
height: 0;
}
to {
height: var(--radix-accordion-content-height);
}
}
}
`,
{},
{ tailwind: { cssVariables: true } },
{
tailwindVersion: "v4",
tailwindConfig: {
theme: {
extend: {
keyframes: {
"accordion-down": {
from: { height: "0" },
to: { height: "var(--radix-accordion-content-height)" },
},
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: "0" },
},
},
},
},
},
}
)
).toMatchInlineSnapshot(`
"@import "tailwindcss";
@custom-variant dark (&:is(.dark *));
@theme inline {
@keyframes accordion-down {
from {
height: 0;
}
to {
height: var(--radix-accordion-content-height);
}
}
@keyframes accordion-up {
from {
height: var(--radix-accordion-content-height);
}
to {
height: 0;
}
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}
"
`)
})

test("should add --animation if not present", async () => {
expect(
await transformCssVars(
`@import "tailwindcss";
`,
{},
{ tailwind: { cssVariables: true } },
{
tailwindVersion: "v4",
tailwindConfig: {
theme: {
extend: {
keyframes: {
"accordion-down": {
from: { height: "0" },
to: { height: "var(--radix-accordion-content-height)" },
},
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: "0" },
},
},
animation: {
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
},
},
},
},
}
)
).toMatchInlineSnapshot(`
"@import "tailwindcss";
@custom-variant dark (&:is(.dark *));
@theme inline {
--animation-accordion-down: accordion-down 0.2s ease-out;
--animation-accordion-up: accordion-up 0.2s ease-out;
@keyframes accordion-down {
from {
height: 0;
}
to {
height: var(--radix-accordion-content-height);
}
}
@keyframes accordion-up {
from {
height: var(--radix-accordion-content-height);
}
to {
height: 0;
}
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}
"
`)
})

test("should NOT add --animation if already present", async () => {
expect(
await transformCssVars(
`@import "tailwindcss";
@theme inline {
--animation-accordion-up: accordion-up 0.3s ease-out;
}
`,
{},
{ tailwind: { cssVariables: true } },
{
tailwindVersion: "v4",
tailwindConfig: {
theme: {
extend: {
keyframes: {
"accordion-down": {
from: { height: "0" },
to: { height: "var(--radix-accordion-content-height)" },
},
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: "0" },
},
},
animation: {
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
},
},
},
},
}
)
).toMatchInlineSnapshot(`
"@import "tailwindcss";
@custom-variant dark (&:is(.dark *));
@theme inline {
--animation-accordion-up: accordion-up 0.3s ease-out;
--animation-accordion-down: accordion-down 0.2s ease-out;
@keyframes accordion-down {
from {
height: 0;
}
to {
height: var(--radix-accordion-content-height);
}
}
@keyframes accordion-up {
from {
height: var(--radix-accordion-content-height);
}
to {
height: 0;
}
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}
"
`)
})
})

0 comments on commit 3ff0dfa

Please sign in to comment.