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))
 | 
						|
}
 |