expo-font 58.0.0 → 58.0.2
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.
- package/CHANGELOG.md +22 -0
- package/android/build.gradle +2 -2
- package/android/src/main/java/expo/modules/font/FontFamilyFaces.kt +66 -0
- package/android/src/main/java/expo/modules/font/FontLoaderModule.kt +47 -13
- package/android/src/main/java/expo/modules/font/FontLoaderRecords.kt +17 -0
- package/android/src/main/java/expo/modules/font/FontSource.kt +13 -0
- package/android/src/main/java/expo/modules/font/MultiFaceTypeface.kt +130 -0
- package/android/src/main/java/expo/modules/font/VariableTypefaces.kt +5 -2
- package/build/ExpoFontLoader.d.ts +6 -0
- package/build/ExpoFontLoader.js +3 -0
- package/build/ExpoFontLoader.js.map +1 -1
- package/build/ExpoFontLoader.web.d.ts +5 -2
- package/build/ExpoFontLoader.web.js +110 -29
- package/build/ExpoFontLoader.web.js.map +1 -1
- package/build/ExpoFontUtils.web.d.ts +1 -1
- package/build/Font.d.ts +9 -5
- package/build/Font.js +54 -6
- package/build/Font.js.map +1 -1
- package/build/Font.types.d.ts +80 -4
- package/build/Font.types.js.map +1 -1
- package/build/FontHooks.d.ts +22 -2
- package/build/FontHooks.js +27 -2
- package/build/FontHooks.js.map +1 -1
- package/build/FontLoader.d.ts +4 -1
- package/build/FontLoader.js +32 -1
- package/build/FontLoader.js.map +1 -1
- package/build/FontLoader.web.d.ts +2 -1
- package/build/FontLoader.web.js +45 -22
- package/build/FontLoader.web.js.map +1 -1
- package/build/fontFaceValidation.d.ts +7 -0
- package/build/fontFaceValidation.js +86 -0
- package/build/fontFaceValidation.js.map +1 -0
- package/build/fontSourceFromFace.d.ts +2 -0
- package/build/fontSourceFromFace.js +32 -0
- package/build/fontSourceFromFace.js.map +1 -0
- package/build/serverContext.web.js +4 -2
- package/build/serverContext.web.js.map +1 -1
- package/expo-module.config.json +1 -1
- package/ios/FontExceptions.swift +14 -0
- package/ios/FontFamilyAliasManager.swift +56 -23
- package/ios/FontLoaderModule.swift +128 -5
- package/ios/FontLoaderRecords.swift +10 -0
- package/ios/FontUtils.swift +48 -5
- package/ios/UIFont+FontFamilyAlias.swift +19 -17
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.2/expo.modules.font-58.0.2-sources.jar +0 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.2/expo.modules.font-58.0.2-sources.jar.md5 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.2/expo.modules.font-58.0.2-sources.jar.sha1 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.2/expo.modules.font-58.0.2-sources.jar.sha256 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.2/expo.modules.font-58.0.2-sources.jar.sha512 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.2/expo.modules.font-58.0.2.aar +0 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.2/expo.modules.font-58.0.2.aar.md5 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.2/expo.modules.font-58.0.2.aar.sha1 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.2/expo.modules.font-58.0.2.aar.sha256 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.2/expo.modules.font-58.0.2.aar.sha512 +1 -0
- package/{android/build/publications/release/module.json → local-maven-repo/host/exp/exponent/expo.modules.font/58.0.2/expo.modules.font-58.0.2.module} +22 -22
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.2/expo.modules.font-58.0.2.module.md5 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.2/expo.modules.font-58.0.2.module.sha1 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.2/expo.modules.font-58.0.2.module.sha256 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.2/expo.modules.font-58.0.2.module.sha512 +1 -0
- package/{android/build/publications/release/pom-default.xml → local-maven-repo/host/exp/exponent/expo.modules.font/58.0.2/expo.modules.font-58.0.2.pom} +1 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.2/expo.modules.font-58.0.2.pom.md5 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.2/expo.modules.font-58.0.2.pom.sha1 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.2/expo.modules.font-58.0.2.pom.sha256 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.2/expo.modules.font-58.0.2.pom.sha512 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.font/maven-metadata.xml +4 -4
- package/local-maven-repo/host/exp/exponent/expo.modules.font/maven-metadata.xml.md5 +1 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.font/maven-metadata.xml.sha1 +1 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.font/maven-metadata.xml.sha256 +1 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.font/maven-metadata.xml.sha512 +1 -1
- package/mocks/ExpoFontLoader.ts +6 -0
- package/package.json +3 -7
- package/prebuilds/output/debug/xcframeworks/ExpoFont.tar.gz +0 -0
- package/prebuilds/output/release/xcframeworks/ExpoFont.tar.gz +0 -0
- package/src/ExpoFontLoader.ts +11 -0
- package/src/ExpoFontLoader.web.ts +152 -39
- package/src/Font.ts +75 -12
- package/src/Font.types.ts +86 -4
- package/src/FontHooks.ts +31 -6
- package/src/FontLoader.ts +51 -6
- package/src/FontLoader.web.ts +61 -26
- package/src/fontFaceValidation.ts +124 -0
- package/src/fontSourceFromFace.ts +29 -0
- package/src/serverContext.web.ts +1 -1
- package/.npmignore +0 -19
- package/.tsbuildinfo +0 -1
- package/android/.gitignore +0 -261
- package/android/build/intermediates/aapt_friendly_merged_manifests/release/processReleaseManifest/aapt/AndroidManifest.xml +0 -7
- package/android/build/intermediates/aapt_friendly_merged_manifests/release/processReleaseManifest/aapt/output-metadata.json +0 -18
- package/android/build/intermediates/aar_main_jar/release/syncReleaseLibJars/classes.jar +0 -0
- package/android/build/intermediates/aar_metadata/release/writeReleaseAarMetadata/aar-metadata.properties +0 -7
- package/android/build/intermediates/annotation_processor_list/release/javaPreCompileRelease/annotationProcessors.json +0 -1
- package/android/build/intermediates/annotations_typedef_file/release/extractReleaseAnnotations/typedefs.txt +0 -0
- package/android/build/intermediates/compile_r_class_jar/release/generateReleaseRFile/R.jar +0 -0
- package/android/build/intermediates/compile_symbol_list/release/generateReleaseRFile/R.txt +0 -0
- package/android/build/intermediates/incremental/mergeReleaseAssets/merger.xml +0 -2
- package/android/build/intermediates/incremental/mergeReleaseJniLibFolders/merger.xml +0 -2
- package/android/build/intermediates/incremental/release/packageReleaseResources/compile-file-map.properties +0 -1
- package/android/build/intermediates/incremental/release/packageReleaseResources/merger.xml +0 -2
- package/android/build/intermediates/incremental/release-mergeJavaRes/merge-state +0 -0
- package/android/build/intermediates/java_res/release/processReleaseJavaRes/out/META-INF/expo-font_release.kotlin_module +0 -0
- package/android/build/intermediates/local_only_symbol_list/release/parseReleaseLocalResources/R-def.txt +0 -2
- package/android/build/intermediates/manifest_merge_blame_file/release/processReleaseManifest/manifest-merger-blame-release-report.txt +0 -9
- package/android/build/intermediates/merged_java_res/release/mergeReleaseJavaResource/feature-expo-font.jar +0 -0
- package/android/build/intermediates/merged_manifest/release/processReleaseManifest/AndroidManifest.xml +0 -7
- package/android/build/intermediates/nested_resources_validation_report/release/generateReleaseResources/nestedResourcesValidationReport.txt +0 -1
- package/android/build/intermediates/source_jar/release/release-sources.jar +0 -0
- package/android/build/intermediates/symbol_list_with_package_name/release/generateReleaseRFile/package-aware-r.txt +0 -1
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/inputs/source-to-output.tab +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.keystream +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.keystream.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.values.at +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab_i +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab_i.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.keystream +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.keystream.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.values.at +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab_i +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab_i.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.values.at +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.values.at +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/counters.tab +0 -2
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/file-to-id.tab +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.values.at +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/id-to-file.tab +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.values.at +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/lookups.tab +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/lookups.tab.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/lookups.tab_i +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/lookups.tab_i.len +0 -0
- package/android/build/kotlin/compileReleaseKotlin/cacheable/last-build.bin +0 -0
- package/android/build/kotlin/compileReleaseKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin +0 -0
- package/android/build/outputs/aar/expo-font-release.aar +0 -0
- package/android/build/outputs/logs/manifest-merger-release-report.txt +0 -14
- package/android/build/tmp/kotlin-classes/release/META-INF/expo-font_release.kotlin_module +0 -0
- package/android/build/tmp/kotlin-classes/release/expo/modules/font/FileNotFoundException.class +0 -0
- package/android/build/tmp/kotlin-classes/release/expo/modules/font/FontBytesKt.class +0 -0
- package/android/build/tmp/kotlin-classes/release/expo/modules/font/FontLoaderModule$definition$lambda$4$$inlined$AsyncFunction$1.class +0 -0
- package/android/build/tmp/kotlin-classes/release/expo/modules/font/FontLoaderModule$definition$lambda$4$$inlined$AsyncFunction$2.class +0 -0
- package/android/build/tmp/kotlin-classes/release/expo/modules/font/FontLoaderModule$definition$lambda$4$$inlined$AsyncFunction$3.class +0 -0
- package/android/build/tmp/kotlin-classes/release/expo/modules/font/FontLoaderModule$definition$lambda$4$$inlined$FunctionWithoutArgs$1.class +0 -0
- package/android/build/tmp/kotlin-classes/release/expo/modules/font/FontLoaderModule.class +0 -0
- package/android/build/tmp/kotlin-classes/release/expo/modules/font/FontLoaderModuleKt.class +0 -0
- package/android/build/tmp/kotlin-classes/release/expo/modules/font/FontSource$Asset.class +0 -0
- package/android/build/tmp/kotlin-classes/release/expo/modules/font/FontSource$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/release/expo/modules/font/FontSource$LocalFile.class +0 -0
- package/android/build/tmp/kotlin-classes/release/expo/modules/font/FontSource.class +0 -0
- package/android/build/tmp/kotlin-classes/release/expo/modules/font/FontSourceKt.class +0 -0
- package/android/build/tmp/kotlin-classes/release/expo/modules/font/FontUtilsModule$definition$lambda$5$$inlined$AsyncFunctionWithPromise$1.class +0 -0
- package/android/build/tmp/kotlin-classes/release/expo/modules/font/FontUtilsModule$definition$lambda$5$$inlined$AsyncFunctionWithPromise$2.class +0 -0
- package/android/build/tmp/kotlin-classes/release/expo/modules/font/FontUtilsModule$definition$lambda$5$$inlined$AsyncFunctionWithPromise$3.class +0 -0
- package/android/build/tmp/kotlin-classes/release/expo/modules/font/FontUtilsModule.class +0 -0
- package/android/build/tmp/kotlin-classes/release/expo/modules/font/FontVariationAxes.class +0 -0
- package/android/build/tmp/kotlin-classes/release/expo/modules/font/RenderToImageOptions$__Pika.class +0 -0
- package/android/build/tmp/kotlin-classes/release/expo/modules/font/RenderToImageOptions.class +0 -0
- package/android/build/tmp/kotlin-classes/release/expo/modules/font/SaveImageException.class +0 -0
- package/android/build/tmp/kotlin-classes/release/expo/modules/font/VariableTypefaces.class +0 -0
- package/android/build/tmp/publishReleasePublicationToNPMPackageRepository/module-maven-metadata.xml +0 -13
- package/android/build/tmp/sourceReleaseJar/MANIFEST.MF +0 -2
- package/jest.config.js +0 -3
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.0/expo.modules.font-58.0.0-sources.jar +0 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.0/expo.modules.font-58.0.0-sources.jar.md5 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.0/expo.modules.font-58.0.0-sources.jar.sha1 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.0/expo.modules.font-58.0.0-sources.jar.sha256 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.0/expo.modules.font-58.0.0-sources.jar.sha512 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.0/expo.modules.font-58.0.0.aar +0 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.0/expo.modules.font-58.0.0.aar.md5 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.0/expo.modules.font-58.0.0.aar.sha1 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.0/expo.modules.font-58.0.0.aar.sha256 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.0/expo.modules.font-58.0.0.aar.sha512 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.0/expo.modules.font-58.0.0.module +0 -105
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.0/expo.modules.font-58.0.0.module.md5 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.0/expo.modules.font-58.0.0.module.sha1 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.0/expo.modules.font-58.0.0.module.sha256 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.0/expo.modules.font-58.0.0.module.sha512 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.0/expo.modules.font-58.0.0.pom +0 -64
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.0/expo.modules.font-58.0.0.pom.md5 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.0/expo.modules.font-58.0.0.pom.sha1 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.0/expo.modules.font-58.0.0.pom.sha256 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.font/58.0.0/expo.modules.font-58.0.0.pom.sha512 +0 -1
- package/plugin/.tsbuildinfo +0 -1
- package/plugin/tsconfig.json +0 -10
- package/plugin/tsconfig.tsbuildinfo +0 -1
- package/tsconfig.all.json +0 -11
- package/tsconfig.json +0 -10
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,28 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 58.0.2 — 2026-09-21
|
|
14
|
+
|
|
15
|
+
### 🐛 Bug fixes
|
|
16
|
+
|
|
17
|
+
- [iOS] Import `UIKit` in the `UIFont` extension, which relied on another file in the module importing it. ([#50277](https://github.com/expo/expo/pull/50277) by [@chrfalch](https://github.com/chrfalch))
|
|
18
|
+
|
|
19
|
+
## 58.0.1 — 2026-09-15
|
|
20
|
+
|
|
21
|
+
### 🛠 Breaking changes
|
|
22
|
+
|
|
23
|
+
- [web] Removed `FontResource.testString`. The CSS Font Loading API detects font loading without a test string. ([#49497](https://github.com/expo/expo/pull/49497) by [@vonovak](https://github.com/vonovak))
|
|
24
|
+
|
|
25
|
+
### 🎉 New features
|
|
26
|
+
|
|
27
|
+
- [android][ios] Select a face of a multi-face font family with the `fontWeight` and `fontStyle` style props. ([#49486](https://github.com/expo/expo/pull/49486) by [@vonovak](https://github.com/vonovak))
|
|
28
|
+
- Support loading multiple font weights and styles per `fontFamily` in `useFonts`/`loadAsync` on Android, iOS, and web. Use `fontWeight` and `fontStyle` style props to select the correct face. ([#47939](https://github.com/expo/expo/pull/47939) by [@bryanmylee](https://github.com/bryanmylee))
|
|
29
|
+
- [web] Accept a variable-font weight range, for example `weight: '100 900'`, on a font face. Android and iOS ignore a range and read the weight from the font file. ([#49487](https://github.com/expo/expo/pull/49487) by [@vonovak](https://github.com/vonovak))
|
|
30
|
+
|
|
31
|
+
### 💡 Others
|
|
32
|
+
|
|
33
|
+
- [web] Replaced the `fontfaceobserver` dependency with the CSS Font Loading API, so `loadAsync` also waits for the font on Safari and iOS browsers. ([#49497](https://github.com/expo/expo/pull/49497) by [@vonovak](https://github.com/vonovak))
|
|
34
|
+
|
|
13
35
|
## 58.0.0 — 2026-09-10
|
|
14
36
|
|
|
15
37
|
### 🛠 Breaking changes
|
package/android/build.gradle
CHANGED
|
@@ -4,13 +4,13 @@ plugins {
|
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
group = 'host.exp.exponent'
|
|
7
|
-
version = '58.0.
|
|
7
|
+
version = '58.0.2'
|
|
8
8
|
|
|
9
9
|
android {
|
|
10
10
|
namespace "expo.modules.font"
|
|
11
11
|
defaultConfig {
|
|
12
12
|
versionCode 29
|
|
13
|
-
versionName "58.0.
|
|
13
|
+
versionName "58.0.2"
|
|
14
14
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
15
15
|
}
|
|
16
16
|
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
package expo.modules.font
|
|
2
|
+
|
|
3
|
+
import expo.modules.kotlin.exception.CodedException
|
|
4
|
+
|
|
5
|
+
private const val MIN_WEIGHT = 1
|
|
6
|
+
private const val MAX_WEIGHT = 1000
|
|
7
|
+
private const val DEFAULT_WEIGHT = 400
|
|
8
|
+
|
|
9
|
+
// Kept free of android.* imports so it can be unit-tested on the plain JVM.
|
|
10
|
+
object FontFamilyFaces {
|
|
11
|
+
private fun isItalic(style: String?) = style == "italic"
|
|
12
|
+
|
|
13
|
+
fun assertWeightsInRange(fontFamilyName: String, faces: List<FontFaceRecord>) {
|
|
14
|
+
for (face in faces) {
|
|
15
|
+
val weight = face.weight ?: DEFAULT_WEIGHT
|
|
16
|
+
if (weight !in MIN_WEIGHT..MAX_WEIGHT) {
|
|
17
|
+
throw CodedException(
|
|
18
|
+
"Font face '${face.localUri}' for family '$fontFamilyName' declares weight $weight, " +
|
|
19
|
+
"but weight must be between $MIN_WEIGHT and $MAX_WEIGHT. " +
|
|
20
|
+
"Set the 'weight' of this face to a value in that range."
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Call only with resolved values (after `setWeight`/`setSlant`).
|
|
27
|
+
fun assertNoDuplicateFaces(fontFamilyName: String, faces: List<FontFaceRecord>) {
|
|
28
|
+
val seenFaces = mutableMapOf<Pair<Int, Boolean>, String>()
|
|
29
|
+
|
|
30
|
+
for (face in faces) {
|
|
31
|
+
val weight = face.weight ?: DEFAULT_WEIGHT
|
|
32
|
+
val italic = isItalic(face.style)
|
|
33
|
+
val key = weight to italic
|
|
34
|
+
val conflictingUri = seenFaces[key]
|
|
35
|
+
if (conflictingUri != null) {
|
|
36
|
+
throw CodedException(
|
|
37
|
+
"Font family '$fontFamilyName' declares two faces with weight $weight and " +
|
|
38
|
+
"style '${if (italic) "italic" else "normal"}': '$conflictingUri' and '${face.localUri}'. " +
|
|
39
|
+
"Give each face of a family a distinct weight or style so the correct file is selected at render time."
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
seenFaces[key] = face.localUri
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// The face to load when only one can be (below API 29).
|
|
47
|
+
fun defaultFaceIndex(faces: List<FontFaceRecord>): Int {
|
|
48
|
+
var bestIndex = 0
|
|
49
|
+
var bestDistance = Int.MAX_VALUE
|
|
50
|
+
var bestIsItalic = true
|
|
51
|
+
|
|
52
|
+
faces.forEachIndexed { index, face ->
|
|
53
|
+
val distance = kotlin.math.abs((face.weight ?: DEFAULT_WEIGHT) - DEFAULT_WEIGHT)
|
|
54
|
+
val isItalic = isItalic(face.style)
|
|
55
|
+
|
|
56
|
+
val isBetter = distance < bestDistance || (distance == bestDistance && bestIsItalic && !isItalic)
|
|
57
|
+
if (isBetter) {
|
|
58
|
+
bestIndex = index
|
|
59
|
+
bestDistance = distance
|
|
60
|
+
bestIsItalic = isItalic
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return bestIndex
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -8,6 +8,7 @@ import android.os.Build
|
|
|
8
8
|
import android.util.Log
|
|
9
9
|
import androidx.annotation.RequiresApi
|
|
10
10
|
import com.facebook.react.common.assets.ReactFontManager
|
|
11
|
+
import expo.modules.kotlin.exception.CodedException
|
|
11
12
|
import expo.modules.kotlin.exception.Exceptions
|
|
12
13
|
import expo.modules.kotlin.modules.Module
|
|
13
14
|
import expo.modules.kotlin.modules.ModuleDefinition
|
|
@@ -32,24 +33,57 @@ open class FontLoaderModule : Module() {
|
|
|
32
33
|
return@Function getLoadedFonts()
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
fun registerTypeface(fontFamilyName: String, typeface: Typeface) {
|
|
37
|
+
ReactFontManager.getInstance().addCustomFont(fontFamilyName, typeface)
|
|
38
|
+
loadedFonts = getLoadedFonts().toMutableSet().apply { add(fontFamilyName) }.toList()
|
|
39
|
+
}
|
|
37
40
|
|
|
38
|
-
|
|
39
|
-
|
|
41
|
+
AsyncFunction("loadAsync") { fontFamilyName: String, localUri: String ->
|
|
42
|
+
registerTypeface(fontFamilyName, loadSingleFaceTypeface(fontFamilyName, localUri))
|
|
43
|
+
}
|
|
40
44
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
AsyncFunction("loadFontFamilyAsync") { fontFamilyName: String, faces: List<FontFaceRecord> ->
|
|
46
|
+
if (faces.isEmpty()) {
|
|
47
|
+
throw CodedException(
|
|
48
|
+
"Could not load font family '$fontFamilyName' because 'faces' is empty. Pass at " +
|
|
49
|
+
"least one face with a 'localUri' pointing to a font file."
|
|
50
|
+
)
|
|
47
51
|
}
|
|
48
|
-
|
|
52
|
+
FontFamilyFaces.assertWeightsInRange(fontFamilyName, faces)
|
|
49
53
|
|
|
50
|
-
|
|
51
|
-
|
|
54
|
+
registerTypeface(fontFamilyName, familyTypeface(fontFamilyName, faces))
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Below API 29, `android.graphics.fonts.FontFamily` doesn't exist, so only the default face
|
|
59
|
+
// loads and Android synthesizes bold/italic from it.
|
|
60
|
+
private fun familyTypeface(fontFamilyName: String, faces: List<FontFaceRecord>): Typeface {
|
|
61
|
+
val face = faces.first()
|
|
62
|
+
if (faces.size == 1 && face.weight == null && face.style == null) {
|
|
63
|
+
return loadSingleFaceTypeface(fontFamilyName, face.localUri)
|
|
64
|
+
}
|
|
65
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
|
66
|
+
val defaultFace = faces[FontFamilyFaces.defaultFaceIndex(faces)]
|
|
67
|
+
return loadSingleFaceTypeface(fontFamilyName, defaultFace.localUri)
|
|
52
68
|
}
|
|
69
|
+
return buildMultiFaceTypeface(fontFamilyName, faces)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private fun loadSingleFaceTypeface(fontFamilyName: String, localUri: String): Typeface {
|
|
73
|
+
val source = FontSource.resolve(localUri, fontFamilyName, context)
|
|
74
|
+
|
|
75
|
+
val instanced = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
76
|
+
buildVariableWeightTypeface(fontFamilyName, source)
|
|
77
|
+
} else {
|
|
78
|
+
null
|
|
79
|
+
}
|
|
80
|
+
return instanced ?: source.load()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@RequiresApi(Build.VERSION_CODES.Q)
|
|
84
|
+
private fun buildMultiFaceTypeface(fontFamilyName: String, faces: List<FontFaceRecord>): Typeface {
|
|
85
|
+
val sources = faces.map { FontSource.resolve(it.localUri, fontFamilyName, context) }
|
|
86
|
+
return MultiFaceTypeface.build(fontFamilyName, faces, sources)
|
|
53
87
|
}
|
|
54
88
|
|
|
55
89
|
/**
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
package expo.modules.font
|
|
2
|
+
|
|
3
|
+
import expo.modules.kotlin.records.Field
|
|
4
|
+
import expo.modules.kotlin.records.Record
|
|
5
|
+
import expo.modules.kotlin.types.OptimizedRecord
|
|
6
|
+
|
|
7
|
+
@OptimizedRecord
|
|
8
|
+
data class FontFaceRecord(
|
|
9
|
+
@Field
|
|
10
|
+
val localUri: String = "",
|
|
11
|
+
|
|
12
|
+
@Field
|
|
13
|
+
val weight: Int? = null,
|
|
14
|
+
|
|
15
|
+
@Field
|
|
16
|
+
val style: String? = null
|
|
17
|
+
) : Record
|
|
@@ -4,7 +4,10 @@ package expo.modules.font
|
|
|
4
4
|
|
|
5
5
|
import android.content.Context
|
|
6
6
|
import android.graphics.Typeface
|
|
7
|
+
import android.graphics.fonts.Font
|
|
7
8
|
import android.net.Uri
|
|
9
|
+
import android.os.Build
|
|
10
|
+
import androidx.annotation.RequiresApi
|
|
8
11
|
import expo.modules.kotlin.exception.CodedException
|
|
9
12
|
import java.io.File
|
|
10
13
|
import java.io.FileInputStream
|
|
@@ -35,6 +38,10 @@ internal sealed interface FontSource {
|
|
|
35
38
|
*/
|
|
36
39
|
fun readForInstancing(): ByteBuffer?
|
|
37
40
|
|
|
41
|
+
// Reads the file itself; no [readForInstancing] buffer needed.
|
|
42
|
+
@RequiresApi(Build.VERSION_CODES.Q)
|
|
43
|
+
fun newFontBuilder(): Font.Builder
|
|
44
|
+
|
|
38
45
|
class Asset(private val path: String, private val context: Context) : FontSource {
|
|
39
46
|
override fun load(): Typeface =
|
|
40
47
|
Typeface.createFromAsset(context.assets, path)
|
|
@@ -49,6 +56,9 @@ internal sealed interface FontSource {
|
|
|
49
56
|
|
|
50
57
|
readWholeFont(header, input)
|
|
51
58
|
}
|
|
59
|
+
|
|
60
|
+
@RequiresApi(Build.VERSION_CODES.Q)
|
|
61
|
+
override fun newFontBuilder(): Font.Builder = Font.Builder(context.assets, path)
|
|
52
62
|
}
|
|
53
63
|
|
|
54
64
|
class LocalFile(private val file: File) : FontSource {
|
|
@@ -60,6 +70,9 @@ internal sealed interface FontSource {
|
|
|
60
70
|
}
|
|
61
71
|
return mapped.takeIf { FontVariationAxes.declaresVariations(it) }
|
|
62
72
|
}
|
|
73
|
+
|
|
74
|
+
@RequiresApi(Build.VERSION_CODES.Q)
|
|
75
|
+
override fun newFontBuilder(): Font.Builder = Font.Builder(file)
|
|
63
76
|
}
|
|
64
77
|
|
|
65
78
|
companion object {
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// Copyright 2015-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
package expo.modules.font
|
|
4
|
+
|
|
5
|
+
import android.graphics.Typeface
|
|
6
|
+
import android.graphics.fonts.Font
|
|
7
|
+
import android.graphics.fonts.FontFamily
|
|
8
|
+
import android.graphics.fonts.FontStyle
|
|
9
|
+
import android.os.Build
|
|
10
|
+
import androidx.annotation.RequiresApi
|
|
11
|
+
import expo.modules.kotlin.exception.CodedException
|
|
12
|
+
import java.io.IOException
|
|
13
|
+
import java.nio.ByteBuffer
|
|
14
|
+
import kotlin.math.abs
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Builds one [Typeface] from the faces of a font family. `fontWeight` and `fontStyle` then select
|
|
18
|
+
* between them.
|
|
19
|
+
*
|
|
20
|
+
* A face that is a variable font keeps its `wght` axis: a declared weight pins the face to that
|
|
21
|
+
* weight's instance, and a face with no declared weight contributes one instance per weight that
|
|
22
|
+
* `fontWeight` can request. Without the instances, every weight would render the file's default.
|
|
23
|
+
*/
|
|
24
|
+
@RequiresApi(Build.VERSION_CODES.Q)
|
|
25
|
+
internal object MultiFaceTypeface {
|
|
26
|
+
/** [faces] and [sources] pair up by index. */
|
|
27
|
+
fun build(
|
|
28
|
+
fontFamilyName: String,
|
|
29
|
+
faces: List<FontFaceRecord>,
|
|
30
|
+
sources: List<FontSource>
|
|
31
|
+
): Typeface {
|
|
32
|
+
val builtFaces = faces.zip(sources).map { (face, source) ->
|
|
33
|
+
try {
|
|
34
|
+
buildFace(face, source)
|
|
35
|
+
} catch (e: IOException) {
|
|
36
|
+
throw CodedException(
|
|
37
|
+
"Could not read font face '${face.localUri}' for family '$fontFamilyName'. The file " +
|
|
38
|
+
"may be corrupted or in a format Android can't parse. Open it in a font editor to " +
|
|
39
|
+
"check it, or replace it with a valid .ttf or .otf file.",
|
|
40
|
+
e
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// The duplicate check runs on each face's primary font. The extra instances of a variable
|
|
46
|
+
// face are not declared by the caller, so a collision there is resolved below, not an error.
|
|
47
|
+
val resolvedFaces = faces.zip(builtFaces).map { (face, built) ->
|
|
48
|
+
FontFaceRecord(
|
|
49
|
+
localUri = face.localUri,
|
|
50
|
+
weight = built.primary.style.weight,
|
|
51
|
+
style = if (built.primary.style.slant == FontStyle.FONT_SLANT_ITALIC) "italic" else "normal"
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
FontFamilyFaces.assertNoDuplicateFaces(fontFamilyName, resolvedFaces)
|
|
55
|
+
|
|
56
|
+
// Primaries first: a weight and slant a face declares wins over another face's instance of it.
|
|
57
|
+
val seenStyles = mutableSetOf<Pair<Int, Int>>()
|
|
58
|
+
val fonts = mutableListOf<Font>()
|
|
59
|
+
for (built in builtFaces) {
|
|
60
|
+
seenStyles.add(built.primary.styleKey)
|
|
61
|
+
fonts.add(built.primary)
|
|
62
|
+
}
|
|
63
|
+
for (built in builtFaces) {
|
|
64
|
+
for (instance in built.instances) {
|
|
65
|
+
if (seenStyles.add(instance.styleKey)) {
|
|
66
|
+
fonts.add(instance)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
val familyBuilder = FontFamily.Builder(fonts[0])
|
|
72
|
+
for (font in fonts.drop(1)) {
|
|
73
|
+
try {
|
|
74
|
+
familyBuilder.addFont(font)
|
|
75
|
+
} catch (e: IllegalArgumentException) {
|
|
76
|
+
throw CodedException(
|
|
77
|
+
"expo-font couldn't build the font family '$fontFamilyName' because of an internal " +
|
|
78
|
+
"error. Please report this at https://github.com/expo/expo/issues.",
|
|
79
|
+
e
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return VariableTypefaces.wrapWithSystemFallback(familyBuilder.build())
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The fonts one face contributes to the family. [primary] carries the face's declared (or the
|
|
89
|
+
* file's own) weight and slant; [instances] cover the rest of a variable face's `wght` axis.
|
|
90
|
+
*/
|
|
91
|
+
private class BuiltFace(val primary: Font, val instances: List<Font> = emptyList())
|
|
92
|
+
|
|
93
|
+
private val Font.styleKey: Pair<Int, Int>
|
|
94
|
+
get() = style.weight to style.slant
|
|
95
|
+
|
|
96
|
+
private fun buildFace(face: FontFaceRecord, source: FontSource): BuiltFace {
|
|
97
|
+
val fontData = source.readForInstancing()
|
|
98
|
+
val axis = fontData?.let { FontVariationAxes.readWeightAxis(it) }
|
|
99
|
+
if (axis == null) {
|
|
100
|
+
val builder = source.newFontBuilder()
|
|
101
|
+
face.weight?.let { builder.setWeight(it) }
|
|
102
|
+
face.style?.let { builder.setSlant(slantFor(it)) }
|
|
103
|
+
return BuiltFace(builder.build())
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (face.weight != null) {
|
|
107
|
+
// A declared weight pins the face to that instance; the clamp keeps the axis ends.
|
|
108
|
+
return BuiltFace(instance(fontData, face.weight.coerceIn(axis), face.weight, face.style))
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// `FontFamily.Builder.buildVariableFamily` can't replace the fixed instances here: it exists
|
|
112
|
+
// only on Android 15 and later, and accepts nothing but one upright font plus at most one
|
|
113
|
+
// italic one. The instance nearest the regular weight stands in as the face's primary, which
|
|
114
|
+
// is also the weight the face resolves to today when the whole file is loaded as one font.
|
|
115
|
+
val instances = FontVariationAxes.weightsFor(axis).map { instance(fontData, it, it, face.style) }
|
|
116
|
+
val primary = instances.minByOrNull { abs(it.style.weight - FontStyle.FONT_WEIGHT_NORMAL) }!!
|
|
117
|
+
return BuiltFace(primary, instances)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
private fun instance(fontData: ByteBuffer, axisWeight: Int, weight: Int, style: String?): Font {
|
|
121
|
+
val builder = Font.Builder(fontData)
|
|
122
|
+
.setFontVariationSettings("'wght' $axisWeight")
|
|
123
|
+
.setWeight(weight)
|
|
124
|
+
style?.let { builder.setSlant(slantFor(it)) }
|
|
125
|
+
return builder.build()
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private fun slantFor(style: String) =
|
|
129
|
+
if (style == "italic") FontStyle.FONT_SLANT_ITALIC else FontStyle.FONT_SLANT_UPRIGHT
|
|
130
|
+
}
|
|
@@ -36,10 +36,13 @@ internal object VariableTypefaces {
|
|
|
36
36
|
?: buildInstancedFamily(fontData)
|
|
37
37
|
?: return null
|
|
38
38
|
|
|
39
|
-
return
|
|
39
|
+
return wrapWithSystemFallback(family)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
fun wrapWithSystemFallback(family: FontFamily): Typeface =
|
|
43
|
+
Typeface.CustomFallbackBuilder(family)
|
|
40
44
|
.setSystemFallback(SYSTEM_FALLBACK)
|
|
41
45
|
.build()
|
|
42
|
-
}
|
|
43
46
|
|
|
44
47
|
/**
|
|
45
48
|
* The family that Android builds. It covers the axis continuously, not at nine fixed steps. It
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import type { ServerFontResourceDescriptor, UnloadFontOptions } from './Font.types';
|
|
2
|
+
export type NativeFontFace = {
|
|
3
|
+
localUri: string;
|
|
4
|
+
weight?: number;
|
|
5
|
+
style?: 'normal' | 'italic';
|
|
6
|
+
};
|
|
2
7
|
export type ExpoFontLoaderModule = {
|
|
3
8
|
getLoadedFonts: () => string[];
|
|
4
9
|
loadAsync: (fontFamilyName: string, localUriOrWebAsset: any) => Promise<void>;
|
|
10
|
+
loadFontFamilyAsync: (fontFamilyName: string, faces: NativeFontFace[]) => Promise<void>;
|
|
5
11
|
unloadAllAsync?: () => Promise<void>;
|
|
6
12
|
unloadAsync?: (fontFamilyName: string, options?: UnloadFontOptions) => Promise<void>;
|
|
7
13
|
isLoaded?: (fontFamilyName: string, options?: UnloadFontOptions) => boolean;
|
package/build/ExpoFontLoader.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["ExpoFontLoader.ts"],"sourcesContent":[null],"names":["requireNativeModule","m","window","getLoadedFonts","loadAsync","Promise","resolve"],"mappings":"AAAA,SAASA,mBAAmB,QAAQ,oBAAoB;
|
|
1
|
+
{"version":3,"sources":["ExpoFontLoader.ts"],"sourcesContent":[null],"names":["requireNativeModule","m","window","getLoadedFonts","loadAsync","Promise","resolve","loadFontFamilyAsync"],"mappings":"AAAA,SAASA,mBAAmB,QAAQ,oBAAoB;AAuBxD,MAAMC,IACJ,OAAOC,WAAW,cAEd;IACEC;QACE,OAAO,EAAE;IACX;IACAC;QACE,OAAOC,QAAQC,OAAO;IACxB;IACAC;QACE,OAAOF,QAAQC,OAAO;IACxB;AACF,IACAN,oBAAoB;AAC1B,eAAeC,EAAE"}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { ExpoFontLoaderModule } from './ExpoFontLoader';
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import type { UnloadFontOptions } from './Font';
|
|
3
|
+
import type { FontResource } from './Font.types';
|
|
4
|
+
export declare function _matchesFontFaceOptions(rule: Pick<CSSFontFaceRule, 'style'>, fontFamilyName: string, options?: UnloadFontOptions): boolean;
|
|
5
|
+
export declare function _fontFaceRuleSrcMatches(rule: Pick<CSSFontFaceRule, 'style'>, uri: string | number | undefined): boolean;
|
|
6
|
+
declare const ExpoFontLoader: Required<Omit<ExpoFontLoaderModule, 'loadFontFamilyAsync'>>;
|
|
4
7
|
declare const _default: typeof ExpoFontLoader;
|
|
5
8
|
export default _default;
|
|
6
9
|
export declare function _createWebFontTemplate(fontFamily: string, resource: FontResource): string;
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { CodedError, registerWebModule } from 'expo-modules-core';
|
|
2
|
-
import FontObserver from 'fontfaceobserver';
|
|
3
|
-
import { FontDisplay } from './Font.types';
|
|
4
2
|
import { addServerFont, getLoadedServerFonts, getServerResourceDescriptors as readServerResourceDescriptors, isServerFontLoaded } from './serverContext';
|
|
5
3
|
function getFontFaceStyleSheet() {
|
|
6
4
|
if (typeof window === 'undefined') {
|
|
@@ -44,11 +42,56 @@ function normalizeFontFamilyName(fontFamily) {
|
|
|
44
42
|
}
|
|
45
43
|
return trimmed;
|
|
46
44
|
}
|
|
45
|
+
function canonicalCssWeight(weight) {
|
|
46
|
+
if (weight == null || weight === '') {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
if (typeof weight === 'number') {
|
|
50
|
+
return Number.isFinite(weight) ? weight : undefined;
|
|
51
|
+
}
|
|
52
|
+
const lower = weight.trim().toLowerCase();
|
|
53
|
+
if (lower === 'normal') {
|
|
54
|
+
return 400;
|
|
55
|
+
}
|
|
56
|
+
if (lower === 'bold') {
|
|
57
|
+
return 700;
|
|
58
|
+
}
|
|
59
|
+
const numeric = Number(lower);
|
|
60
|
+
return Number.isFinite(numeric) ? numeric : lower;
|
|
61
|
+
}
|
|
62
|
+
// jsdom doesn't implement `CSSFontFaceRule`, so tests call this directly with plain `{ style }` objects.
|
|
63
|
+
export function _matchesFontFaceOptions(rule, fontFamilyName, options) {
|
|
64
|
+
if (normalizeFontFamilyName(rule.style.fontFamily) !== fontFamilyName) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
if (options?.display && options.display !== rule.style.fontDisplay) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
if (options?.weight != null && canonicalCssWeight(options.weight) !== canonicalCssWeight(rule.style.fontWeight)) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
if (options?.style != null && options.style !== rule.style.fontStyle) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
47
78
|
function getFontFaceRulesMatchingResource(fontFamilyName, options) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
79
|
+
return getFontFaceRules().filter(({ rule })=>_matchesFontFaceOptions(rule, fontFamilyName, options));
|
|
80
|
+
}
|
|
81
|
+
export function _fontFaceRuleSrcMatches(rule, uri) {
|
|
82
|
+
const src = rule.style.getPropertyValue('src');
|
|
83
|
+
const match = src.match(/url\((['"]?)([^'")]*)\1\)/);
|
|
84
|
+
if (!match) {
|
|
85
|
+
// Every rule carries a `url(...)`; an unreadable `src` means the engine doesn't expose it.
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
let ruleUri = match[2] ?? '';
|
|
89
|
+
try {
|
|
90
|
+
ruleUri = decodeURIComponent(ruleUri);
|
|
91
|
+
} catch {
|
|
92
|
+
// decodeURIComponent throws on malformed percent-encoding; compare the raw value instead.
|
|
93
|
+
}
|
|
94
|
+
return ruleUri === String(uri);
|
|
52
95
|
}
|
|
53
96
|
const ExpoFontLoader = {
|
|
54
97
|
async unloadAllAsync () {
|
|
@@ -62,7 +105,11 @@ const ExpoFontLoader = {
|
|
|
62
105
|
const sheet = getFontFaceStyleSheet();
|
|
63
106
|
if (!sheet) return;
|
|
64
107
|
const items = getFontFaceRulesMatchingResource(fontFamilyName, options);
|
|
65
|
-
|
|
108
|
+
// Descending: `deleteRule` shifts every later index down by one.
|
|
109
|
+
const descending = [
|
|
110
|
+
...items
|
|
111
|
+
].sort((a, b)=>b.index - a.index);
|
|
112
|
+
for (const item of descending){
|
|
66
113
|
sheet.deleteRule(item.index);
|
|
67
114
|
}
|
|
68
115
|
},
|
|
@@ -86,8 +133,16 @@ const ExpoFontLoader = {
|
|
|
86
133
|
if (typeof window === 'undefined') {
|
|
87
134
|
return getLoadedServerFonts();
|
|
88
135
|
}
|
|
89
|
-
const
|
|
90
|
-
|
|
136
|
+
const seen = new Set();
|
|
137
|
+
const families = [];
|
|
138
|
+
for (const { rule } of getFontFaceRules()){
|
|
139
|
+
const name = normalizeFontFamilyName(rule.style.fontFamily);
|
|
140
|
+
if (!seen.has(name)) {
|
|
141
|
+
seen.add(name);
|
|
142
|
+
families.push(name);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return families;
|
|
91
146
|
},
|
|
92
147
|
isLoaded (fontFamilyName, resource = {}) {
|
|
93
148
|
if (typeof window === 'undefined') {
|
|
@@ -117,19 +172,39 @@ const ExpoFontLoader = {
|
|
|
117
172
|
}
|
|
118
173
|
const style = getStyleElement();
|
|
119
174
|
document.head.appendChild(style);
|
|
120
|
-
const
|
|
121
|
-
if (!
|
|
175
|
+
const alreadyLoaded = getFontFaceRulesMatchingResource(fontFamilyName, resource).some(({ rule })=>_fontFaceRuleSrcMatches(rule, resource.uri));
|
|
176
|
+
if (!alreadyLoaded) {
|
|
122
177
|
_createWebStyle(fontFamilyName, resource);
|
|
123
178
|
}
|
|
124
|
-
if (
|
|
179
|
+
if (typeof document.fonts?.load !== 'function') {
|
|
125
180
|
return Promise.resolve();
|
|
126
181
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
182
|
+
// Resolve when the browser has fetched the file, so text renders with it on resolution. The
|
|
183
|
+
// face is selected with the `font` shorthand syntax; skip a descriptor the CSS sanitization
|
|
184
|
+
// in `_createWebFontTemplate` drops, and a range weight, which the shorthand can't express.
|
|
185
|
+
let shorthand = '';
|
|
186
|
+
if (typeof resource.style === 'string' && CSS_IDENT_RE.test(resource.style)) {
|
|
187
|
+
shorthand += `${resource.style} `;
|
|
188
|
+
}
|
|
189
|
+
if (typeof resource.weight === 'number' && Number.isFinite(resource.weight) || typeof resource.weight === 'string' && (CSS_IDENT_RE.test(resource.weight) || CSS_WEIGHT_NUMERIC_RE.test(resource.weight) && !resource.weight.includes(' '))) {
|
|
190
|
+
shorthand += `${resource.weight} `;
|
|
191
|
+
}
|
|
192
|
+
return withLoadTimeout(document.fonts.load(`${shorthand}1em ${JSON.stringify(fontFamilyName)}`), fontFamilyName);
|
|
131
193
|
}
|
|
132
194
|
};
|
|
195
|
+
const FONT_LOAD_TIMEOUT_MS = 12000;
|
|
196
|
+
function withLoadTimeout(loading, fontFamilyName) {
|
|
197
|
+
let timer;
|
|
198
|
+
const timingOut = new Promise((_resolve, reject)=>{
|
|
199
|
+
timer = setTimeout(()=>{
|
|
200
|
+
reject(new CodedError('ERR_DOWNLOAD', `Fetching the font family "${fontFamilyName}" timed out after ${FONT_LOAD_TIMEOUT_MS}ms. ` + `Check that the font URL is reachable and served with CORS headers.`));
|
|
201
|
+
}, FONT_LOAD_TIMEOUT_MS);
|
|
202
|
+
});
|
|
203
|
+
return Promise.race([
|
|
204
|
+
loading,
|
|
205
|
+
timingOut
|
|
206
|
+
]).finally(()=>clearTimeout(timer)).then(()=>undefined);
|
|
207
|
+
}
|
|
133
208
|
const isServer = process.env.EXPO_OS === 'web' && typeof window === 'undefined';
|
|
134
209
|
function createExpoFontLoader() {
|
|
135
210
|
return ExpoFontLoader;
|
|
@@ -149,9 +224,26 @@ function getStyleElement() {
|
|
|
149
224
|
return styleElement;
|
|
150
225
|
}
|
|
151
226
|
const CSS_IDENT_RE = /^[a-zA-Z_-][\w-]*$/;
|
|
227
|
+
// CSS font weights run from 1 to 1000, alone or as a variable-font range ('100 900').
|
|
228
|
+
// No leading zero: '0400' is not a weight.
|
|
229
|
+
const CSS_WEIGHT_NUMERIC_RE = /^(1000|[1-9]\d{0,2})( (1000|[1-9]\d{0,2}))?$/;
|
|
152
230
|
export function _createWebFontTemplate(fontFamily, resource) {
|
|
153
|
-
const
|
|
154
|
-
|
|
231
|
+
const declarations = [
|
|
232
|
+
`font-family:${JSON.stringify(fontFamily)}`,
|
|
233
|
+
`src:url(${JSON.stringify(resource.uri)})`
|
|
234
|
+
];
|
|
235
|
+
if (typeof resource.display === 'string' && CSS_IDENT_RE.test(resource.display)) {
|
|
236
|
+
declarations.push(`font-display:${resource.display}`);
|
|
237
|
+
}
|
|
238
|
+
if (typeof resource.weight === 'number' && Number.isFinite(resource.weight)) {
|
|
239
|
+
declarations.push(`font-weight:${resource.weight}`);
|
|
240
|
+
} else if (typeof resource.weight === 'string' && (CSS_IDENT_RE.test(resource.weight) || CSS_WEIGHT_NUMERIC_RE.test(resource.weight))) {
|
|
241
|
+
declarations.push(`font-weight:${resource.weight}`);
|
|
242
|
+
}
|
|
243
|
+
if (typeof resource.style === 'string' && CSS_IDENT_RE.test(resource.style)) {
|
|
244
|
+
declarations.push(`font-style:${resource.style}`);
|
|
245
|
+
}
|
|
246
|
+
return `@font-face{${declarations.join(';')}}`;
|
|
155
247
|
}
|
|
156
248
|
function _createWebStyle(fontFamily, resource) {
|
|
157
249
|
const fontStyle = _createWebFontTemplate(fontFamily, resource);
|
|
@@ -167,16 +259,5 @@ function _createWebStyle(fontFamily, resource) {
|
|
|
167
259
|
}
|
|
168
260
|
return styleElement;
|
|
169
261
|
}
|
|
170
|
-
function isFontLoadingListenerSupported() {
|
|
171
|
-
const { userAgent } = window.navigator;
|
|
172
|
-
// WebKit is broken https://github.com/bramstein/fontfaceobserver/issues/95
|
|
173
|
-
const isIOS = !!userAgent.match(/iPad|iPhone/i);
|
|
174
|
-
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
|
175
|
-
// Edge is broken https://github.com/bramstein/fontfaceobserver/issues/109#issuecomment-333356795
|
|
176
|
-
const isEdge = userAgent.includes('Edge');
|
|
177
|
-
// Internet Explorer
|
|
178
|
-
const isIE = userAgent.includes('Trident');
|
|
179
|
-
return !isSafari && !isIOS && !isEdge && !isIE;
|
|
180
|
-
}
|
|
181
262
|
|
|
182
263
|
//# sourceMappingURL=ExpoFontLoader.web.js.map
|