You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
135 lines
3.4 KiB
135 lines
3.4 KiB
// @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>,
|
|
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.
|
|
*
|
|
* @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,
|
|
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))
|
|
}
|