polished
Version:
A lightweight toolset for writing styles in Javascript.
135 lines (121 loc) • 3.62 kB
Flow
// @flow
import PolishedError from '../internalHelpers/_errors'
import type { FontFaceConfiguration } from '../types/fontFaceConfiguration'
import type { Styles } from '../types/style'
const dataURIRegex = /^\s*data:([a-z]+\/[a-z-]+(;[a-z-]+=[a-z-]+)?)?(;charset=[a-z0-9-]+)?(;base64)?,[a-z0-9!$&',()*+,;=\-._~:@/?%\s]*\s*$/i
const formatHintMap = {
woff: 'woff',
woff2: 'woff2',
ttf: 'truetype',
otf: 'opentype',
eot: 'embedded-opentype',
svg: 'svg',
svgz: 'svg',
}
function generateFormatHint(format: string, formatHint: boolean): string {
if (!formatHint) return ''
return ` format("${formatHintMap[format]}")`
}
function isDataURI(fontFilePath: string): boolean {
return !!fontFilePath.replace(/\s+/g, ' ').match(dataURIRegex)
}
function generateFileReferences(
fontFilePath: string,
fileFormats: Array<string>,
formatHint: boolean,
): string {
if (isDataURI(fontFilePath)) {
return `url("${fontFilePath}")${generateFormatHint(fileFormats[0], formatHint)}`
}
const fileFontReferences = fileFormats.map(
format => `url("${fontFilePath}.${format}")${generateFormatHint(format, formatHint)}`,
)
return fileFontReferences.join(', ')
}
function generateLocalReferences(localFonts: Array<string>): string {
const localFontReferences = localFonts.map(font => `local("${font}")`)
return localFontReferences.join(', ')
}
function generateSources(
fontFilePath?: string,
localFonts: Array<string> | null,
fileFormats: Array<string>,
formatHint: boolean,
): string {
const fontReferences = []
if (localFonts) fontReferences.push(generateLocalReferences(localFonts))
if (fontFilePath) {
fontReferences.push(generateFileReferences(fontFilePath, fileFormats, formatHint))
}
return fontReferences.join(', ')
}
/**
* CSS for a @font-face declaration. Defaults to check for local copies of the font on the user's machine. You can disable this by passing `null` to localFonts.
*
* @example
* // Styles as object basic usage
* const styles = {
* ...fontFace({
* 'fontFamily': 'Sans-Pro',
* 'fontFilePath': 'path/to/file'
* })
* }
*
* // styled-components basic usage
* const GlobalStyle = createGlobalStyle`${
* fontFace({
* 'fontFamily': 'Sans-Pro',
* 'fontFilePath': 'path/to/file'
* }
* )}`
*
* // CSS as JS Output
*
* '@font-face': {
* 'fontFamily': 'Sans-Pro',
* 'src': 'url("path/to/file.eot"), url("path/to/file.woff2"), url("path/to/file.woff"), url("path/to/file.ttf"), url("path/to/file.svg")',
* }
*/
export default function fontFace({
fontFamily,
fontFilePath,
fontStretch,
fontStyle,
fontVariant,
fontWeight,
fileFormats = ['eot', 'woff2', 'woff', 'ttf', 'svg'],
formatHint = false,
localFonts = [fontFamily],
unicodeRange,
fontDisplay,
fontVariationSettings,
fontFeatureSettings,
}: FontFaceConfiguration): Styles {
// Error Handling
if (!fontFamily) throw new PolishedError(55)
if (!fontFilePath && !localFonts) {
throw new PolishedError(52)
}
if (localFonts && !Array.isArray(localFonts)) {
throw new PolishedError(53)
}
if (!Array.isArray(fileFormats)) {
throw new PolishedError(54)
}
const fontFaceDeclaration = {
'@font-face': {
fontFamily,
src: generateSources(fontFilePath, localFonts, fileFormats, formatHint),
unicodeRange,
fontStretch,
fontStyle,
fontVariant,
fontWeight,
fontDisplay,
fontVariationSettings,
fontFeatureSettings,
},
}
// Removes undefined fields for cleaner css object.
return JSON.parse(JSON.stringify(fontFaceDeclaration))
}