1 |
|
2 |
|
3 | import invariant from 'invariant';
|
4 | import { NativeModules } from 'react-native';
|
5 |
|
6 | import Asset from './Asset';
|
7 | import Constants from './Constants';
|
8 |
|
9 | type FontSource = string | number | Asset;
|
10 |
|
11 | const loaded: { [name: string]: boolean } = {};
|
12 | const loadPromises: { [name: string]: Promise<void> } = {};
|
13 |
|
14 | export function processFontFamily(name: ?string): ?string {
|
15 | if (!name || Constants.systemFonts.includes(name) || name === 'System') {
|
16 | return name;
|
17 | }
|
18 |
|
19 | if (name.includes(Constants.sessionId)) {
|
20 | return name;
|
21 | }
|
22 |
|
23 | if (!isLoaded(name)) {
|
24 | if (__DEV__) {
|
25 | if (isLoading(name)) {
|
26 | console.error(
|
27 | `You started loading '${name}', but used it before it finished loading\n\n` +
|
28 | `- You need to wait for Expo.Font.loadAsync to complete before using the font.\n\n` +
|
29 | `- We recommend loading all fonts before rendering the app, and rendering only ` +
|
30 | `Expo.AppLoading while waiting for loading to complete.`
|
31 | );
|
32 | } else {
|
33 | console.error(
|
34 | `fontFamily '${name}' is not a system font and has not been loaded through ` +
|
35 | `Expo.Font.loadAsync.\n\n` +
|
36 | `- If you intended to use a system font, make sure you typed the name ` +
|
37 | `correctly and that it is supported by your device operating system.\n\n` +
|
38 | `- If this is a custom font, be sure to load it with Expo.Font.loadAsync.`
|
39 | );
|
40 | }
|
41 | }
|
42 |
|
43 | return 'System';
|
44 | }
|
45 |
|
46 | return `ExponentFont-${_getNativeFontName(name)}`;
|
47 | }
|
48 |
|
49 | export function isLoaded(name: string): boolean {
|
50 | return loaded.hasOwnProperty(name);
|
51 | }
|
52 |
|
53 | export function isLoading(name: string): boolean {
|
54 | return loadPromises.hasOwnProperty(name);
|
55 | }
|
56 |
|
57 | export async function loadAsync(
|
58 | nameOrMap: string | { [string]: FontSource } | Array<{ [string]: FontSource }>,
|
59 | uriOrModuleOrAsset?: FontSource
|
60 | ): Promise<void> {
|
61 | if (Array.isArray(nameOrMap)) {
|
62 | console.warn(
|
63 | `Passing in an array to Font.loadAsync like Font.loadAsync([fontMap1, fontMap2, fontMap3]) is deprecated and will be removed in SDK 25. Instead, pass in a single font map. The object spread syntax may help with this: Font.loadAsync({ ...fontMap1, ...fontMap2, ...fontMap3 })`
|
64 | );
|
65 | await Promise.all(nameOrMap.map(loadAsync));
|
66 | return;
|
67 | } else if (typeof nameOrMap === 'object') {
|
68 | const fontMap = nameOrMap;
|
69 | const names = Object.keys(fontMap);
|
70 | await Promise.all(names.map(name => loadAsync(name, fontMap[name])));
|
71 | return;
|
72 | }
|
73 |
|
74 | const name = nameOrMap;
|
75 |
|
76 | if (loaded[name]) {
|
77 | return;
|
78 | }
|
79 |
|
80 | if (loadPromises[name]) {
|
81 | return loadPromises[name];
|
82 | }
|
83 |
|
84 |
|
85 |
|
86 |
|
87 |
|
88 |
|
89 | invariant(uriOrModuleOrAsset, `No source from which to load font "${name}"`);
|
90 | const asset = _getAssetForSource(uriOrModuleOrAsset);
|
91 | loadPromises[name] = (async () => {
|
92 | try {
|
93 | await _loadSingleFontAsync(name, asset);
|
94 | loaded[name] = true;
|
95 | } finally {
|
96 | delete loadPromises[name];
|
97 | }
|
98 | })();
|
99 |
|
100 | await loadPromises[name];
|
101 | }
|
102 |
|
103 | function _getAssetForSource(uriOrModuleOrAsset: FontSource): Asset {
|
104 | if (typeof uriOrModuleOrAsset === 'string') {
|
105 |
|
106 |
|
107 | throw new Error(
|
108 | 'Loading fonts from remote URIs is temporarily not supported. Please download the font file and load it using require. See: https://docs.expo.io/versions/latest/guides/using-custom-fonts.html#downloading-the-font'
|
109 | );
|
110 | }
|
111 |
|
112 | if (typeof uriOrModuleOrAsset === 'number') {
|
113 | return Asset.fromModule(uriOrModuleOrAsset);
|
114 | }
|
115 |
|
116 | return uriOrModuleOrAsset;
|
117 | }
|
118 |
|
119 | async function _loadSingleFontAsync(name: string, asset: Asset): Promise<void> {
|
120 | await asset.downloadAsync();
|
121 | if (!asset.downloaded) {
|
122 | throw new Error(`Failed to download asset for font "${name}"`);
|
123 | }
|
124 |
|
125 | await NativeModules.ExponentFontLoader.loadAsync(_getNativeFontName(name), asset.localUri);
|
126 | }
|
127 |
|
128 | function _getNativeFontName(name: string): string {
|
129 | return `${Constants.sessionId}-${name}`;
|
130 | }
|