expo-modules-core 1.1.1 → 1.2.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.
- package/CHANGELOG.md +18 -0
- package/android/CMakeLists.txt +9 -25
- package/android/ExpoModulesCorePlugin.gradle +0 -1
- package/android/build.gradle +13 -22
- package/android/legacy/CMakeLists.txt +2 -0
- package/android/src/fabric/CMakeLists.txt +12 -9
- package/android/src/main/cpp/JavaReferencesCache.cpp +6 -0
- package/android/src/main/cpp/JavaReferencesCache.h +20 -6
- package/android/src/main/cpp/JavaScriptModuleObject.cpp +9 -9
- package/android/src/main/cpp/JavaScriptModuleObject.h +5 -3
- package/android/src/main/cpp/JavaScriptRuntime.cpp +4 -0
- package/android/src/main/cpp/MethodMetadata.cpp +13 -2
- package/android/src/main/cpp/types/CppType.h +12 -11
- package/android/src/main/cpp/types/FrontendConverter.cpp +23 -0
- package/android/src/main/cpp/types/FrontendConverter.h +15 -0
- package/android/src/main/cpp/types/FrontendConverterProvider.cpp +1 -0
- package/android/src/main/java/expo/modules/kotlin/DynamicExtenstions.kt +3 -0
- package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +8 -2
- package/android/src/main/java/expo/modules/kotlin/functions/AnyFunction.kt +35 -24
- package/android/src/main/java/expo/modules/kotlin/jni/CppType.kt +1 -0
- package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptValue.kt +4 -0
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +1 -4
- package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionBuilder.kt +30 -0
- package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionData.kt +5 -1
- package/android/src/main/java/expo/modules/kotlin/types/JSTypeConverter.kt +1 -0
- package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +6 -0
- package/android/src/main/java/expo/modules/kotlin/views/AnyViewProp.kt +2 -0
- package/android/src/main/java/expo/modules/kotlin/views/ConcreteViewProp.kt +2 -0
- package/android/src/main/java/expo/modules/kotlin/views/ViewDefinitionBuilder.kt +56 -6
- package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinitionBuilder.kt +73 -1
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinition.kt +20 -16
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +2 -2
- package/build/NativeViewManagerAdapter.native.d.ts.map +1 -1
- package/build/NativeViewManagerAdapter.native.js +19 -1
- package/build/NativeViewManagerAdapter.native.js.map +1 -1
- package/build/SyntheticPlatformEmitter.d.ts +1 -1
- package/build/SyntheticPlatformEmitter.d.ts.map +1 -1
- package/build/SyntheticPlatformEmitter.js +1 -1
- package/build/SyntheticPlatformEmitter.js.map +1 -1
- package/ios/Fabric/ExpoFabricView.swift +6 -6
- package/ios/Fabric/ExpoFabricViewObjC.h +1 -1
- package/ios/Fabric/ExpoFabricViewObjC.mm +3 -9
- package/ios/Swift/ExpoBridgeModule.swift +23 -2
- package/ios/Swift/Views/ViewModuleWrapper.swift +7 -9
- package/package.json +2 -2
- package/src/NativeViewManagerAdapter.native.tsx +23 -2
- package/src/SyntheticPlatformEmitter.ts +1 -1
- package/build/SyntheticPlatformEmitter.web.d.ts +0 -6
- package/build/SyntheticPlatformEmitter.web.d.ts.map +0 -1
- package/build/SyntheticPlatformEmitter.web.js +0 -6
- package/build/SyntheticPlatformEmitter.web.js.map +0 -1
- package/src/SyntheticPlatformEmitter.web.ts +0 -5
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
package expo.modules.kotlin.modules
|
|
2
2
|
|
|
3
|
-
import expo.modules.kotlin.ConcatIterator
|
|
4
3
|
import expo.modules.kotlin.activityresult.AppContextActivityResultCaller
|
|
5
4
|
import expo.modules.kotlin.events.EventListener
|
|
6
5
|
import expo.modules.kotlin.events.EventName
|
|
@@ -20,7 +19,5 @@ class ModuleDefinitionData(
|
|
|
20
19
|
val asyncFunctions = objectDefinition.asyncFunctions
|
|
21
20
|
val eventsDefinition = objectDefinition.eventsDefinition
|
|
22
21
|
val properties = objectDefinition.properties
|
|
23
|
-
|
|
24
|
-
val functions
|
|
25
|
-
get() = ConcatIterator(syncFunctions.values.iterator(), asyncFunctions.values.iterator())
|
|
22
|
+
val functions = objectDefinition.functions
|
|
26
23
|
}
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
package expo.modules.kotlin.objects
|
|
16
16
|
|
|
17
|
+
import com.facebook.react.bridge.Arguments
|
|
17
18
|
import expo.modules.kotlin.Promise
|
|
18
19
|
import expo.modules.kotlin.events.EventsDefinition
|
|
19
20
|
import expo.modules.kotlin.functions.AsyncFunction
|
|
@@ -21,6 +22,9 @@ import expo.modules.kotlin.functions.AsyncFunctionBuilder
|
|
|
21
22
|
import expo.modules.kotlin.functions.AsyncFunctionComponent
|
|
22
23
|
import expo.modules.kotlin.functions.AsyncFunctionWithPromiseComponent
|
|
23
24
|
import expo.modules.kotlin.functions.SyncFunctionComponent
|
|
25
|
+
import expo.modules.kotlin.jni.JavaScriptModuleObject
|
|
26
|
+
import expo.modules.kotlin.modules.Module
|
|
27
|
+
import expo.modules.kotlin.modules.ModuleDefinitionBuilder
|
|
24
28
|
import expo.modules.kotlin.types.toAnyType
|
|
25
29
|
import kotlin.reflect.typeOf
|
|
26
30
|
|
|
@@ -350,3 +354,29 @@ open class ObjectDefinitionBuilder {
|
|
|
350
354
|
}
|
|
351
355
|
}
|
|
352
356
|
}
|
|
357
|
+
|
|
358
|
+
inline fun ModuleDefinitionBuilder.Object(block: ObjectDefinitionBuilder.() -> Unit): JavaScriptModuleObject {
|
|
359
|
+
return module!!.Object(block)
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
inline fun Module.Object(block: ObjectDefinitionBuilder.() -> Unit): JavaScriptModuleObject {
|
|
363
|
+
val objectData = ObjectDefinitionBuilder().also(block).buildObject()
|
|
364
|
+
return JavaScriptModuleObject("[Anonymous Object]")
|
|
365
|
+
.apply {
|
|
366
|
+
val constants = objectData.constantsProvider()
|
|
367
|
+
val convertedConstants = Arguments.makeNativeMap(constants)
|
|
368
|
+
exportConstants(convertedConstants)
|
|
369
|
+
|
|
370
|
+
objectData
|
|
371
|
+
.functions
|
|
372
|
+
.forEach { function ->
|
|
373
|
+
function.attachToJSObject(appContext, this)
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
objectData
|
|
377
|
+
.properties
|
|
378
|
+
.forEach { (_, prop) ->
|
|
379
|
+
prop.attachToJSObject(this)
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
package expo.modules.kotlin.objects
|
|
2
2
|
|
|
3
|
+
import expo.modules.kotlin.ConcatIterator
|
|
3
4
|
import expo.modules.kotlin.events.EventsDefinition
|
|
4
5
|
import expo.modules.kotlin.functions.BaseAsyncFunctionComponent
|
|
5
6
|
import expo.modules.kotlin.functions.SyncFunctionComponent
|
|
@@ -10,4 +11,7 @@ class ObjectDefinitionData(
|
|
|
10
11
|
val asyncFunctions: Map<String, BaseAsyncFunctionComponent>,
|
|
11
12
|
val eventsDefinition: EventsDefinition?,
|
|
12
13
|
val properties: Map<String, PropertyComponent>
|
|
13
|
-
)
|
|
14
|
+
) {
|
|
15
|
+
val functions
|
|
16
|
+
get() = ConcatIterator(syncFunctions.values.iterator(), asyncFunctions.values.iterator())
|
|
17
|
+
}
|
|
@@ -135,6 +135,9 @@ object TypeConverterProviderImpl : TypeConverterProvider {
|
|
|
135
135
|
val intTypeConverter = createTrivialTypeConverter(
|
|
136
136
|
isOptional, ExpectedType(CppType.INT)
|
|
137
137
|
) { it.asDouble().toInt() }
|
|
138
|
+
val longTypeConverter = createTrivialTypeConverter(
|
|
139
|
+
isOptional, ExpectedType(CppType.LONG)
|
|
140
|
+
) { it.asDouble().toLong() }
|
|
138
141
|
val doubleTypeConverter = createTrivialTypeConverter(
|
|
139
142
|
isOptional, ExpectedType(CppType.DOUBLE)
|
|
140
143
|
) { it.asDouble() }
|
|
@@ -149,6 +152,9 @@ object TypeConverterProviderImpl : TypeConverterProvider {
|
|
|
149
152
|
Int::class.createType(nullable = isOptional) to intTypeConverter,
|
|
150
153
|
java.lang.Integer::class.createType(nullable = isOptional) to intTypeConverter,
|
|
151
154
|
|
|
155
|
+
Long::class.createType(nullable = isOptional) to longTypeConverter,
|
|
156
|
+
java.lang.Long::class.createType(nullable = isOptional) to longTypeConverter,
|
|
157
|
+
|
|
152
158
|
Double::class.createType(nullable = isOptional) to doubleTypeConverter,
|
|
153
159
|
java.lang.Double::class.createType(nullable = isOptional) to doubleTypeConverter,
|
|
154
160
|
|
|
@@ -5,15 +5,17 @@ package expo.modules.kotlin.views
|
|
|
5
5
|
|
|
6
6
|
import android.content.Context
|
|
7
7
|
import android.view.View
|
|
8
|
+
import android.view.ViewGroup
|
|
8
9
|
import expo.modules.kotlin.AppContext
|
|
9
10
|
import expo.modules.kotlin.modules.DefinitionMarker
|
|
10
11
|
import expo.modules.kotlin.types.toAnyType
|
|
11
12
|
import kotlin.reflect.KClass
|
|
13
|
+
import kotlin.reflect.KFunction
|
|
12
14
|
import kotlin.reflect.full.primaryConstructor
|
|
13
15
|
import kotlin.reflect.typeOf
|
|
14
16
|
|
|
15
17
|
@DefinitionMarker
|
|
16
|
-
class ViewDefinitionBuilder<T : View>(
|
|
18
|
+
class ViewDefinitionBuilder<T : View>(@PublishedApi internal val viewType: KClass<T>) {
|
|
17
19
|
@PublishedApi
|
|
18
20
|
internal var props = mutableMapOf<String, AnyViewProp>()
|
|
19
21
|
|
|
@@ -41,20 +43,57 @@ class ViewDefinitionBuilder<T : View>(private val viewType: KClass<T>) {
|
|
|
41
43
|
/**
|
|
42
44
|
* Creates view's lifecycle listener that is called right after the view isn't longer used by React Native.
|
|
43
45
|
*/
|
|
44
|
-
|
|
46
|
+
@Suppress("UNCHECKED_CAST")
|
|
47
|
+
inline fun OnViewDestroys(crossinline body: (view: T) -> Unit) {
|
|
48
|
+
onViewDestroys = {
|
|
49
|
+
body(it as T)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Creates view's lifecycle listener that is called right after the view isn't longer used by React Native.
|
|
55
|
+
*/
|
|
56
|
+
@JvmName("OnViewDestroysGeneric")
|
|
57
|
+
inline fun <reified ViewType : T> OnViewDestroys(noinline body: (view: ViewType) -> Unit) {
|
|
45
58
|
onViewDestroys = { body(it as ViewType) }
|
|
46
59
|
}
|
|
47
60
|
|
|
48
61
|
/**
|
|
49
62
|
* Defines the view lifecycle method that is called when the view finished updating all props.
|
|
50
63
|
*/
|
|
51
|
-
|
|
64
|
+
@Suppress("UNCHECKED_CAST")
|
|
65
|
+
inline fun OnViewDidUpdateProps(crossinline body: (view: T) -> Unit) {
|
|
66
|
+
onViewDidUpdateProps = {
|
|
67
|
+
body(it as T)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Defines the view lifecycle method that is called when the view finished updating all props.
|
|
73
|
+
*/
|
|
74
|
+
@JvmName("OnViewDidUpdatePropsGeneric")
|
|
75
|
+
inline fun <reified ViewType : T> OnViewDidUpdateProps(noinline body: (view: ViewType) -> Unit) {
|
|
52
76
|
onViewDidUpdateProps = { body(it as ViewType) }
|
|
53
77
|
}
|
|
54
78
|
|
|
55
79
|
/**
|
|
56
80
|
* Creates a view prop that defines its name and setter.
|
|
57
81
|
*/
|
|
82
|
+
inline fun <reified PropType> Prop(
|
|
83
|
+
name: String,
|
|
84
|
+
noinline body: (view: T, prop: PropType) -> Unit
|
|
85
|
+
) {
|
|
86
|
+
props[name] = ConcreteViewProp(
|
|
87
|
+
name,
|
|
88
|
+
typeOf<PropType>().toAnyType(),
|
|
89
|
+
body
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Creates a view prop that defines its name and setter.
|
|
95
|
+
*/
|
|
96
|
+
@JvmName("PropGeneric")
|
|
58
97
|
inline fun <reified ViewType : View, reified PropType> Prop(
|
|
59
98
|
name: String,
|
|
60
99
|
noinline body: (view: ViewType, prop: PropType) -> Unit
|
|
@@ -84,16 +123,17 @@ class ViewDefinitionBuilder<T : View>(private val viewType: KClass<T>) {
|
|
|
84
123
|
/**
|
|
85
124
|
* Creates the group view definition that scopes group view-related definitions.
|
|
86
125
|
*/
|
|
87
|
-
inline fun GroupView(body: ViewGroupDefinitionBuilder
|
|
126
|
+
inline fun <reified ParentType : ViewGroup> GroupView(body: ViewGroupDefinitionBuilder<ParentType>.() -> Unit) {
|
|
127
|
+
assert(viewType == ParentType::class) { "Provided type and view type have to be the same." }
|
|
88
128
|
require(viewGroupDefinition == null) { "The viewManager definition may have exported only one groupView definition." }
|
|
89
129
|
|
|
90
|
-
val groupViewDefinitionBuilder = ViewGroupDefinitionBuilder()
|
|
130
|
+
val groupViewDefinitionBuilder = ViewGroupDefinitionBuilder<ParentType>()
|
|
91
131
|
body.invoke(groupViewDefinitionBuilder)
|
|
92
132
|
viewGroupDefinition = groupViewDefinitionBuilder.build()
|
|
93
133
|
}
|
|
94
134
|
|
|
95
135
|
private fun createViewFactory(): (Context, AppContext) -> View = viewFactory@{ context: Context, appContext: AppContext ->
|
|
96
|
-
val primaryConstructor = requireNotNull(
|
|
136
|
+
val primaryConstructor = requireNotNull(getPrimaryConstructor()) { "$viewType doesn't have a primary constructor" }
|
|
97
137
|
val args = primaryConstructor.parameters
|
|
98
138
|
|
|
99
139
|
if (args.isEmpty()) {
|
|
@@ -121,4 +161,14 @@ class ViewDefinitionBuilder<T : View>(private val viewType: KClass<T>) {
|
|
|
121
161
|
|
|
122
162
|
return@viewFactory primaryConstructor.call(context, appContext)
|
|
123
163
|
}
|
|
164
|
+
|
|
165
|
+
private fun getPrimaryConstructor(): KFunction<T>? {
|
|
166
|
+
val kotlinContractor = viewType.primaryConstructor
|
|
167
|
+
if (kotlinContractor != null) {
|
|
168
|
+
return kotlinContractor
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Add compatibility with Java
|
|
172
|
+
return viewType.constructors.firstOrNull()
|
|
173
|
+
}
|
|
124
174
|
}
|
|
@@ -7,7 +7,79 @@ import android.view.ViewGroup
|
|
|
7
7
|
import expo.modules.kotlin.modules.DefinitionMarker
|
|
8
8
|
|
|
9
9
|
@DefinitionMarker
|
|
10
|
-
class ViewGroupDefinitionBuilder {
|
|
10
|
+
class ViewGroupDefinitionBuilder<ParentType : ViewGroup> {
|
|
11
|
+
@PublishedApi
|
|
12
|
+
internal var addViewAction: AddViewAction? = null
|
|
13
|
+
|
|
14
|
+
@PublishedApi
|
|
15
|
+
internal var getChildAtAction: GetChildAtAction? = null
|
|
16
|
+
|
|
17
|
+
@PublishedApi
|
|
18
|
+
internal var getChildCountAction: GetChildCountAction? = null
|
|
19
|
+
|
|
20
|
+
@PublishedApi
|
|
21
|
+
internal var removeViewAction: RemoveViewAction? = null
|
|
22
|
+
|
|
23
|
+
@PublishedApi
|
|
24
|
+
internal var removeViewAtAction: RemoveViewAtAction? = null
|
|
25
|
+
|
|
26
|
+
fun build() = ViewGroupDefinition(
|
|
27
|
+
addViewAction,
|
|
28
|
+
getChildAtAction,
|
|
29
|
+
getChildCountAction,
|
|
30
|
+
removeViewAction,
|
|
31
|
+
removeViewAtAction
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
@Suppress("UNCHECKED_CAST")
|
|
35
|
+
inline fun <reified ChildViewType : View> AddChildView(
|
|
36
|
+
crossinline body: (parent: ParentType, child: ChildViewType, index: Int) -> Unit
|
|
37
|
+
) {
|
|
38
|
+
addViewAction = { parent, child, index ->
|
|
39
|
+
body(parent as ParentType, child as ChildViewType, index)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@Suppress("UNCHECKED_CAST")
|
|
44
|
+
inline fun GetChildCount(
|
|
45
|
+
crossinline body: (view: ParentType) -> Int
|
|
46
|
+
) {
|
|
47
|
+
getChildCountAction = { view ->
|
|
48
|
+
body(view as ParentType)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
@Suppress("UNCHECKED_CAST")
|
|
53
|
+
inline fun <reified ChildViewType : View> GetChildViewAt(
|
|
54
|
+
crossinline body: (view: ParentType, index: Int) -> ChildViewType?
|
|
55
|
+
) {
|
|
56
|
+
getChildAtAction = { view, index ->
|
|
57
|
+
body(view as ParentType, index)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@Suppress("UNCHECKED_CAST")
|
|
62
|
+
inline fun RemoveChildViewAt(
|
|
63
|
+
crossinline body: (view: ParentType, index: Int) -> Unit
|
|
64
|
+
) {
|
|
65
|
+
removeViewAtAction = { view, index ->
|
|
66
|
+
body(view as ParentType, index)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@Suppress("UNCHECKED_CAST")
|
|
71
|
+
inline fun <reified ChildViewType : View> RemoveChildView(
|
|
72
|
+
noinline body: (parent: ParentType, child: ChildViewType) -> Unit
|
|
73
|
+
) {
|
|
74
|
+
removeViewAction = { view, child ->
|
|
75
|
+
body(view as ParentType, child as ChildViewType)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@Deprecated("Use `ViewGroupDefinitionBuilder` instead.")
|
|
81
|
+
@DefinitionMarker
|
|
82
|
+
class ViewGroupDefinitionLegacyBuilder {
|
|
11
83
|
@PublishedApi
|
|
12
84
|
internal var addViewAction: AddViewAction? = null
|
|
13
85
|
|
|
@@ -8,6 +8,7 @@ import com.facebook.react.bridge.ReadableMap
|
|
|
8
8
|
import expo.modules.adapters.react.NativeModulesProxy
|
|
9
9
|
import expo.modules.core.ViewManager
|
|
10
10
|
import expo.modules.kotlin.AppContext
|
|
11
|
+
import expo.modules.kotlin.DynamicNull
|
|
11
12
|
import expo.modules.kotlin.exception.CodedException
|
|
12
13
|
import expo.modules.kotlin.exception.UnexpectedException
|
|
13
14
|
import expo.modules.kotlin.logger
|
|
@@ -36,24 +37,27 @@ class ViewManagerDefinition(
|
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
fun setProps(propsToSet: ReadableMap, onView: View) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
} catch (exception: Throwable) {
|
|
47
|
-
logger.error("❌ Cannot set the '$key' prop on the '${viewType.simpleName}'", exception)
|
|
48
|
-
|
|
49
|
-
handleException(
|
|
50
|
-
onView,
|
|
51
|
-
when (exception) {
|
|
52
|
-
is CodedException -> exception
|
|
53
|
-
else -> UnexpectedException(exception)
|
|
40
|
+
props.forEach { (name, propDelegate) ->
|
|
41
|
+
try {
|
|
42
|
+
if (propsToSet.hasKey(name)) {
|
|
43
|
+
propsToSet
|
|
44
|
+
.getDynamic(name)
|
|
45
|
+
.recycle {
|
|
46
|
+
propDelegate.set(this, onView)
|
|
54
47
|
}
|
|
55
|
-
|
|
48
|
+
} else if (propDelegate.isNullable) {
|
|
49
|
+
propDelegate.set(DynamicNull, onView)
|
|
56
50
|
}
|
|
51
|
+
} catch (exception: Throwable) {
|
|
52
|
+
logger.error("❌ Cannot set the '$name' prop on the '${viewType.simpleName}'", exception)
|
|
53
|
+
|
|
54
|
+
handleException(
|
|
55
|
+
onView,
|
|
56
|
+
when (exception) {
|
|
57
|
+
is CodedException -> exception
|
|
58
|
+
else -> UnexpectedException(exception)
|
|
59
|
+
}
|
|
60
|
+
)
|
|
57
61
|
}
|
|
58
62
|
}
|
|
59
63
|
}
|
|
@@ -122,10 +122,10 @@ class ViewManagerDefinitionBuilder {
|
|
|
122
122
|
/**
|
|
123
123
|
* Creates the group view definition that scopes group view-related definitions.
|
|
124
124
|
*/
|
|
125
|
-
inline fun GroupView(body:
|
|
125
|
+
inline fun GroupView(body: ViewGroupDefinitionLegacyBuilder.() -> Unit) {
|
|
126
126
|
require(viewGroupDefinition == null) { "The viewManager definition may have exported only one groupView definition." }
|
|
127
127
|
|
|
128
|
-
val groupViewDefinitionBuilder =
|
|
128
|
+
val groupViewDefinitionBuilder = ViewGroupDefinitionLegacyBuilder()
|
|
129
129
|
body.invoke(groupViewDefinitionBuilder)
|
|
130
130
|
viewGroupDefinition = groupViewDefinitionBuilder.build()
|
|
131
131
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NativeViewManagerAdapter.native.d.ts","sourceRoot":"","sources":["../src/NativeViewManagerAdapter.native.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
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,5 +1,23 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { NativeModules, requireNativeComponent } from 'react-native';
|
|
3
|
+
/**
|
|
4
|
+
* A map that caches registered native components.
|
|
5
|
+
*/
|
|
6
|
+
const nativeComponentsCache = new Map();
|
|
7
|
+
/**
|
|
8
|
+
* Requires a React Native component from cache if possible. This prevents
|
|
9
|
+
* "Tried to register two views with the same name" errors on fast refresh, but
|
|
10
|
+
* also when there are multiple versions of the same package with native component.
|
|
11
|
+
*/
|
|
12
|
+
function requireCachedNativeComponent(viewName) {
|
|
13
|
+
const cachedNativeComponent = nativeComponentsCache.get(viewName);
|
|
14
|
+
if (!cachedNativeComponent) {
|
|
15
|
+
const nativeComponent = requireNativeComponent(viewName);
|
|
16
|
+
nativeComponentsCache.set(viewName, nativeComponent);
|
|
17
|
+
return nativeComponent;
|
|
18
|
+
}
|
|
19
|
+
return cachedNativeComponent;
|
|
20
|
+
}
|
|
3
21
|
/**
|
|
4
22
|
* A drop-in replacement for `requireNativeComponent`.
|
|
5
23
|
*/
|
|
@@ -13,7 +31,7 @@ export function requireNativeViewManager(viewName) {
|
|
|
13
31
|
// Set up the React Native native component, which is an adapter to the universal module's view
|
|
14
32
|
// manager
|
|
15
33
|
const reactNativeViewName = `ViewManagerAdapter_${viewName}`;
|
|
16
|
-
const ReactNativeComponent =
|
|
34
|
+
const ReactNativeComponent = requireCachedNativeComponent(reactNativeViewName);
|
|
17
35
|
const proxiedPropsNames = viewManagerConfig?.propsNames ?? [];
|
|
18
36
|
// Define a component for universal-module authors to access their native view manager
|
|
19
37
|
const NativeComponentAdapter = React.forwardRef((props, ref) => {
|
|
@@ -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,
|
|
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"]}
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
* This emitter is used for sending synthetic native events to listeners
|
|
3
3
|
* registered in the API layer with `NativeEventEmitter`.
|
|
4
4
|
*/
|
|
5
|
-
export { default } from 'react-native
|
|
5
|
+
export { DeviceEventEmitter as default } from 'react-native';
|
|
6
6
|
//# sourceMappingURL=SyntheticPlatformEmitter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SyntheticPlatformEmitter.d.ts","sourceRoot":"","sources":["../src/SyntheticPlatformEmitter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"SyntheticPlatformEmitter.d.ts","sourceRoot":"","sources":["../src/SyntheticPlatformEmitter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,kBAAkB,IAAI,OAAO,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
* This emitter is used for sending synthetic native events to listeners
|
|
3
3
|
* registered in the API layer with `NativeEventEmitter`.
|
|
4
4
|
*/
|
|
5
|
-
export { default } from 'react-native
|
|
5
|
+
export { DeviceEventEmitter as default } from 'react-native';
|
|
6
6
|
//# sourceMappingURL=SyntheticPlatformEmitter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SyntheticPlatformEmitter.js","sourceRoot":"","sources":["../src/SyntheticPlatformEmitter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"SyntheticPlatformEmitter.js","sourceRoot":"","sources":["../src/SyntheticPlatformEmitter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,kBAAkB,IAAI,OAAO,EAAE,MAAM,cAAc,CAAC","sourcesContent":["/**\n * This emitter is used for sending synthetic native events to listeners\n * registered in the API layer with `NativeEventEmitter`.\n */\nexport { DeviceEventEmitter as default } from 'react-native';\n"]}
|
|
@@ -51,17 +51,17 @@ public class ExpoFabricView: ExpoFabricViewObjC {
|
|
|
51
51
|
|
|
52
52
|
// MARK: - ExpoFabricViewInterface
|
|
53
53
|
|
|
54
|
-
public override func
|
|
55
|
-
guard let view = contentView else {
|
|
54
|
+
public override func updateProps(_ props: [String: Any]) {
|
|
55
|
+
guard let view = contentView, let propsDict = viewManagerPropDict else {
|
|
56
56
|
return
|
|
57
57
|
}
|
|
58
|
-
|
|
58
|
+
for (key, prop) in propsDict {
|
|
59
|
+
let newValue = props[key] as Any
|
|
60
|
+
|
|
59
61
|
// TODO: @tsapeta: Figure out better way to rethrow errors from here.
|
|
60
62
|
// Adding `throws` keyword to the function results in different
|
|
61
63
|
// method signature in Objective-C. Maybe just call `RCTLogError`?
|
|
62
|
-
try? prop.set(value:
|
|
63
|
-
} else if let _ = legacyViewManager {
|
|
64
|
-
legacyViewManager?.updateProp(propName, withValue: value, on: view)
|
|
64
|
+
try? prop.set(value: Conversions.fromNSObject(newValue), onView: view)
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
|
|
34
34
|
- (void)dispatchEvent:(nonnull NSString *)eventName payload:(nullable id)payload;
|
|
35
35
|
|
|
36
|
-
- (void)
|
|
36
|
+
- (void)updateProps:(nonnull NSDictionary<NSString *, id> *)props;
|
|
37
37
|
|
|
38
38
|
- (void)viewDidUpdateProps;
|
|
39
39
|
|
|
@@ -140,15 +140,9 @@ 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
|
-
|
|
144
|
-
if (proxiedProperties.isObject()) {
|
|
145
|
-
for (auto& item : proxiedProperties.items()) {
|
|
146
|
-
NSString *name = [NSString stringWithCString:item.first.c_str() encoding:NSUTF8StringEncoding];
|
|
147
|
-
id value = convertFollyDynamicToId(item.second);
|
|
148
|
-
[self updateProp:name withValue:value];
|
|
149
|
-
}
|
|
150
|
-
}
|
|
143
|
+
NSDictionary<NSString *, id> *proxiedProperties = convertFollyDynamicToId(newViewProps.proxiedProperties);
|
|
151
144
|
|
|
145
|
+
[self updateProps:proxiedProperties];
|
|
152
146
|
[super updateProps:props oldProps:oldProps];
|
|
153
147
|
[self viewDidUpdateProps];
|
|
154
148
|
}
|
|
@@ -170,7 +164,7 @@ static std::unordered_map<std::string, ExpoViewComponentDescriptor::Flavor> _com
|
|
|
170
164
|
|
|
171
165
|
#pragma mark - Methods to override in Swift
|
|
172
166
|
|
|
173
|
-
- (void)
|
|
167
|
+
- (void)updateProps:(nonnull NSDictionary<NSString *, id> *)props
|
|
174
168
|
{
|
|
175
169
|
// Implemented in `ExpoFabricView.swift`
|
|
176
170
|
}
|
|
@@ -41,12 +41,33 @@ public final class ExpoBridgeModule: NSObject, RCTBridgeModule {
|
|
|
41
41
|
public var bridge: RCTBridge! {
|
|
42
42
|
didSet {
|
|
43
43
|
appContext.reactBridge = bridge
|
|
44
|
-
|
|
44
|
+
|
|
45
|
+
let attachRuntime = { [weak self] in
|
|
45
46
|
guard let self = self, let bridge = self.appContext.reactBridge else {
|
|
46
47
|
return
|
|
47
48
|
}
|
|
48
49
|
self.appContext.runtime = EXJavaScriptRuntimeManager.runtime(fromBridge: bridge)
|
|
49
|
-
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if bridge.responds(to: Selector(("runtime"))) {
|
|
53
|
+
// Getting the `runtime` on a different thread than JS is considered to be dangerous.
|
|
54
|
+
// However, we just checking if it exists. We don't do anything with it.
|
|
55
|
+
let result = bridge.perform(Selector(("runtime")))
|
|
56
|
+
if result == nil {
|
|
57
|
+
// When exporting expo modules using `extraModulesForBridge` (e.g. in Expo Go),
|
|
58
|
+
// the runtime won't be initiated before the bridge didSet method is called.
|
|
59
|
+
// Therefore, we need to wait for the main thread to complete its initialization by dispatching on it first.
|
|
60
|
+
bridge.dispatchBlock({ [weak self] in
|
|
61
|
+
guard let self = self, let bridge = self.appContext.reactBridge else {
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
bridge.dispatchBlock(attachRuntime, queue: RCTJSThread)
|
|
65
|
+
}, queue: DispatchQueue.main)
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
bridge.dispatchBlock(attachRuntime, queue: RCTJSThread)
|
|
50
71
|
}
|
|
51
72
|
}
|
|
52
73
|
|
|
@@ -109,15 +109,13 @@ public final class ViewModuleWrapper: RCTViewManager, DynamicModuleWrapperProtoc
|
|
|
109
109
|
}
|
|
110
110
|
let props = viewManager.propsDict()
|
|
111
111
|
|
|
112
|
-
for (key,
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
try? prop.set(value: value, onView: view)
|
|
120
|
-
}
|
|
112
|
+
for (key, prop) in props {
|
|
113
|
+
let newValue = json[key] as Any
|
|
114
|
+
|
|
115
|
+
// TODO: @tsapeta: Figure out better way to rethrow errors from here.
|
|
116
|
+
// Adding `throws` keyword to the function results in different
|
|
117
|
+
// method signature in Objective-C. Maybe just call `RCTLogError`?
|
|
118
|
+
try? prop.set(value: Conversions.fromNSObject(newValue), onView: view)
|
|
121
119
|
}
|
|
122
120
|
viewManager.callLifecycleMethods(withType: .didUpdateProps, forView: view)
|
|
123
121
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-modules-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "The core of Expo Modules architecture",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -42,5 +42,5 @@
|
|
|
42
42
|
"@testing-library/react-hooks": "^7.0.1",
|
|
43
43
|
"expo-module-scripts": "^3.0.0"
|
|
44
44
|
},
|
|
45
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "1815e2eaad8c753588c7b1eb74420174a28e01f4"
|
|
46
46
|
}
|