@react-native-vector-icons/common
Version:
Customizable Icons for React Native with support for image source and full styling.
98 lines (78 loc) • 2.94 kB
text/typescript
/*
* The following imports are always present when react native is installed
* in the future, more explicit apis will be exposed by the core, including typings
* */
import { Image, Platform } from 'react-native';
// @ts-expect-error missing types
// eslint-disable-next-line import/no-extraneous-dependencies,import/no-unresolved
import { getAssetByID } from '@react-native/assets-registry/registry';
import { assertExpoModulesPresent, getErrorCallback, type LoadAsyncAsset } from './dynamic-loading-setting';
import type { DynamicLoader, FontSource } from './types';
const loadPromises: { [fontSource: string]: Promise<void> } = {};
const loadFontAsync = async (fontFamily: string, fontSource: FontSource): Promise<void> => {
const globalRef = globalThis;
assertExpoModulesPresent(globalRef);
const expoModules = globalRef.expo.modules;
if (loadPromises[fontFamily]) {
return loadPromises[fontFamily];
}
loadPromises[fontFamily] = (async function LoadFont() {
try {
const localUri = await (() => {
if (typeof fontSource === 'string') {
// a local filesystem uri
return fontSource;
}
// a module id
const { uri, type, hash } = getLocalFontUrl(fontSource, fontFamily);
return expoModules.ExpoAsset.downloadAsync(uri, hash, type);
})();
const asset = Platform.select<LoadAsyncAsset>({
web: { uri: localUri, display: 'auto' },
default: localUri,
});
await expoModules.ExpoFontLoader.loadAsync(fontFamily, asset);
} catch (error) {
console.error(`Failed to load font ${fontFamily}`, error); // eslint-disable-line no-console
getErrorCallback()?.({
error: error as Error,
fontFamily,
fontSource,
});
} finally {
delete loadPromises[fontFamily];
}
})();
return loadPromises[fontFamily];
};
type AssetRegistryEntry = {
name: string;
httpServerLocation: string;
hash: string;
type: string; // file extension
};
const getLocalFontUrl = (fontModuleId: number, fontFamily: string) => {
const assetMeta: AssetRegistryEntry = getAssetByID(fontModuleId);
if (!assetMeta) {
throw new Error(`no asset found for font family "${fontFamily}", moduleId: ${String(fontModuleId)}`);
}
const assetSource = Image.resolveAssetSource(fontModuleId);
return { ...assetMeta, ...assetSource };
};
const loadedFontsCache: { [name: string]: boolean } = {};
const isLoadedNative = (fontFamily: string) => {
if (fontFamily in loadedFontsCache) {
return true;
}
const globalRef = globalThis;
assertExpoModulesPresent(globalRef);
const loadedNativeFonts = globalRef.expo.modules.ExpoFontLoader.getLoadedFonts();
loadedNativeFonts.forEach((font) => {
loadedFontsCache[font] = true;
});
return fontFamily in loadedFontsCache;
};
export const dynamicLoader: DynamicLoader = {
isLoaded: isLoadedNative,
loadFontAsync,
};