expo-modules-core 0.6.5 → 0.9.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 (219) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/README.md +1 -1
  3. package/android/ExpoModulesCorePlugin.gradle +15 -0
  4. package/android/build.gradle +31 -15
  5. package/android/src/main/java/expo/modules/adapters/react/NativeModulesProxy.java +5 -5
  6. package/android/src/main/java/expo/modules/adapters/react/services/UIManagerModuleWrapper.java +13 -0
  7. package/android/src/main/java/expo/modules/core/ViewManager.java +9 -0
  8. package/android/src/main/java/expo/modules/core/interfaces/JavaScriptContextProvider.java +4 -0
  9. package/android/src/main/java/expo/modules/core/interfaces/ReactActivityHandler.java +37 -1
  10. package/android/src/main/java/expo/modules/core/interfaces/ReactNativeHostHandler.java +30 -0
  11. package/android/src/main/java/expo/modules/core/interfaces/services/UIManager.java +2 -0
  12. package/android/src/main/java/expo/modules/kotlin/AppContext.kt +23 -5
  13. package/android/src/main/java/expo/modules/kotlin/DynamicExtenstions.kt +5 -3
  14. package/android/src/main/java/expo/modules/kotlin/KPromiseWrapper.kt +3 -8
  15. package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +24 -9
  16. package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +12 -7
  17. package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +23 -1
  18. package/android/src/main/java/expo/modules/kotlin/Promise.kt +1 -1
  19. package/android/src/main/java/expo/modules/kotlin/callbacks/Callback.kt +5 -0
  20. package/android/src/main/java/expo/modules/kotlin/callbacks/ViewCallback.kt +39 -0
  21. package/android/src/main/java/expo/modules/kotlin/callbacks/ViewCallbackDelegate.kt +27 -0
  22. package/android/src/main/java/expo/modules/kotlin/defaultmodules/ErrorManagerModule.kt +25 -0
  23. package/android/src/main/java/expo/modules/kotlin/events/EventEmitter.kt +13 -0
  24. package/android/src/main/java/expo/modules/kotlin/events/KModuleEventEmitterWrapper.kt +102 -0
  25. package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +93 -9
  26. package/android/src/main/java/expo/modules/kotlin/exception/ExceptionDecorator.kt +11 -0
  27. package/android/src/main/java/expo/modules/kotlin/{methods/AnyMethod.kt → functions/AnyFunction.kt} +18 -18
  28. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunction.kt +15 -0
  29. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionBuilder.kt +170 -0
  30. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromise.kt +15 -0
  31. package/android/src/main/java/expo/modules/kotlin/functions/AsyncSuspendFunction.kt +36 -0
  32. package/android/src/main/java/expo/modules/kotlin/modules/DefinitionMarker.kt +4 -0
  33. package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +17 -2
  34. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +416 -43
  35. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +2 -2
  36. package/android/src/main/java/expo/modules/kotlin/records/FieldValidator.kt +139 -0
  37. package/android/src/main/java/expo/modules/kotlin/records/RecordTypeConverter.kt +71 -15
  38. package/android/src/main/java/expo/modules/kotlin/records/Required.kt +5 -0
  39. package/android/src/main/java/expo/modules/kotlin/records/ValidationBinder.kt +110 -0
  40. package/android/src/main/java/expo/modules/kotlin/records/Validators.kt +61 -0
  41. package/android/src/main/java/expo/modules/kotlin/types/ArrayTypeConverter.kt +11 -5
  42. package/android/src/main/java/expo/modules/kotlin/types/JSTypeConverter.kt +35 -0
  43. package/android/src/main/java/expo/modules/kotlin/types/JSTypeConverterHelper.kt +148 -0
  44. package/android/src/main/java/expo/modules/kotlin/types/ListTypeConverter.kt +10 -4
  45. package/android/src/main/java/expo/modules/kotlin/types/MapTypeConverter.kt +12 -6
  46. package/android/src/main/java/expo/modules/kotlin/types/PairTypeConverter.kt +29 -13
  47. package/android/src/main/java/expo/modules/kotlin/types/TypeConverter.kt +2 -1
  48. package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +9 -1
  49. package/android/src/main/java/expo/modules/kotlin/views/CallbacksDefinition.kt +3 -0
  50. package/android/src/main/java/expo/modules/kotlin/views/GroupViewManagerWrapper.kt +71 -0
  51. package/android/src/main/java/expo/modules/kotlin/views/SimpleViewManagerWrapper.kt +22 -0
  52. package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinition.kt +18 -0
  53. package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinitionBuilder.kt +114 -0
  54. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinition.kt +30 -2
  55. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +81 -2
  56. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerWrapperDelegate.kt +62 -2
  57. package/build/EventEmitter.d.ts +1 -0
  58. package/build/EventEmitter.d.ts.map +1 -0
  59. package/build/NativeModulesProxy.d.ts +1 -0
  60. package/build/NativeModulesProxy.d.ts.map +1 -0
  61. package/build/NativeModulesProxy.native.d.ts +1 -4
  62. package/build/NativeModulesProxy.native.d.ts.map +1 -0
  63. package/build/NativeModulesProxy.native.js +1 -14
  64. package/build/NativeModulesProxy.native.js.map +1 -1
  65. package/build/NativeModulesProxy.types.d.ts +1 -3
  66. package/build/NativeModulesProxy.types.d.ts.map +1 -0
  67. package/build/NativeModulesProxy.types.js.map +1 -1
  68. package/build/NativeViewManagerAdapter.d.ts +1 -0
  69. package/build/NativeViewManagerAdapter.d.ts.map +1 -0
  70. package/build/NativeViewManagerAdapter.native.d.ts +1 -0
  71. package/build/NativeViewManagerAdapter.native.d.ts.map +1 -0
  72. package/build/NativeViewManagerAdapter.native.js +9 -33
  73. package/build/NativeViewManagerAdapter.native.js.map +1 -1
  74. package/build/PermissionsHook.d.ts +1 -0
  75. package/build/PermissionsHook.d.ts.map +1 -0
  76. package/build/PermissionsInterface.d.ts +1 -0
  77. package/build/PermissionsInterface.d.ts.map +1 -0
  78. package/build/Platform.d.ts +1 -0
  79. package/build/Platform.d.ts.map +1 -0
  80. package/build/SyntheticPlatformEmitter.d.ts +1 -0
  81. package/build/SyntheticPlatformEmitter.d.ts.map +1 -0
  82. package/build/SyntheticPlatformEmitter.web.d.ts +1 -0
  83. package/build/SyntheticPlatformEmitter.web.d.ts.map +1 -0
  84. package/build/deprecate.d.ts +1 -0
  85. package/build/deprecate.d.ts.map +1 -0
  86. package/build/environment/browser.d.ts +1 -0
  87. package/build/environment/browser.d.ts.map +1 -0
  88. package/build/environment/browser.web.d.ts +1 -0
  89. package/build/environment/browser.web.d.ts.map +1 -0
  90. package/build/errors/CodedError.d.ts +1 -0
  91. package/build/errors/CodedError.d.ts.map +1 -0
  92. package/build/errors/UnavailabilityError.d.ts +1 -0
  93. package/build/errors/UnavailabilityError.d.ts.map +1 -0
  94. package/build/index.d.ts +3 -0
  95. package/build/index.d.ts.map +1 -0
  96. package/build/index.js +2 -0
  97. package/build/index.js.map +1 -1
  98. package/build/requireNativeModule.d.ts +16 -0
  99. package/build/requireNativeModule.d.ts.map +1 -0
  100. package/build/requireNativeModule.js +18 -0
  101. package/build/requireNativeModule.js.map +1 -0
  102. package/build/sweet/NativeErrorManager.d.ts +3 -0
  103. package/build/sweet/NativeErrorManager.d.ts.map +1 -0
  104. package/build/sweet/NativeErrorManager.js +3 -0
  105. package/build/sweet/NativeErrorManager.js.map +1 -0
  106. package/build/sweet/setUpErrorManager.fx.d.ts +2 -0
  107. package/build/sweet/setUpErrorManager.fx.d.ts.map +1 -0
  108. package/build/sweet/setUpErrorManager.fx.js +11 -0
  109. package/build/sweet/setUpErrorManager.fx.js.map +1 -0
  110. package/ios/AppDelegates/EXAppDelegatesLoader.m +4 -8
  111. package/ios/AppDelegates/ExpoAppDelegate.swift +22 -20
  112. package/ios/EXAppDefines.h +1 -0
  113. package/ios/EXAppDefines.m +6 -0
  114. package/ios/EXUtilities.h +2 -0
  115. package/ios/EXUtilities.m +12 -0
  116. package/ios/ExpoModulesCore.h +4 -0
  117. package/ios/ExpoModulesCore.podspec +4 -2
  118. package/ios/Interfaces/FileSystem/EXFileSystemInterface.h +1 -1
  119. package/ios/Interfaces/TaskManager/EXTaskServiceInterface.h +1 -0
  120. package/ios/JSI/{JSIConversions.h → EXJSIConversions.h} +5 -0
  121. package/ios/JSI/{JSIConversions.mm → EXJSIConversions.mm} +21 -1
  122. package/ios/JSI/{JSIInstaller.h → EXJSIInstaller.h} +10 -0
  123. package/ios/JSI/EXJSIInstaller.mm +17 -0
  124. package/ios/JSI/EXJSIUtils.h +19 -0
  125. package/ios/JSI/EXJSIUtils.mm +89 -0
  126. package/ios/JSI/EXJavaScriptObject.h +97 -0
  127. package/ios/JSI/EXJavaScriptObject.mm +121 -0
  128. package/ios/JSI/EXJavaScriptRuntime.h +73 -0
  129. package/ios/JSI/EXJavaScriptRuntime.mm +153 -0
  130. package/ios/JSI/EXJavaScriptValue.h +57 -0
  131. package/ios/JSI/EXJavaScriptValue.mm +166 -0
  132. package/ios/JSI/ExpoModulesHostObject.h +33 -0
  133. package/ios/JSI/ExpoModulesHostObject.mm +41 -0
  134. package/ios/JSI/JavaScriptRuntime.swift +32 -0
  135. package/ios/JSI/JavaScriptValue.swift +94 -0
  136. package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +3 -23
  137. package/ios/NativeModulesProxy/EXNativeModulesProxy.h +2 -2
  138. package/ios/NativeModulesProxy/EXNativeModulesProxy.mm +101 -75
  139. package/ios/RCTComponentData+Privates.h +12 -0
  140. package/ios/ReactDelegates/EXReactCompatibleHelpers.h +18 -0
  141. package/ios/ReactDelegates/EXReactCompatibleHelpers.m +19 -0
  142. package/ios/ReactDelegates/ExpoReactDelegate.swift +3 -3
  143. package/ios/ReactDelegates/ExpoReactDelegateHandler.swift +4 -4
  144. package/ios/ReactDelegates/ModulePriorities.swift +1 -1
  145. package/ios/Swift/AppContext.swift +57 -4
  146. package/ios/Swift/Arguments/AnyArgumentType.swift +1 -1
  147. package/ios/Swift/Arguments/ArgumentType.swift +4 -0
  148. package/ios/Swift/Arguments/Convertibles.swift +13 -13
  149. package/ios/Swift/Arguments/Types/EnumArgumentType.swift +11 -17
  150. package/ios/Swift/Arguments/Types/PromiseArgumentType.swift +1 -1
  151. package/ios/Swift/Arguments/Types/RawArgumentType.swift +2 -2
  152. package/ios/Swift/Conversions.swift +51 -56
  153. package/ios/Swift/EventListener.swift +8 -10
  154. package/ios/Swift/Events/Callback.swift +66 -0
  155. package/ios/Swift/Events/Event.swift +43 -0
  156. package/ios/Swift/Exceptions/ChainableException.swift +51 -0
  157. package/ios/Swift/{CodedError.swift → Exceptions/CodedError.swift} +1 -12
  158. package/ios/Swift/Exceptions/Exception.swift +62 -0
  159. package/ios/Swift/Exceptions/ExceptionOrigin.swift +28 -0
  160. package/ios/Swift/Exceptions/GenericException.swift +20 -0
  161. package/ios/Swift/Exceptions/UnexpectedException.swift +16 -0
  162. package/ios/Swift/Functions/AnyFunction.swift +16 -1
  163. package/ios/Swift/Functions/AsyncFunctionComponent.swift +182 -0
  164. package/ios/Swift/Functions/ConcreteFunction.swift +52 -59
  165. package/ios/Swift/Functions/SyncFunctionComponent.swift +181 -0
  166. package/ios/Swift/JavaScriptUtils.swift +99 -0
  167. package/ios/Swift/ModuleHolder.swift +69 -18
  168. package/ios/Swift/ModuleRegistry.swift +4 -1
  169. package/ios/Swift/Modules/AnyModule.swift +0 -1
  170. package/ios/Swift/Modules/ModuleDefinition.swift +4 -13
  171. package/ios/Swift/Modules/ModuleDefinitionBuilder.swift +0 -1
  172. package/ios/Swift/Modules/ModuleDefinitionComponents.swift +54 -220
  173. package/ios/Swift/ModulesProvider.swift +3 -11
  174. package/ios/Swift/Objects/ObjectDefinition.swift +30 -0
  175. package/ios/Swift/Objects/ObjectDefinitionComponents.swift +257 -0
  176. package/ios/Swift/Promise.swift +8 -3
  177. package/ios/Swift/Records/AnyField.swift +7 -0
  178. package/ios/Swift/Records/Field.swift +24 -19
  179. package/ios/Swift/Records/FieldOption.swift +1 -1
  180. package/ios/Swift/Records/Record.swift +12 -4
  181. package/ios/Swift/SwiftInteropBridge.swift +53 -15
  182. package/ios/Swift/Views/AnyViewProp.swift +1 -1
  183. package/ios/Swift/Views/ComponentData.swift +96 -0
  184. package/ios/Swift/Views/ConcreteViewProp.swift +6 -8
  185. package/ios/Swift/Views/ExpoView.swift +8 -0
  186. package/ios/Swift/Views/ViewFactory.swift +1 -1
  187. package/ios/Swift/Views/ViewManagerDefinition.swift +23 -2
  188. package/ios/Swift/Views/ViewManagerDefinitionBuilder.swift +0 -1
  189. package/ios/Swift/Views/ViewManagerDefinitionComponents.swift +49 -0
  190. package/ios/Swift/Views/ViewModuleWrapper.swift +5 -2
  191. package/ios/Swift.h +5 -0
  192. package/ios/Tests/ArgumentTypeSpec.swift +5 -7
  193. package/ios/Tests/ConstantsSpec.swift +6 -7
  194. package/ios/Tests/ConvertiblesSpec.swift +35 -36
  195. package/ios/Tests/ExceptionsSpec.swift +111 -0
  196. package/ios/Tests/ExpoModulesSpec.swift +75 -0
  197. package/ios/Tests/FunctionSpec.swift +21 -25
  198. package/ios/Tests/FunctionWithConvertiblesSpec.swift +4 -5
  199. package/ios/Tests/JavaScriptObjectSpec.swift +97 -0
  200. package/ios/Tests/JavaScriptRuntimeSpec.swift +94 -0
  201. package/ios/Tests/Mocks/ModuleMocks.swift +1 -1
  202. package/ios/Tests/Mocks/ModulesProviderMock.swift +0 -1
  203. package/ios/Tests/ModuleEventListenersSpec.swift +16 -17
  204. package/ios/Tests/ModuleRegistrySpec.swift +2 -3
  205. package/ios/Tests/RecordSpec.swift +9 -20
  206. package/package.json +3 -3
  207. package/src/NativeModulesProxy.native.ts +2 -22
  208. package/src/NativeModulesProxy.types.ts +0 -8
  209. package/src/NativeViewManagerAdapter.native.tsx +12 -28
  210. package/src/index.ts +4 -0
  211. package/src/requireNativeModule.ts +29 -0
  212. package/src/sweet/NativeErrorManager.ts +2 -0
  213. package/src/sweet/setUpErrorManager.fx.ts +12 -0
  214. package/android/src/main/java/expo/modules/kotlin/events/KEventEmitterWrapper.kt +0 -26
  215. package/android/src/main/java/expo/modules/kotlin/methods/Method.kt +0 -14
  216. package/android/src/main/java/expo/modules/kotlin/methods/PromiseMethod.kt +0 -15
  217. package/ios/JSI/ExpoModulesProxySpec.h +0 -24
  218. package/ios/JSI/ExpoModulesProxySpec.mm +0 -135
  219. package/ios/JSI/JSIInstaller.mm +0 -22
@@ -1,15 +1,17 @@
1
1
  package expo.modules.kotlin.types
2
2
 
3
3
  import com.facebook.react.bridge.Dynamic
4
+ import expo.modules.kotlin.exception.CollectionElementCastException
5
+ import expo.modules.kotlin.exception.exceptionDecorator
4
6
  import expo.modules.kotlin.recycle
5
7
  import kotlin.reflect.KType
6
8
 
7
9
  class ListTypeConverter(
8
10
  converterProvider: TypeConverterProvider,
9
- type: KType,
10
- ) : TypeConverter<List<*>>(type.isMarkedNullable) {
11
+ private val listType: KType,
12
+ ) : TypeConverter<List<*>>(listType.isMarkedNullable) {
11
13
  private val elementConverter = converterProvider.obtainTypeConverter(
12
- requireNotNull(type.arguments.first().type) {
14
+ requireNotNull(listType.arguments.first().type) {
13
15
  "The list type should contain the type of elements."
14
16
  }
15
17
  )
@@ -18,7 +20,11 @@ class ListTypeConverter(
18
20
  val jsArray = value.asArray()
19
21
  return List(jsArray.size()) { index ->
20
22
  jsArray.getDynamic(index).recycle {
21
- elementConverter.convert(this)
23
+ exceptionDecorator({ cause ->
24
+ CollectionElementCastException(listType, listType.arguments.first().type!!, type, cause)
25
+ }) {
26
+ elementConverter.convert(this)
27
+ }
22
28
  }
23
29
  }
24
30
  }
@@ -4,22 +4,24 @@ package expo.modules.kotlin.types
4
4
 
5
5
  import com.facebook.react.bridge.Dynamic
6
6
  import com.facebook.react.bridge.DynamicFromObject
7
+ import expo.modules.kotlin.exception.CollectionElementCastException
8
+ import expo.modules.kotlin.exception.exceptionDecorator
7
9
  import expo.modules.kotlin.recycle
8
10
  import kotlin.reflect.KType
9
11
  import kotlin.reflect.typeOf
10
12
 
11
13
  class MapTypeConverter(
12
14
  converterProvider: TypeConverterProvider,
13
- type: KType
14
- ) : TypeConverter<Map<*, *>>(type.isMarkedNullable) {
15
+ private val mapType: KType
16
+ ) : TypeConverter<Map<*, *>>(mapType.isMarkedNullable) {
15
17
  init {
16
- require(type.arguments.first().type == typeOf<String>()) {
17
- "The map key type should be String, but received ${type.arguments.first()}."
18
+ require(mapType.arguments.first().type == typeOf<String>()) {
19
+ "The map key type should be String, but received ${mapType.arguments.first()}."
18
20
  }
19
21
  }
20
22
 
21
23
  private val valueConverter = converterProvider.obtainTypeConverter(
22
- requireNotNull(type.arguments.getOrNull(1)?.type) {
24
+ requireNotNull(mapType.arguments.getOrNull(1)?.type) {
23
25
  "The map type should contain the key type."
24
26
  }
25
27
  )
@@ -30,7 +32,11 @@ class MapTypeConverter(
30
32
 
31
33
  jsMap.entryIterator.forEach { (key, value) ->
32
34
  DynamicFromObject(value).recycle {
33
- result[key] = valueConverter.convert(this)
35
+ exceptionDecorator({ cause ->
36
+ CollectionElementCastException(mapType, mapType.arguments[1].type!!, type, cause)
37
+ }) {
38
+ result[key] = valueConverter.convert(this)
39
+ }
34
40
  }
35
41
  }
36
42
 
@@ -1,28 +1,44 @@
1
1
  package expo.modules.kotlin.types
2
2
 
3
3
  import com.facebook.react.bridge.Dynamic
4
+ import com.facebook.react.bridge.ReadableArray
5
+ import expo.modules.kotlin.exception.CollectionElementCastException
6
+ import expo.modules.kotlin.exception.exceptionDecorator
7
+ import expo.modules.kotlin.recycle
4
8
  import kotlin.reflect.KType
5
9
 
6
10
  class PairTypeConverter(
7
11
  converterProvider: TypeConverterProvider,
8
- type: KType,
9
- ) : TypeConverter<Pair<*, *>>(type.isMarkedNullable) {
10
- private val firstConverter = converterProvider.obtainTypeConverter(
11
- requireNotNull(type.arguments.getOrNull(0)?.type) {
12
- "The pair type should contain the type of the first parameter."
13
- }
14
- )
15
- private val secondConverter = converterProvider.obtainTypeConverter(
16
- requireNotNull(type.arguments.getOrNull(1)?.type) {
17
- "The pair type should contain the type of the second parameter."
18
- }
12
+ private val pairType: KType,
13
+ ) : TypeConverter<Pair<*, *>>(pairType.isMarkedNullable) {
14
+ private val converters = listOf(
15
+ converterProvider.obtainTypeConverter(
16
+ requireNotNull(pairType.arguments.getOrNull(0)?.type) {
17
+ "The pair type should contain the type of the first parameter."
18
+ }
19
+ ),
20
+ converterProvider.obtainTypeConverter(
21
+ requireNotNull(pairType.arguments.getOrNull(1)?.type) {
22
+ "The pair type should contain the type of the second parameter."
23
+ }
24
+ )
19
25
  )
20
26
 
21
27
  override fun convertNonOptional(value: Dynamic): Pair<*, *> {
22
28
  val jsArray = value.asArray()
23
29
  return Pair(
24
- firstConverter.convert(jsArray.getDynamic(0)),
25
- secondConverter.convert(jsArray.getDynamic(1)),
30
+ convertElement(jsArray, 0),
31
+ convertElement(jsArray, 1)
26
32
  )
27
33
  }
34
+
35
+ private fun convertElement(array: ReadableArray, index: Int): Any? {
36
+ return array.getDynamic(index).recycle {
37
+ exceptionDecorator({ cause ->
38
+ CollectionElementCastException(pairType, pairType.arguments[index].type!!, type, cause)
39
+ }) {
40
+ converters[index].convert(this)
41
+ }
42
+ }
43
+ }
28
44
  }
@@ -1,6 +1,7 @@
1
1
  package expo.modules.kotlin.types
2
2
 
3
3
  import com.facebook.react.bridge.Dynamic
4
+ import expo.modules.kotlin.exception.NullArgumentException
4
5
 
5
6
  abstract class TypeConverter<Type : Any>(
6
7
  private val isOptional: Boolean
@@ -10,7 +11,7 @@ abstract class TypeConverter<Type : Any>(
10
11
  if (isOptional) {
11
12
  return null
12
13
  }
13
- throw IllegalArgumentException()
14
+ throw NullArgumentException()
14
15
  }
15
16
  return convertNonOptional(value)
16
17
  }
@@ -35,6 +35,7 @@ fun convert(value: Dynamic, type: KType): Any? {
35
35
 
36
36
  object TypeConverterProviderImpl : TypeConverterProvider {
37
37
  private val cachedConverters = createCashedConverters(false) + createCashedConverters(true)
38
+ private val cachedRecordConverters = mutableMapOf<KClass<*>, TypeConverter<*>>()
38
39
 
39
40
  override fun obtainTypeConverter(type: KType): TypeConverter<*> {
40
41
  cachedConverters[type]?.let {
@@ -68,8 +69,15 @@ object TypeConverterProviderImpl : TypeConverterProvider {
68
69
  return EnumTypeConverter(kClass as KClass<Enum<*>>, type.isMarkedNullable)
69
70
  }
70
71
 
72
+ val cachedConverter = cachedRecordConverters[kClass]
73
+ if (cachedConverter != null) {
74
+ return cachedConverter
75
+ }
76
+
71
77
  if (kClass.isSubclassOf(Record::class)) {
72
- return RecordTypeConverter<Record>(this, type)
78
+ val converter = RecordTypeConverter<Record>(this, type)
79
+ cachedRecordConverters[kClass] = converter
80
+ return converter
73
81
  }
74
82
 
75
83
  throw MissingTypeConverter(type)
@@ -0,0 +1,3 @@
1
+ package expo.modules.kotlin.views
2
+
3
+ class CallbacksDefinition(val names: Array<out String>)
@@ -3,9 +3,11 @@ package expo.modules.kotlin.views
3
3
  import android.view.View
4
4
  import android.view.ViewGroup
5
5
  import com.facebook.react.bridge.ReadableMap
6
+ import com.facebook.react.common.MapBuilder
6
7
  import com.facebook.react.uimanager.ThemedReactContext
7
8
  import com.facebook.react.uimanager.ViewGroupManager
8
9
  import com.facebook.react.uimanager.annotations.ReactProp
10
+ import expo.modules.core.utilities.ifNull
9
11
 
10
12
  class GroupViewManagerWrapper(
11
13
  override val viewWrapperDelegate: ViewManagerWrapperDelegate
@@ -19,4 +21,73 @@ class GroupViewManagerWrapper(
19
21
  fun setProxiedProperties(view: View, proxiedProperties: ReadableMap) {
20
22
  viewWrapperDelegate.setProxiedProperties(view, proxiedProperties)
21
23
  }
24
+
25
+ override fun onDropViewInstance(view: ViewGroup) {
26
+ super.onDropViewInstance(view)
27
+ viewWrapperDelegate.onDestroy(view)
28
+ }
29
+
30
+ override fun getExportedCustomDirectEventTypeConstants(): Map<String, Any>? {
31
+ viewWrapperDelegate.getExportedCustomDirectEventTypeConstants()?.let {
32
+ val directEvents = super.getExportedCustomDirectEventTypeConstants() ?: emptyMap()
33
+ val builder = MapBuilder.builder<String, Any>()
34
+ directEvents.forEach { event ->
35
+ builder.put(event.key, event.value)
36
+ }
37
+ it.forEach { event ->
38
+ builder.put(event.key, event.value)
39
+ }
40
+ return builder.build()
41
+ }
42
+
43
+ return super.getExportedCustomDirectEventTypeConstants()
44
+ }
45
+
46
+ override fun addView(parent: ViewGroup, child: View, index: Int) {
47
+ viewWrapperDelegate
48
+ .viewGroupDefinition
49
+ ?.addViewAction
50
+ ?.invoke(parent, child, index)
51
+ .ifNull {
52
+ super.addView(parent, child, index)
53
+ }
54
+ }
55
+
56
+ override fun getChildCount(parent: ViewGroup): Int {
57
+ return viewWrapperDelegate.viewGroupDefinition
58
+ ?.getChildCountAction
59
+ ?.invoke(parent)
60
+ .ifNull {
61
+ super.getChildCount(parent)
62
+ }
63
+ }
64
+
65
+ override fun getChildAt(parent: ViewGroup, index: Int): View? {
66
+ viewWrapperDelegate.viewGroupDefinition
67
+ ?.getChildAtAction
68
+ ?.let {
69
+ return it.invoke(parent, index)
70
+ }
71
+ .ifNull {
72
+ return super.getChildAt(parent, index)
73
+ }
74
+ }
75
+
76
+ override fun removeViewAt(parent: ViewGroup, index: Int) {
77
+ viewWrapperDelegate.viewGroupDefinition
78
+ ?.removeViewAtAction
79
+ ?.invoke(parent, index)
80
+ .ifNull {
81
+ super.removeViewAt(parent, index)
82
+ }
83
+ }
84
+
85
+ override fun removeView(parent: ViewGroup, view: View) {
86
+ viewWrapperDelegate.viewGroupDefinition
87
+ ?.removeViewAction
88
+ ?.invoke(parent, view)
89
+ .ifNull {
90
+ super.removeView(parent, view)
91
+ }
92
+ }
22
93
  }
@@ -2,6 +2,7 @@ package expo.modules.kotlin.views
2
2
 
3
3
  import android.view.View
4
4
  import com.facebook.react.bridge.ReadableMap
5
+ import com.facebook.react.common.MapBuilder
5
6
  import com.facebook.react.uimanager.SimpleViewManager
6
7
  import com.facebook.react.uimanager.ThemedReactContext
7
8
  import com.facebook.react.uimanager.annotations.ReactProp
@@ -18,4 +19,25 @@ class SimpleViewManagerWrapper(
18
19
  fun setProxiedProperties(view: View, proxiedProperties: ReadableMap) {
19
20
  viewWrapperDelegate.setProxiedProperties(view, proxiedProperties)
20
21
  }
22
+
23
+ override fun onDropViewInstance(view: View) {
24
+ super.onDropViewInstance(view)
25
+ viewWrapperDelegate.onDestroy(view)
26
+ }
27
+
28
+ override fun getExportedCustomDirectEventTypeConstants(): Map<String, Any>? {
29
+ viewWrapperDelegate.getExportedCustomDirectEventTypeConstants()?.let {
30
+ val directEvents = super.getExportedCustomDirectEventTypeConstants() ?: emptyMap()
31
+ val builder = MapBuilder.builder<String, Any>()
32
+ directEvents.forEach { event ->
33
+ builder.put(event.key, event.value)
34
+ }
35
+ it.forEach { event ->
36
+ builder.put(event.key, event.value)
37
+ }
38
+ return builder.build()
39
+ }
40
+
41
+ return super.getExportedCustomDirectEventTypeConstants()
42
+ }
21
43
  }
@@ -0,0 +1,18 @@
1
+ package expo.modules.kotlin.views
2
+
3
+ import android.view.View
4
+ import android.view.ViewGroup
5
+
6
+ class ViewGroupDefinition(
7
+ val addViewAction: AddViewAction?,
8
+ val getChildAtAction: GetChildAtAction?,
9
+ val getChildCountAction: GetChildCountAction?,
10
+ val removeViewAction: RemoveViewAction?,
11
+ val removeViewAtAction: RemoveViewAtAction?
12
+ )
13
+
14
+ internal typealias AddViewAction = (parent: ViewGroup, child: View, index: Int) -> Unit
15
+ internal typealias GetChildAtAction = (parent: ViewGroup, index: Int) -> View?
16
+ internal typealias GetChildCountAction = (parent: ViewGroup) -> Int
17
+ internal typealias RemoveViewAction = (parent: ViewGroup, childToRemove: View) -> Unit
18
+ internal typealias RemoveViewAtAction = (parent: ViewGroup, index: Int) -> Unit
@@ -0,0 +1,114 @@
1
+ @file:OptIn(ExperimentalStdlibApi::class)
2
+ @file:Suppress("FunctionName")
3
+
4
+ package expo.modules.kotlin.views
5
+
6
+ import android.view.View
7
+ import android.view.ViewGroup
8
+ import expo.modules.kotlin.modules.DefinitionMarker
9
+
10
+ @DefinitionMarker
11
+ class ViewGroupDefinitionBuilder {
12
+ @PublishedApi
13
+ internal var addViewAction: AddViewAction? = null
14
+
15
+ @PublishedApi
16
+ internal var getChildAtAction: GetChildAtAction? = null
17
+
18
+ @PublishedApi
19
+ internal var getChildCountAction: GetChildCountAction? = null
20
+
21
+ @PublishedApi
22
+ internal var removeViewAction: RemoveViewAction? = null
23
+
24
+ @PublishedApi
25
+ internal var removeViewAtAction: RemoveViewAtAction? = null
26
+
27
+ fun build() = ViewGroupDefinition(
28
+ addViewAction,
29
+ getChildAtAction,
30
+ getChildCountAction,
31
+ removeViewAction,
32
+ removeViewAtAction
33
+ )
34
+
35
+ @Deprecated(
36
+ message = "The 'addChildView' component was renamed to 'AddChildView'.",
37
+ replaceWith = ReplaceWith("AddChildView(body)")
38
+ )
39
+ inline fun <reified ParentViewType : ViewGroup, reified ChildViewType : View> addChildView(
40
+ noinline body: (parent: ParentViewType, child: ChildViewType, index: Int) -> Unit
41
+ ) = AddChildView(body)
42
+
43
+ inline fun <reified ParentViewType : ViewGroup, reified ChildViewType : View> AddChildView(
44
+ noinline body: (parent: ParentViewType, child: ChildViewType, index: Int) -> Unit
45
+ ) {
46
+ addViewAction = { parent, child, index ->
47
+ body(parent as ParentViewType, child as ChildViewType, index)
48
+ }
49
+ }
50
+
51
+ @Deprecated(
52
+ message = "The 'getChildCount' component was renamed to 'GetChildCount'.",
53
+ replaceWith = ReplaceWith("GetChildCount(body)")
54
+ )
55
+ inline fun <reified ParentViewType : ViewGroup> getChildCount(
56
+ noinline body: (view: ParentViewType) -> Int
57
+ ) = GetChildCount(body)
58
+
59
+ inline fun <reified ParentViewType : ViewGroup> GetChildCount(
60
+ noinline body: (view: ParentViewType) -> Int
61
+ ) {
62
+ getChildCountAction = { view ->
63
+ body(view as ParentViewType)
64
+ }
65
+ }
66
+
67
+ @Deprecated(
68
+ message = "The 'getChildViewAt' component was renamed to 'GetChildViewAt'.",
69
+ replaceWith = ReplaceWith("GetChildViewAt(body)")
70
+ )
71
+ inline fun <reified ParentViewType : ViewGroup, reified ChildViewType : View> getChildViewAt(
72
+ noinline body: (view: ParentViewType, index: Int) -> ChildViewType?
73
+ ) = GetChildViewAt(body)
74
+
75
+ inline fun <reified ParentViewType : ViewGroup, reified ChildViewType : View> GetChildViewAt(
76
+ noinline body: (view: ParentViewType, index: Int) -> ChildViewType?
77
+ ) {
78
+ getChildAtAction = { view, index ->
79
+ body(view as ParentViewType, index)
80
+ }
81
+ }
82
+
83
+ @Deprecated(
84
+ message = "The 'removeChildViewAt' component was renamed to 'RemoveChildViewAt'.",
85
+ replaceWith = ReplaceWith("RemoveChildViewAt(body)")
86
+ )
87
+ inline fun <reified ParentViewType : ViewGroup> removeChildViewAt(
88
+ noinline body: (view: ParentViewType, index: Int) -> Unit
89
+ ) = RemoveChildViewAt(body)
90
+
91
+ inline fun <reified ParentViewType : ViewGroup> RemoveChildViewAt(
92
+ noinline body: (view: ParentViewType, index: Int) -> Unit
93
+ ) {
94
+ removeViewAtAction = { view, index ->
95
+ body(view as ParentViewType, index)
96
+ }
97
+ }
98
+
99
+ @Deprecated(
100
+ message = "The 'removeChildView' component was renamed to 'RemoveChildView'.",
101
+ replaceWith = ReplaceWith("RemoveChildView(body)")
102
+ )
103
+ inline fun <reified ParentViewType : ViewGroup, reified ChildViewType : View> removeChildView(
104
+ noinline body: (parent: ParentViewType, child: ChildViewType) -> Unit
105
+ ) = RemoveChildView(body)
106
+
107
+ inline fun <reified ParentViewType : ViewGroup, reified ChildViewType : View> RemoveChildView(
108
+ noinline body: (parent: ParentViewType, child: ChildViewType) -> Unit
109
+ ) {
110
+ removeViewAction = { view, child ->
111
+ body(view as ParentViewType, child as ChildViewType)
112
+ }
113
+ }
114
+ }
@@ -4,18 +4,27 @@ import android.content.Context
4
4
  import android.util.Log
5
5
  import android.view.View
6
6
  import android.view.ViewGroup
7
+ import com.facebook.react.bridge.ReactContext
7
8
  import com.facebook.react.bridge.ReadableMap
9
+ import expo.modules.adapters.react.NativeModulesProxy
8
10
  import expo.modules.core.ViewManager
11
+ import expo.modules.kotlin.exception.CodedException
12
+ import expo.modules.kotlin.exception.UnexpectedException
9
13
  import expo.modules.kotlin.recycle
10
14
 
11
15
  class ViewManagerDefinition(
12
16
  private val viewFactory: (Context) -> View,
13
17
  private val viewType: Class<out View>,
14
- private val props: Map<String, AnyViewProp>
18
+ private val props: Map<String, AnyViewProp>,
19
+ val onViewDestroys: ((View) -> Unit)? = null,
20
+ val callbacksDefinition: CallbacksDefinition? = null,
21
+ val viewGroupDefinition: ViewGroupDefinition? = null
15
22
  ) {
16
23
 
17
24
  fun createView(context: Context): View = viewFactory(context)
18
25
 
26
+ val propsNames: List<String> = props.keys.toList()
27
+
19
28
  fun getViewManagerType(): ViewManager.ViewManagerType {
20
29
  return if (ViewGroup::class.java.isAssignableFrom(viewType)) {
21
30
  ViewManager.ViewManagerType.GROUP
@@ -33,9 +42,28 @@ class ViewManagerDefinition(
33
42
  try {
34
43
  propDelegate.set(this, onView)
35
44
  } catch (exception: Throwable) {
36
- Log.e("ExpoModulesCore", "Cannot set the $key prop on the ${viewType.simpleName}.", exception)
45
+ Log.e("ExpoModulesCore", "Cannot set the '$key' prop on the '${viewType.simpleName}'.", exception)
46
+
47
+ handleException(
48
+ onView,
49
+ when (exception) {
50
+ is CodedException -> exception
51
+ else -> UnexpectedException(exception)
52
+ }
53
+ )
37
54
  }
38
55
  }
39
56
  }
40
57
  }
58
+
59
+ fun handleException(view: View, exception: CodedException) {
60
+ val reactContext = (view.context as? ReactContext) ?: return
61
+ val nativeModulesProxy = reactContext
62
+ .catalystInstance
63
+ ?.getNativeModule("NativeUnimoduleProxy") as? NativeModulesProxy
64
+ ?: return
65
+ val appContext = nativeModulesProxy.kotlinInteropModuleRegistry.appContext
66
+
67
+ appContext.errorManager?.reportExceptionToLogBox(exception)
68
+ }
41
69
  }
@@ -1,35 +1,84 @@
1
1
  @file:OptIn(ExperimentalStdlibApi::class)
2
+ @file:Suppress("FunctionName")
2
3
 
3
4
  package expo.modules.kotlin.views
4
5
 
5
6
  import android.content.Context
6
7
  import android.view.View
8
+ import expo.modules.kotlin.modules.DefinitionMarker
7
9
  import expo.modules.kotlin.types.toAnyType
8
10
  import kotlin.reflect.typeOf
9
11
 
12
+ @DefinitionMarker
10
13
  class ViewManagerDefinitionBuilder {
11
14
  @PublishedApi
12
15
  internal var viewFactory: ((Context) -> View)? = null
16
+
13
17
  @PublishedApi
14
18
  internal var viewType: Class<out View>? = null
19
+
15
20
  @PublishedApi
16
21
  internal var props = mutableMapOf<String, AnyViewProp>()
17
22
 
23
+ @PublishedApi
24
+ internal var onViewDestroys: ((View) -> Unit)? = null
25
+
26
+ @PublishedApi
27
+ internal var viewGroupDefinition: ViewGroupDefinition? = null
28
+ private var callbacksDefinition: CallbacksDefinition? = null
29
+
18
30
  fun build(): ViewManagerDefinition =
19
31
  ViewManagerDefinition(
20
32
  requireNotNull(viewFactory),
21
33
  requireNotNull(viewType),
22
- props
34
+ props,
35
+ onViewDestroys,
36
+ callbacksDefinition,
37
+ viewGroupDefinition
23
38
  )
24
39
 
25
- inline fun <reified ViewType : View> view(noinline body: (Context) -> ViewType) {
40
+ @Deprecated(
41
+ message = "The 'view' component was renamed to 'View'.",
42
+ replaceWith = ReplaceWith("View(body)")
43
+ )
44
+ inline fun <reified ViewType : View> view(noinline body: (Context) -> ViewType) = View(body)
45
+
46
+ /**
47
+ * Defines the factory creating a native view when the module is used as a view.
48
+ */
49
+ inline fun <reified ViewType : View> View(noinline body: (Context) -> ViewType) {
26
50
  viewType = ViewType::class.java
27
51
  viewFactory = body
28
52
  }
29
53
 
54
+ @Deprecated(
55
+ message = "The 'onViewDestroys' component was renamed to 'OnViewDestroys'.",
56
+ replaceWith = ReplaceWith("OnViewDestroys(body)")
57
+ )
58
+ inline fun <reified ViewType : View> onViewDestroys(noinline body: (view: ViewType) -> Unit) = OnViewDestroys(body)
59
+
60
+ /**
61
+ * Creates view's lifecycle listener that is called right after the view isn't longer used by React Native.
62
+ */
63
+ inline fun <reified ViewType : View> OnViewDestroys(noinline body: (view: ViewType) -> Unit) {
64
+ onViewDestroys = { body(it as ViewType) }
65
+ }
66
+
67
+ @Deprecated(
68
+ message = "The 'prop' component was renamed to 'Prop'.",
69
+ replaceWith = ReplaceWith("Prop(body)")
70
+ )
30
71
  inline fun <reified ViewType : View, reified PropType> prop(
31
72
  name: String,
32
73
  noinline body: (view: ViewType, prop: PropType) -> Unit
74
+ ) = Prop(name, body)
75
+
76
+ /**
77
+ * Creates a view prop that defines its name and setter.
78
+ */
79
+ inline fun <reified ViewType : View, reified PropType> Prop(
80
+ name: String,
81
+ noinline body: (view: ViewType, prop: PropType) -> Unit
33
82
  ) {
34
83
  props[name] = ConcreteViewProp(
35
84
  name,
@@ -37,4 +86,34 @@ class ViewManagerDefinitionBuilder {
37
86
  body
38
87
  )
39
88
  }
89
+
90
+ @Deprecated(
91
+ message = "The 'events' component was renamed to 'Events'.",
92
+ replaceWith = ReplaceWith("Events(callbacks)")
93
+ )
94
+ fun events(vararg callbacks: String) = Events(*callbacks)
95
+
96
+ /**
97
+ * Defines prop names that should be treated as callbacks.
98
+ */
99
+ fun Events(vararg callbacks: String) {
100
+ callbacksDefinition = CallbacksDefinition(callbacks)
101
+ }
102
+
103
+ @Deprecated(
104
+ message = "The 'groupView' component was renamed to 'GroupView'.",
105
+ replaceWith = ReplaceWith("GroupView(callbacks)")
106
+ )
107
+ inline fun groupView(body: ViewGroupDefinitionBuilder.() -> Unit) = GroupView(body)
108
+
109
+ /**
110
+ * Creates the group view definition that scopes group view-related definitions.
111
+ */
112
+ inline fun GroupView(body: ViewGroupDefinitionBuilder.() -> Unit) {
113
+ require(viewGroupDefinition == null) { "The viewManager definition may have exported only one groupView definition." }
114
+
115
+ val groupViewDefinitionBuilder = ViewGroupDefinitionBuilder()
116
+ body.invoke(groupViewDefinitionBuilder)
117
+ viewGroupDefinition = groupViewDefinitionBuilder.build()
118
+ }
40
119
  }