UNPKG

next

Version:

The React Framework

154 lines (153 loc) 6.49 kB
import postcss from 'postcss'; /** * The next/font postcss plugin recieves the @font-face declarations returned from the next/font loaders. * * It hashes the font-family name to make it unguessable, it shouldn't be globally accessible. * If it were global, we wouldn't be able to tell which pages are using which fonts when generating preload tags. * * If the font loader returned fallback metrics, generate a fallback @font-face. * * If the font loader returned a variable name, add a CSS class that declares a variable containing the font and fallback fonts. * * Lastly, it adds the font-family to the exports object. * This enables you to access the actual font-family name, not just through the CSS class. * e.g: * const inter = Inter({ subsets: ['latin'] }) * inter.style.fontFamily // => '__Inter_123456' */ const postcssNextFontPlugin = ({ exports, fallbackFonts = [], adjustFontFallback, variable, weight, style })=>{ return { postcssPlugin: 'postcss-next-font', Once (root) { let fontFamily; const normalizeFamily = (family)=>{ return family.replace(/['"]/g, ''); }; const formatFamily = (family)=>{ return `'${family}'`; }; // Hash font-family names for (const node of root.nodes){ if (node.type === 'atrule' && node.name === 'font-face') { const familyNode = node.nodes.find((decl)=>decl.prop === 'font-family'); if (!familyNode) { continue; } if (!fontFamily) { fontFamily = normalizeFamily(familyNode.value); } familyNode.value = formatFamily(fontFamily); } } if (!fontFamily) { throw Object.defineProperty(new Error("Font loaders must return one or more @font-face's"), "__NEXT_ERROR_CODE", { value: "E428", enumerable: false, configurable: true }); } // Add fallback @font-face with the provided override values let adjustFontFallbackFamily; if (adjustFontFallback) { adjustFontFallbackFamily = formatFamily(`${fontFamily} Fallback`); const fallbackFontFace = postcss.atRule({ name: 'font-face' }); const { fallbackFont, ascentOverride, descentOverride, lineGapOverride, sizeAdjust } = adjustFontFallback; fallbackFontFace.nodes = [ new postcss.Declaration({ prop: 'font-family', value: adjustFontFallbackFamily }), new postcss.Declaration({ prop: 'src', value: `local("${fallbackFont}")` }), ...ascentOverride ? [ new postcss.Declaration({ prop: 'ascent-override', value: ascentOverride }) ] : [], ...descentOverride ? [ new postcss.Declaration({ prop: 'descent-override', value: descentOverride }) ] : [], ...lineGapOverride ? [ new postcss.Declaration({ prop: 'line-gap-override', value: lineGapOverride }) ] : [], ...sizeAdjust ? [ new postcss.Declaration({ prop: 'size-adjust', value: sizeAdjust }) ] : [] ]; root.nodes.push(fallbackFontFace); } // Variable fonts can define ranges of values const isRange = (value)=>value.trim().includes(' '); // Format the font families to be used in the CSS const formattedFontFamilies = [ formatFamily(fontFamily), ...adjustFontFallbackFamily ? [ adjustFontFallbackFamily ] : [], ...fallbackFonts ].join(', '); // Add class with family, weight and style const classRule = new postcss.Rule({ selector: '.className' }); classRule.nodes = [ new postcss.Declaration({ prop: 'font-family', value: formattedFontFamilies }), // If the font only has one weight or style, we can set it on the class ...weight && !isRange(weight) ? [ new postcss.Declaration({ prop: 'font-weight', value: weight }) ] : [], ...style && !isRange(style) ? [ new postcss.Declaration({ prop: 'font-style', value: style }) ] : [] ]; root.nodes.push(classRule); // Add CSS class that defines a variable with the font families if (variable) { const varialbeRule = new postcss.Rule({ selector: '.variable' }); varialbeRule.nodes = [ new postcss.Declaration({ prop: variable, value: formattedFontFamilies }) ]; root.nodes.push(varialbeRule); } // Export @font-face values as is exports.push({ name: 'style', value: { fontFamily: formattedFontFamilies, fontWeight: !Number.isNaN(Number(weight)) ? Number(weight) : undefined, fontStyle: style && !isRange(style) ? style : undefined } }); } }; }; postcssNextFontPlugin.postcss = true; export default postcssNextFontPlugin; //# sourceMappingURL=postcss-next-font.js.map