expo-modules-core 1.2.7 → 1.3.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 (180) hide show
  1. package/CHANGELOG.md +28 -5
  2. package/ExpoModulesCore.podspec +1 -0
  3. package/README.md +1 -1
  4. package/android/ExpoModulesCorePlugin.gradle +16 -0
  5. package/android/build.gradle +3 -2
  6. package/android/src/main/cpp/Exceptions.cpp +8 -0
  7. package/android/src/main/cpp/Exceptions.h +11 -0
  8. package/android/src/main/cpp/ExpoModulesHostObject.cpp +22 -5
  9. package/android/src/main/cpp/ExpoModulesHostObject.h +5 -0
  10. package/android/src/main/cpp/JNIInjector.cpp +2 -0
  11. package/android/src/main/cpp/JSIInteropModuleRegistry.cpp +25 -1
  12. package/android/src/main/cpp/JSIInteropModuleRegistry.h +14 -0
  13. package/android/src/main/cpp/JSIObjectWrapper.h +15 -4
  14. package/android/src/main/cpp/JSITypeConverter.h +3 -2
  15. package/android/src/main/cpp/JavaReferencesCache.cpp +2 -0
  16. package/android/src/main/cpp/JavaScriptFunction.cpp +56 -0
  17. package/android/src/main/cpp/JavaScriptFunction.h +54 -0
  18. package/android/src/main/cpp/JavaScriptModuleObject.cpp +225 -105
  19. package/android/src/main/cpp/JavaScriptModuleObject.h +67 -34
  20. package/android/src/main/cpp/JavaScriptObject.cpp +55 -1
  21. package/android/src/main/cpp/JavaScriptObject.h +17 -13
  22. package/android/src/main/cpp/JavaScriptRuntime.cpp +12 -3
  23. package/android/src/main/cpp/JavaScriptRuntime.h +9 -1
  24. package/android/src/main/cpp/JavaScriptValue.cpp +9 -0
  25. package/android/src/main/cpp/JavaScriptValue.h +4 -0
  26. package/android/src/main/cpp/MethodMetadata.cpp +66 -87
  27. package/android/src/main/cpp/MethodMetadata.h +18 -16
  28. package/android/src/main/cpp/ObjectDeallocator.h +25 -0
  29. package/android/src/main/cpp/WeakRuntimeHolder.cpp +7 -0
  30. package/android/src/main/cpp/WeakRuntimeHolder.h +4 -0
  31. package/android/src/main/cpp/types/CppType.h +4 -1
  32. package/android/src/main/cpp/types/FrontendConverter.cpp +58 -0
  33. package/android/src/main/cpp/types/FrontendConverter.h +45 -0
  34. package/android/src/main/cpp/types/FrontendConverterProvider.cpp +3 -0
  35. package/android/src/main/cpp/types/JNIToJSIConverter.cpp +88 -0
  36. package/android/src/main/cpp/types/JNIToJSIConverter.h +22 -0
  37. package/android/src/main/java/com/facebook/react/uimanager/ReactStylesDiffMapHelper.kt +10 -0
  38. package/android/src/main/java/expo/modules/kotlin/AppContext.kt +8 -25
  39. package/android/src/main/java/expo/modules/kotlin/FilteredIterator.kt +37 -0
  40. package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +1 -1
  41. package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +30 -23
  42. package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +0 -3
  43. package/android/src/main/java/expo/modules/kotlin/Utils.kt +21 -0
  44. package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultCaller.kt +21 -1
  45. package/android/src/main/java/expo/modules/kotlin/classcomponent/ClassComponentBuilder.kt +112 -0
  46. package/android/src/main/java/expo/modules/kotlin/classcomponent/ClassDefinitionData.kt +10 -0
  47. package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +21 -0
  48. package/android/src/main/java/expo/modules/kotlin/exception/CommonExceptions.kt +15 -0
  49. package/android/src/main/java/expo/modules/kotlin/functions/AnyFunction.kt +17 -3
  50. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunction.kt +38 -8
  51. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionComponent.kt +3 -2
  52. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromiseComponent.kt +3 -2
  53. package/android/src/main/java/expo/modules/kotlin/functions/SuspendFunctionComponent.kt +1 -0
  54. package/android/src/main/java/expo/modules/kotlin/functions/SyncFunctionComponent.kt +18 -11
  55. package/android/src/main/java/expo/modules/kotlin/jni/CppType.kt +4 -1
  56. package/android/src/main/java/expo/modules/kotlin/jni/JNIDeallocator.kt +73 -0
  57. package/android/src/main/java/expo/modules/kotlin/jni/JSIInteropModuleRegistry.kt +28 -2
  58. package/android/src/main/java/expo/modules/kotlin/jni/JavaCallback.kt +8 -1
  59. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptFunction.kt +48 -0
  60. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptModuleObject.kt +40 -3
  61. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptObject.kt +23 -3
  62. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptValue.kt +26 -1
  63. package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +0 -11
  64. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +26 -16
  65. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +3 -1
  66. package/android/src/main/java/expo/modules/kotlin/sharedobjects/SharedObject.kt +12 -0
  67. package/android/src/main/java/expo/modules/kotlin/sharedobjects/SharedObjectRegistry.kt +62 -0
  68. package/android/src/main/java/expo/modules/kotlin/sharedobjects/SharedObjectTypeConverter.kt +27 -0
  69. package/android/src/main/java/expo/modules/kotlin/types/AnyType.kt +2 -1
  70. package/android/src/main/java/expo/modules/kotlin/types/EitherTypeConverter.kt +7 -6
  71. package/android/src/main/java/expo/modules/kotlin/types/JavaScriptFunctionTypeConverter.kt +22 -0
  72. package/android/src/main/java/expo/modules/kotlin/types/TypeConverter.kt +30 -24
  73. package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +45 -1
  74. package/android/src/main/java/expo/modules/kotlin/types/TypedArrayTypeConverter.kt +3 -2
  75. package/android/src/main/java/expo/modules/kotlin/views/AnyViewProp.kt +3 -1
  76. package/android/src/main/java/expo/modules/kotlin/views/ConcreteViewProp.kt +3 -3
  77. package/android/src/main/java/expo/modules/kotlin/views/FilteredReadableMap.kt +53 -0
  78. package/android/src/main/java/expo/modules/kotlin/views/GroupViewManagerWrapper.kt +25 -5
  79. package/android/src/main/java/expo/modules/kotlin/views/SimpleViewManagerWrapper.kt +25 -5
  80. package/android/src/main/java/expo/modules/kotlin/views/ViewDefinitionBuilder.kt +161 -10
  81. package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinitionBuilder.kt +0 -67
  82. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinition.kt +6 -7
  83. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerWrapperDelegate.kt +40 -3
  84. package/android/src/main/java/expo/modules/kotlin/views/ViewTypeConverter.kt +44 -0
  85. package/android-annotation/build.gradle +45 -0
  86. package/android-annotation/src/main/java/expo/modules/annotation/Config.kt +7 -0
  87. package/android-annotation/src/main/java/expo/modules/annotation/ConverterBinder.kt +7 -0
  88. package/android-annotation-processor/build.gradle +51 -0
  89. package/android-annotation-processor/src/main/java/expo/modules/annotationprocessor/ExpoSymbolProcessor.kt +175 -0
  90. package/android-annotation-processor/src/main/java/expo/modules/annotationprocessor/ExpoSymbolProcessorProvider.kt +10 -0
  91. package/android-annotation-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider +1 -0
  92. package/build/NativeViewManagerAdapter.native.d.ts.map +1 -1
  93. package/build/NativeViewManagerAdapter.native.js +36 -23
  94. package/build/NativeViewManagerAdapter.native.js.map +1 -1
  95. package/build/requireNativeModule.js +2 -2
  96. package/build/requireNativeModule.js.map +1 -1
  97. package/common/cpp/fabric/ExpoViewProps.cpp +18 -3
  98. package/common/cpp/fabric/ExpoViewProps.h +4 -1
  99. package/ios/Fabric/ExpoFabricView.swift +10 -10
  100. package/ios/Fabric/ExpoFabricViewObjC.h +2 -0
  101. package/ios/Fabric/ExpoFabricViewObjC.mm +17 -2
  102. package/ios/JSI/EXJSIInstaller.mm +1 -1
  103. package/ios/JSI/EXJSIUtils.h +5 -0
  104. package/ios/JSI/EXJSIUtils.mm +17 -0
  105. package/ios/JSI/EXJavaScriptRuntime.h +5 -0
  106. package/ios/JSI/EXJavaScriptRuntime.mm +6 -0
  107. package/ios/JSI/EXJavaScriptValue.h +2 -0
  108. package/ios/JSI/EXJavaScriptValue.mm +8 -0
  109. package/ios/JSI/EXJavaScriptWeakObject.mm +29 -8
  110. package/ios/JSI/EXRawJavaScriptFunction.h +24 -0
  111. package/ios/JSI/EXRawJavaScriptFunction.mm +52 -0
  112. package/ios/JSI/ExpoModulesHostObject.mm +1 -1
  113. package/ios/JSI/JavaScriptValue.swift +28 -1
  114. package/ios/ModuleRegistry/EXModuleRegistry.h +0 -4
  115. package/ios/ModuleRegistry/EXModuleRegistry.m +0 -23
  116. package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +0 -16
  117. package/ios/ModuleRegistryProvider/EXModuleRegistryProvider.m +0 -6
  118. package/ios/NativeModulesProxy/EXNativeModulesProxy.mm +1 -31
  119. package/ios/Swift/AppContext.swift +46 -6
  120. package/ios/Swift/Arguments/Convertible.swift +3 -3
  121. package/ios/Swift/Arguments/Convertibles.swift +5 -5
  122. package/ios/Swift/Classes/ClassComponent.swift +18 -12
  123. package/ios/Swift/Classes/ClassRegistry.swift +31 -0
  124. package/ios/Swift/Conversions.swift +19 -3
  125. package/ios/Swift/Convertibles/Convertibles+Color.swift +3 -3
  126. package/ios/Swift/Convertibles/Either.swift +6 -4
  127. package/ios/Swift/DynamicTypes/AnyDynamicType.swift +18 -2
  128. package/ios/Swift/DynamicTypes/DynamicArrayType.swift +3 -3
  129. package/ios/Swift/DynamicTypes/DynamicConvertibleType.swift +2 -2
  130. package/ios/Swift/DynamicTypes/DynamicEnumType.swift +1 -1
  131. package/ios/Swift/DynamicTypes/DynamicJavaScriptType.swift +27 -0
  132. package/ios/Swift/DynamicTypes/DynamicOptionalType.swift +9 -2
  133. package/ios/Swift/DynamicTypes/DynamicRawType.swift +1 -1
  134. package/ios/Swift/DynamicTypes/DynamicSharedObjectType.swift +16 -2
  135. package/ios/Swift/DynamicTypes/DynamicType.swift +6 -0
  136. package/ios/Swift/DynamicTypes/DynamicTypedArrayType.swift +15 -4
  137. package/ios/Swift/DynamicTypes/DynamicViewType.swift +68 -0
  138. package/ios/Swift/ExpoBridgeModule.swift +1 -1
  139. package/ios/Swift/Functions/AnyFunction.swift +5 -4
  140. package/ios/Swift/Functions/AsyncFunctionComponent.swift +22 -19
  141. package/ios/Swift/Functions/ConcurrentFunctionDefinition.swift +29 -13
  142. package/ios/Swift/Functions/SyncFunctionComponent.swift +26 -15
  143. package/ios/Swift/JavaScriptFunction.swift +68 -0
  144. package/ios/Swift/JavaScriptUtils.swift +57 -18
  145. package/ios/Swift/ModuleHolder.swift +22 -10
  146. package/ios/Swift/Modules/ModuleDefinition.swift +8 -2
  147. package/ios/Swift/Objects/JavaScriptObjectBuilder.swift +8 -8
  148. package/ios/Swift/Objects/ObjectDefinition.swift +17 -15
  149. package/ios/Swift/Objects/PropertyComponent.swift +23 -17
  150. package/ios/Swift/Records/AnyField.swift +1 -1
  151. package/ios/Swift/Records/Field.swift +2 -2
  152. package/ios/Swift/Records/Record.swift +5 -5
  153. package/ios/Swift/SharedObjects/SharedObjectRegistry.swift +4 -0
  154. package/ios/Swift/Views/AnyViewProp.swift +1 -1
  155. package/ios/Swift/Views/ComponentData.swift +37 -2
  156. package/ios/Swift/Views/ConcreteViewProp.swift +2 -2
  157. package/ios/Swift/Views/ViewDefinition.swift +39 -0
  158. package/ios/Swift/Views/ViewModuleWrapper.swift +0 -29
  159. package/ios/Tests/ClassComponentSpec.swift +39 -27
  160. package/ios/Tests/ConvertiblesSpec.swift +75 -49
  161. package/ios/Tests/DynamicTypeSpec.swift +29 -27
  162. package/ios/Tests/EitherSpec.swift +9 -7
  163. package/ios/Tests/ExpoModulesSpec.swift +13 -13
  164. package/ios/Tests/FunctionSpec.swift +38 -22
  165. package/ios/Tests/JavaScriptRuntimeSpec.swift +4 -0
  166. package/ios/Tests/PropertyComponentSpec.swift +33 -30
  167. package/ios/Tests/RecordSpec.swift +7 -5
  168. package/ios/Tests/SharedObjectRegistrySpec.swift +12 -12
  169. package/ios/Tests/TypedArraysSpec.swift +1 -1
  170. package/ios/Tests/ViewDefinitionSpec.swift +4 -2
  171. package/package.json +2 -2
  172. package/src/NativeViewManagerAdapter.native.tsx +33 -29
  173. package/src/requireNativeModule.ts +2 -2
  174. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +0 -132
  175. package/ios/EXViewManager.h +0 -21
  176. package/ios/EXViewManager.m +0 -128
  177. package/ios/ModuleRegistryAdapter/EXViewManagerAdapterClassesRegistry.h +0 -17
  178. package/ios/ModuleRegistryAdapter/EXViewManagerAdapterClassesRegistry.m +0 -67
  179. package/ios/ViewManagerAdapter/EXViewManagerAdapter.h +0 -17
  180. package/ios/ViewManagerAdapter/EXViewManagerAdapter.m +0 -45
@@ -0,0 +1,51 @@
1
+ apply plugin: 'java-library'
2
+ apply plugin: 'org.jetbrains.kotlin.jvm'
3
+ apply plugin: 'kotlin'
4
+
5
+ group = 'host.exp.exponent'
6
+ version = '1.1.1'
7
+
8
+ buildscript {
9
+ def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
10
+ if (expoModulesCorePlugin.exists()) {
11
+ apply from: expoModulesCorePlugin
12
+ applyKotlinExpoModulesCorePlugin()
13
+ }
14
+
15
+ // Simple helper that allows the root project to override versions declared by this library.
16
+ ext.safeExtGet = { prop, fallback ->
17
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
18
+ }
19
+
20
+ // Ensures backward compatibility
21
+ ext.getKotlinVersion = {
22
+ if (ext.has("kotlinVersion")) {
23
+ ext.kotlinVersion()
24
+ } else {
25
+ ext.safeExtGet("kotlinVersion", "1.6.10")
26
+ }
27
+ }
28
+
29
+ repositories {
30
+ mavenCentral()
31
+ }
32
+
33
+ dependencies {
34
+ classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${getKotlinVersion()}")
35
+ }
36
+ }
37
+
38
+ java {
39
+ sourceCompatibility = JavaVersion.VERSION_1_8
40
+ targetCompatibility = JavaVersion.VERSION_1_8
41
+ }
42
+
43
+ dependencies {
44
+ implementation project(':expo-modules-core$android-annotation')
45
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}"
46
+
47
+ implementation "com.google.devtools.ksp:symbol-processing-api:${kspVersion()}"
48
+
49
+ implementation 'com.squareup:kotlinpoet:1.12.0'
50
+ implementation 'com.squareup:kotlinpoet-ksp:1.12.0'
51
+ }
@@ -0,0 +1,175 @@
1
+ package expo.modules.annotationprocessor
2
+
3
+ import com.google.devtools.ksp.getVisibility
4
+ import com.google.devtools.ksp.processing.CodeGenerator
5
+ import com.google.devtools.ksp.processing.Dependencies
6
+ import com.google.devtools.ksp.processing.KSPLogger
7
+ import com.google.devtools.ksp.processing.Resolver
8
+ import com.google.devtools.ksp.processing.SymbolProcessor
9
+ import com.google.devtools.ksp.symbol.FunctionKind
10
+ import com.google.devtools.ksp.symbol.KSAnnotated
11
+ import com.google.devtools.ksp.symbol.KSFunctionDeclaration
12
+ import com.google.devtools.ksp.symbol.KSType
13
+ import com.google.devtools.ksp.symbol.KSVisitorVoid
14
+ import com.google.devtools.ksp.symbol.Visibility
15
+ import com.squareup.kotlinpoet.ClassName
16
+ import com.squareup.kotlinpoet.FileSpec
17
+ import com.squareup.kotlinpoet.FunSpec
18
+ import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
19
+ import com.squareup.kotlinpoet.TypeSpec
20
+ import com.squareup.kotlinpoet.ksp.toClassName
21
+ import expo.modules.annotation.Config
22
+ import expo.modules.annotation.ConverterBinder
23
+ import java.io.OutputStreamWriter
24
+ import java.nio.charset.StandardCharsets
25
+
26
+ class ExpoSymbolProcessor(
27
+ private val codeGenerator: CodeGenerator,
28
+ private val logger: KSPLogger,
29
+ ) : SymbolProcessor {
30
+ override fun process(resolver: Resolver): List<KSAnnotated> {
31
+ val symbols = resolver
32
+ .getSymbolsWithAnnotation(ConverterBinder::class.java.name)
33
+ .filterIsInstance<KSFunctionDeclaration>()
34
+
35
+ if (symbols.iterator().hasNext().not()) {
36
+ return emptyList()
37
+ }
38
+
39
+ symbols.forEach { symbol ->
40
+ val clazz = symbol.annotations.find {
41
+ it.shortName.asString() == ConverterBinder::class.java.simpleName
42
+ }!!.arguments[0].value as KSType
43
+
44
+ val parsedClazz = if (clazz.toString() == "Void") {
45
+ null
46
+ } else {
47
+ clazz.toClassName()
48
+ }
49
+
50
+ symbol.accept(ConverterBinderVisitor(parsedClazz, codeGenerator, logger), Unit)
51
+ }
52
+
53
+ return emptyList()
54
+ }
55
+ }
56
+
57
+ class ConverterBinderVisitor(
58
+ private val clazz: ClassName?,
59
+ private val codeGenerator: CodeGenerator,
60
+ private val logger: KSPLogger,
61
+ ) : KSVisitorVoid() {
62
+
63
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
64
+ if (function.functionKind != FunctionKind.TOP_LEVEL ||
65
+ function.getVisibility() != Visibility.PUBLIC
66
+ ) {
67
+ logger.error("ConverterBinder has to be a public top-level function", function)
68
+ return
69
+ }
70
+
71
+ val resolvedType = resolveConverterType(function) ?: return
72
+ val shouldReceiveType = shouldReceiveType(function) ?: return
73
+
74
+ val packageName = "${Config.packageNamePrefix}${resolvedType.packageName}"
75
+ val className = "${resolvedType.simpleName}${Config.classNameSuffix}"
76
+
77
+ val content = generateConverterProvider(
78
+ packageName,
79
+ className,
80
+ function,
81
+ resolvedType,
82
+ shouldReceiveType
83
+ )
84
+
85
+ logger.info("Generating: $packageName.$className")
86
+
87
+ val file = codeGenerator.createNewFile(
88
+ createFileDependencies(function),
89
+ packageName,
90
+ className
91
+ )
92
+ OutputStreamWriter(file, StandardCharsets.UTF_8).use {
93
+ content.writeTo(it)
94
+ }
95
+ }
96
+
97
+ private fun shouldReceiveType(function: KSFunctionDeclaration): Boolean? {
98
+ val argsNumber = function.parameters.size
99
+ if (argsNumber != 0 && argsNumber != 1) {
100
+ logger.error("ConverterBinder cannot receive more then one argument", function)
101
+ return null
102
+ }
103
+
104
+ return function.parameters.firstOrNull()?.type?.toString() == "KType"
105
+ }
106
+
107
+ private fun createFileDependencies(function: KSFunctionDeclaration): Dependencies {
108
+ val containingFile = function.containingFile
109
+ return if (containingFile == null) {
110
+ Dependencies(false)
111
+ } else {
112
+ Dependencies(false, containingFile)
113
+ }
114
+ }
115
+
116
+ private fun resolveConverterType(function: KSFunctionDeclaration): ClassName? {
117
+ if (clazz != null) {
118
+ return clazz
119
+ }
120
+
121
+ val returnType = function.returnType?.resolve()
122
+ if (returnType == null) {
123
+ logger.error("Cannot resolve return type", function)
124
+ return null
125
+ }
126
+
127
+ if (returnType.arguments.size != 1) {
128
+ logger.error("Incorrect return type", function)
129
+ return null
130
+ }
131
+
132
+ val type = returnType.arguments.first().type?.resolve()
133
+ if (type == null) {
134
+ logger.error("Cannot resolve converter inner type", function)
135
+ return null
136
+ }
137
+
138
+ return type.toClassName()
139
+ }
140
+
141
+ private fun generateConverterProvider(
142
+ packageName: String,
143
+ className: String,
144
+ function: KSFunctionDeclaration,
145
+ forType: ClassName,
146
+ receivesType: Boolean
147
+ ): FileSpec {
148
+ val typeConverter = ClassName("expo.modules.kotlin.types", "TypeConverter")
149
+ .parameterizedBy(forType)
150
+ val kType = ClassName("kotlin.reflect", "KType")
151
+
152
+ return FileSpec
153
+ .builder(packageName, className)
154
+ .addType(
155
+ TypeSpec
156
+ .classBuilder(className)
157
+ .addFunction(
158
+ FunSpec
159
+ .builder(Config.converterProviderFunctionName)
160
+ .addParameter("type", kType)
161
+ .returns(typeConverter)
162
+ .apply {
163
+ if (receivesType) {
164
+ addStatement("return ${function.packageName.asString()}.${function.simpleName.asString()}(type)")
165
+ } else {
166
+ addStatement("return ${function.packageName.asString()}.${function.simpleName.asString()}()")
167
+ }
168
+ }
169
+ .build()
170
+ )
171
+ .build()
172
+ )
173
+ .build()
174
+ }
175
+ }
@@ -0,0 +1,10 @@
1
+ package expo.modules.annotationprocessor
2
+
3
+ import com.google.devtools.ksp.processing.SymbolProcessor
4
+ import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
5
+ import com.google.devtools.ksp.processing.SymbolProcessorProvider
6
+
7
+ class ExpoSymbolProcessorProvider : SymbolProcessorProvider {
8
+ override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor =
9
+ ExpoSymbolProcessor(environment.codeGenerator, environment.logger)
10
+ }
@@ -0,0 +1 @@
1
+ expo.modules.annotationprocessor.ExpoSymbolProcessorProvider
@@ -1 +1 @@
1
- {"version":3,"file":"NativeViewManagerAdapter.native.d.ts","sourceRoot":"","sources":["../src/NativeViewManagerAdapter.native.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAqC1B;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CA0BpF"}
1
+ {"version":3,"file":"NativeViewManagerAdapter.native.d.ts","sourceRoot":"","sources":["../src/NativeViewManagerAdapter.native.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAmC1B;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAiDpF"}
@@ -1,5 +1,14 @@
1
1
  import React from 'react';
2
- import { NativeModules, requireNativeComponent } from 'react-native';
2
+ import { findNodeHandle, NativeModules, requireNativeComponent } from 'react-native';
3
+ import { requireNativeModule } from './requireNativeModule';
4
+ // To make the transition from React Native's `requireNativeComponent` to Expo's
5
+ // `requireNativeViewManager` as easy as possible, `requireNativeViewManager` is a drop-in
6
+ // replacement for `requireNativeComponent`.
7
+ //
8
+ // For each view manager, we create a wrapper component that accepts all of the props available to
9
+ // the author of the universal module. This wrapper component splits the props into two sets: props
10
+ // passed to React Native's View (ex: style, testID) and custom view props, which are passed to the
11
+ // adapter view component in a prop called `proxiedProperties`.
3
12
  /**
4
13
  * A map that caches registered native components.
5
14
  */
@@ -32,29 +41,33 @@ export function requireNativeViewManager(viewName) {
32
41
  // manager
33
42
  const reactNativeViewName = `ViewManagerAdapter_${viewName}`;
34
43
  const ReactNativeComponent = requireCachedNativeComponent(reactNativeViewName);
35
- const proxiedPropsNames = viewManagerConfig?.propsNames ?? [];
36
- // Define a component for universal-module authors to access their native view manager
37
- const NativeComponentAdapter = React.forwardRef((props, ref) => {
38
- const nativeProps = omit(props, proxiedPropsNames);
39
- const proxiedProps = pick(props, proxiedPropsNames);
40
- return React.createElement(ReactNativeComponent, { ...nativeProps, proxiedProperties: proxiedProps, ref: ref });
41
- });
42
- NativeComponentAdapter.displayName = `Adapter<${viewName}>`;
43
- return NativeComponentAdapter;
44
- }
45
- function omit(props, propNames) {
46
- const copied = { ...props };
47
- for (const propName of propNames) {
48
- delete copied[propName];
44
+ class NativeComponent extends React.PureComponent {
45
+ static displayName = viewName;
46
+ // This will be accessed from native when the prototype functions are called,
47
+ // in order to find the associated native view.
48
+ nativeTag = null;
49
+ componentDidMount() {
50
+ this.nativeTag = findNodeHandle(this);
51
+ }
52
+ render() {
53
+ return React.createElement(ReactNativeComponent, { ...this.props });
54
+ }
49
55
  }
50
- return copied;
51
- }
52
- function pick(props, propNames) {
53
- return propNames.reduce((prev, curr) => {
54
- if (curr in props) {
55
- prev[curr] = props[curr];
56
+ try {
57
+ const nativeModule = requireNativeModule(viewName);
58
+ const nativeViewPrototype = nativeModule.ViewPrototype;
59
+ if (nativeViewPrototype) {
60
+ // Assign native view functions to the component prototype so they can be accessed from the ref.
61
+ Object.assign(NativeComponent.prototype, nativeViewPrototype);
56
62
  }
57
- return prev;
58
- }, {});
63
+ }
64
+ catch {
65
+ // `requireNativeModule` may throw an error when the native module cannot be found.
66
+ // In some tests we don't mock the entire modules, but we do want to mock native views. For now,
67
+ // until we still have to support the legacy modules proxy and don't have better ways to mock,
68
+ // let's just gracefully skip assigning the prototype functions.
69
+ // See: https://github.com/expo/expo/blob/main/packages/expo-modules-core/src/__tests__/NativeViewManagerAdapter-test.native.tsx
70
+ }
71
+ return NativeComponent;
59
72
  }
60
73
  //# sourceMappingURL=NativeViewManagerAdapter.native.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"NativeViewManagerAdapter.native.js","sourceRoot":"","sources":["../src/NativeViewManagerAdapter.native.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAiB,MAAM,cAAc,CAAC;AAepF;;GAEG;AACH,MAAM,qBAAqB,GAAG,IAAI,GAAG,EAA8B,CAAC;AAEpE;;;;GAIG;AACH,SAAS,4BAA4B,CAAQ,QAAgB;IAC3D,MAAM,qBAAqB,GAAG,qBAAqB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAElE,IAAI,CAAC,qBAAqB,EAAE;QAC1B,MAAM,eAAe,GAAG,sBAAsB,CAAQ,QAAQ,CAAC,CAAC;QAChE,qBAAqB,CAAC,GAAG,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;QACrD,OAAO,eAAe,CAAC;KACxB;IACD,OAAO,qBAAqB,CAAC;AAC/B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,wBAAwB,CAAI,QAAgB;IAC1D,MAAM,EAAE,oBAAoB,EAAE,GAAG,aAAa,CAAC,oBAAoB,CAAC;IACpE,MAAM,iBAAiB,GAAG,oBAAoB,EAAE,CAAC,QAAQ,CAAC,CAAC;IAE3D,IAAI,OAAO,IAAI,CAAC,iBAAiB,EAAE;QACjC,MAAM,wBAAwB,GAAG,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9E,OAAO,CAAC,IAAI,CACV,6CAA6C,QAAQ,8IAA8I,wBAAwB,IAAI,CAChO,CAAC;KACH;IAED,+FAA+F;IAC/F,UAAU;IACV,MAAM,mBAAmB,GAAG,sBAAsB,QAAQ,EAAE,CAAC;IAC7D,MAAM,oBAAoB,GACxB,4BAA4B,CAA2B,mBAAmB,CAAC,CAAC;IAC9E,MAAM,iBAAiB,GAAG,iBAAiB,EAAE,UAAU,IAAI,EAAE,CAAC;IAE9D,sFAAsF;IACtF,MAAM,sBAAsB,GAAG,KAAK,CAAC,UAAU,CAAM,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QAClE,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,EAAE,iBAAiB,CAAC,CAAC;QACnD,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,EAAE,iBAAiB,CAAC,CAAC;QACpD,OAAO,oBAAC,oBAAoB,OAAK,WAAW,EAAE,iBAAiB,EAAE,YAAY,EAAE,GAAG,EAAE,GAAG,GAAI,CAAC;IAC9F,CAAC,CAA2B,CAAC;IAC7B,sBAAsB,CAAC,WAAW,GAAG,WAAW,QAAQ,GAAG,CAAC;IAC5D,OAAO,sBAAsB,CAAC;AAChC,CAAC;AAED,SAAS,IAAI,CAAC,KAA0B,EAAE,SAAmB;IAC3D,MAAM,MAAM,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC;IAC5B,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE;QAChC,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC;KACzB;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,IAAI,CAAC,KAA0B,EAAE,SAAmB;IAC3D,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE;QACrC,IAAI,IAAI,IAAI,KAAK,EAAE;YACjB,IAAI,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;SAC1B;QACD,OAAO,IAAI,CAAC;IACd,CAAC,EAAE,EAAE,CAAC,CAAC;AACT,CAAC","sourcesContent":["import React from 'react';\nimport { NativeModules, requireNativeComponent, HostComponent } from 'react-native';\n\n// To make the transition from React Native's `requireNativeComponent` to Expo's\n// `requireNativeViewManager` as easy as possible, `requireNativeViewManager` is a drop-in\n// replacement for `requireNativeComponent`.\n//\n// For each view manager, we create a wrapper component that accepts all of the props available to\n// the author of the universal module. This wrapper component splits the props into two sets: props\n// passed to React Native's View (ex: style, testID) and custom view props, which are passed to the\n// adapter view component in a prop called `proxiedProperties`.\n\ntype NativeExpoComponentProps = {\n proxiedProperties: object;\n};\n\n/**\n * A map that caches registered native components.\n */\nconst nativeComponentsCache = new Map<string, HostComponent<any>>();\n\n/**\n * Requires a React Native component from cache if possible. This prevents\n * \"Tried to register two views with the same name\" errors on fast refresh, but\n * also when there are multiple versions of the same package with native component.\n */\nfunction requireCachedNativeComponent<Props>(viewName: string): HostComponent<Props> {\n const cachedNativeComponent = nativeComponentsCache.get(viewName);\n\n if (!cachedNativeComponent) {\n const nativeComponent = requireNativeComponent<Props>(viewName);\n nativeComponentsCache.set(viewName, nativeComponent);\n return nativeComponent;\n }\n return cachedNativeComponent;\n}\n\n/**\n * A drop-in replacement for `requireNativeComponent`.\n */\nexport function requireNativeViewManager<P>(viewName: string): React.ComponentType<P> {\n const { viewManagersMetadata } = NativeModules.NativeUnimoduleProxy;\n const viewManagerConfig = viewManagersMetadata?.[viewName];\n\n if (__DEV__ && !viewManagerConfig) {\n const exportedViewManagerNames = Object.keys(viewManagersMetadata).join(', ');\n console.warn(\n `The native view manager required by name (${viewName}) from NativeViewManagerAdapter isn't exported by expo-modules-core. Views of this type may not render correctly. Exported view managers: [${exportedViewManagerNames}].`\n );\n }\n\n // Set up the React Native native component, which is an adapter to the universal module's view\n // manager\n const reactNativeViewName = `ViewManagerAdapter_${viewName}`;\n const ReactNativeComponent =\n requireCachedNativeComponent<NativeExpoComponentProps>(reactNativeViewName);\n const proxiedPropsNames = viewManagerConfig?.propsNames ?? [];\n\n // Define a component for universal-module authors to access their native view manager\n const NativeComponentAdapter = React.forwardRef<any>((props, ref) => {\n const nativeProps = omit(props, proxiedPropsNames);\n const proxiedProps = pick(props, proxiedPropsNames);\n return <ReactNativeComponent {...nativeProps} proxiedProperties={proxiedProps} ref={ref} />;\n }) as React.ComponentType<P>;\n NativeComponentAdapter.displayName = `Adapter<${viewName}>`;\n return NativeComponentAdapter;\n}\n\nfunction omit(props: Record<string, any>, propNames: string[]) {\n const copied = { ...props };\n for (const propName of propNames) {\n delete copied[propName];\n }\n return copied;\n}\n\nfunction pick(props: Record<string, any>, propNames: string[]) {\n return propNames.reduce((prev, curr) => {\n if (curr in props) {\n prev[curr] = props[curr];\n }\n return prev;\n }, {});\n}\n"]}
1
+ {"version":3,"file":"NativeViewManagerAdapter.native.js","sourceRoot":"","sources":["../src/NativeViewManagerAdapter.native.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,sBAAsB,EAAiB,MAAM,cAAc,CAAC;AAEpG,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,gFAAgF;AAChF,0FAA0F;AAC1F,4CAA4C;AAC5C,EAAE;AACF,kGAAkG;AAClG,mGAAmG;AACnG,mGAAmG;AACnG,+DAA+D;AAE/D;;GAEG;AACH,MAAM,qBAAqB,GAAG,IAAI,GAAG,EAA8B,CAAC;AAEpE;;;;GAIG;AACH,SAAS,4BAA4B,CAAQ,QAAgB;IAC3D,MAAM,qBAAqB,GAAG,qBAAqB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAElE,IAAI,CAAC,qBAAqB,EAAE;QAC1B,MAAM,eAAe,GAAG,sBAAsB,CAAQ,QAAQ,CAAC,CAAC;QAChE,qBAAqB,CAAC,GAAG,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;QACrD,OAAO,eAAe,CAAC;KACxB;IACD,OAAO,qBAAqB,CAAC;AAC/B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,wBAAwB,CAAI,QAAgB;IAC1D,MAAM,EAAE,oBAAoB,EAAE,GAAG,aAAa,CAAC,oBAAoB,CAAC;IACpE,MAAM,iBAAiB,GAAG,oBAAoB,EAAE,CAAC,QAAQ,CAAC,CAAC;IAE3D,IAAI,OAAO,IAAI,CAAC,iBAAiB,EAAE;QACjC,MAAM,wBAAwB,GAAG,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9E,OAAO,CAAC,IAAI,CACV,6CAA6C,QAAQ,8IAA8I,wBAAwB,IAAI,CAChO,CAAC;KACH;IAED,+FAA+F;IAC/F,UAAU;IACV,MAAM,mBAAmB,GAAG,sBAAsB,QAAQ,EAAE,CAAC;IAC7D,MAAM,oBAAoB,GAAG,4BAA4B,CAAC,mBAAmB,CAAC,CAAC;IAE/E,MAAM,eAAgB,SAAQ,KAAK,CAAC,aAAgB;QAClD,MAAM,CAAC,WAAW,GAAG,QAAQ,CAAC;QAE9B,6EAA6E;QAC7E,+CAA+C;QAC/C,SAAS,GAAkB,IAAI,CAAC;QAEhC,iBAAiB;YACf,IAAI,CAAC,SAAS,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;QACxC,CAAC;QAED,MAAM;YACJ,OAAO,oBAAC,oBAAoB,OAAK,IAAI,CAAC,KAAK,GAAI,CAAC;QAClD,CAAC;;IAGH,IAAI;QACF,MAAM,YAAY,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QACnD,MAAM,mBAAmB,GAAG,YAAY,CAAC,aAAa,CAAC;QAEvD,IAAI,mBAAmB,EAAE;YACvB,gGAAgG;YAChG,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC;SAC/D;KACF;IAAC,MAAM;QACN,mFAAmF;QACnF,gGAAgG;QAChG,8FAA8F;QAC9F,gEAAgE;QAChE,gIAAgI;KACjI;IAED,OAAO,eAAe,CAAC;AACzB,CAAC","sourcesContent":["import React from 'react';\nimport { findNodeHandle, NativeModules, requireNativeComponent, HostComponent } from 'react-native';\n\nimport { requireNativeModule } from './requireNativeModule';\n\n// To make the transition from React Native's `requireNativeComponent` to Expo's\n// `requireNativeViewManager` as easy as possible, `requireNativeViewManager` is a drop-in\n// replacement for `requireNativeComponent`.\n//\n// For each view manager, we create a wrapper component that accepts all of the props available to\n// the author of the universal module. This wrapper component splits the props into two sets: props\n// passed to React Native's View (ex: style, testID) and custom view props, which are passed to the\n// adapter view component in a prop called `proxiedProperties`.\n\n/**\n * A map that caches registered native components.\n */\nconst nativeComponentsCache = new Map<string, HostComponent<any>>();\n\n/**\n * Requires a React Native component from cache if possible. This prevents\n * \"Tried to register two views with the same name\" errors on fast refresh, but\n * also when there are multiple versions of the same package with native component.\n */\nfunction requireCachedNativeComponent<Props>(viewName: string): HostComponent<Props> {\n const cachedNativeComponent = nativeComponentsCache.get(viewName);\n\n if (!cachedNativeComponent) {\n const nativeComponent = requireNativeComponent<Props>(viewName);\n nativeComponentsCache.set(viewName, nativeComponent);\n return nativeComponent;\n }\n return cachedNativeComponent;\n}\n\n/**\n * A drop-in replacement for `requireNativeComponent`.\n */\nexport function requireNativeViewManager<P>(viewName: string): React.ComponentType<P> {\n const { viewManagersMetadata } = NativeModules.NativeUnimoduleProxy;\n const viewManagerConfig = viewManagersMetadata?.[viewName];\n\n if (__DEV__ && !viewManagerConfig) {\n const exportedViewManagerNames = Object.keys(viewManagersMetadata).join(', ');\n console.warn(\n `The native view manager required by name (${viewName}) from NativeViewManagerAdapter isn't exported by expo-modules-core. Views of this type may not render correctly. Exported view managers: [${exportedViewManagerNames}].`\n );\n }\n\n // Set up the React Native native component, which is an adapter to the universal module's view\n // manager\n const reactNativeViewName = `ViewManagerAdapter_${viewName}`;\n const ReactNativeComponent = requireCachedNativeComponent(reactNativeViewName);\n\n class NativeComponent extends React.PureComponent<P> {\n static displayName = viewName;\n\n // This will be accessed from native when the prototype functions are called,\n // in order to find the associated native view.\n nativeTag: number | null = null;\n\n componentDidMount(): void {\n this.nativeTag = findNodeHandle(this);\n }\n\n render(): React.ReactNode {\n return <ReactNativeComponent {...this.props} />;\n }\n }\n\n try {\n const nativeModule = requireNativeModule(viewName);\n const nativeViewPrototype = nativeModule.ViewPrototype;\n\n if (nativeViewPrototype) {\n // Assign native view functions to the component prototype so they can be accessed from the ref.\n Object.assign(NativeComponent.prototype, nativeViewPrototype);\n }\n } catch {\n // `requireNativeModule` may throw an error when the native module cannot be found.\n // In some tests we don't mock the entire modules, but we do want to mock native views. For now,\n // until we still have to support the legacy modules proxy and don't have better ways to mock,\n // let's just gracefully skip assigning the prototype functions.\n // See: https://github.com/expo/expo/blob/main/packages/expo-modules-core/src/__tests__/NativeViewManagerAdapter-test.native.tsx\n }\n\n return NativeComponent;\n}\n"]}
@@ -9,8 +9,8 @@ import NativeModulesProxy from './NativeModulesProxy';
9
9
  * @throws Error when there is no native module with given name.
10
10
  */
11
11
  export function requireNativeModule(moduleName) {
12
- const nativeModule = global.expo?.modules?.[moduleName] ??
13
- global.ExpoModules?.[moduleName] ??
12
+ const nativeModule = globalThis.expo?.modules?.[moduleName] ??
13
+ globalThis.ExpoModules?.[moduleName] ??
14
14
  NativeModulesProxy[moduleName];
15
15
  if (!nativeModule) {
16
16
  throw new Error(`Cannot find native module '${moduleName}'`);
@@ -1 +1 @@
1
- {"version":3,"file":"requireNativeModule.js","sourceRoot":"","sources":["../src/requireNativeModule.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,MAAM,sBAAsB,CAAC;AAyBtD;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CAAmB,UAAkB;IACtE,MAAM,YAAY,GAChB,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,UAAU,CAAC;QAClC,MAAM,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC;QAChC,kBAAkB,CAAC,UAAU,CAAC,CAAC;IAEjC,IAAI,CAAC,YAAY,EAAE;QACjB,MAAM,IAAI,KAAK,CAAC,8BAA8B,UAAU,GAAG,CAAC,CAAC;KAC9D;IACD,OAAO,YAAY,CAAC;AACtB,CAAC","sourcesContent":["import NativeModulesProxy from './NativeModulesProxy';\n\ntype ExpoObject = {\n modules:\n | undefined\n | {\n [key: string]: any;\n };\n};\n\ndeclare global {\n // eslint-disable-next-line no-var\n var expo: ExpoObject | undefined;\n\n /**\n * @deprecated `global.ExpoModules` is deprecated, use `global.expo.modules` instead.\n */\n // eslint-disable-next-line no-var\n var ExpoModules:\n | undefined\n | {\n [key: string]: any;\n };\n}\n\n/**\n * Imports the native module registered with given name. In the first place it tries to load\n * the module installed through the JSI host object and then falls back to the bridge proxy module.\n * Notice that the modules loaded from the proxy may not support some features like synchronous functions.\n *\n * @param moduleName Name of the requested native module.\n * @returns Object representing the native module.\n * @throws Error when there is no native module with given name.\n */\nexport function requireNativeModule<ModuleType = any>(moduleName: string): ModuleType {\n const nativeModule: ModuleType =\n global.expo?.modules?.[moduleName] ??\n global.ExpoModules?.[moduleName] ??\n NativeModulesProxy[moduleName];\n\n if (!nativeModule) {\n throw new Error(`Cannot find native module '${moduleName}'`);\n }\n return nativeModule;\n}\n"]}
1
+ {"version":3,"file":"requireNativeModule.js","sourceRoot":"","sources":["../src/requireNativeModule.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,MAAM,sBAAsB,CAAC;AAyBtD;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CAAmB,UAAkB;IACtE,MAAM,YAAY,GAChB,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,UAAU,CAAC;QACtC,UAAU,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC;QACpC,kBAAkB,CAAC,UAAU,CAAC,CAAC;IAEjC,IAAI,CAAC,YAAY,EAAE;QACjB,MAAM,IAAI,KAAK,CAAC,8BAA8B,UAAU,GAAG,CAAC,CAAC;KAC9D;IACD,OAAO,YAAY,CAAC;AACtB,CAAC","sourcesContent":["import NativeModulesProxy from './NativeModulesProxy';\n\ntype ExpoObject = {\n modules:\n | undefined\n | {\n [key: string]: any;\n };\n};\n\ndeclare global {\n // eslint-disable-next-line no-var\n var expo: ExpoObject | undefined;\n\n /**\n * @deprecated `global.ExpoModules` is deprecated, use `global.expo.modules` instead.\n */\n // eslint-disable-next-line no-var\n var ExpoModules:\n | undefined\n | {\n [key: string]: any;\n };\n}\n\n/**\n * Imports the native module registered with given name. In the first place it tries to load\n * the module installed through the JSI host object and then falls back to the bridge proxy module.\n * Notice that the modules loaded from the proxy may not support some features like synchronous functions.\n *\n * @param moduleName Name of the requested native module.\n * @returns Object representing the native module.\n * @throws Error when there is no native module with given name.\n */\nexport function requireNativeModule<ModuleType = any>(moduleName: string): ModuleType {\n const nativeModule: ModuleType =\n globalThis.expo?.modules?.[moduleName] ??\n globalThis.ExpoModules?.[moduleName] ??\n NativeModulesProxy[moduleName];\n\n if (!nativeModule) {\n throw new Error(`Cannot find native module '${moduleName}'`);\n }\n return nativeModule;\n}\n"]}
@@ -7,12 +7,27 @@ namespace react = facebook::react;
7
7
 
8
8
  namespace expo {
9
9
 
10
+ /**
11
+ Borrows the props map from the source props and applies the update given in the raw props.
12
+ */
13
+ std::unordered_map<std::string, folly::dynamic> propsMapFromProps(const ExpoViewProps &sourceProps, const react::RawProps &rawProps) {
14
+ // Move the contents of the source props map – the source props instance will not be used anymore.
15
+ std::unordered_map<std::string, folly::dynamic> propsMap = std::move(sourceProps.propsMap);
16
+
17
+ // Iterate over values in the raw props object.
18
+ // Note that it contains only updated props.
19
+ rawProps.iterateOverValues([&propsMap](react::RawPropsPropNameHash hash, const char *name, const react::RawValue &value) {
20
+ std::string propName(name);
21
+ propsMap[propName] = (folly::dynamic)value;
22
+ });
23
+
24
+ return propsMap;
25
+ }
26
+
10
27
  ExpoViewProps::ExpoViewProps(const react::PropsParserContext &context,
11
28
  const ExpoViewProps &sourceProps,
12
29
  const react::RawProps &rawProps)
13
30
  : ViewProps(context, sourceProps, rawProps),
14
- proxiedProperties(
15
- facebook::react::convertRawProp(context, rawProps, "proxiedProperties", sourceProps.proxiedProperties, {})) {
16
- }
31
+ propsMap(propsMapFromProps(sourceProps, rawProps)) {}
17
32
 
18
33
  } // namespace expo
@@ -19,7 +19,10 @@ public:
19
19
 
20
20
  #pragma mark - Props
21
21
 
22
- const folly::dynamic proxiedProperties;
22
+ /**
23
+ A map with props stored as `folly::dynamic` objects.
24
+ */
25
+ std::unordered_map<std::string, folly::dynamic> propsMap;
23
26
  };
24
27
 
25
28
  } // namespace expo
@@ -21,13 +21,6 @@ public class ExpoFabricView: ExpoFabricViewObjC {
21
21
  return appContext?.moduleRegistry.get(moduleHolderForName: moduleName)
22
22
  }
23
23
 
24
- /**
25
- The view manager of the associated legacy module.
26
- Not available if the module is registered in the new module registry.
27
- */
28
- lazy var legacyViewManager = appContext?.legacyModuleRegistry?.getAllViewManagers()
29
- .filter { $0.viewName() == moduleName }
30
- .first
31
24
 
32
25
  /**
33
26
  A dictionary of prop objects that contain prop setters.
@@ -52,7 +45,7 @@ public class ExpoFabricView: ExpoFabricViewObjC {
52
45
  // MARK: - ExpoFabricViewInterface
53
46
 
54
47
  public override func updateProps(_ props: [String: Any]) {
55
- guard let view = contentView, let propsDict = viewManagerPropDict else {
48
+ guard let view = contentView, let context = appContext, let propsDict = viewManagerPropDict else {
56
49
  return
57
50
  }
58
51
  for (key, prop) in propsDict {
@@ -61,7 +54,7 @@ public class ExpoFabricView: ExpoFabricViewObjC {
61
54
  // TODO: @tsapeta: Figure out better way to rethrow errors from here.
62
55
  // Adding `throws` keyword to the function results in different
63
56
  // method signature in Objective-C. Maybe just call `RCTLogError`?
64
- try? prop.set(value: Conversions.fromNSObject(newValue), onView: view)
57
+ try? prop.set(value: Conversions.fromNSObject(newValue), onView: view, appContext: context)
65
58
  }
66
59
  }
67
60
 
@@ -75,6 +68,13 @@ public class ExpoFabricView: ExpoFabricViewObjC {
75
68
  viewManager.callLifecycleMethods(withType: .didUpdateProps, forView: view)
76
69
  }
77
70
 
71
+ /**
72
+ Returns a bool value whether the view supports prop with the given name.
73
+ */
74
+ public override func supportsProp(withName name: String) -> Bool {
75
+ return viewManagerPropDict?.index(forKey: name) != nil
76
+ }
77
+
78
78
  /**
79
79
  The function that is called by Fabric when the view is unmounted and is being enqueued for recycling.
80
80
  It can also be called on app reload, so be careful to wipe out any dependencies specific to the currently running AppContext.
@@ -110,7 +110,7 @@ public class ExpoFabricView: ExpoFabricViewObjC {
110
110
  guard let appContext = appContext else {
111
111
  fatalError(Exceptions.AppContextLost().reason)
112
112
  }
113
- guard let view = moduleHolder?.definition.viewManager?.createView(appContext: appContext) ?? legacyViewManager?.view() else {
113
+ guard let view = moduleHolder?.definition.viewManager?.createView(appContext: appContext) else {
114
114
  fatalError("Cannot create a view from module '\(moduleName)'")
115
115
  }
116
116
  // Setting the content view automatically adds the view as a subview.
@@ -37,6 +37,8 @@
37
37
 
38
38
  - (void)viewDidUpdateProps;
39
39
 
40
+ - (BOOL)supportsPropWithName:(nonnull NSString *)name;
41
+
40
42
  - (void)prepareForRecycle;
41
43
 
42
44
  #pragma mark - Methods injected to the class in runtime
@@ -140,9 +140,18 @@ static std::unordered_map<std::string, ExpoViewComponentDescriptor::Flavor> _com
140
140
  - (void)updateProps:(const facebook::react::Props::Shared &)props oldProps:(const facebook::react::Props::Shared &)oldProps
141
141
  {
142
142
  const auto &newViewProps = *std::static_pointer_cast<ExpoViewProps const>(props);
143
- NSDictionary<NSString *, id> *proxiedProperties = convertFollyDynamicToId(newViewProps.proxiedProperties);
143
+ NSMutableDictionary<NSString *, id> *propsMap = [[NSMutableDictionary alloc] init];
144
144
 
145
- [self updateProps:proxiedProperties];
145
+ for (const auto &item : newViewProps.propsMap) {
146
+ NSString *propName = [NSString stringWithUTF8String:item.first.c_str()];
147
+
148
+ // Ignore props inherited from the base view and Yoga.
149
+ if ([self supportsPropWithName:propName]) {
150
+ propsMap[propName] = convertFollyDynamicToId(item.second);
151
+ }
152
+ }
153
+
154
+ [self updateProps:propsMap];
146
155
  [super updateProps:props oldProps:oldProps];
147
156
  [self viewDidUpdateProps];
148
157
  }
@@ -174,6 +183,12 @@ static std::unordered_map<std::string, ExpoViewComponentDescriptor::Flavor> _com
174
183
  // Implemented in `ExpoFabricView.swift`
175
184
  }
176
185
 
186
+ - (BOOL)supportsPropWithName:(nonnull NSString *)name
187
+ {
188
+ // Implemented in `ExpoFabricView.swift`
189
+ return NO;
190
+ }
191
+
177
192
  #pragma mark - Methods to override in the subclass
178
193
 
179
194
  - (nullable EXAppContext *)__injectedAppContext
@@ -35,7 +35,7 @@ static NSString *modulesHostObjectLegacyPropertyName = @"ExpoModules";
35
35
 
36
36
  + (BOOL)installExpoModulesHostObject:(nonnull EXAppContext *)appContext
37
37
  {
38
- EXJavaScriptRuntime *runtime = [appContext runtime];
38
+ EXJavaScriptRuntime *runtime = [appContext _runtime];
39
39
 
40
40
  // The runtime may be unavailable, e.g. remote debugger is enabled or it hasn't been set yet.
41
41
  if (!runtime) {
@@ -26,6 +26,11 @@ using ClassConstructor = std::function<void(jsi::Runtime &runtime, const jsi::Va
26
26
 
27
27
  std::shared_ptr<jsi::Function> createClass(jsi::Runtime &runtime, const char *name, ClassConstructor constructor);
28
28
 
29
+ /**
30
+ Creates a new object, using the provided object as the prototype.
31
+ */
32
+ std::shared_ptr<jsi::Object> createObjectWithPrototype(jsi::Runtime &runtime, std::shared_ptr<jsi::Object> prototype);
33
+
29
34
  #pragma mark - Weak objects
30
35
 
31
36
  /**
@@ -115,6 +115,23 @@ std::shared_ptr<jsi::Function> createClass(jsi::Runtime &runtime, const char *na
115
115
  return std::make_shared<jsi::Function>(klass.asFunction(runtime));
116
116
  }
117
117
 
118
+ std::shared_ptr<jsi::Object> createObjectWithPrototype(jsi::Runtime &runtime, std::shared_ptr<jsi::Object> prototype) {
119
+ // Get the "Object" class.
120
+ jsi::Object objectClass = runtime
121
+ .global()
122
+ .getPropertyAsObject(runtime, "Object");
123
+
124
+ // Call "Object.create(prototype)" to create an object with the given prototype without calling the constructor.
125
+ jsi::Object object = objectClass
126
+ .getPropertyAsFunction(runtime, "create")
127
+ .callWithThis(runtime, objectClass, {
128
+ jsi::Value(runtime, *prototype)
129
+ })
130
+ .asObject(runtime);
131
+
132
+ return std::make_shared<jsi::Object>(std::move(object));
133
+ }
134
+
118
135
  #pragma mark - Weak objects
119
136
 
120
137
  bool isWeakRefSupported(jsi::Runtime &runtime) {
@@ -103,6 +103,11 @@ typedef void (^ClassConstructorBlock)(EXJavaScriptObject * _Nonnull thisValue, N
103
103
  - (nonnull EXJavaScriptObject *)createClass:(nonnull NSString *)name
104
104
  constructor:(nonnull ClassConstructorBlock)constructor;
105
105
 
106
+ /**
107
+ Creates a new object, using the provided object as the prototype.
108
+ */
109
+ - (nullable EXJavaScriptObject *)createObjectWithPrototype:(nonnull EXJavaScriptObject *)prototype;
110
+
106
111
  #pragma mark - Script evaluation
107
112
 
108
113
  /**
@@ -160,6 +160,12 @@ static NSString *mainObjectPropertyName = @"expo";
160
160
  return [[EXJavaScriptObject alloc] initWith:klass runtime:self];
161
161
  }
162
162
 
163
+ - (nullable EXJavaScriptObject *)createObjectWithPrototype:(nonnull EXJavaScriptObject *)prototype
164
+ {
165
+ std::shared_ptr<jsi::Object> object = expo::createObjectWithPrototype(*_runtime, [prototype getShared]);
166
+ return object ? [[EXJavaScriptObject alloc] initWith:object runtime:self] : nil;
167
+ }
168
+
163
169
  #pragma mark - Script evaluation
164
170
 
165
171
  - (nonnull EXJavaScriptValue *)evaluateScript:(nonnull NSString *)scriptSource
@@ -9,6 +9,7 @@ namespace jsi = facebook::jsi;
9
9
  #endif // __cplusplus
10
10
 
11
11
  @class EXJavaScriptRuntime;
12
+ @class EXRawJavaScriptFunction;
12
13
  @class EXJavaScriptTypedArray;
13
14
 
14
15
  /**
@@ -49,6 +50,7 @@ NS_SWIFT_NAME(JavaScriptValue)
49
50
  - (nonnull NSArray<EXJavaScriptValue *> *)getArray;
50
51
  - (nonnull NSDictionary<NSString *, id> *)getDictionary;
51
52
  - (nonnull EXJavaScriptObject *)getObject;
53
+ - (nonnull EXRawJavaScriptFunction *)getFunction;
52
54
  - (nullable EXJavaScriptTypedArray *)getTypedArray;
53
55
 
54
56
  #pragma mark - Helpers
@@ -3,6 +3,7 @@
3
3
  #import <ExpoModulesCore/EXJSIConversions.h>
4
4
  #import <ExpoModulesCore/EXJavaScriptValue.h>
5
5
  #import <ExpoModulesCore/EXJavaScriptRuntime.h>
6
+ #import <ExpoModulesCore/EXRawJavaScriptFunction.h>
6
7
  #import <ExpoModulesCore/EXJavaScriptTypedArray.h>
7
8
  #import <ExpoModulesCore/TypedArray.h>
8
9
 
@@ -142,6 +143,13 @@
142
143
  return [[EXJavaScriptObject alloc] initWith:objectPtr runtime:_runtime];
143
144
  }
144
145
 
146
+ - (nonnull EXRawJavaScriptFunction *)getFunction
147
+ {
148
+ jsi::Runtime *runtime = [_runtime get];
149
+ std::shared_ptr<jsi::Function> functionPtr = std::make_shared<jsi::Function>(_value->asObject(*runtime).asFunction(*runtime));
150
+ return [[EXRawJavaScriptFunction alloc] initWith:functionPtr runtime:_runtime];
151
+ }
152
+
145
153
  - (nullable EXJavaScriptTypedArray *)getTypedArray
146
154
  {
147
155
  if (![self isTypedArray]) {