mirror of
https://github.com/shadcn-ui/ui.git
synced 2026-07-08 22:45:47 +00:00
fix: issue with fonts
This commit is contained in:
@@ -159,7 +159,7 @@ export default function RootLayout({
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<html lang="en" className={cn("font-sans", "font-mono", inter.variable, jetbrainsMono.variable)}>
|
||||
<html lang="en" className={cn("font-mono", inter.variable, jetbrainsMono.variable)}>
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
)
|
||||
@@ -962,7 +962,7 @@ export default function RootLayout({
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<html lang="en" className={cn("font-sans", "font-serif", inter.variable, lora.variable)}>
|
||||
<html lang="en" className={cn("font-serif", inter.variable, lora.variable)}>
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
)
|
||||
@@ -971,6 +971,49 @@ export default function RootLayout({
|
||||
`)
|
||||
})
|
||||
|
||||
it("should replace existing font-sans with font-serif on html", async () => {
|
||||
const input = `
|
||||
import { Inter } from "next/font/google";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const inter = Inter({subsets:['latin'],variable:'--font-sans'});
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<html lang="en" className={cn("font-sans", inter.variable)}>
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
`
|
||||
const fonts = [
|
||||
{
|
||||
name: "font-playfair-display",
|
||||
type: "registry:font" as const,
|
||||
font: {
|
||||
family: "'Playfair Display Variable', serif",
|
||||
provider: "google" as const,
|
||||
import: "Playfair_Display",
|
||||
variable: "--font-serif",
|
||||
subsets: ["latin"],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
const result = await transformLayoutFonts(input, fonts, mockConfig)
|
||||
|
||||
// font-sans should be replaced with font-serif.
|
||||
expect(result).toContain('"font-serif"')
|
||||
expect(result).not.toContain('"font-sans"')
|
||||
expect(result).toContain("playfairDisplay.variable")
|
||||
// Inter's variable should remain since we only added Playfair.
|
||||
expect(result).toContain("inter.variable")
|
||||
})
|
||||
|
||||
it("should be idempotent with multiple fonts", async () => {
|
||||
const input = `
|
||||
export default function RootLayout({
|
||||
|
||||
@@ -250,12 +250,25 @@ export async function transformLayoutFonts(
|
||||
fontUtilityClasses.push(font.font.variable.replace("--", ""))
|
||||
}
|
||||
|
||||
// Only keep one font-family class (font-sans, font-serif, font-mono) on <html>.
|
||||
// The last one in the array takes priority as it's the one being added/changed.
|
||||
const fontFamilyClasses = new Set(["font-sans", "font-serif", "font-mono"])
|
||||
const lastFontFamilyClass = [...fontUtilityClasses]
|
||||
.reverse()
|
||||
.find((cls) => fontFamilyClasses.has(cls))
|
||||
const filteredUtilityClasses = fontUtilityClasses.filter(
|
||||
(cls) => !fontFamilyClasses.has(cls)
|
||||
)
|
||||
if (lastFontFamilyClass) {
|
||||
filteredUtilityClasses.unshift(lastFontFamilyClass)
|
||||
}
|
||||
|
||||
// Update html className to include font variables and utility classes.
|
||||
if (fontVariableNames.length > 0) {
|
||||
updateHtmlClassName(
|
||||
sourceFile,
|
||||
fontVariableNames,
|
||||
fontUtilityClasses,
|
||||
filteredUtilityClasses,
|
||||
config
|
||||
)
|
||||
}
|
||||
@@ -403,17 +416,18 @@ function updateHtmlClassName(
|
||||
const hasAllUtilityClasses = fontUtilityClasses.every((cls) =>
|
||||
exprText.includes(`"${cls}"`)
|
||||
)
|
||||
if (hasAllFontVars && hasAllUtilityClasses) {
|
||||
// Check there are no stale font-family classes (e.g., "font-sans" when we want "font-serif").
|
||||
const staleFontFamilyClasses = ["font-sans", "font-serif", "font-mono"]
|
||||
.filter((cls) => !fontUtilityClasses.includes(cls))
|
||||
.some((cls) => exprText.includes(`"${cls}"`))
|
||||
if (hasAllFontVars && hasAllUtilityClasses && !staleFontFamilyClasses) {
|
||||
// Already has everything, skip.
|
||||
continue
|
||||
}
|
||||
|
||||
// Remove existing font variables and utility classes, then add new ones.
|
||||
let cleanedExpr = removeFontVariablesFromCn(exprText)
|
||||
cleanedExpr = removeFontUtilityClassesFromCn(
|
||||
cleanedExpr,
|
||||
fontUtilityClasses
|
||||
)
|
||||
// Remove existing font variables and font-family classes, then add new ones.
|
||||
let cleanedExpr = removeFontVariablesFromCn(exprText, newVarExpressions)
|
||||
cleanedExpr = removeFontFamilyClassesFromCn(cleanedExpr)
|
||||
const newExpr = insertFontVariablesIntoCn(cleanedExpr, allNewArgs)
|
||||
jsxExpr.replaceWithText(`{${newExpr}}`)
|
||||
} else if (/^\w+\.variable$/.test(exprText)) {
|
||||
@@ -510,18 +524,25 @@ function parseTemplateLiteralToCnArgs(templateLiteral: string) {
|
||||
return [...staticArgs, ...variableArgs]
|
||||
}
|
||||
|
||||
function removeFontVariablesFromCn(cnExpr: string) {
|
||||
// Remove patterns like "fontName.variable" from cn() call.
|
||||
return cnExpr.replace(/,?\s*\w+\.variable/g, "").replace(/cn\(\s*,/, "cn(")
|
||||
function removeFontVariablesFromCn(
|
||||
cnExpr: string,
|
||||
variablesToRemove: string[]
|
||||
) {
|
||||
// Remove specific font variable expressions from cn() call.
|
||||
let result = cnExpr
|
||||
for (const varExpr of variablesToRemove) {
|
||||
result = result
|
||||
.replace(new RegExp(`,?\\s*${varExpr.replace(".", "\\.")}`, "g"), "")
|
||||
.replace(/cn\(\s*,/, "cn(")
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function removeFontUtilityClassesFromCn(
|
||||
cnExpr: string,
|
||||
utilityClasses: string[]
|
||||
) {
|
||||
// Remove font utility class strings like "font-sans", "font-serif" from cn() call.
|
||||
function removeFontFamilyClassesFromCn(cnExpr: string) {
|
||||
// Remove font-family class strings (font-sans, font-serif, font-mono) from cn() call.
|
||||
// Does not remove other font classes like font-bold, font-semibold, etc.
|
||||
let result = cnExpr
|
||||
for (const cls of utilityClasses) {
|
||||
for (const cls of ["font-sans", "font-serif", "font-mono"]) {
|
||||
result = result
|
||||
.replace(new RegExp(`,?\\s*"${cls}"`, "g"), "")
|
||||
.replace(/cn\(\s*,/, "cn(")
|
||||
|
||||
Reference in New Issue
Block a user