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
			| 
								 
											3 years ago
										 
									 | 
							
								// @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))
							 | 
						||
| 
								 | 
							
								}
							 |