fontFace.js.flow 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. // @flow
  2. import PolishedError from '../internalHelpers/_errors'
  3. import type { FontFaceConfiguration } from '../types/fontFaceConfiguration'
  4. import type { Styles } from '../types/style'
  5. const dataURIRegex = /^\s*data:([a-z]+\/[a-z-]+(;[a-z-]+=[a-z-]+)?)?(;charset=[a-z0-9-]+)?(;base64)?,[a-z0-9!$&',()*+,;=\-._~:@/?%\s]*\s*$/i
  6. const formatHintMap = {
  7. woff: 'woff',
  8. woff2: 'woff2',
  9. ttf: 'truetype',
  10. otf: 'opentype',
  11. eot: 'embedded-opentype',
  12. svg: 'svg',
  13. svgz: 'svg',
  14. }
  15. function generateFormatHint(format: string, formatHint: boolean): string {
  16. if (!formatHint) return ''
  17. return ` format("${formatHintMap[format]}")`
  18. }
  19. function isDataURI(fontFilePath: string): boolean {
  20. return !!fontFilePath.replace(/\s+/g, ' ').match(dataURIRegex)
  21. }
  22. function generateFileReferences(
  23. fontFilePath: string,
  24. fileFormats: Array<string>,
  25. formatHint: boolean,
  26. ): string {
  27. if (isDataURI(fontFilePath)) {
  28. return `url("${fontFilePath}")${generateFormatHint(fileFormats[0], formatHint)}`
  29. }
  30. const fileFontReferences = fileFormats.map(
  31. format => `url("${fontFilePath}.${format}")${generateFormatHint(format, formatHint)}`,
  32. )
  33. return fileFontReferences.join(', ')
  34. }
  35. function generateLocalReferences(localFonts: Array<string>): string {
  36. const localFontReferences = localFonts.map(font => `local("${font}")`)
  37. return localFontReferences.join(', ')
  38. }
  39. function generateSources(
  40. fontFilePath?: string,
  41. localFonts: Array<string> | null,
  42. fileFormats: Array<string>,
  43. formatHint: boolean,
  44. ): string {
  45. const fontReferences = []
  46. if (localFonts) fontReferences.push(generateLocalReferences(localFonts))
  47. if (fontFilePath) {
  48. fontReferences.push(generateFileReferences(fontFilePath, fileFormats, formatHint))
  49. }
  50. return fontReferences.join(', ')
  51. }
  52. /**
  53. * 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.
  54. *
  55. * @example
  56. * // Styles as object basic usage
  57. * const styles = {
  58. * ...fontFace({
  59. * 'fontFamily': 'Sans-Pro',
  60. * 'fontFilePath': 'path/to/file'
  61. * })
  62. * }
  63. *
  64. * // styled-components basic usage
  65. * const GlobalStyle = createGlobalStyle`${
  66. * fontFace({
  67. * 'fontFamily': 'Sans-Pro',
  68. * 'fontFilePath': 'path/to/file'
  69. * }
  70. * )}`
  71. *
  72. * // CSS as JS Output
  73. *
  74. * '@font-face': {
  75. * 'fontFamily': 'Sans-Pro',
  76. * '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")',
  77. * }
  78. */
  79. export default function fontFace({
  80. fontFamily,
  81. fontFilePath,
  82. fontStretch,
  83. fontStyle,
  84. fontVariant,
  85. fontWeight,
  86. fileFormats = ['eot', 'woff2', 'woff', 'ttf', 'svg'],
  87. formatHint = false,
  88. localFonts = [fontFamily],
  89. unicodeRange,
  90. fontDisplay,
  91. fontVariationSettings,
  92. fontFeatureSettings,
  93. }: FontFaceConfiguration): Styles {
  94. // Error Handling
  95. if (!fontFamily) throw new PolishedError(55)
  96. if (!fontFilePath && !localFonts) {
  97. throw new PolishedError(52)
  98. }
  99. if (localFonts && !Array.isArray(localFonts)) {
  100. throw new PolishedError(53)
  101. }
  102. if (!Array.isArray(fileFormats)) {
  103. throw new PolishedError(54)
  104. }
  105. const fontFaceDeclaration = {
  106. '@font-face': {
  107. fontFamily,
  108. src: generateSources(fontFilePath, localFonts, fileFormats, formatHint),
  109. unicodeRange,
  110. fontStretch,
  111. fontStyle,
  112. fontVariant,
  113. fontWeight,
  114. fontDisplay,
  115. fontVariationSettings,
  116. fontFeatureSettings,
  117. },
  118. }
  119. // Removes undefined fields for cleaner css object.
  120. return JSON.parse(JSON.stringify(fontFaceDeclaration))
  121. }