UNPKG

astro

Version:

Astro is a modern site builder with web best practices, performance, and DX front-of-mind.

249 lines (248 loc) • 10.2 kB
import type { Font } from '@capsizecss/unpack'; import type * as unifont from 'unifont'; import type * as z from 'zod/v4'; import type { DisplaySchema, StyleSchema, WeightSchema } from './config.js'; import type { FONT_TYPES, GENERIC_FALLBACK_NAMES } from './constants.js'; import type { CollectedFontForMetrics } from './core/optimize-fallbacks.js'; export type Weight = z.infer<typeof WeightSchema>; type Display = z.infer<typeof DisplaySchema>; export interface FontProviderInitContext { /** * Useful for caching. */ storage: { getItem: { <T = unknown>(key: string): Promise<T | null>; <T = unknown>(key: string, init: () => Awaitable<T>): Promise<T>; }; setItem: (key: string, value: unknown) => Awaitable<void>; }; /** * The project root, useful for resolving local files paths. */ root: URL; } type Awaitable<T> = T | Promise<T>; export interface FontProvider<TFamilyOptions extends Record<string, any> | undefined | never = never> { /** * A unique name for the provider, used in logs and for identification. */ name: string; /** * A serializable object, used for identification. */ config?: Record<string, any> | undefined; /** * Optional callback, used to perform any initialization logic. */ init?: ((context: FontProviderInitContext) => Awaitable<void>) | undefined; /** * Used to retrieve and return font face data based on the given options. */ resolveFont: (options: ResolveFontOptions<TFamilyOptions>) => Awaitable<{ fonts: Array<unifont.FontFaceData>; } | undefined>; /** * Optional callback, used to return the list of available font names. */ listFonts?: (() => Awaitable<Array<string> | undefined>) | undefined; } export interface FamilyProperties { /** * @default `"swap"` * * Defines [how a font displays](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display) based on when it is downloaded and ready for use. */ display?: Display | undefined; /** * A [font stretch](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-stretch). */ stretch?: string | undefined; /** * Controls the [typographic font features](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-feature-settings) (e.g. ligatures, small caps, or swashes). */ featureSettings?: string | undefined; /** * Font [variation settings](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-variation-settings). */ variationSettings?: string | undefined; /** * Determines when a font must be downloaded and used based on a specific [range of unicode characters](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/unicode-range). * If a character on the page matches the configured range, the browser will download the font and all characters will be available for use on the page. To configure a subset of * characters preloaded for a single font, see the [subsets](#fontsubsets) property instead. * * This can be useful for localization to avoid unnecessary font downloads when a specific part of your website uses a different alphabet and will be displayed with a separate * font. For example, a website that offers both English and Japanese versions can prevent the browser from downloading the Japanese font on English versions of the page that do * not contain any of the Japanese characters provided in `unicodeRange`. */ unicodeRange?: [string, ...Array<string>] | undefined; } type WithOptions<TFontProvider extends FontProvider> = TFontProvider extends FontProvider<infer TFamilyOptions> ? [TFamilyOptions] extends [never] ? { /** * An object to pass provider specific options. It is typed automatically based on the font family provider. */ options?: undefined; } : undefined extends TFamilyOptions ? { /** * An object to pass provider specific options. It is typed automatically based on the font family provider. */ options?: TFamilyOptions; } : { /** * An object to pass provider specific options. It is typed automatically based on the font family provider. */ options: TFamilyOptions; } : { /** * An object to pass provider specific options. It is typed automatically based on the font family provider. */ options?: undefined; }; export type FontFamily<TFontProvider extends FontProvider = FontProvider> = FamilyProperties & WithOptions<NoInfer<TFontProvider>> & { /** * The font family name, as identified by your font provider. */ name: string; /** * A valid [ident](https://developer.mozilla.org/en-US/docs/Web/CSS/ident) in the form of a CSS variable (i.e. starting with `--`). */ cssVariable: string; /** * The source of your font files. You can use a built-in provider or write your own custom provider. */ provider: TFontProvider; /** * @default `[400]` * * An array of [font weights](https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight). If no value is specified in your configuration, only weight `400` is * included by default to prevent unnecessary downloads. You will need to include this property to access any other font weights. * * If the associated font is a [variable font](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_fonts/Variable_fonts_guide), you can specify a range of weights: * * ```js * weight: "100 900" * ``` */ weights?: [Weight, ...Array<Weight>] | undefined; /** * @default `["normal", "italic"]` * * An array of [font styles](https://developer.mozilla.org/en-US/docs/Web/CSS/font-style). */ styles?: [Style, ...Array<Style>] | undefined; /** * @default `["latin"]` * * Defines a list of [font subsets](https://knaap.dev/posts/font-subsetting/). */ subsets?: [string, ...Array<string>] | undefined; /** * @default `["woff2"]` * * An array of [font formats](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@font-face/src#font_formats). */ formats?: [FontType, ...Array<FontType>] | undefined; /** * @default `["sans-serif"]` * * An array of fonts to use when your chosen font is unavailable, or loading. Fallback fonts will be chosen in the order listed. The first available font will be used: * * ```js * fallbacks: ["CustomFont", "serif"] * ``` * * To disable fallback fonts completely, configure an empty array: * * ```js * fallbacks: [] * ``` * * If the last font in the `fallbacks` array is a [generic family name](https://developer.mozilla.org/en-US/docs/Web/CSS/font-family#generic-name), Astro will attempt to * generate [optimized fallbacks](https://developer.chrome.com/blog/font-fallbacks) using font metrics will be generated. To disable this optimization, set `optimizedFallbacks` to false. */ fallbacks?: Array<string> | undefined; /** * @default `true` * * Whether or not to enable Astro's default optimization when generating fallback fonts. You may disable this default optimization to have full control over how `fallbacks` are generated. */ optimizedFallbacks?: boolean | undefined; }; export interface ResolvedFontFamily extends Omit<FontFamily, 'weights'> { uniqueName: string; weights?: Array<string>; } export type FontType = (typeof FONT_TYPES)[number]; /** * Preload data is used for links generation inside the <Font /> component */ export interface PreloadData { /** * Absolute link to a font file, eg. /_astro/fonts/abc.woff */ url: string; /** * A font type, eg. woff2, woff, ttf... */ type: FontType; weight: string | undefined; style: string | undefined; subset: string | undefined; } export type FontFaceMetrics = Pick<Font, 'ascent' | 'descent' | 'lineGap' | 'unitsPerEm' | 'xWidthAvg'>; export type GenericFallbackName = (typeof GENERIC_FALLBACK_NAMES)[number]; export type Defaults = Required<Pick<ResolvedFontFamily, 'weights' | 'styles' | 'subsets' | 'fallbacks' | 'optimizedFallbacks' | 'formats'>>; export interface FontFileData { id: string; url: string; init: RequestInit | undefined; } /** * Holds associations of id and original font file URLs, so they can be * downloaded whenever the id is requested. */ export type FontFileById = Map<FontFileData['id'], Pick<FontFileData, 'url' | 'init'>>; export type ComponentDataByCssVariable = Map<string, { preloads: Array<PreloadData>; css: string; }>; export interface FontData { src: Array<{ url: string; format?: string; tech?: string; }>; weight?: string; style?: string; } /** * Holds associations of CSS variables and font data to be exposed via virtual module. */ export type FontDataByCssVariable = Record<string, Array<FontData>>; export type Style = z.output<typeof StyleSchema>; export type PreloadFilter = boolean | Array<{ weight?: string | number; style?: string; subset?: string; }>; export interface ResolveFontOptions<FamilyOptions extends Record<string, any> | undefined | never = never> { familyName: string; weights: string[]; styles: Style[]; subsets: string[]; formats: FontType[]; options: [FamilyOptions] extends [never] ? undefined : FamilyOptions | undefined; } export type CssProperties = Record<string, string | undefined>; export interface FontFamilyAssets { family: ResolvedFontFamily; fonts: Array<unifont.FontFaceData>; /** * Holds a list of font files to be used for optimized fallbacks generation */ collectedFontsForMetricsByUniqueKey: Map<string, CollectedFontForMetrics>; preloads: Array<PreloadData>; } export type FontFamilyAssetsByUniqueKey = Map<string, FontFamilyAssets>; export type Collaborator<T extends (input: any) => any, U extends keyof Parameters<T>[0]> = (params: Pick<Parameters<T>[0], U>) => ReturnType<T>; export {};