expo-font 11.5.0 → 11.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/android/build.gradle +11 -8
  3. package/android/src/main/java/expo/modules/font/FontLoaderModule.kt +22 -49
  4. package/build/ExpoFontLoader.d.ts +1 -1
  5. package/build/ExpoFontLoader.d.ts.map +1 -1
  6. package/build/ExpoFontLoader.js +2 -2
  7. package/build/ExpoFontLoader.js.map +1 -1
  8. package/build/ExpoFontLoader.web.d.ts +4 -0
  9. package/build/ExpoFontLoader.web.d.ts.map +1 -1
  10. package/build/ExpoFontLoader.web.js +69 -10
  11. package/build/ExpoFontLoader.web.js.map +1 -1
  12. package/build/Font.d.ts.map +1 -1
  13. package/build/Font.js +24 -13
  14. package/build/Font.js.map +1 -1
  15. package/build/FontHooks.d.ts +1 -1
  16. package/build/FontHooks.d.ts.map +1 -1
  17. package/build/FontHooks.js +27 -11
  18. package/build/FontHooks.js.map +1 -1
  19. package/build/FontLoader.web.d.ts.map +1 -1
  20. package/build/FontLoader.web.js +4 -2
  21. package/build/FontLoader.web.js.map +1 -1
  22. package/build/memory.d.ts +7 -0
  23. package/build/memory.d.ts.map +1 -0
  24. package/build/memory.js +3 -0
  25. package/build/memory.js.map +1 -0
  26. package/build/server.d.ts +13 -0
  27. package/build/server.d.ts.map +1 -0
  28. package/build/server.js +26 -0
  29. package/build/server.js.map +1 -0
  30. package/expo-module.config.json +7 -0
  31. package/package.json +2 -2
  32. package/src/ExpoFontLoader.ts +2 -2
  33. package/src/ExpoFontLoader.web.ts +88 -10
  34. package/src/Font.ts +35 -18
  35. package/src/FontHooks.ts +33 -13
  36. package/src/FontLoader.web.ts +5 -5
  37. package/src/memory.ts +2 -0
  38. package/src/server.ts +34 -0
  39. package/tsconfig.json +1 -1
  40. package/android/src/main/java/expo/modules/font/FontLoaderPackage.kt +0 -11
package/CHANGELOG.md CHANGED
@@ -10,6 +10,23 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 11.6.0 — 2023-09-04
14
+
15
+ ### 🎉 New features
16
+
17
+ - Added support for React Native 0.73. ([#24018](https://github.com/expo/expo/pull/24018) by [@kudo](https://github.com/kudo))
18
+ - Add static font extraction support with `expo-router`. ([#24027](https://github.com/expo/expo/pull/24027) by [@EvanBacon](https://github.com/EvanBacon))
19
+
20
+ ### 💡 Others
21
+
22
+ - Migrated `FontLoaderModule` to use Expo Modules API. ([#24015](https://github.com/expo/expo/pull/24015) by [@lukmccall](https://github.com/lukmccall))
23
+
24
+ ## 11.5.1 — 2023-08-02
25
+
26
+ ### 💡 Others
27
+
28
+ - Change unloaded font error to a warning. ([#23788](https://github.com/expo/expo/pull/23788) by [@EvanBacon](https://github.com/EvanBacon))
29
+
13
30
  ## 11.5.0 — 2023-07-28
14
31
 
15
32
  ### 🐛 Bug fixes
@@ -3,7 +3,7 @@ apply plugin: 'kotlin-android'
3
3
  apply plugin: 'maven-publish'
4
4
 
5
5
  group = 'host.exp.exponent'
6
- version = '11.5.0'
6
+ version = '11.6.0'
7
7
 
8
8
  buildscript {
9
9
  def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
@@ -53,13 +53,16 @@ afterEvaluate {
53
53
  android {
54
54
  compileSdkVersion safeExtGet("compileSdkVersion", 33)
55
55
 
56
- compileOptions {
57
- sourceCompatibility JavaVersion.VERSION_11
58
- targetCompatibility JavaVersion.VERSION_11
59
- }
56
+ def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION
57
+ if (agpVersion.tokenize('.')[0].toInteger() < 8) {
58
+ compileOptions {
59
+ sourceCompatibility JavaVersion.VERSION_11
60
+ targetCompatibility JavaVersion.VERSION_11
61
+ }
60
62
 
61
- kotlinOptions {
62
- jvmTarget = JavaVersion.VERSION_11.majorVersion
63
+ kotlinOptions {
64
+ jvmTarget = JavaVersion.VERSION_11.majorVersion
65
+ }
63
66
  }
64
67
 
65
68
  namespace "expo.modules.font"
@@ -67,7 +70,7 @@ android {
67
70
  minSdkVersion safeExtGet("minSdkVersion", 21)
68
71
  targetSdkVersion safeExtGet("targetSdkVersion", 33)
69
72
  versionCode 29
70
- versionName "11.5.0"
73
+ versionName "11.6.0"
71
74
  }
72
75
  lintOptions {
73
76
  abortOnError false
@@ -2,48 +2,32 @@
2
2
 
3
3
  package expo.modules.font
4
4
 
5
- import android.content.Context
6
5
  import android.graphics.Typeface
7
6
  import android.net.Uri
8
-
9
- import expo.modules.core.ExportedModule
10
- import expo.modules.core.ModuleRegistry
11
- import expo.modules.core.ModuleRegistryDelegate
12
- import expo.modules.core.interfaces.ExpoMethod
13
- import expo.modules.core.Promise
14
-
15
7
  import expo.modules.interfaces.font.FontManagerInterface
16
- import expo.modules.interfaces.constants.ConstantsInterface
17
-
8
+ import expo.modules.kotlin.exception.CodedException
9
+ import expo.modules.kotlin.exception.Exceptions
10
+ import expo.modules.kotlin.modules.Module
11
+ import expo.modules.kotlin.modules.ModuleDefinition
18
12
  import java.io.File
19
- import java.lang.Exception
20
13
 
21
14
  private const val ASSET_SCHEME = "asset://"
22
- private const val EXPORTED_NAME = "ExpoFontLoader"
23
15
 
24
- class FontLoaderModule(context: Context) : ExportedModule(context) {
25
- private val moduleRegistryDelegate: ModuleRegistryDelegate = ModuleRegistryDelegate()
16
+ private class FontManagerInterfaceNotFoundException :
17
+ CodedException("FontManagerInterface not found")
26
18
 
27
- private inline fun <reified T> moduleRegistry() = moduleRegistryDelegate.getFromModuleRegistry<T>()
19
+ private class FileNotFoundException(uri: String) :
20
+ CodedException("File '$uri' doesn't exist")
28
21
 
29
- override fun onCreate(moduleRegistry: ModuleRegistry) {
30
- moduleRegistryDelegate.onCreate(moduleRegistry)
31
- }
22
+ open class FontLoaderModule : Module() {
23
+ @Suppress("MemberVisibilityCanBePrivate")
24
+ open val prefix = ""
32
25
 
33
- override fun getName(): String {
34
- return EXPORTED_NAME
35
- }
26
+ override fun definition() = ModuleDefinition {
27
+ Name("ExpoFontLoader")
36
28
 
37
- @ExpoMethod
38
- fun loadAsync(fontFamilyName: String, localUri: String, promise: Promise) {
39
- try {
40
- // TODO: remove Expo references
41
- // https://github.com/expo/expo/pull/4652#discussion_r296630843
42
- val prefix = if (isScoped) {
43
- "ExpoFont-"
44
- } else {
45
- ""
46
- }
29
+ AsyncFunction("loadAsync") { fontFamilyName: String, localUri: String ->
30
+ val context = appContext.reactContext ?: throw Exceptions.ReactContextLost()
47
31
 
48
32
  // TODO(nikki): make sure path is in experience's scope
49
33
  val typeface: Typeface = if (localUri.startsWith(ASSET_SCHEME)) {
@@ -52,27 +36,16 @@ class FontLoaderModule(context: Context) : ExportedModule(context) {
52
36
  localUri.substring(ASSET_SCHEME.length + 1)
53
37
  )
54
38
  } else {
55
- Typeface.createFromFile(File(Uri.parse(localUri).path))
56
- }
39
+ val file = Uri.parse(localUri).path?.let { File(it) }
40
+ ?: throw FileNotFoundException(localUri)
57
41
 
58
- val fontManager: FontManagerInterface? by moduleRegistry()
59
- if (fontManager == null) {
60
- promise.reject("E_NO_FONT_MANAGER", "There is no FontManager in module registry. Are you sure all the dependencies of expo-font are installed and linked?")
61
- return
42
+ Typeface.createFromFile(file)
62
43
  }
63
44
 
64
- fontManager!!.setTypeface(prefix + fontFamilyName, Typeface.NORMAL, typeface)
65
- promise.resolve(null)
66
- } catch (e: Exception) {
67
- promise.reject("E_UNEXPECTED", "Font.loadAsync unexpected exception: " + e.message, e)
68
- }
69
- }
45
+ val fontManager = appContext.legacyModule<FontManagerInterface>()
46
+ ?: throw FontManagerInterfaceNotFoundException()
70
47
 
71
- // If there's no constants module, or app ownership isn't "expo", we're not in Expo Client.
72
- private val isScoped: Boolean
73
- get() {
74
- val constantsModule: ConstantsInterface? by moduleRegistry()
75
- // If there's no constants module, or app ownership isn't "expo", we're not in Expo Client.
76
- return constantsModule != null && "expo" == constantsModule!!.appOwnership
48
+ fontManager.setTypeface(prefix + fontFamilyName, Typeface.NORMAL, typeface)
77
49
  }
50
+ }
78
51
  }
@@ -1,3 +1,3 @@
1
- declare const _default: import("expo-modules-core").ProxyNativeModule;
1
+ declare const _default: any;
2
2
  export default _default;
3
3
  //# sourceMappingURL=ExpoFontLoader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoFontLoader.d.ts","sourceRoot":"","sources":["../src/ExpoFontLoader.ts"],"names":[],"mappings":";AACA,wBAAiD"}
1
+ {"version":3,"file":"ExpoFontLoader.d.ts","sourceRoot":"","sources":["../src/ExpoFontLoader.ts"],"names":[],"mappings":";AACA,wBAAqD"}
@@ -1,3 +1,3 @@
1
- import { NativeModulesProxy } from 'expo-modules-core';
2
- export default NativeModulesProxy.ExpoFontLoader;
1
+ import { requireNativeModule } from 'expo-modules-core';
2
+ export default requireNativeModule('ExpoFontLoader');
3
3
  //# sourceMappingURL=ExpoFontLoader.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoFontLoader.js","sourceRoot":"","sources":["../src/ExpoFontLoader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,eAAe,kBAAkB,CAAC,cAAc,CAAC","sourcesContent":["import { NativeModulesProxy } from 'expo-modules-core';\nexport default NativeModulesProxy.ExpoFontLoader;\n"]}
1
+ {"version":3,"file":"ExpoFontLoader.js","sourceRoot":"","sources":["../src/ExpoFontLoader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,eAAe,mBAAmB,CAAC,gBAAgB,CAAC,CAAC","sourcesContent":["import { requireNativeModule } from 'expo-modules-core';\nexport default requireNativeModule('ExpoFontLoader');\n"]}
@@ -4,7 +4,11 @@ declare const _default: {
4
4
  readonly name: string;
5
5
  unloadAllAsync(): Promise<void>;
6
6
  unloadAsync(fontFamilyName: string, options?: UnloadFontOptions): Promise<void>;
7
+ getServerResources(): string[];
8
+ resetServerContext(): void;
9
+ isLoaded(fontFamilyName: string, resource?: UnloadFontOptions): boolean;
7
10
  loadAsync(fontFamilyName: string, resource: FontResource): Promise<void>;
8
11
  };
9
12
  export default _default;
13
+ export declare function _createWebFontTemplate(fontFamily: string, resource: FontResource): string;
10
14
  //# sourceMappingURL=ExpoFontLoader.web.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoFontLoader.web.d.ts","sourceRoot":"","sources":["../src/ExpoFontLoader.web.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAC3C,OAAO,EAAe,YAAY,EAAE,MAAM,cAAc,CAAC;;;sBAiD/B,QAAQ,IAAI,CAAC;gCASH,MAAM,YAAY,iBAAiB,GAAG,QAAQ,IAAI,CAAC;8BASrD,MAAM,YAAY,YAAY,GAAG,QAAQ,IAAI,CAAC;;AAvBhF,wBA6CE"}
1
+ {"version":3,"file":"ExpoFontLoader.web.d.ts","sourceRoot":"","sources":["../src/ExpoFontLoader.web.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAC3C,OAAO,EAAe,YAAY,EAAE,MAAM,cAAc,CAAC;;;sBAqF/B,QAAQ,IAAI,CAAC;gCASH,MAAM,YAAY,iBAAiB,GAAG,QAAQ,IAAI,CAAC;0BAS/D,MAAM,EAAE;;6BAmBL,MAAM,aAAY,iBAAiB,GAAQ,OAAO;8BAUjD,MAAM,YAAY,YAAY,GAAG,QAAQ,IAAI,CAAC;;AApD1E,wBAqFE;AAeF,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG,MAAM,CAIzF"}
@@ -31,6 +31,31 @@ function getFontFaceRulesMatchingResource(fontFamilyName, options) {
31
31
  (options && options.display ? options.display === rule.style.fontDisplay : true));
32
32
  });
33
33
  }
34
+ const serverContext = new Set();
35
+ function getHeadElements() {
36
+ const entries = [...serverContext.entries()];
37
+ if (!entries.length) {
38
+ return [];
39
+ }
40
+ const css = entries.map(([{ css }]) => css).join('\n');
41
+ const links = entries.map(([{ resourceId }]) => resourceId);
42
+ // TODO: Maybe return nothing if no fonts were loaded.
43
+ return [
44
+ {
45
+ $$type: 'style',
46
+ children: css,
47
+ id: ID,
48
+ type: 'text/css',
49
+ },
50
+ ...links.map((resourceId) => ({
51
+ $$type: 'link',
52
+ rel: 'preload',
53
+ href: resourceId,
54
+ as: 'font',
55
+ crossorigin: '',
56
+ })),
57
+ ];
58
+ }
34
59
  export default {
35
60
  get name() {
36
61
  return 'ExpoFontLoader';
@@ -52,18 +77,53 @@ export default {
52
77
  sheet.deleteRule(item.index);
53
78
  }
54
79
  },
55
- async loadAsync(fontFamilyName, resource) {
56
- if (!Platform.isDOMAvailable) {
57
- return;
80
+ getServerResources() {
81
+ const elements = getHeadElements();
82
+ return elements.map((element) => {
83
+ switch (element.$$type) {
84
+ case 'style':
85
+ return `<style id="${element.id}" type="${element.type}">${element.children}</style>`;
86
+ case 'link':
87
+ return `<link rel="${element.rel}" href="${element.href}" as="${element.as}" crossorigin="${element.crossorigin}" />`;
88
+ default:
89
+ return '';
90
+ }
91
+ });
92
+ },
93
+ resetServerContext() {
94
+ serverContext.clear();
95
+ },
96
+ isLoaded(fontFamilyName, resource = {}) {
97
+ if (typeof window === 'undefined') {
98
+ return !![...serverContext.values()].find((asset) => {
99
+ return asset.name === fontFamilyName;
100
+ });
101
+ }
102
+ return getFontFaceRulesMatchingResource(fontFamilyName, resource)?.length > 0;
103
+ },
104
+ // NOTE(EvanBacon): No async keyword! This cannot return a promise in Node environments.
105
+ loadAsync(fontFamilyName, resource) {
106
+ if (typeof window === 'undefined') {
107
+ serverContext.add({
108
+ name: fontFamilyName,
109
+ css: _createWebFontTemplate(fontFamilyName, resource),
110
+ // @ts-expect-error: typeof string
111
+ resourceId: resource.uri,
112
+ });
113
+ return Promise.resolve();
58
114
  }
59
115
  const canInjectStyle = document.head && typeof document.head.appendChild === 'function';
60
116
  if (!canInjectStyle) {
61
117
  throw new CodedError('ERR_WEB_ENVIRONMENT', `The browser's \`document.head\` element doesn't support injecting fonts.`);
62
118
  }
63
- const style = _createWebStyle(fontFamilyName, resource);
119
+ const style = getStyleElement();
64
120
  document.head.appendChild(style);
121
+ const res = getFontFaceRulesMatchingResource(fontFamilyName, resource);
122
+ if (!res.length) {
123
+ _createWebStyle(fontFamilyName, resource);
124
+ }
65
125
  if (!isFontLoadingListenerSupported()) {
66
- return;
126
+ return Promise.resolve();
67
127
  }
68
128
  return new FontObserver(fontFamilyName, { display: resource.display }).load(null, 6000);
69
129
  },
@@ -79,12 +139,11 @@ function getStyleElement() {
79
139
  styleElement.type = 'text/css';
80
140
  return styleElement;
81
141
  }
142
+ export function _createWebFontTemplate(fontFamily, resource) {
143
+ return `@font-face{font-family:${fontFamily};src:url(${resource.uri});font-display:${resource.display || FontDisplay.AUTO}}`;
144
+ }
82
145
  function _createWebStyle(fontFamily, resource) {
83
- const fontStyle = `@font-face {
84
- font-family: ${fontFamily};
85
- src: url(${resource.uri});
86
- font-display: ${resource.display || FontDisplay.AUTO};
87
- }`;
146
+ const fontStyle = _createWebFontTemplate(fontFamily, resource);
88
147
  const styleElement = getStyleElement();
89
148
  // @ts-ignore: TypeScript does not define HTMLStyleElement::styleSheet. This is just for IE and
90
149
  // possibly can be removed if it's unnecessary on IE 11.
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoFontLoader.web.js","sourceRoot":"","sources":["../src/ExpoFontLoader.web.ts"],"names":[],"mappings":"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","sourcesContent":["import { CodedError, Platform } from 'expo-modules-core';\nimport FontObserver from 'fontfaceobserver';\n\nimport { UnloadFontOptions } from './Font';\nimport { FontDisplay, FontResource } from './Font.types';\n\nfunction getFontFaceStyleSheet(): CSSStyleSheet | null {\n if (!Platform.isDOMAvailable) {\n return null;\n }\n const styleSheet = getStyleElement();\n return styleSheet.sheet ? (styleSheet.sheet as CSSStyleSheet) : null;\n}\n\ntype RuleItem = { rule: CSSFontFaceRule; index: number };\n\nfunction getFontFaceRules(): RuleItem[] {\n const sheet = getFontFaceStyleSheet();\n if (sheet) {\n // @ts-ignore: rule iterator\n const rules = [...sheet.cssRules];\n\n const items: RuleItem[] = [];\n\n for (let i = 0; i < rules.length; i++) {\n const rule = rules[i];\n if (rule instanceof CSSFontFaceRule) {\n items.push({ rule, index: i });\n }\n }\n return items;\n }\n return [];\n}\n\nfunction getFontFaceRulesMatchingResource(\n fontFamilyName: string,\n options?: UnloadFontOptions\n): RuleItem[] {\n const rules = getFontFaceRules();\n return rules.filter(({ rule }) => {\n return (\n rule.style.fontFamily === fontFamilyName &&\n (options && options.display ? options.display === (rule.style as any).fontDisplay : true)\n );\n });\n}\n\nexport default {\n get name(): string {\n return 'ExpoFontLoader';\n },\n\n async unloadAllAsync(): Promise<void> {\n if (!Platform.isDOMAvailable) return;\n\n const element = document.getElementById(ID);\n if (element && element instanceof HTMLStyleElement) {\n document.removeChild(element);\n }\n },\n\n async unloadAsync(fontFamilyName: string, options?: UnloadFontOptions): Promise<void> {\n const sheet = getFontFaceStyleSheet();\n if (!sheet) return;\n const items = getFontFaceRulesMatchingResource(fontFamilyName, options);\n for (const item of items) {\n sheet.deleteRule(item.index);\n }\n },\n\n async loadAsync(fontFamilyName: string, resource: FontResource): Promise<void> {\n if (!Platform.isDOMAvailable) {\n return;\n }\n\n const canInjectStyle = document.head && typeof document.head.appendChild === 'function';\n if (!canInjectStyle) {\n throw new CodedError(\n 'ERR_WEB_ENVIRONMENT',\n `The browser's \\`document.head\\` element doesn't support injecting fonts.`\n );\n }\n\n const style = _createWebStyle(fontFamilyName, resource);\n document.head!.appendChild(style);\n\n if (!isFontLoadingListenerSupported()) {\n return;\n }\n\n return new FontObserver(fontFamilyName, { display: resource.display }).load(null, 6000);\n },\n};\n\nconst ID = 'expo-generated-fonts';\n\nfunction getStyleElement(): HTMLStyleElement {\n const element = document.getElementById(ID);\n if (element && element instanceof HTMLStyleElement) {\n return element;\n }\n const styleElement = document.createElement('style');\n styleElement.id = ID;\n styleElement.type = 'text/css';\n return styleElement;\n}\n\nfunction _createWebStyle(fontFamily: string, resource: FontResource): HTMLStyleElement {\n const fontStyle = `@font-face {\n font-family: ${fontFamily};\n src: url(${resource.uri});\n font-display: ${resource.display || FontDisplay.AUTO};\n }`;\n\n const styleElement = getStyleElement();\n // @ts-ignore: TypeScript does not define HTMLStyleElement::styleSheet. This is just for IE and\n // possibly can be removed if it's unnecessary on IE 11.\n if (styleElement.styleSheet) {\n const styleElementIE = styleElement as any;\n styleElementIE.styleSheet.cssText = styleElementIE.styleSheet.cssText\n ? styleElementIE.styleSheet.cssText + fontStyle\n : fontStyle;\n } else {\n const textNode = document.createTextNode(fontStyle);\n styleElement.appendChild(textNode);\n }\n return styleElement;\n}\n\nfunction isFontLoadingListenerSupported(): boolean {\n const { userAgent } = window.navigator;\n // WebKit is broken https://github.com/bramstein/fontfaceobserver/issues/95\n const isIOS = !!userAgent.match(/iPad|iPhone/i);\n const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\n // Edge is broken https://github.com/bramstein/fontfaceobserver/issues/109#issuecomment-333356795\n const isEdge = userAgent.includes('Edge');\n // Internet Explorer\n const isIE = userAgent.includes('Trident');\n // Firefox\n const isFirefox = userAgent.includes('Firefox');\n return !isSafari && !isIOS && !isEdge && !isIE && !isFirefox;\n}\n"]}
1
+ {"version":3,"file":"ExpoFontLoader.web.js","sourceRoot":"","sources":["../src/ExpoFontLoader.web.ts"],"names":[],"mappings":"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","sourcesContent":["import { CodedError, Platform } from 'expo-modules-core';\nimport FontObserver from 'fontfaceobserver';\n\nimport { UnloadFontOptions } from './Font';\nimport { FontDisplay, FontResource } from './Font.types';\n\nfunction getFontFaceStyleSheet(): CSSStyleSheet | null {\n if (!Platform.isDOMAvailable) {\n return null;\n }\n const styleSheet = getStyleElement();\n return styleSheet.sheet ? (styleSheet.sheet as CSSStyleSheet) : null;\n}\n\ntype RuleItem = { rule: CSSFontFaceRule; index: number };\n\nfunction getFontFaceRules(): RuleItem[] {\n const sheet = getFontFaceStyleSheet();\n if (sheet) {\n // @ts-ignore: rule iterator\n const rules = [...sheet.cssRules];\n\n const items: RuleItem[] = [];\n\n for (let i = 0; i < rules.length; i++) {\n const rule = rules[i];\n if (rule instanceof CSSFontFaceRule) {\n items.push({ rule, index: i });\n }\n }\n return items;\n }\n return [];\n}\n\nfunction getFontFaceRulesMatchingResource(\n fontFamilyName: string,\n options?: UnloadFontOptions\n): RuleItem[] {\n const rules = getFontFaceRules();\n return rules.filter(({ rule }) => {\n return (\n rule.style.fontFamily === fontFamilyName &&\n (options && options.display ? options.display === (rule.style as any).fontDisplay : true)\n );\n });\n}\n\nconst serverContext: Set<{ name: string; css: string; resourceId: string }> = new Set();\n\nfunction getHeadElements(): {\n $$type: string;\n rel?: string;\n href?: string;\n as?: string;\n crossorigin?: string;\n children?: string;\n id?: string;\n type?: string;\n}[] {\n const entries = [...serverContext.entries()];\n if (!entries.length) {\n return [];\n }\n const css = entries.map(([{ css }]) => css).join('\\n');\n const links = entries.map(([{ resourceId }]) => resourceId);\n // TODO: Maybe return nothing if no fonts were loaded.\n return [\n {\n $$type: 'style',\n children: css,\n id: ID,\n type: 'text/css',\n },\n ...links.map((resourceId) => ({\n $$type: 'link',\n rel: 'preload',\n href: resourceId,\n as: 'font',\n crossorigin: '',\n })),\n ];\n}\n\nexport default {\n get name(): string {\n return 'ExpoFontLoader';\n },\n\n async unloadAllAsync(): Promise<void> {\n if (!Platform.isDOMAvailable) return;\n\n const element = document.getElementById(ID);\n if (element && element instanceof HTMLStyleElement) {\n document.removeChild(element);\n }\n },\n\n async unloadAsync(fontFamilyName: string, options?: UnloadFontOptions): Promise<void> {\n const sheet = getFontFaceStyleSheet();\n if (!sheet) return;\n const items = getFontFaceRulesMatchingResource(fontFamilyName, options);\n for (const item of items) {\n sheet.deleteRule(item.index);\n }\n },\n\n getServerResources(): string[] {\n const elements = getHeadElements();\n\n return elements.map((element) => {\n switch (element.$$type) {\n case 'style':\n return `<style id=\"${element.id}\" type=\"${element.type}\">${element.children}</style>`;\n case 'link':\n return `<link rel=\"${element.rel}\" href=\"${element.href}\" as=\"${element.as}\" crossorigin=\"${element.crossorigin}\" />`;\n default:\n return '';\n }\n });\n },\n\n resetServerContext() {\n serverContext.clear();\n },\n\n isLoaded(fontFamilyName: string, resource: UnloadFontOptions = {}): boolean {\n if (typeof window === 'undefined') {\n return !![...serverContext.values()].find((asset) => {\n return asset.name === fontFamilyName;\n });\n }\n return getFontFaceRulesMatchingResource(fontFamilyName, resource)?.length > 0;\n },\n\n // NOTE(EvanBacon): No async keyword! This cannot return a promise in Node environments.\n loadAsync(fontFamilyName: string, resource: FontResource): Promise<void> {\n if (typeof window === 'undefined') {\n serverContext.add({\n name: fontFamilyName,\n css: _createWebFontTemplate(fontFamilyName, resource),\n // @ts-expect-error: typeof string\n resourceId: resource.uri!,\n });\n return Promise.resolve();\n }\n\n const canInjectStyle = document.head && typeof document.head.appendChild === 'function';\n if (!canInjectStyle) {\n throw new CodedError(\n 'ERR_WEB_ENVIRONMENT',\n `The browser's \\`document.head\\` element doesn't support injecting fonts.`\n );\n }\n\n const style = getStyleElement();\n document.head!.appendChild(style);\n\n const res = getFontFaceRulesMatchingResource(fontFamilyName, resource);\n if (!res.length) {\n _createWebStyle(fontFamilyName, resource);\n }\n\n if (!isFontLoadingListenerSupported()) {\n return Promise.resolve();\n }\n\n return new FontObserver(fontFamilyName, { display: resource.display }).load(null, 6000);\n },\n};\n\nconst ID = 'expo-generated-fonts';\n\nfunction getStyleElement(): HTMLStyleElement {\n const element = document.getElementById(ID);\n if (element && element instanceof HTMLStyleElement) {\n return element;\n }\n const styleElement = document.createElement('style');\n styleElement.id = ID;\n styleElement.type = 'text/css';\n return styleElement;\n}\n\nexport function _createWebFontTemplate(fontFamily: string, resource: FontResource): string {\n return `@font-face{font-family:${fontFamily};src:url(${resource.uri});font-display:${\n resource.display || FontDisplay.AUTO\n }}`;\n}\n\nfunction _createWebStyle(fontFamily: string, resource: FontResource): HTMLStyleElement {\n const fontStyle = _createWebFontTemplate(fontFamily, resource);\n\n const styleElement = getStyleElement();\n // @ts-ignore: TypeScript does not define HTMLStyleElement::styleSheet. This is just for IE and\n // possibly can be removed if it's unnecessary on IE 11.\n if (styleElement.styleSheet) {\n const styleElementIE = styleElement as any;\n styleElementIE.styleSheet.cssText = styleElementIE.styleSheet.cssText\n ? styleElementIE.styleSheet.cssText + fontStyle\n : fontStyle;\n } else {\n const textNode = document.createTextNode(fontStyle);\n styleElement.appendChild(textNode);\n }\n return styleElement;\n}\n\nfunction isFontLoadingListenerSupported(): boolean {\n const { userAgent } = window.navigator;\n // WebKit is broken https://github.com/bramstein/fontfaceobserver/issues/95\n const isIOS = !!userAgent.match(/iPad|iPhone/i);\n const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\n // Edge is broken https://github.com/bramstein/fontfaceobserver/issues/109#issuecomment-333356795\n const isEdge = userAgent.includes('Edge');\n // Internet Explorer\n const isIE = userAgent.includes('Trident');\n // Firefox\n const isFirefox = userAgent.includes('Firefox');\n return !isSafari && !isIOS && !isEdge && !isIE && !isFirefox;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"Font.d.ts","sourceRoot":"","sources":["../src/Font.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAaxF;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAwB1E;AAGD;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAEpD;AAGD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAErD;AAGD;;;;;;;;;;;GAWG;AACH,wBAAsB,SAAS,CAC7B,mBAAmB,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,EACxD,MAAM,CAAC,EAAE,UAAU,GAClB,OAAO,CAAC,IAAI,CAAC,CAef;AAwCD;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAiBpD;AAGD;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAC/B,mBAAmB,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,EAC/D,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,IAAI,CAAC,CAkBf;AA0BD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,iBAAiB,EAAE,CAAC"}
1
+ {"version":3,"file":"Font.d.ts","sourceRoot":"","sources":["../src/Font.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAYxF;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAoB1E;AAGD;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAKpD;AAGD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAErD;AAGD;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CACvB,mBAAmB,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,EACxD,MAAM,CAAC,EAAE,UAAU,GAClB,OAAO,CAAC,IAAI,CAAC,CAkCf;AAwCD;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAiBpD;AAGD;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAC/B,mBAAmB,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,EAC/D,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,IAAI,CAAC,CAkBf;AA0BD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,iBAAiB,EAAE,CAAC"}
package/build/Font.js CHANGED
@@ -1,9 +1,9 @@
1
- import { CodedError, UnavailabilityError } from 'expo-modules-core';
1
+ import { CodedError, Platform, UnavailabilityError } from 'expo-modules-core';
2
2
  import ExpoFontLoader from './ExpoFontLoader';
3
3
  import { FontDisplay } from './Font.types';
4
4
  import { getAssetForSource, loadSingleFontAsync, fontFamilyNeedsScoping, getNativeFontName, } from './FontLoader';
5
- const loaded = {};
6
- const loadPromises = {};
5
+ import { loaded, loadPromises } from './memory';
6
+ import { registerStaticFont } from './server';
7
7
  // @needsAudit
8
8
  // note(brentvatne): at some point we may want to warn if this is called outside of a managed app.
9
9
  /**
@@ -21,15 +21,12 @@ export function processFontFamily(fontFamily) {
21
21
  if (!isLoaded(fontFamily)) {
22
22
  if (__DEV__) {
23
23
  if (isLoading(fontFamily)) {
24
- console.error(`You started loading the font "${fontFamily}", but used it before it finished loading. You need to wait for Font.loadAsync to complete before using the font.`);
24
+ console.warn(`You started loading the font "${fontFamily}", but used it before it finished loading. You need to wait for Font.loadAsync to complete before using the font.`);
25
25
  }
26
26
  else {
27
- console.error(`fontFamily "${fontFamily}" is not a system font and has not been loaded through Font.loadAsync.\n
28
- - If you intended to use a system font, make sure you typed the name correctly and that it is supported by your device operating system.\n
29
- - If this is a custom font, be sure to load it with Font.loadAsync.`);
27
+ console.warn(`fontFamily "${fontFamily}" is not a system font and has not been loaded through expo-font.`);
30
28
  }
31
29
  }
32
- return 'System';
33
30
  }
34
31
  return `ExpoFont-${getNativeFontName(fontFamily)}`;
35
32
  }
@@ -41,6 +38,9 @@ export function processFontFamily(fontFamily) {
41
38
  * @return Returns `true` if the font has fully loaded.
42
39
  */
43
40
  export function isLoaded(fontFamily) {
41
+ if (Platform.OS === 'web') {
42
+ return fontFamily in loaded || !!ExpoFontLoader.isLoaded(fontFamily);
43
+ }
44
44
  return fontFamily in loaded;
45
45
  }
46
46
  // @needsAudit
@@ -66,17 +66,28 @@ export function isLoading(fontFamily) {
66
66
  * @return Returns a promise that fulfils when the font has loaded. Often you may want to wrap the
67
67
  * method in a `try/catch/finally` to ensure the app continues if the font fails to load.
68
68
  */
69
- export async function loadAsync(fontFamilyOrFontMap, source) {
69
+ export function loadAsync(fontFamilyOrFontMap, source) {
70
+ // NOTE(EvanBacon): Static render pass on web must be synchronous to collect all fonts.
71
+ // Because of this, `loadAsync` doesn't use the `async` keyword and deviates from the
72
+ // standard Expo SDK style guide.
73
+ const isServer = Platform.OS === 'web' && typeof window === 'undefined';
70
74
  if (typeof fontFamilyOrFontMap === 'object') {
71
75
  if (source) {
72
- throw new CodedError(`ERR_FONT_API`, `No fontFamily can be used for the provided source: ${source}. The second argument of \`loadAsync()\` can only be used with a \`string\` value as the first argument.`);
76
+ return Promise.reject(new CodedError(`ERR_FONT_API`, `No fontFamily can be used for the provided source: ${source}. The second argument of \`loadAsync()\` can only be used with a \`string\` value as the first argument.`));
73
77
  }
74
78
  const fontMap = fontFamilyOrFontMap;
75
79
  const names = Object.keys(fontMap);
76
- await Promise.all(names.map((name) => loadFontInNamespaceAsync(name, fontMap[name])));
77
- return;
80
+ if (isServer) {
81
+ names.map((name) => registerStaticFont(name, fontMap[name]));
82
+ return Promise.resolve();
83
+ }
84
+ return Promise.all(names.map((name) => loadFontInNamespaceAsync(name, fontMap[name]))).then(() => { });
85
+ }
86
+ if (isServer) {
87
+ registerStaticFont(fontFamilyOrFontMap, source);
88
+ return Promise.resolve();
78
89
  }
79
- return await loadFontInNamespaceAsync(fontFamilyOrFontMap, source);
90
+ return loadFontInNamespaceAsync(fontFamilyOrFontMap, source);
80
91
  }
81
92
  async function loadFontInNamespaceAsync(fontFamily, source) {
82
93
  if (!source) {
package/build/Font.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Font.js","sourceRoot":"","sources":["../src/Font.ts"],"names":[],"mappings":"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","sourcesContent":["import { CodedError, UnavailabilityError } from 'expo-modules-core';\n\nimport ExpoFontLoader from './ExpoFontLoader';\nimport { FontDisplay, FontSource, FontResource, UnloadFontOptions } from './Font.types';\nimport {\n getAssetForSource,\n loadSingleFontAsync,\n fontFamilyNeedsScoping,\n getNativeFontName,\n} from './FontLoader';\n\nconst loaded: { [name: string]: boolean } = {};\nconst loadPromises: { [name: string]: Promise<void> } = {};\n\n// @needsAudit\n// note(brentvatne): at some point we may want to warn if this is called outside of a managed app.\n/**\n * Used to transform font family names to the scoped name. This does not need to\n * be called in standalone or bare apps but it will return unscoped font family\n * names if it is called in those contexts.\n *\n * @param fontFamily Name of font to process.\n * @returns Returns a name processed for use with the [current workflow](https://docs.expo.dev/archive/managed-vs-bare/).\n */\nexport function processFontFamily(fontFamily: string | null): string | null {\n if (!fontFamily || !fontFamilyNeedsScoping(fontFamily)) {\n return fontFamily;\n }\n\n if (!isLoaded(fontFamily)) {\n if (__DEV__) {\n if (isLoading(fontFamily)) {\n console.error(\n `You started loading the font \"${fontFamily}\", but used it before it finished loading. You need to wait for Font.loadAsync to complete before using the font.`\n );\n } else {\n console.error(\n `fontFamily \"${fontFamily}\" is not a system font and has not been loaded through Font.loadAsync.\\n\n- If you intended to use a system font, make sure you typed the name correctly and that it is supported by your device operating system.\\n\n- If this is a custom font, be sure to load it with Font.loadAsync.`\n );\n }\n }\n\n return 'System';\n }\n\n return `ExpoFont-${getNativeFontName(fontFamily)}`;\n}\n\n// @needsAudit\n/**\n * Synchronously detect if the font for `fontFamily` has finished loading.\n *\n * @param fontFamily The name used to load the `FontResource`.\n * @return Returns `true` if the font has fully loaded.\n */\nexport function isLoaded(fontFamily: string): boolean {\n return fontFamily in loaded;\n}\n\n// @needsAudit\n/**\n * Synchronously detect if the font for `fontFamily` is still being loaded.\n *\n * @param fontFamily The name used to load the `FontResource`.\n * @returns Returns `true` if the font is still loading.\n */\nexport function isLoading(fontFamily: string): boolean {\n return fontFamily in loadPromises;\n}\n\n// @needsAudit\n/**\n * Highly efficient method for loading fonts from static or remote resources which can then be used\n * with the platform's native text elements. In the browser this generates a `@font-face` block in\n * a shared style sheet for fonts. No CSS is needed to use this method.\n *\n * @param fontFamilyOrFontMap string or map of values that can be used as the [`fontFamily`](https://reactnative.dev/docs/text#style)\n * style prop with React Native Text elements.\n * @param source the font asset that should be loaded into the `fontFamily` namespace.\n *\n * @return Returns a promise that fulfils when the font has loaded. Often you may want to wrap the\n * method in a `try/catch/finally` to ensure the app continues if the font fails to load.\n */\nexport async function loadAsync(\n fontFamilyOrFontMap: string | Record<string, FontSource>,\n source?: FontSource\n): Promise<void> {\n if (typeof fontFamilyOrFontMap === 'object') {\n if (source) {\n throw new CodedError(\n `ERR_FONT_API`,\n `No fontFamily can be used for the provided source: ${source}. The second argument of \\`loadAsync()\\` can only be used with a \\`string\\` value as the first argument.`\n );\n }\n const fontMap = fontFamilyOrFontMap;\n const names = Object.keys(fontMap);\n await Promise.all(names.map((name) => loadFontInNamespaceAsync(name, fontMap[name])));\n return;\n }\n\n return await loadFontInNamespaceAsync(fontFamilyOrFontMap, source);\n}\n\nasync function loadFontInNamespaceAsync(\n fontFamily: string,\n source?: FontSource | null\n): Promise<void> {\n if (!source) {\n throw new CodedError(\n `ERR_FONT_SOURCE`,\n `Cannot load null or undefined font source: { \"${fontFamily}\": ${source} }. Expected asset of type \\`FontSource\\` for fontFamily of name: \"${fontFamily}\"`\n );\n }\n\n if (loaded[fontFamily]) {\n return;\n }\n\n if (loadPromises.hasOwnProperty(fontFamily)) {\n return loadPromises[fontFamily];\n }\n\n // Important: we want all callers that concurrently try to load the same font to await the same\n // promise. If we're here, we haven't created the promise yet. To ensure we create only one\n // promise in the program, we need to create the promise synchronously without yielding the event\n // loop from this point.\n\n const asset = getAssetForSource(source);\n loadPromises[fontFamily] = (async () => {\n try {\n await loadSingleFontAsync(fontFamily, asset);\n loaded[fontFamily] = true;\n } finally {\n delete loadPromises[fontFamily];\n }\n })();\n\n await loadPromises[fontFamily];\n}\n\n// @needsAudit\n/**\n * Unloads all the custom fonts. This is used for testing.\n */\nexport async function unloadAllAsync(): Promise<void> {\n if (!ExpoFontLoader.unloadAllAsync) {\n throw new UnavailabilityError('expo-font', 'unloadAllAsync');\n }\n\n if (Object.keys(loadPromises).length) {\n throw new CodedError(\n `ERR_UNLOAD`,\n `Cannot unload fonts while they're still loading: ${Object.keys(loadPromises).join(', ')}`\n );\n }\n\n for (const fontFamily of Object.keys(loaded)) {\n delete loaded[fontFamily];\n }\n\n await ExpoFontLoader.unloadAllAsync();\n}\n\n// @needsAudit\n/**\n * Unload custom fonts matching the `fontFamily`s and display values provided.\n * Because fonts are automatically unloaded on every platform this is mostly used for testing.\n *\n * @param fontFamilyOrFontMap The name or names of the custom fonts that will be unloaded.\n * @param options When `fontFamilyOrFontMap` is a string, this should be the font source used to load\n * the custom font originally.\n */\nexport async function unloadAsync(\n fontFamilyOrFontMap: string | Record<string, UnloadFontOptions>,\n options?: UnloadFontOptions\n): Promise<void> {\n if (!ExpoFontLoader.unloadAsync) {\n throw new UnavailabilityError('expo-font', 'unloadAsync');\n }\n if (typeof fontFamilyOrFontMap === 'object') {\n if (options) {\n throw new CodedError(\n `ERR_FONT_API`,\n `No fontFamily can be used for the provided options: ${options}. The second argument of \\`unloadAsync()\\` can only be used with a \\`string\\` value as the first argument.`\n );\n }\n const fontMap = fontFamilyOrFontMap;\n const names = Object.keys(fontMap);\n await Promise.all(names.map((name) => unloadFontInNamespaceAsync(name, fontMap[name])));\n return;\n }\n\n return await unloadFontInNamespaceAsync(fontFamilyOrFontMap, options);\n}\n\nasync function unloadFontInNamespaceAsync(\n fontFamily: string,\n options?: UnloadFontOptions | null\n): Promise<void> {\n if (!loaded[fontFamily]) {\n return;\n } else {\n delete loaded[fontFamily];\n }\n\n // Important: we want all callers that concurrently try to load the same font to await the same\n // promise. If we're here, we haven't created the promise yet. To ensure we create only one\n // promise in the program, we need to create the promise synchronously without yielding the event\n // loop from this point.\n\n const nativeFontName = getNativeFontName(fontFamily);\n\n if (!nativeFontName) {\n throw new CodedError(`ERR_FONT_FAMILY`, `Cannot unload an empty name`);\n }\n\n await ExpoFontLoader.unloadAsync(nativeFontName, options);\n}\n\nexport { FontDisplay, FontSource, FontResource, UnloadFontOptions };\n"]}
1
+ {"version":3,"file":"Font.js","sourceRoot":"","sources":["../src/Font.ts"],"names":[],"mappings":"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","sourcesContent":["import { CodedError, Platform, UnavailabilityError } from 'expo-modules-core';\n\nimport ExpoFontLoader from './ExpoFontLoader';\nimport { FontDisplay, FontSource, FontResource, UnloadFontOptions } from './Font.types';\nimport {\n getAssetForSource,\n loadSingleFontAsync,\n fontFamilyNeedsScoping,\n getNativeFontName,\n} from './FontLoader';\nimport { loaded, loadPromises } from './memory';\nimport { registerStaticFont } from './server';\n\n// @needsAudit\n// note(brentvatne): at some point we may want to warn if this is called outside of a managed app.\n/**\n * Used to transform font family names to the scoped name. This does not need to\n * be called in standalone or bare apps but it will return unscoped font family\n * names if it is called in those contexts.\n *\n * @param fontFamily Name of font to process.\n * @returns Returns a name processed for use with the [current workflow](https://docs.expo.dev/archive/managed-vs-bare/).\n */\nexport function processFontFamily(fontFamily: string | null): string | null {\n if (!fontFamily || !fontFamilyNeedsScoping(fontFamily)) {\n return fontFamily;\n }\n\n if (!isLoaded(fontFamily)) {\n if (__DEV__) {\n if (isLoading(fontFamily)) {\n console.warn(\n `You started loading the font \"${fontFamily}\", but used it before it finished loading. You need to wait for Font.loadAsync to complete before using the font.`\n );\n } else {\n console.warn(\n `fontFamily \"${fontFamily}\" is not a system font and has not been loaded through expo-font.`\n );\n }\n }\n }\n\n return `ExpoFont-${getNativeFontName(fontFamily)}`;\n}\n\n// @needsAudit\n/**\n * Synchronously detect if the font for `fontFamily` has finished loading.\n *\n * @param fontFamily The name used to load the `FontResource`.\n * @return Returns `true` if the font has fully loaded.\n */\nexport function isLoaded(fontFamily: string): boolean {\n if (Platform.OS === 'web') {\n return fontFamily in loaded || !!ExpoFontLoader.isLoaded(fontFamily);\n }\n return fontFamily in loaded;\n}\n\n// @needsAudit\n/**\n * Synchronously detect if the font for `fontFamily` is still being loaded.\n *\n * @param fontFamily The name used to load the `FontResource`.\n * @returns Returns `true` if the font is still loading.\n */\nexport function isLoading(fontFamily: string): boolean {\n return fontFamily in loadPromises;\n}\n\n// @needsAudit\n/**\n * Highly efficient method for loading fonts from static or remote resources which can then be used\n * with the platform's native text elements. In the browser this generates a `@font-face` block in\n * a shared style sheet for fonts. No CSS is needed to use this method.\n *\n * @param fontFamilyOrFontMap string or map of values that can be used as the [`fontFamily`](https://reactnative.dev/docs/text#style)\n * style prop with React Native Text elements.\n * @param source the font asset that should be loaded into the `fontFamily` namespace.\n *\n * @return Returns a promise that fulfils when the font has loaded. Often you may want to wrap the\n * method in a `try/catch/finally` to ensure the app continues if the font fails to load.\n */\nexport function loadAsync(\n fontFamilyOrFontMap: string | Record<string, FontSource>,\n source?: FontSource\n): Promise<void> {\n // NOTE(EvanBacon): Static render pass on web must be synchronous to collect all fonts.\n // Because of this, `loadAsync` doesn't use the `async` keyword and deviates from the\n // standard Expo SDK style guide.\n const isServer = Platform.OS === 'web' && typeof window === 'undefined';\n\n if (typeof fontFamilyOrFontMap === 'object') {\n if (source) {\n return Promise.reject(\n new CodedError(\n `ERR_FONT_API`,\n `No fontFamily can be used for the provided source: ${source}. The second argument of \\`loadAsync()\\` can only be used with a \\`string\\` value as the first argument.`\n )\n );\n }\n const fontMap = fontFamilyOrFontMap;\n const names = Object.keys(fontMap);\n\n if (isServer) {\n names.map((name) => registerStaticFont(name, fontMap[name]));\n return Promise.resolve();\n }\n\n return Promise.all(names.map((name) => loadFontInNamespaceAsync(name, fontMap[name]))).then(\n () => {}\n );\n }\n\n if (isServer) {\n registerStaticFont(fontFamilyOrFontMap, source);\n return Promise.resolve();\n }\n\n return loadFontInNamespaceAsync(fontFamilyOrFontMap, source);\n}\n\nasync function loadFontInNamespaceAsync(\n fontFamily: string,\n source?: FontSource | null\n): Promise<void> {\n if (!source) {\n throw new CodedError(\n `ERR_FONT_SOURCE`,\n `Cannot load null or undefined font source: { \"${fontFamily}\": ${source} }. Expected asset of type \\`FontSource\\` for fontFamily of name: \"${fontFamily}\"`\n );\n }\n\n if (loaded[fontFamily]) {\n return;\n }\n\n if (loadPromises.hasOwnProperty(fontFamily)) {\n return loadPromises[fontFamily];\n }\n\n // Important: we want all callers that concurrently try to load the same font to await the same\n // promise. If we're here, we haven't created the promise yet. To ensure we create only one\n // promise in the program, we need to create the promise synchronously without yielding the event\n // loop from this point.\n\n const asset = getAssetForSource(source);\n loadPromises[fontFamily] = (async () => {\n try {\n await loadSingleFontAsync(fontFamily, asset);\n loaded[fontFamily] = true;\n } finally {\n delete loadPromises[fontFamily];\n }\n })();\n\n await loadPromises[fontFamily];\n}\n\n// @needsAudit\n/**\n * Unloads all the custom fonts. This is used for testing.\n */\nexport async function unloadAllAsync(): Promise<void> {\n if (!ExpoFontLoader.unloadAllAsync) {\n throw new UnavailabilityError('expo-font', 'unloadAllAsync');\n }\n\n if (Object.keys(loadPromises).length) {\n throw new CodedError(\n `ERR_UNLOAD`,\n `Cannot unload fonts while they're still loading: ${Object.keys(loadPromises).join(', ')}`\n );\n }\n\n for (const fontFamily of Object.keys(loaded)) {\n delete loaded[fontFamily];\n }\n\n await ExpoFontLoader.unloadAllAsync();\n}\n\n// @needsAudit\n/**\n * Unload custom fonts matching the `fontFamily`s and display values provided.\n * Because fonts are automatically unloaded on every platform this is mostly used for testing.\n *\n * @param fontFamilyOrFontMap The name or names of the custom fonts that will be unloaded.\n * @param options When `fontFamilyOrFontMap` is a string, this should be the font source used to load\n * the custom font originally.\n */\nexport async function unloadAsync(\n fontFamilyOrFontMap: string | Record<string, UnloadFontOptions>,\n options?: UnloadFontOptions\n): Promise<void> {\n if (!ExpoFontLoader.unloadAsync) {\n throw new UnavailabilityError('expo-font', 'unloadAsync');\n }\n if (typeof fontFamilyOrFontMap === 'object') {\n if (options) {\n throw new CodedError(\n `ERR_FONT_API`,\n `No fontFamily can be used for the provided options: ${options}. The second argument of \\`unloadAsync()\\` can only be used with a \\`string\\` value as the first argument.`\n );\n }\n const fontMap = fontFamilyOrFontMap;\n const names = Object.keys(fontMap);\n await Promise.all(names.map((name) => unloadFontInNamespaceAsync(name, fontMap[name])));\n return;\n }\n\n return await unloadFontInNamespaceAsync(fontFamilyOrFontMap, options);\n}\n\nasync function unloadFontInNamespaceAsync(\n fontFamily: string,\n options?: UnloadFontOptions | null\n): Promise<void> {\n if (!loaded[fontFamily]) {\n return;\n } else {\n delete loaded[fontFamily];\n }\n\n // Important: we want all callers that concurrently try to load the same font to await the same\n // promise. If we're here, we haven't created the promise yet. To ensure we create only one\n // promise in the program, we need to create the promise synchronously without yielding the event\n // loop from this point.\n\n const nativeFontName = getNativeFontName(fontFamily);\n\n if (!nativeFontName) {\n throw new CodedError(`ERR_FONT_FAMILY`, `Cannot unload an empty name`);\n }\n\n await ExpoFontLoader.unloadAsync(nativeFontName, options);\n}\n\nexport { FontDisplay, FontSource, FontResource, UnloadFontOptions };\n"]}
@@ -16,5 +16,5 @@ import { FontSource } from './Font.types';
16
16
  * loading.
17
17
  * - __error__ (`Error | null`) - An error encountered when loading the fonts.
18
18
  */
19
- export declare function useFonts(map: string | Record<string, FontSource>): [boolean, Error | null];
19
+ export declare const useFonts: (map: string | Record<string, FontSource>) => [boolean, Error | null];
20
20
  //# sourceMappingURL=FontHooks.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"FontHooks.d.ts","sourceRoot":"","sources":["../src/FontHooks.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,GAAG,IAAI,CAAC,CAW1F"}
1
+ {"version":3,"file":"FontHooks.d.ts","sourceRoot":"","sources":["../src/FontHooks.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAiC1C;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,GAAG,IAAI,CACzB,CAAC"}
@@ -1,5 +1,30 @@
1
1
  import { useEffect, useState } from 'react';
2
- import { loadAsync } from './Font';
2
+ import { loadAsync, isLoaded } from './Font';
3
+ function isMapLoaded(map) {
4
+ if (typeof map === 'string') {
5
+ return isLoaded(map);
6
+ }
7
+ else {
8
+ return Object.keys(map).every((fontFamily) => isLoaded(fontFamily));
9
+ }
10
+ }
11
+ function useRuntimeFonts(map) {
12
+ const [loaded, setLoaded] = useState(
13
+ // For web rehydration, we need to check if the fonts are already loaded during the static render.
14
+ // Native will also benefit from this optimization.
15
+ isMapLoaded(map));
16
+ const [error, setError] = useState(null);
17
+ useEffect(() => {
18
+ loadAsync(map)
19
+ .then(() => setLoaded(true))
20
+ .catch(setError);
21
+ }, []);
22
+ return [loaded, error];
23
+ }
24
+ function useStaticFonts(map) {
25
+ loadAsync(map);
26
+ return [true, null];
27
+ }
3
28
  // @needsAudit
4
29
  /**
5
30
  * ```ts
@@ -18,14 +43,5 @@ import { loadAsync } from './Font';
18
43
  * loading.
19
44
  * - __error__ (`Error | null`) - An error encountered when loading the fonts.
20
45
  */
21
- export function useFonts(map) {
22
- const [loaded, setLoaded] = useState(false);
23
- const [error, setError] = useState(null);
24
- useEffect(() => {
25
- loadAsync(map)
26
- .then(() => setLoaded(true))
27
- .catch(setError);
28
- }, []);
29
- return [loaded, error];
30
- }
46
+ export const useFonts = typeof window === 'undefined' ? useStaticFonts : useRuntimeFonts;
31
47
  //# sourceMappingURL=FontHooks.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"FontHooks.js","sourceRoot":"","sources":["../src/FontHooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE5C,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAGnC,cAAc;AACd;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,QAAQ,CAAC,GAAwC;IAC/D,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC5C,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAe,IAAI,CAAC,CAAC;IAEvD,SAAS,CAAC,GAAG,EAAE;QACb,SAAS,CAAC,GAAG,CAAC;aACX,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;aAC3B,KAAK,CAAC,QAAQ,CAAC,CAAC;IACrB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AACzB,CAAC","sourcesContent":["import { useEffect, useState } from 'react';\n\nimport { loadAsync } from './Font';\nimport { FontSource } from './Font.types';\n\n// @needsAudit\n/**\n * ```ts\n * const [loaded, error] = useFonts({ ... });\n * ```\n * Load a map of fonts with [`loadAsync`](#loadasync). This returns a `boolean` if the fonts are\n * loaded and ready to use. It also returns an error if something went wrong, to use in development.\n *\n * > Note, the fonts are not \"reloaded\" when you dynamically change the font map.\n *\n * @param map A map of `fontFamily`s to [`FontSource`](#fontsource)s. After loading the font you can\n * use the key in the `fontFamily` style prop of a `Text` element.\n *\n * @return\n * - __loaded__ (`boolean`) - A boolean to detect if the font for `fontFamily` has finished\n * loading.\n * - __error__ (`Error | null`) - An error encountered when loading the fonts.\n */\nexport function useFonts(map: string | Record<string, FontSource>): [boolean, Error | null] {\n const [loaded, setLoaded] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n loadAsync(map)\n .then(() => setLoaded(true))\n .catch(setError);\n }, []);\n\n return [loaded, error];\n}\n"]}
1
+ {"version":3,"file":"FontHooks.js","sourceRoot":"","sources":["../src/FontHooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE5C,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAG7C,SAAS,WAAW,CAAC,GAAwC;IAC3D,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;QAC3B,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC;KACtB;SAAM;QACL,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;KACrE;AACH,CAAC;AAED,SAAS,eAAe,CAAC,GAAwC;IAC/D,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ;IAClC,kGAAkG;IAClG,mDAAmD;IACnD,WAAW,CAAC,GAAG,CAAC,CACjB,CAAC;IACF,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAe,IAAI,CAAC,CAAC;IAEvD,SAAS,CAAC,GAAG,EAAE;QACb,SAAS,CAAC,GAAG,CAAC;aACX,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;aAC3B,KAAK,CAAC,QAAQ,CAAC,CAAC;IACrB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AACzB,CAAC;AAED,SAAS,cAAc,CAAC,GAAwC;IAC9D,SAAS,CAAC,GAAG,CAAC,CAAC;IACf,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AACtB,CAAC;AAED,cAAc;AACd;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,QAAQ,GACnB,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,eAAe,CAAC","sourcesContent":["import { useEffect, useState } from 'react';\n\nimport { loadAsync, isLoaded } from './Font';\nimport { FontSource } from './Font.types';\n\nfunction isMapLoaded(map: string | Record<string, FontSource>) {\n if (typeof map === 'string') {\n return isLoaded(map);\n } else {\n return Object.keys(map).every((fontFamily) => isLoaded(fontFamily));\n }\n}\n\nfunction useRuntimeFonts(map: string | Record<string, FontSource>): [boolean, Error | null] {\n const [loaded, setLoaded] = useState(\n // For web rehydration, we need to check if the fonts are already loaded during the static render.\n // Native will also benefit from this optimization.\n isMapLoaded(map)\n );\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n loadAsync(map)\n .then(() => setLoaded(true))\n .catch(setError);\n }, []);\n\n return [loaded, error];\n}\n\nfunction useStaticFonts(map: string | Record<string, FontSource>): [boolean, Error | null] {\n loadAsync(map);\n return [true, null];\n}\n\n// @needsAudit\n/**\n * ```ts\n * const [loaded, error] = useFonts({ ... });\n * ```\n * Load a map of fonts with [`loadAsync`](#loadasync). This returns a `boolean` if the fonts are\n * loaded and ready to use. It also returns an error if something went wrong, to use in development.\n *\n * > Note, the fonts are not \"reloaded\" when you dynamically change the font map.\n *\n * @param map A map of `fontFamily`s to [`FontSource`](#fontsource)s. After loading the font you can\n * use the key in the `fontFamily` style prop of a `Text` element.\n *\n * @return\n * - __loaded__ (`boolean`) - A boolean to detect if the font for `fontFamily` has finished\n * loading.\n * - __error__ (`Error | null`) - An error encountered when loading the fonts.\n */\nexport const useFonts: (map: string | Record<string, FontSource>) => [boolean, Error | null] =\n typeof window === 'undefined' ? useStaticFonts : useRuntimeFonts;\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"FontLoader.web.d.ts","sourceRoot":"","sources":["../src/FontLoader.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAInC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAe,MAAM,cAAc,CAAC;AAiBrE,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,GAAG,KAAK,GAAG,YAAY,CAY1E;AAWD,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,KAAK,GAAG,YAAY,GAC1B,OAAO,CAAC,IAAI,CAAC,CAUf;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtD"}
1
+ {"version":3,"file":"FontLoader.web.d.ts","sourceRoot":"","sources":["../src/FontLoader.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAInC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAe,MAAM,cAAc,CAAC;AAiBrE,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,GAAG,KAAK,GAAG,YAAY,CAY1E;AAYD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAY5F;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtD"}
@@ -37,16 +37,18 @@ function throwInvalidSourceError(source) {
37
37
  type = JSON.stringify(source, null, 2);
38
38
  throw new CodedError(`ERR_FONT_SOURCE`, `Expected font asset of type \`string | FontResource | Asset\` instead got: ${type}`);
39
39
  }
40
- export async function loadSingleFontAsync(name, input) {
40
+ // NOTE(EvanBacon): No async keyword!
41
+ export function loadSingleFontAsync(name, input) {
41
42
  if (typeof input !== 'object' || typeof input.uri !== 'string' || input.downloadAsync) {
42
43
  throwInvalidSourceError(input);
43
44
  }
44
45
  try {
45
- await ExpoFontLoader.loadAsync(name, input);
46
+ return ExpoFontLoader.loadAsync(name, input);
46
47
  }
47
48
  catch {
48
49
  // No-op.
49
50
  }
51
+ return Promise.resolve();
50
52
  }
51
53
  export function getNativeFontName(name) {
52
54
  return name;
@@ -1 +1 @@
1
- {"version":3,"file":"FontLoader.web.js","sourceRoot":"","sources":["../src/FontLoader.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,OAAO,cAAc,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAA4B,WAAW,EAAE,MAAM,cAAc,CAAC;AAErE,SAAS,iBAAiB,CAAC,KAAU;IACnC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;QAC7B,OAAO,KAAK,IAAI,IAAI,CAAC;KACtB;SAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;QACpC,OAAO,KAAK,CAAC,GAAG,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,OAAO,IAAI,IAAI,CAAC;KAC7D;SAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;QACpC,OAAO,iBAAiB,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;KACnD;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAU;IACvC,OAAO,KAAK,CAAC,OAAO,IAAI,WAAW,CAAC,IAAI,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,IAAY;IACjD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAkB;IAClD,MAAM,GAAG,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAE9C,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;QACnC,uBAAuB,CAAC,GAAG,CAAC,CAAC;KAC9B;IAED,OAAO;QACL,GAAG,EAAE,GAAI;QACT,OAAO;KACR,CAAC;AACJ,CAAC;AAED,SAAS,uBAAuB,CAAC,MAAW;IAC1C,IAAI,IAAI,GAAW,OAAO,MAAM,CAAC;IACjC,IAAI,IAAI,KAAK,QAAQ;QAAE,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC9D,MAAM,IAAI,UAAU,CAClB,iBAAiB,EACjB,8EAA8E,IAAI,EAAE,CACrF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,IAAY,EACZ,KAA2B;IAE3B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ,IAAK,KAAa,CAAC,aAAa,EAAE;QAC9F,uBAAuB,CAAC,KAAK,CAAC,CAAC;KAChC;IAED,IAAI;QACF,MAAM,cAAc,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;KAC7C;IAAC,MAAM;QACN,SAAS;KACV;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["import { Asset } from 'expo-asset';\nimport { CodedError } from 'expo-modules-core';\n\nimport ExpoFontLoader from './ExpoFontLoader';\nimport { FontResource, FontSource, FontDisplay } from './Font.types';\n\nfunction uriFromFontSource(asset: any): string | null {\n if (typeof asset === 'string') {\n return asset || null;\n } else if (typeof asset === 'object') {\n return asset.uri || asset.localUri || asset.default || null;\n } else if (typeof asset === 'number') {\n return uriFromFontSource(Asset.fromModule(asset));\n }\n return null;\n}\n\nfunction displayFromFontSource(asset: any): FontDisplay | undefined {\n return asset.display || FontDisplay.AUTO;\n}\n\nexport function fontFamilyNeedsScoping(name: string): boolean {\n return false;\n}\n\nexport function getAssetForSource(source: FontSource): Asset | FontResource {\n const uri = uriFromFontSource(source);\n const display = displayFromFontSource(source);\n\n if (!uri || typeof uri !== 'string') {\n throwInvalidSourceError(uri);\n }\n\n return {\n uri: uri!,\n display,\n };\n}\n\nfunction throwInvalidSourceError(source: any): never {\n let type: string = typeof source;\n if (type === 'object') type = JSON.stringify(source, null, 2);\n throw new CodedError(\n `ERR_FONT_SOURCE`,\n `Expected font asset of type \\`string | FontResource | Asset\\` instead got: ${type}`\n );\n}\n\nexport async function loadSingleFontAsync(\n name: string,\n input: Asset | FontResource\n): Promise<void> {\n if (typeof input !== 'object' || typeof input.uri !== 'string' || (input as any).downloadAsync) {\n throwInvalidSourceError(input);\n }\n\n try {\n await ExpoFontLoader.loadAsync(name, input);\n } catch {\n // No-op.\n }\n}\n\nexport function getNativeFontName(name: string): string {\n return name;\n}\n"]}
1
+ {"version":3,"file":"FontLoader.web.js","sourceRoot":"","sources":["../src/FontLoader.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,OAAO,cAAc,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAA4B,WAAW,EAAE,MAAM,cAAc,CAAC;AAErE,SAAS,iBAAiB,CAAC,KAAU;IACnC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;QAC7B,OAAO,KAAK,IAAI,IAAI,CAAC;KACtB;SAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;QACpC,OAAO,KAAK,CAAC,GAAG,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,OAAO,IAAI,IAAI,CAAC;KAC7D;SAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;QACpC,OAAO,iBAAiB,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;KACnD;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAU;IACvC,OAAO,KAAK,CAAC,OAAO,IAAI,WAAW,CAAC,IAAI,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,IAAY;IACjD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAkB;IAClD,MAAM,GAAG,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAE9C,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;QACnC,uBAAuB,CAAC,GAAG,CAAC,CAAC;KAC9B;IAED,OAAO;QACL,GAAG,EAAE,GAAI;QACT,OAAO;KACR,CAAC;AACJ,CAAC;AAED,SAAS,uBAAuB,CAAC,MAAW;IAC1C,IAAI,IAAI,GAAW,OAAO,MAAM,CAAC;IACjC,IAAI,IAAI,KAAK,QAAQ;QAAE,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC9D,MAAM,IAAI,UAAU,CAClB,iBAAiB,EACjB,8EAA8E,IAAI,EAAE,CACrF,CAAC;AACJ,CAAC;AAED,qCAAqC;AACrC,MAAM,UAAU,mBAAmB,CAAC,IAAY,EAAE,KAA2B;IAC3E,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ,IAAK,KAAa,CAAC,aAAa,EAAE;QAC9F,uBAAuB,CAAC,KAAK,CAAC,CAAC;KAChC;IAED,IAAI;QACF,OAAO,cAAc,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;KAC9C;IAAC,MAAM;QACN,SAAS;KACV;IAED,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["import { Asset } from 'expo-asset';\nimport { CodedError } from 'expo-modules-core';\n\nimport ExpoFontLoader from './ExpoFontLoader';\nimport { FontResource, FontSource, FontDisplay } from './Font.types';\n\nfunction uriFromFontSource(asset: any): string | null {\n if (typeof asset === 'string') {\n return asset || null;\n } else if (typeof asset === 'object') {\n return asset.uri || asset.localUri || asset.default || null;\n } else if (typeof asset === 'number') {\n return uriFromFontSource(Asset.fromModule(asset));\n }\n return null;\n}\n\nfunction displayFromFontSource(asset: any): FontDisplay | undefined {\n return asset.display || FontDisplay.AUTO;\n}\n\nexport function fontFamilyNeedsScoping(name: string): boolean {\n return false;\n}\n\nexport function getAssetForSource(source: FontSource): Asset | FontResource {\n const uri = uriFromFontSource(source);\n const display = displayFromFontSource(source);\n\n if (!uri || typeof uri !== 'string') {\n throwInvalidSourceError(uri);\n }\n\n return {\n uri: uri!,\n display,\n };\n}\n\nfunction throwInvalidSourceError(source: any): never {\n let type: string = typeof source;\n if (type === 'object') type = JSON.stringify(source, null, 2);\n throw new CodedError(\n `ERR_FONT_SOURCE`,\n `Expected font asset of type \\`string | FontResource | Asset\\` instead got: ${type}`\n );\n}\n\n// NOTE(EvanBacon): No async keyword!\nexport function loadSingleFontAsync(name: string, input: Asset | FontResource): Promise<void> {\n if (typeof input !== 'object' || typeof input.uri !== 'string' || (input as any).downloadAsync) {\n throwInvalidSourceError(input);\n }\n\n try {\n return ExpoFontLoader.loadAsync(name, input);\n } catch {\n // No-op.\n }\n\n return Promise.resolve();\n}\n\nexport function getNativeFontName(name: string): string {\n return name;\n}\n"]}
@@ -0,0 +1,7 @@
1
+ export declare const loaded: {
2
+ [name: string]: boolean;
3
+ };
4
+ export declare const loadPromises: {
5
+ [name: string]: Promise<void>;
6
+ };
7
+ //# sourceMappingURL=memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,MAAM,EAAE;IAAE,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;CAAO,CAAC;AACtD,eAAO,MAAM,YAAY,EAAE;IAAE,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAAO,CAAC"}
@@ -0,0 +1,3 @@
1
+ export const loaded = {};
2
+ export const loadPromises = {};
3
+ //# sourceMappingURL=memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,MAAM,GAAgC,EAAE,CAAC;AACtD,MAAM,CAAC,MAAM,YAAY,GAAsC,EAAE,CAAC","sourcesContent":["export const loaded: { [name: string]: boolean } = {};\nexport const loadPromises: { [name: string]: Promise<void> } = {};\n"]}
@@ -0,0 +1,13 @@
1
+ import { FontSource } from './Font.types';
2
+ /**
3
+ * @returns the server resources that should be statically extracted.
4
+ * @private
5
+ */
6
+ export declare function getServerResources(): any;
7
+ /**
8
+ * @returns clear the server resources from the global scope.
9
+ * @private
10
+ */
11
+ export declare function resetServerContext(): any;
12
+ export declare function registerStaticFont(fontFamily: string, source?: FontSource | null): void;
13
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C;;;GAGG;AACH,wBAAgB,kBAAkB,QAEjC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,QAEjC;AAED,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,IAAI,QAWhF"}
@@ -0,0 +1,26 @@
1
+ import { CodedError } from 'expo-modules-core';
2
+ import ExpoFontLoader from './ExpoFontLoader';
3
+ import { getAssetForSource, loadSingleFontAsync } from './FontLoader';
4
+ /**
5
+ * @returns the server resources that should be statically extracted.
6
+ * @private
7
+ */
8
+ export function getServerResources() {
9
+ return ExpoFontLoader.getServerResources();
10
+ }
11
+ /**
12
+ * @returns clear the server resources from the global scope.
13
+ * @private
14
+ */
15
+ export function resetServerContext() {
16
+ return ExpoFontLoader.resetServerContext();
17
+ }
18
+ export function registerStaticFont(fontFamily, source) {
19
+ // MUST BE A SYNC FUNCTION!
20
+ if (!source) {
21
+ throw new CodedError(`ERR_FONT_SOURCE`, `Cannot load null or undefined font source: { "${fontFamily}": ${source} }. Expected asset of type \`FontSource\` for fontFamily of name: "${fontFamily}"`);
22
+ }
23
+ const asset = getAssetForSource(source);
24
+ loadSingleFontAsync(fontFamily, asset);
25
+ }
26
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,OAAO,cAAc,MAAM,kBAAkB,CAAC;AAE9C,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAEtE;;;GAGG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO,cAAc,CAAC,kBAAkB,EAAE,CAAC;AAC7C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO,cAAc,CAAC,kBAAkB,EAAE,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,UAAkB,EAAE,MAA0B;IAC/E,2BAA2B;IAC3B,IAAI,CAAC,MAAM,EAAE;QACX,MAAM,IAAI,UAAU,CAClB,iBAAiB,EACjB,iDAAiD,UAAU,MAAM,MAAM,sEAAsE,UAAU,GAAG,CAC3J,CAAC;KACH;IACD,MAAM,KAAK,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAExC,mBAAmB,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;AACzC,CAAC","sourcesContent":["import { CodedError } from 'expo-modules-core';\n\nimport ExpoFontLoader from './ExpoFontLoader';\nimport { FontSource } from './Font.types';\nimport { getAssetForSource, loadSingleFontAsync } from './FontLoader';\n\n/**\n * @returns the server resources that should be statically extracted.\n * @private\n */\nexport function getServerResources() {\n return ExpoFontLoader.getServerResources();\n}\n\n/**\n * @returns clear the server resources from the global scope.\n * @private\n */\nexport function resetServerContext() {\n return ExpoFontLoader.resetServerContext();\n}\n\nexport function registerStaticFont(fontFamily: string, source?: FontSource | null) {\n // MUST BE A SYNC FUNCTION!\n if (!source) {\n throw new CodedError(\n `ERR_FONT_SOURCE`,\n `Cannot load null or undefined font source: { \"${fontFamily}\": ${source} }. Expected asset of type \\`FontSource\\` for fontFamily of name: \"${fontFamily}\"`\n );\n }\n const asset = getAssetForSource(source);\n\n loadSingleFontAsync(fontFamily, asset);\n}\n"]}
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "expo-font",
3
+ "platforms": ["ios", "android", "web"],
4
+ "android": {
5
+ "modules": ["expo.modules.font.FontLoaderModule"]
6
+ }
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-font",
3
- "version": "11.5.0",
3
+ "version": "11.6.0",
4
4
  "description": "Load fonts at runtime and use them in React Native components.",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -42,5 +42,5 @@
42
42
  "peerDependencies": {
43
43
  "expo": "*"
44
44
  },
45
- "gitHead": "663654577a7068c641b5e9474efbc502e3f334ea"
45
+ "gitHead": "79607a7325f47aa17c36d266100d09a4ff2cc544"
46
46
  }
@@ -1,2 +1,2 @@
1
- import { NativeModulesProxy } from 'expo-modules-core';
2
- export default NativeModulesProxy.ExpoFontLoader;
1
+ import { requireNativeModule } from 'expo-modules-core';
2
+ export default requireNativeModule('ExpoFontLoader');
@@ -46,6 +46,42 @@ function getFontFaceRulesMatchingResource(
46
46
  });
47
47
  }
48
48
 
49
+ const serverContext: Set<{ name: string; css: string; resourceId: string }> = new Set();
50
+
51
+ function getHeadElements(): {
52
+ $$type: string;
53
+ rel?: string;
54
+ href?: string;
55
+ as?: string;
56
+ crossorigin?: string;
57
+ children?: string;
58
+ id?: string;
59
+ type?: string;
60
+ }[] {
61
+ const entries = [...serverContext.entries()];
62
+ if (!entries.length) {
63
+ return [];
64
+ }
65
+ const css = entries.map(([{ css }]) => css).join('\n');
66
+ const links = entries.map(([{ resourceId }]) => resourceId);
67
+ // TODO: Maybe return nothing if no fonts were loaded.
68
+ return [
69
+ {
70
+ $$type: 'style',
71
+ children: css,
72
+ id: ID,
73
+ type: 'text/css',
74
+ },
75
+ ...links.map((resourceId) => ({
76
+ $$type: 'link',
77
+ rel: 'preload',
78
+ href: resourceId,
79
+ as: 'font',
80
+ crossorigin: '',
81
+ })),
82
+ ];
83
+ }
84
+
49
85
  export default {
50
86
  get name(): string {
51
87
  return 'ExpoFontLoader';
@@ -69,9 +105,44 @@ export default {
69
105
  }
70
106
  },
71
107
 
72
- async loadAsync(fontFamilyName: string, resource: FontResource): Promise<void> {
73
- if (!Platform.isDOMAvailable) {
74
- return;
108
+ getServerResources(): string[] {
109
+ const elements = getHeadElements();
110
+
111
+ return elements.map((element) => {
112
+ switch (element.$$type) {
113
+ case 'style':
114
+ return `<style id="${element.id}" type="${element.type}">${element.children}</style>`;
115
+ case 'link':
116
+ return `<link rel="${element.rel}" href="${element.href}" as="${element.as}" crossorigin="${element.crossorigin}" />`;
117
+ default:
118
+ return '';
119
+ }
120
+ });
121
+ },
122
+
123
+ resetServerContext() {
124
+ serverContext.clear();
125
+ },
126
+
127
+ isLoaded(fontFamilyName: string, resource: UnloadFontOptions = {}): boolean {
128
+ if (typeof window === 'undefined') {
129
+ return !![...serverContext.values()].find((asset) => {
130
+ return asset.name === fontFamilyName;
131
+ });
132
+ }
133
+ return getFontFaceRulesMatchingResource(fontFamilyName, resource)?.length > 0;
134
+ },
135
+
136
+ // NOTE(EvanBacon): No async keyword! This cannot return a promise in Node environments.
137
+ loadAsync(fontFamilyName: string, resource: FontResource): Promise<void> {
138
+ if (typeof window === 'undefined') {
139
+ serverContext.add({
140
+ name: fontFamilyName,
141
+ css: _createWebFontTemplate(fontFamilyName, resource),
142
+ // @ts-expect-error: typeof string
143
+ resourceId: resource.uri!,
144
+ });
145
+ return Promise.resolve();
75
146
  }
76
147
 
77
148
  const canInjectStyle = document.head && typeof document.head.appendChild === 'function';
@@ -82,11 +153,16 @@ export default {
82
153
  );
83
154
  }
84
155
 
85
- const style = _createWebStyle(fontFamilyName, resource);
156
+ const style = getStyleElement();
86
157
  document.head!.appendChild(style);
87
158
 
159
+ const res = getFontFaceRulesMatchingResource(fontFamilyName, resource);
160
+ if (!res.length) {
161
+ _createWebStyle(fontFamilyName, resource);
162
+ }
163
+
88
164
  if (!isFontLoadingListenerSupported()) {
89
- return;
165
+ return Promise.resolve();
90
166
  }
91
167
 
92
168
  return new FontObserver(fontFamilyName, { display: resource.display }).load(null, 6000);
@@ -106,12 +182,14 @@ function getStyleElement(): HTMLStyleElement {
106
182
  return styleElement;
107
183
  }
108
184
 
185
+ export function _createWebFontTemplate(fontFamily: string, resource: FontResource): string {
186
+ return `@font-face{font-family:${fontFamily};src:url(${resource.uri});font-display:${
187
+ resource.display || FontDisplay.AUTO
188
+ }}`;
189
+ }
190
+
109
191
  function _createWebStyle(fontFamily: string, resource: FontResource): HTMLStyleElement {
110
- const fontStyle = `@font-face {
111
- font-family: ${fontFamily};
112
- src: url(${resource.uri});
113
- font-display: ${resource.display || FontDisplay.AUTO};
114
- }`;
192
+ const fontStyle = _createWebFontTemplate(fontFamily, resource);
115
193
 
116
194
  const styleElement = getStyleElement();
117
195
  // @ts-ignore: TypeScript does not define HTMLStyleElement::styleSheet. This is just for IE and
package/src/Font.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { CodedError, UnavailabilityError } from 'expo-modules-core';
1
+ import { CodedError, Platform, UnavailabilityError } from 'expo-modules-core';
2
2
 
3
3
  import ExpoFontLoader from './ExpoFontLoader';
4
4
  import { FontDisplay, FontSource, FontResource, UnloadFontOptions } from './Font.types';
@@ -8,9 +8,8 @@ import {
8
8
  fontFamilyNeedsScoping,
9
9
  getNativeFontName,
10
10
  } from './FontLoader';
11
-
12
- const loaded: { [name: string]: boolean } = {};
13
- const loadPromises: { [name: string]: Promise<void> } = {};
11
+ import { loaded, loadPromises } from './memory';
12
+ import { registerStaticFont } from './server';
14
13
 
15
14
  // @needsAudit
16
15
  // note(brentvatne): at some point we may want to warn if this is called outside of a managed app.
@@ -30,19 +29,15 @@ export function processFontFamily(fontFamily: string | null): string | null {
30
29
  if (!isLoaded(fontFamily)) {
31
30
  if (__DEV__) {
32
31
  if (isLoading(fontFamily)) {
33
- console.error(
32
+ console.warn(
34
33
  `You started loading the font "${fontFamily}", but used it before it finished loading. You need to wait for Font.loadAsync to complete before using the font.`
35
34
  );
36
35
  } else {
37
- console.error(
38
- `fontFamily "${fontFamily}" is not a system font and has not been loaded through Font.loadAsync.\n
39
- - If you intended to use a system font, make sure you typed the name correctly and that it is supported by your device operating system.\n
40
- - If this is a custom font, be sure to load it with Font.loadAsync.`
36
+ console.warn(
37
+ `fontFamily "${fontFamily}" is not a system font and has not been loaded through expo-font.`
41
38
  );
42
39
  }
43
40
  }
44
-
45
- return 'System';
46
41
  }
47
42
 
48
43
  return `ExpoFont-${getNativeFontName(fontFamily)}`;
@@ -56,6 +51,9 @@ export function processFontFamily(fontFamily: string | null): string | null {
56
51
  * @return Returns `true` if the font has fully loaded.
57
52
  */
58
53
  export function isLoaded(fontFamily: string): boolean {
54
+ if (Platform.OS === 'web') {
55
+ return fontFamily in loaded || !!ExpoFontLoader.isLoaded(fontFamily);
56
+ }
59
57
  return fontFamily in loaded;
60
58
  }
61
59
 
@@ -83,24 +81,43 @@ export function isLoading(fontFamily: string): boolean {
83
81
  * @return Returns a promise that fulfils when the font has loaded. Often you may want to wrap the
84
82
  * method in a `try/catch/finally` to ensure the app continues if the font fails to load.
85
83
  */
86
- export async function loadAsync(
84
+ export function loadAsync(
87
85
  fontFamilyOrFontMap: string | Record<string, FontSource>,
88
86
  source?: FontSource
89
87
  ): Promise<void> {
88
+ // NOTE(EvanBacon): Static render pass on web must be synchronous to collect all fonts.
89
+ // Because of this, `loadAsync` doesn't use the `async` keyword and deviates from the
90
+ // standard Expo SDK style guide.
91
+ const isServer = Platform.OS === 'web' && typeof window === 'undefined';
92
+
90
93
  if (typeof fontFamilyOrFontMap === 'object') {
91
94
  if (source) {
92
- throw new CodedError(
93
- `ERR_FONT_API`,
94
- `No fontFamily can be used for the provided source: ${source}. The second argument of \`loadAsync()\` can only be used with a \`string\` value as the first argument.`
95
+ return Promise.reject(
96
+ new CodedError(
97
+ `ERR_FONT_API`,
98
+ `No fontFamily can be used for the provided source: ${source}. The second argument of \`loadAsync()\` can only be used with a \`string\` value as the first argument.`
99
+ )
95
100
  );
96
101
  }
97
102
  const fontMap = fontFamilyOrFontMap;
98
103
  const names = Object.keys(fontMap);
99
- await Promise.all(names.map((name) => loadFontInNamespaceAsync(name, fontMap[name])));
100
- return;
104
+
105
+ if (isServer) {
106
+ names.map((name) => registerStaticFont(name, fontMap[name]));
107
+ return Promise.resolve();
108
+ }
109
+
110
+ return Promise.all(names.map((name) => loadFontInNamespaceAsync(name, fontMap[name]))).then(
111
+ () => {}
112
+ );
113
+ }
114
+
115
+ if (isServer) {
116
+ registerStaticFont(fontFamilyOrFontMap, source);
117
+ return Promise.resolve();
101
118
  }
102
119
 
103
- return await loadFontInNamespaceAsync(fontFamilyOrFontMap, source);
120
+ return loadFontInNamespaceAsync(fontFamilyOrFontMap, source);
104
121
  }
105
122
 
106
123
  async function loadFontInNamespaceAsync(
package/src/FontHooks.ts CHANGED
@@ -1,8 +1,38 @@
1
1
  import { useEffect, useState } from 'react';
2
2
 
3
- import { loadAsync } from './Font';
3
+ import { loadAsync, isLoaded } from './Font';
4
4
  import { FontSource } from './Font.types';
5
5
 
6
+ function isMapLoaded(map: string | Record<string, FontSource>) {
7
+ if (typeof map === 'string') {
8
+ return isLoaded(map);
9
+ } else {
10
+ return Object.keys(map).every((fontFamily) => isLoaded(fontFamily));
11
+ }
12
+ }
13
+
14
+ function useRuntimeFonts(map: string | Record<string, FontSource>): [boolean, Error | null] {
15
+ const [loaded, setLoaded] = useState(
16
+ // For web rehydration, we need to check if the fonts are already loaded during the static render.
17
+ // Native will also benefit from this optimization.
18
+ isMapLoaded(map)
19
+ );
20
+ const [error, setError] = useState<Error | null>(null);
21
+
22
+ useEffect(() => {
23
+ loadAsync(map)
24
+ .then(() => setLoaded(true))
25
+ .catch(setError);
26
+ }, []);
27
+
28
+ return [loaded, error];
29
+ }
30
+
31
+ function useStaticFonts(map: string | Record<string, FontSource>): [boolean, Error | null] {
32
+ loadAsync(map);
33
+ return [true, null];
34
+ }
35
+
6
36
  // @needsAudit
7
37
  /**
8
38
  * ```ts
@@ -21,15 +51,5 @@ import { FontSource } from './Font.types';
21
51
  * loading.
22
52
  * - __error__ (`Error | null`) - An error encountered when loading the fonts.
23
53
  */
24
- export function useFonts(map: string | Record<string, FontSource>): [boolean, Error | null] {
25
- const [loaded, setLoaded] = useState(false);
26
- const [error, setError] = useState<Error | null>(null);
27
-
28
- useEffect(() => {
29
- loadAsync(map)
30
- .then(() => setLoaded(true))
31
- .catch(setError);
32
- }, []);
33
-
34
- return [loaded, error];
35
- }
54
+ export const useFonts: (map: string | Record<string, FontSource>) => [boolean, Error | null] =
55
+ typeof window === 'undefined' ? useStaticFonts : useRuntimeFonts;
@@ -46,19 +46,19 @@ function throwInvalidSourceError(source: any): never {
46
46
  );
47
47
  }
48
48
 
49
- export async function loadSingleFontAsync(
50
- name: string,
51
- input: Asset | FontResource
52
- ): Promise<void> {
49
+ // NOTE(EvanBacon): No async keyword!
50
+ export function loadSingleFontAsync(name: string, input: Asset | FontResource): Promise<void> {
53
51
  if (typeof input !== 'object' || typeof input.uri !== 'string' || (input as any).downloadAsync) {
54
52
  throwInvalidSourceError(input);
55
53
  }
56
54
 
57
55
  try {
58
- await ExpoFontLoader.loadAsync(name, input);
56
+ return ExpoFontLoader.loadAsync(name, input);
59
57
  } catch {
60
58
  // No-op.
61
59
  }
60
+
61
+ return Promise.resolve();
62
62
  }
63
63
 
64
64
  export function getNativeFontName(name: string): string {
package/src/memory.ts ADDED
@@ -0,0 +1,2 @@
1
+ export const loaded: { [name: string]: boolean } = {};
2
+ export const loadPromises: { [name: string]: Promise<void> } = {};
package/src/server.ts ADDED
@@ -0,0 +1,34 @@
1
+ import { CodedError } from 'expo-modules-core';
2
+
3
+ import ExpoFontLoader from './ExpoFontLoader';
4
+ import { FontSource } from './Font.types';
5
+ import { getAssetForSource, loadSingleFontAsync } from './FontLoader';
6
+
7
+ /**
8
+ * @returns the server resources that should be statically extracted.
9
+ * @private
10
+ */
11
+ export function getServerResources() {
12
+ return ExpoFontLoader.getServerResources();
13
+ }
14
+
15
+ /**
16
+ * @returns clear the server resources from the global scope.
17
+ * @private
18
+ */
19
+ export function resetServerContext() {
20
+ return ExpoFontLoader.resetServerContext();
21
+ }
22
+
23
+ export function registerStaticFont(fontFamily: string, source?: FontSource | null) {
24
+ // MUST BE A SYNC FUNCTION!
25
+ if (!source) {
26
+ throw new CodedError(
27
+ `ERR_FONT_SOURCE`,
28
+ `Cannot load null or undefined font source: { "${fontFamily}": ${source} }. Expected asset of type \`FontSource\` for fontFamily of name: "${fontFamily}"`
29
+ );
30
+ }
31
+ const asset = getAssetForSource(source);
32
+
33
+ loadSingleFontAsync(fontFamily, asset);
34
+ }
package/tsconfig.json CHANGED
@@ -5,5 +5,5 @@
5
5
  "outDir": "./build"
6
6
  },
7
7
  "include": ["./src"],
8
- "exclude": ["**/__mocks__/*", "**/__tests__/*", "**/__stories__/*"]
8
+ "exclude": ["**/__mocks__/*", "**/__tests__/*"]
9
9
  }
@@ -1,11 +0,0 @@
1
- package expo.modules.font
2
-
3
- import android.content.Context
4
- import expo.modules.core.BasePackage
5
- import expo.modules.core.ExportedModule
6
-
7
- class FontLoaderPackage : BasePackage() {
8
- override fun createExportedModules(context: Context): List<ExportedModule> {
9
- return listOf<ExportedModule>(FontLoaderModule(context))
10
- }
11
- }