Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Font loader types #41591

Merged
merged 6 commits into from Oct 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6,235 changes: 2,957 additions & 3,278 deletions packages/font/src/google/font-data.json

Large diffs are not rendered by default.

6,049 changes: 2,912 additions & 3,137 deletions packages/font/src/google/index.ts

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/font/src/google/loader.ts
Expand Up @@ -130,7 +130,7 @@ const downloadGoogleFonts: FontLoader = async ({
return {
css: updatedCssResponse,
fallbackFonts: fallback,
weight: weight === 'variable' ? undefined : Number(weight),
weight: weight === 'variable' ? undefined : weight,
style,
variable,
adjustFontFallback: adjustFontFallbackMetrics,
Expand Down
41 changes: 28 additions & 13 deletions packages/font/src/google/utils.ts
Expand Up @@ -19,7 +19,8 @@ type FontOptions = {
}
export function validateData(functionName: string, data: any): FontOptions {
let {
variant,
weight,
style,
display = 'optional',
preload = true,
axes,
Expand All @@ -33,28 +34,44 @@ export function validateData(functionName: string, data: any): FontOptions {

const fontFamily = functionName.replace(/_/g, ' ')

const fontVariants = (fontData as any)[fontFamily]?.variants
if (!fontVariants) {
const fontFamilyData = (fontData as any)[fontFamily]
const fontWeights = fontFamilyData?.weights
if (!fontWeights) {
throw new Error(`Unknown font \`${fontFamily}\``)
}
const fontStyles = fontFamilyData.styles

// Set variable as default, throw if not available
if (!variant) {
if (fontVariants.includes('variable')) {
variant = 'variable'
if (!weight) {
if (fontWeights.includes('variable')) {
weight = 'variable'
} else {
throw new Error(
`Missing variant for font \`${fontFamily}\`.\nAvailable variants: ${formatValues(
fontVariants
`Missing weight for font \`${fontFamily}\`.\nAvailable weights: ${formatValues(
fontWeights
)}`
)
}
}
if (!fontWeights.includes(weight)) {
throw new Error(
`Unknown weight \`${weight}\` for font \`${fontFamily}\`.\nAvailable weights: ${formatValues(
fontWeights
)}`
)
}

if (!fontVariants.includes(variant)) {
if (!style) {
if (fontStyles.length === 1) {
style = fontStyles[0]
} else {
style = 'normal'
}
}
if (!fontStyles.includes(style)) {
throw new Error(
`Unknown variant \`${variant}\` for font \`${fontFamily}\`.\nAvailable variants: ${formatValues(
fontVariants
`Unknown style \`${style}\` for font \`${fontFamily}\`.\nAvailable styles: ${formatValues(
fontStyles
)}`
)
}
Expand All @@ -67,8 +84,6 @@ export function validateData(functionName: string, data: any): FontOptions {
)
}

const [weight, style] = variant.split('-')

if (weight !== 'variable' && axes) {
throw new Error('Axes can only be defined for variable fonts')
}
Expand Down
2 changes: 1 addition & 1 deletion packages/font/src/local/index.ts
Expand Up @@ -5,7 +5,7 @@ type CssVariable = `--${string}`
type LocalFont = {
src: string
display?: Display
weight?: number
weight?: string
style?: string
adjustFontFallback?: 'Arial' | 'Times New Roman' | false
fallback?: string[]
Expand Down
2 changes: 1 addition & 1 deletion packages/font/src/local/utils.ts
Expand Up @@ -17,7 +17,7 @@ type FontOptions = {
ext: string
format: string
display: string
weight?: number
weight?: string
style?: string
fallback?: string[]
preload: boolean
Expand Down
Expand Up @@ -15,7 +15,7 @@ const postcssFontLoaderPlugn = ({
fallbackFonts?: string[]
adjustFontFallback?: AdjustFontFallback
variable?: string
weight?: number
weight?: string
style?: string
}) => {
return {
Expand Down Expand Up @@ -117,6 +117,8 @@ const postcssFontLoaderPlugn = ({
root.nodes.push(fallbackFontFace)
}

// Variable fonts can define ranges of values
const isRange = (value: string) => value.trim().includes(' ')
const formattedFontFamilies = [
formatFamily(fontFamily),
...fallbackFonts,
Expand All @@ -129,15 +131,15 @@ const postcssFontLoaderPlugn = ({
prop: 'font-family',
value: formattedFontFamilies,
}),
...(weight
...(weight && !isRange(weight)
? [
new postcss.Declaration({
prop: 'font-weight',
value: String(weight),
value: weight,
}),
]
: []),
...(style
...(style && !isRange(style)
? [
new postcss.Declaration({
prop: 'font-style',
Expand Down Expand Up @@ -165,8 +167,10 @@ const postcssFontLoaderPlugn = ({
name: 'style',
value: {
fontFamily: formattedFontFamilies,
fontWeight: weight && Number(weight),
fontStyle: style,
fontWeight: !Number.isNaN(Number(weight))
? Number(weight)
: undefined,
fontStyle: style && !isRange(style) ? style : undefined,
},
})
},
Expand Down
2 changes: 1 addition & 1 deletion packages/next/font/index.d.ts
Expand Up @@ -24,6 +24,6 @@ export type FontLoader = (options: {
fallbackFonts?: string[]
variable?: string
adjustFontFallback?: AdjustFontFallback
weight?: number
weight?: string
style?: string
}>
34 changes: 19 additions & 15 deletions scripts/update-google-fonts.js
Expand Up @@ -16,23 +16,25 @@ const fetch = require('node-fetch')
`
const fontData = {}
for (let { family, fonts, axes } of familyMetadataList) {
let hasItalic = false
const variants = Object.keys(fonts).map((variant) => {
const weights = new Set()
const styles = new Set()

for (const variant of Object.keys(fonts)) {
if (variant.endsWith('i')) {
hasItalic = true
return `${variant.slice(0, 3)}-italic`
styles.add('italic')
weights.add(variant.slice(0, -1))
continue
} else {
styles.add('normal')
weights.add(variant)
}
return variant
})
}

const hasVariableFont = axes.length > 0

let optionalAxes
if (hasVariableFont) {
variants.push('variable')
if (hasItalic) {
variants.push('variable-italic')
}
weights.add('variable')

const nonWeightAxes = axes.filter(({ tag }) => tag !== 'wght')
if (nonWeightAxes.length > 0) {
Expand All @@ -41,20 +43,22 @@ const fetch = require('node-fetch')
}

fontData[family] = {
variants,
weights: [...weights],
styles: [...styles],
axes: hasVariableFont ? axes : undefined,
}
const optionalIfVariableFont = hasVariableFont ? '?' : ''
fontFunctions += `export declare function ${family.replaceAll(
' ',
'_'
)}(options${optionalIfVariableFont}: {
variant${optionalIfVariableFont}:${variants
.map((variant) => `"${variant}"`)
weight${optionalIfVariableFont}:${[...weights]
.map((weight) => `"${weight}"`)
.join('|')}
display?:Display,
style?: ${[...styles].map((style) => `"${style}"`).join('|')}
display?:Display
variable?: CssVariable
preload?:boolean,
preload?:boolean
fallback?: string[]
adjustFontFallback?: boolean
${
Expand Down
5 changes: 3 additions & 2 deletions test/e2e/next-font/app/components/CompWithFonts.js
@@ -1,7 +1,8 @@
import { Inter, Roboto } from '@next/font/google'
const inter = Inter({ variant: '900', display: 'swap', preload: false })
const inter = Inter({ weight: '900', display: 'swap', preload: false })
const roboto = Roboto({
variant: '100-italic',
weight: '100',
style: 'italic',
display: 'swap',
preload: true,
})
Expand Down
3 changes: 2 additions & 1 deletion test/e2e/next-font/app/pages/variables.js
Expand Up @@ -3,7 +3,8 @@ import localFont from '@next/font/local'

const firaCode = Fira_Code({ variable: '--fira-code' })
const roboto = Roboto({
variant: '100-italic',
weight: '100',
style: 'italic',
display: 'swap',
preload: true,
variable: '--roboto-100-italic',
Expand Down
4 changes: 2 additions & 2 deletions test/e2e/next-font/app/pages/with-google-fonts.js
@@ -1,7 +1,7 @@
import { Fraunces, Indie_Flower } from '@next/font/google'

const indieFlower = Indie_Flower({ variant: '400' })
const fraunces = Fraunces({ variant: '400' })
const indieFlower = Indie_Flower({ weight: '400' })
const fraunces = Fraunces({ weight: '400' })

export default function WithFonts() {
return (
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/next-font/app/pages/with-local-fonts.js
Expand Up @@ -3,7 +3,7 @@ import localFont from '@next/font/local'
const myFont1 = localFont({
src: '../fonts/my-font.woff2',
style: 'italic',
weight: 100,
weight: '100',
fallback: ['system-ui'],
adjustFontFallback: 'Times New Roman',
})
Expand Down
Expand Up @@ -2,7 +2,7 @@ import { Html, Head, Main, NextScript } from 'next/document'
import { Abel } from '@next/font/google'

// eslint-disable-next-line no-unused-vars
const abel = Abel({ variant: '400' })
const abel = Abel({ weight: '400' })

export default function Document() {
return (
Expand Down
4 changes: 4 additions & 0 deletions test/e2e/next-font/index.test.ts
Expand Up @@ -48,6 +48,7 @@ describe('@next/font/google', () => {
fontFamily: expect.stringMatching(
/^'__Open_Sans_.{6}', '__Open_Sans_Fallback_.{6}'$/
),
fontStyle: 'normal',
},
})

Expand All @@ -59,6 +60,7 @@ describe('@next/font/google', () => {
fontFamily: expect.stringMatching(
/^'__Open_Sans_.{6}', '__Open_Sans_Fallback_.{6}'$/
),
fontStyle: 'normal',
},
})

Expand All @@ -70,6 +72,7 @@ describe('@next/font/google', () => {
/^'__Inter_.{6}', '__Inter_Fallback_.{6}'$/
),
fontWeight: 900,
fontStyle: 'normal',
},
})
expect(JSON.parse($('#comp-with-fonts-roboto').text())).toEqual({
Expand All @@ -96,6 +99,7 @@ describe('@next/font/google', () => {
fontFamily: expect.stringMatching(
/^'__Open_Sans_.{6}', '__Open_Sans_Fallback_.{6}'$/
),
fontStyle: 'normal',
},
})

Expand Down
4 changes: 2 additions & 2 deletions test/e2e/next-font/with-font-declarations-file/fonts.js
Expand Up @@ -9,10 +9,10 @@ import {

const openSans = Open_Sans()
const sourceCodePro = Source_Code_Pro({ display: 'swap', preload: false })
const abel = Abel({ variant: '400', display: 'optional', preload: false })
const abel = Abel({ weight: '400', display: 'optional', preload: false })

export const inter = Inter({ display: 'block', preload: true })
export const roboto = Roboto({ variant: '400' })
export const roboto = Roboto({ weight: '400' })

export const myLocalFont = localFont({
src: './my-font.woff2',
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/next-font/without-preloaded-fonts/pages/_app.js
@@ -1,5 +1,5 @@
import { Abel } from '@next/font/google'
const abel = Abel({ variant: '400', display: 'optional', preload: false })
const abel = Abel({ weight: '400', display: 'optional', preload: false })

function MyApp({ Component, pageProps }) {
return (
Expand Down
@@ -1,5 +1,5 @@
import { Abel } from '@next/font/google'
const abel = Abel({ variant: '400', display: 'optional', preload: false })
const abel = Abel({ weight: '400', display: 'optional', preload: false })

export default function NoPreload() {
return <p className={abel.className}>Hello world</p>
Expand Down