expo-modules-core 57.0.3 → 57.0.5
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 +19 -1
- package/ExpoModulesCore.podspec +15 -7
- package/android/build.gradle +2 -2
- package/android/src/main/java/expo/modules/kotlin/types/ColorCompat.kt +148 -0
- package/android/src/main/java/expo/modules/kotlin/types/ColorTypeConverter.kt +14 -17
- package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +2 -1
- package/ios/Core/AppContext.swift +4 -0
- package/ios/Core/Classes/ClassDefinition.swift +20 -7
- package/ios/Core/Convertibles/Convertibles+Color.swift +162 -63
- package/ios/Core/ExpoModulesMacros.swift +11 -2
- package/ios/Core/Functions/ConcurrentFunctionDefinition.swift +55 -9
- package/ios/Core/ModuleHolder.swift +1 -1
- package/ios/Core/Protocols/AnyModule.swift +2 -2
- package/ios/Core/SharedObjects/SharedObject.swift +14 -0
- package/ios/Core/SharedObjects/SharedObjectNativeState.swift +40 -12
- package/ios/Core/SharedObjects/SharedObjectRegistry.swift +72 -57
- package/ios/Core/Views/SwiftUI/ExpoSwiftUI.swift +12 -0
- package/ios/Core/Views/SwiftUI/SwiftUIVirtualView.swift +21 -5
- package/ios/JS/EXReactSchedulerDispatch.h +38 -7
- package/ios/JS/EXReactSchedulerDispatch.mm +29 -2
- package/package.json +4 -4
- package/prebuilds/output/debug/xcframeworks/ExpoModulesCore.tar.gz +0 -0
- package/prebuilds/output/debug/xcframeworks/ExpoModulesWorklets.tar.gz +0 -0
- package/prebuilds/output/release/xcframeworks/ExpoModulesCore.tar.gz +0 -0
- package/prebuilds/output/release/xcframeworks/ExpoModulesWorklets.tar.gz +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,25 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 57.0.5 — 2026-07-15
|
|
14
|
+
|
|
15
|
+
_This version does not introduce any user-facing changes._
|
|
16
|
+
|
|
17
|
+
## 57.0.4 — 2026-07-15
|
|
18
|
+
|
|
19
|
+
### 🎉 New features
|
|
20
|
+
|
|
21
|
+
- [iOS] `@SharedObject` now binds `@JS` methods, properties and the `@JS init` directly onto the class prototype, so they no longer need `Function(…)` / `Property(…)` / `Constructor { … }` definition entries. ([#47107](https://github.com/expo/expo/pull/47107) by [@tsapeta](https://github.com/tsapeta))
|
|
22
|
+
|
|
23
|
+
### 🐛 Bug fixes
|
|
24
|
+
|
|
25
|
+
- [iOS] Fixed a crash when the runtime is reloaded while async function calls are still suspended in their native body. Concurrent functions now decode `this` and the arguments buffer synchronously inside the host call and schedule only converted native values, so no JSI-owned wrappers are destroyed off the JS thread after the runtime is torn down. ([#47716](https://github.com/expo/expo/issues/47716), [#47717](https://github.com/expo/expo/pull/47717) by [@AlirezaHadjar](https://github.com/AlirezaHadjar))
|
|
26
|
+
- [Android] Support `android.graphics.Color` arguments and props on Android below API 26 by adding a `ColorCompat` wrapper, since the class-based `Color` API (`Color.valueOf` and the float accessors) only exists on API 26 and above. ([#47546](https://github.com/expo/expo/issues/47546) by [@anasvemmully](https://github.com/anasvemmully)) ([#47575](https://github.com/expo/expo/pull/47575) by [@intergalacticspacehighway](https://github.com/intergalacticspacehighway))
|
|
27
|
+
- [iOS] Fix a `SIGABRT` crash when unmounting a SwiftUI view tree that still holds a focused field nested inside a container (e.g. an `@expo/ui` `TextField` inside an `HStack` or `LabeledContent` in a `Form`), such as dismissing a modal from a native header button. Resigning the first responder on unmount now recurses through the removed subtree instead of only handling a top-level focusable view. ([#47682](https://github.com/expo/expo/issues/47682) by [@andreavrr](https://github.com/andreavrr)) ([#47709](https://github.com/expo/expo/pull/47709) by [@intergalacticspacehighway](https://github.com/intergalacticspacehighway))
|
|
28
|
+
- [iOS] Pair a native shared object with one JavaScript object per runtime, so a shared object exposed to several runtimes (e.g. the main and UI runtimes, or worklet contexts) keeps a live pairing in each instead of only the one paired last. ([#47238](https://github.com/expo/expo/pull/47238) by [@tsapeta](https://github.com/tsapeta))
|
|
29
|
+
- [iOS] Fix `hsl()`/`hsla()` color strings failing to parse on some OS versions (observed on the iOS 27.0 beta), caused by regex-literal fragments composed in `RegexBuilder` blocks. The CSS color patterns are now built from `RegexBuilder` primitives only. ([#47543](https://github.com/expo/expo/pull/47543) by [@tsapeta](https://github.com/tsapeta))
|
|
30
|
+
- [iOS] Fixed a potential use-after-free when native code scheduled work onto the JS thread (e.g. settling an async function's promise from a background queue) while the React instance was concurrently tearing down the runtime scheduler on reload. The dispatch trampoline now references the scheduler weakly and drops the task once the scheduler is gone. ([#47492](https://github.com/expo/expo/pull/47492) by [@tsapeta](https://github.com/tsapeta))
|
|
31
|
+
|
|
13
32
|
## 57.0.3 — 2026-07-07
|
|
14
33
|
|
|
15
34
|
_This version does not introduce any user-facing changes._
|
|
@@ -37,7 +56,6 @@ _This version does not introduce any user-facing changes._
|
|
|
37
56
|
|
|
38
57
|
### 🐛 Bug fixes
|
|
39
58
|
|
|
40
|
-
- [iOS] Pair a native shared object with one JavaScript object per runtime, so a shared object exposed to several runtimes (e.g. the main and UI runtimes, or worklet contexts) keeps a live pairing in each instead of only the one paired last. ([#47238](https://github.com/expo/expo/pull/47238) by [@tsapeta](https://github.com/tsapeta))
|
|
41
59
|
- [Android][compose] Guard `onLayout` against detached window to prevent `LayoutNode should be attached to an owner` crash. ([#47085](https://github.com/expo/expo/pull/47085) by [@roitium](https://github.com/roitium))
|
|
42
60
|
- [Android] Fix Jetpack Compose `Host` content disappearing before a react-native-screens pop animation finishes, by deferring composition disposal to window detach while the view is still on-screen for a transition. ([#45914](https://github.com/expo/expo/issues/45914), [#47086](https://github.com/expo/expo/issues/47086) by [@aubrey-wodonga](https://github.com/aubrey-wodonga)) ([#47099](https://github.com/expo/expo/pull/47099) by [@nishan](https://github.com/intergalacticspacehighway))
|
|
43
61
|
- [iOS] Fix a crash on `Updates.reloadAsync()` where the previous `AppContext` could deallocate before the old runtime finished tearing down, releasing cached JSI objects against a dying runtime on the wrong thread. Its lifetime is now tied to the runtime via native state attached to the `global.expo` object. ([#47051](https://github.com/expo/expo/issues/47051) by [@HaiyiMei](https://github.com/HaiyiMei)) ([#47080](https://github.com/expo/expo/pull/47080), [#47098](https://github.com/expo/expo/pull/47098) by [@tsapeta](https://github.com/tsapeta))
|
package/ExpoModulesCore.podspec
CHANGED
|
@@ -127,14 +127,22 @@ Pod::Spec.new do |s|
|
|
|
127
127
|
s.test_spec 'Tests' do |test_spec|
|
|
128
128
|
test_spec.dependency 'ExpoModulesTestCore'
|
|
129
129
|
|
|
130
|
-
test_spec.source_files = 'ios/Tests/**/*.{m,swift}'
|
|
131
|
-
|
|
132
|
-
# The
|
|
133
|
-
#
|
|
134
|
-
#
|
|
135
|
-
#
|
|
130
|
+
test_spec.source_files = 'ios/Tests/**/*.{h,m,mm,swift}'
|
|
131
|
+
|
|
132
|
+
# The Obj-C++ tests include React renderer headers, which need the library's folly
|
|
133
|
+
# config. It reaches them through the library's `compiler_flags`, which test specs
|
|
134
|
+
# inherit and CocoaPods applies per-file to C-family sources.
|
|
135
|
+
#
|
|
136
|
+
# OTHER_LDFLAGS: the library's -lc++ lives in `user_target_xcconfig` (for consuming
|
|
137
|
+
# apps), which a test_spec target doesn't inherit. The test bundle links
|
|
138
|
+
# libExpoModulesCore.a (C++), so link libc++ explicitly.
|
|
139
|
+
#
|
|
140
|
+
# SWIFT_OBJC_BRIDGING_HEADER: a test target has no module for its own Obj-C sources,
|
|
141
|
+
# so the Swift tests see the Obj-C test doubles (`ios/Tests/Mocks`) through the
|
|
142
|
+
# bridging header.
|
|
136
143
|
test_spec.pod_target_xcconfig = {
|
|
137
|
-
'OTHER_LDFLAGS' => '$(inherited) -lc++'
|
|
144
|
+
'OTHER_LDFLAGS' => '$(inherited) -lc++',
|
|
145
|
+
'SWIFT_OBJC_BRIDGING_HEADER' => '$(PODS_TARGET_SRCROOT)/ios/Tests/Tests-Bridging-Header.h'
|
|
138
146
|
}
|
|
139
147
|
end
|
|
140
148
|
end
|
package/android/build.gradle
CHANGED
|
@@ -27,7 +27,7 @@ if (shouldIncludeCompose) {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
group = 'host.exp.exponent'
|
|
30
|
-
version = '57.0.
|
|
30
|
+
version = '57.0.5'
|
|
31
31
|
|
|
32
32
|
def isExpoModulesCoreTests = {
|
|
33
33
|
Gradle gradle = getGradle()
|
|
@@ -94,7 +94,7 @@ android {
|
|
|
94
94
|
defaultConfig {
|
|
95
95
|
consumerProguardFiles 'proguard-rules.pro'
|
|
96
96
|
versionCode 1
|
|
97
|
-
versionName "57.0.
|
|
97
|
+
versionName "57.0.5"
|
|
98
98
|
buildConfigField "String", "EXPO_MODULES_CORE_VERSION", "\"${versionName}\""
|
|
99
99
|
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", "true"
|
|
100
100
|
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
package expo.modules.kotlin.types
|
|
2
|
+
|
|
3
|
+
import android.graphics.Color
|
|
4
|
+
import android.os.Build
|
|
5
|
+
import androidx.annotation.ColorInt
|
|
6
|
+
import androidx.annotation.RequiresApi
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Compatibility wrapper for [Color] instance APIs added in API 26.
|
|
10
|
+
*
|
|
11
|
+
* Remove this class when expo-modules-core minSdkVersion is 26 or higher. Android Lint's
|
|
12
|
+
* ObsoleteSdkInt check should flag these version gates after that bump.
|
|
13
|
+
*/
|
|
14
|
+
class ColorCompat private constructor() {
|
|
15
|
+
companion object {
|
|
16
|
+
private val defaultLegacyColor = LegacyColor(
|
|
17
|
+
red = 0f,
|
|
18
|
+
green = 0f,
|
|
19
|
+
blue = 0f,
|
|
20
|
+
alpha = 1f,
|
|
21
|
+
argb = Color.BLACK
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
@JvmStatic
|
|
25
|
+
fun valueOf(@ColorInt color: Int): Color {
|
|
26
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
27
|
+
return Api26Impl.valueOf(color)
|
|
28
|
+
}
|
|
29
|
+
return LegacyColor(
|
|
30
|
+
red = Color.red(color) / 255f,
|
|
31
|
+
green = Color.green(color) / 255f,
|
|
32
|
+
blue = Color.blue(color) / 255f,
|
|
33
|
+
alpha = Color.alpha(color) / 255f,
|
|
34
|
+
argb = color
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@JvmStatic
|
|
39
|
+
fun valueOf(red: Float, green: Float, blue: Float, alpha: Float): Color {
|
|
40
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
41
|
+
return Api26Impl.valueOf(red, green, blue, alpha)
|
|
42
|
+
}
|
|
43
|
+
val saturatedRed = red.coerceIn(0f, 1f)
|
|
44
|
+
val saturatedGreen = green.coerceIn(0f, 1f)
|
|
45
|
+
val saturatedBlue = blue.coerceIn(0f, 1f)
|
|
46
|
+
val saturatedAlpha = alpha.coerceIn(0f, 1f)
|
|
47
|
+
return LegacyColor(
|
|
48
|
+
red = saturatedRed,
|
|
49
|
+
green = saturatedGreen,
|
|
50
|
+
blue = saturatedBlue,
|
|
51
|
+
alpha = saturatedAlpha,
|
|
52
|
+
argb = Color.argb(
|
|
53
|
+
toColorComponent(saturatedAlpha),
|
|
54
|
+
toColorComponent(saturatedRed),
|
|
55
|
+
toColorComponent(saturatedGreen),
|
|
56
|
+
toColorComponent(saturatedBlue)
|
|
57
|
+
)
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@JvmStatic
|
|
62
|
+
fun toArgb(color: Color): Int {
|
|
63
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
64
|
+
return Api26Impl.toArgb(color)
|
|
65
|
+
}
|
|
66
|
+
return legacyColor(color).argb
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@JvmStatic
|
|
70
|
+
fun alpha(color: Color): Float {
|
|
71
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
72
|
+
return Api26Impl.alpha(color)
|
|
73
|
+
}
|
|
74
|
+
return legacyColor(color).alpha
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@JvmStatic
|
|
78
|
+
fun red(color: Color): Float {
|
|
79
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
80
|
+
return Api26Impl.red(color)
|
|
81
|
+
}
|
|
82
|
+
return legacyColor(color).red
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@JvmStatic
|
|
86
|
+
fun green(color: Color): Float {
|
|
87
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
88
|
+
return Api26Impl.green(color)
|
|
89
|
+
}
|
|
90
|
+
return legacyColor(color).green
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
@JvmStatic
|
|
94
|
+
fun blue(color: Color): Float {
|
|
95
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
96
|
+
return Api26Impl.blue(color)
|
|
97
|
+
}
|
|
98
|
+
return legacyColor(color).blue
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private fun legacyColor(color: Color): LegacyColor {
|
|
102
|
+
return color as? LegacyColor ?: defaultLegacyColor
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
private fun toColorComponent(component: Float): Int {
|
|
106
|
+
return (component * 255f + 0.5f).toInt()
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private class LegacyColor(
|
|
111
|
+
val red: Float,
|
|
112
|
+
val green: Float,
|
|
113
|
+
val blue: Float,
|
|
114
|
+
val alpha: Float,
|
|
115
|
+
@ColorInt val argb: Int
|
|
116
|
+
) : Color()
|
|
117
|
+
|
|
118
|
+
@RequiresApi(Build.VERSION_CODES.O)
|
|
119
|
+
private object Api26Impl {
|
|
120
|
+
fun valueOf(@ColorInt color: Int): Color {
|
|
121
|
+
return Color.valueOf(color)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
fun valueOf(red: Float, green: Float, blue: Float, alpha: Float): Color {
|
|
125
|
+
return Color.valueOf(red, green, blue, alpha)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
fun toArgb(color: Color): Int {
|
|
129
|
+
return color.toArgb()
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
fun alpha(color: Color): Float {
|
|
133
|
+
return color.alpha()
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
fun red(color: Color): Float {
|
|
137
|
+
return color.red()
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
fun green(color: Color): Float {
|
|
141
|
+
return color.green()
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
fun blue(color: Color): Float {
|
|
145
|
+
return color.blue()
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
package expo.modules.kotlin.types
|
|
2
2
|
|
|
3
3
|
import android.graphics.Color
|
|
4
|
-
import android.os.Build
|
|
5
|
-
import androidx.annotation.RequiresApi
|
|
6
4
|
import com.facebook.react.bridge.Dynamic
|
|
7
5
|
import com.facebook.react.bridge.ReadableType
|
|
8
6
|
import expo.modules.kotlin.AppContext
|
|
@@ -262,7 +260,7 @@ private fun hslToColor(h: Float, s: Float, l: Float, a: Float): Color {
|
|
|
262
260
|
g = hueToRgb(p, q, hue)
|
|
263
261
|
b = hueToRgb(p, q, hue - 1f / 3f)
|
|
264
262
|
}
|
|
265
|
-
return
|
|
263
|
+
return ColorCompat.valueOf(r.coerceIn(0f, 1f), g.coerceIn(0f, 1f), b.coerceIn(0f, 1f), a)
|
|
266
264
|
}
|
|
267
265
|
|
|
268
266
|
private fun hwbToColor(h: Float, w: Float, b: Float, a: Float): Color {
|
|
@@ -272,10 +270,10 @@ private fun hwbToColor(h: Float, w: Float, b: Float, a: Float): Color {
|
|
|
272
270
|
val white = if (sum > 1f) ww / sum else ww
|
|
273
271
|
val black = if (sum > 1f) bb / sum else bb
|
|
274
272
|
val rgb = hslToColor(h, 1f, 0.5f, 1f)
|
|
275
|
-
val r =
|
|
276
|
-
val g =
|
|
277
|
-
val bl =
|
|
278
|
-
return
|
|
273
|
+
val r = ColorCompat.red(rgb) * (1f - white - black) + white
|
|
274
|
+
val g = ColorCompat.green(rgb) * (1f - white - black) + white
|
|
275
|
+
val bl = ColorCompat.blue(rgb) * (1f - white - black) + white
|
|
276
|
+
return ColorCompat.valueOf(r.coerceIn(0f, 1f), g.coerceIn(0f, 1f), bl.coerceIn(0f, 1f), a)
|
|
279
277
|
}
|
|
280
278
|
|
|
281
279
|
/**
|
|
@@ -292,7 +290,7 @@ private fun parseHexColor(value: String): Color? {
|
|
|
292
290
|
val r = match.groupValues[1].repeat(2).toInt(16)
|
|
293
291
|
val g = match.groupValues[2].repeat(2).toInt(16)
|
|
294
292
|
val b = match.groupValues[3].repeat(2).toInt(16)
|
|
295
|
-
return
|
|
293
|
+
return ColorCompat.valueOf(r / 255f, g / 255f, b / 255f, 1f)
|
|
296
294
|
}
|
|
297
295
|
|
|
298
296
|
// #RGBA → #RRGGBBAA
|
|
@@ -301,7 +299,7 @@ private fun parseHexColor(value: String): Color? {
|
|
|
301
299
|
val g = match.groupValues[2].repeat(2).toInt(16)
|
|
302
300
|
val b = match.groupValues[3].repeat(2).toInt(16)
|
|
303
301
|
val a = match.groupValues[4].repeat(2).toInt(16)
|
|
304
|
-
return
|
|
302
|
+
return ColorCompat.valueOf(r / 255f, g / 255f, b / 255f, a / 255f)
|
|
305
303
|
}
|
|
306
304
|
|
|
307
305
|
// #RRGGBBAA (CSS byte order: alpha is last, unlike Android's #AARRGGBB)
|
|
@@ -311,7 +309,7 @@ private fun parseHexColor(value: String): Color? {
|
|
|
311
309
|
val g = ((hex shr 16) and 0xFF).toInt()
|
|
312
310
|
val b = ((hex shr 8) and 0xFF).toInt()
|
|
313
311
|
val a = (hex and 0xFF).toInt()
|
|
314
|
-
return
|
|
312
|
+
return ColorCompat.valueOf(r / 255f, g / 255f, b / 255f, a / 255f)
|
|
315
313
|
}
|
|
316
314
|
|
|
317
315
|
return null
|
|
@@ -329,7 +327,7 @@ private fun parseCssColorFunction(value: String): Color? {
|
|
|
329
327
|
val g = parseRgbComponent(match.groupValues[2])
|
|
330
328
|
val b = parseRgbComponent(match.groupValues[3])
|
|
331
329
|
val a = parseAlpha(match.groupValues[4].ifEmpty { null })
|
|
332
|
-
return
|
|
330
|
+
return ColorCompat.valueOf(r, g, b, a)
|
|
333
331
|
}
|
|
334
332
|
|
|
335
333
|
// hsl/hsla
|
|
@@ -355,7 +353,6 @@ private fun parseCssColorFunction(value: String): Color? {
|
|
|
355
353
|
|
|
356
354
|
// endregion
|
|
357
355
|
|
|
358
|
-
@RequiresApi(Build.VERSION_CODES.O)
|
|
359
356
|
class ColorTypeConverter : DynamicAwareTypeConverters<Color>() {
|
|
360
357
|
override fun convertFromDynamic(value: Dynamic, context: AppContext?, forceConversion: Boolean): Color {
|
|
361
358
|
return when (value.type) {
|
|
@@ -389,18 +386,18 @@ class ColorTypeConverter : DynamicAwareTypeConverters<Color>() {
|
|
|
389
386
|
throw InvalidColorComponentsException(value.size)
|
|
390
387
|
}
|
|
391
388
|
val alpha = value.getOrNull(3) ?: 1.0
|
|
392
|
-
return
|
|
389
|
+
return ColorCompat.valueOf(value[0].toFloat(), value[1].toFloat(), value[2].toFloat(), alpha.toFloat())
|
|
393
390
|
}
|
|
394
391
|
|
|
395
392
|
private fun colorFromInt(value: Int): Color {
|
|
396
|
-
return
|
|
393
|
+
return ColorCompat.valueOf(value)
|
|
397
394
|
}
|
|
398
395
|
|
|
399
396
|
private fun colorFromString(value: String): Color {
|
|
400
397
|
val normalizedValue = value.trim().lowercase()
|
|
401
398
|
val colorFromString = namedColors[normalizedValue]
|
|
402
399
|
if (colorFromString != null) {
|
|
403
|
-
return
|
|
400
|
+
return ColorCompat.valueOf(
|
|
404
401
|
colorFromString[0],
|
|
405
402
|
colorFromString[1],
|
|
406
403
|
colorFromString[2],
|
|
@@ -411,12 +408,12 @@ class ColorTypeConverter : DynamicAwareTypeConverters<Color>() {
|
|
|
411
408
|
if (normalizedValue.startsWith('#')) {
|
|
412
409
|
parseHexColor(normalizedValue)?.let { return it }
|
|
413
410
|
// Fall through to toColorInt() for standard #RRGGBB / #AARRGGBB
|
|
414
|
-
return
|
|
411
|
+
return ColorCompat.valueOf(normalizedValue.toColorInt())
|
|
415
412
|
}
|
|
416
413
|
|
|
417
414
|
parseCssColorFunction(normalizedValue)?.let { return it }
|
|
418
415
|
|
|
419
|
-
return
|
|
416
|
+
return ColorCompat.valueOf(normalizedValue.toColorInt())
|
|
420
417
|
}
|
|
421
418
|
|
|
422
419
|
override fun getCppRequiredTypes(): ExpectedType =
|
|
@@ -275,6 +275,8 @@ object TypeConverterProviderImpl : TypeConverterProvider {
|
|
|
275
275
|
|
|
276
276
|
Any::class.java to AnyTypeConverter(),
|
|
277
277
|
|
|
278
|
+
Color::class.java to ColorTypeConverter(),
|
|
279
|
+
|
|
278
280
|
// Unit converter doesn't care about nullability.
|
|
279
281
|
// It will always return Unit
|
|
280
282
|
Unit::class.java to UnitTypeConverter(),
|
|
@@ -285,7 +287,6 @@ object TypeConverterProviderImpl : TypeConverterProvider {
|
|
|
285
287
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
|
286
288
|
return converters + mapOf(
|
|
287
289
|
Path::class.java to PathTypeConverter(),
|
|
288
|
-
Color::class.java to ColorTypeConverter(),
|
|
289
290
|
LocalDate::class.java to DateTypeConverter()
|
|
290
291
|
)
|
|
291
292
|
}
|
|
@@ -436,6 +436,10 @@ public final class AppContext: NSObject, EXAppContextProtocol, @unchecked Sendab
|
|
|
436
436
|
to a synchronous no-op scheduler — callers can detect this via
|
|
437
437
|
`JavaScriptRuntime.supportsAsyncScheduling`.
|
|
438
438
|
|
|
439
|
+
`scheduler` is an opaque handle that `dispatch` understands; the factories pass
|
|
440
|
+
a handle created by `expo::createReactSchedulerHandle` that references the React
|
|
441
|
+
runtime scheduler weakly (see `EXReactSchedulerDispatch.h`).
|
|
442
|
+
|
|
439
443
|
`dispatch` is a raw pointer to a C function with signature
|
|
440
444
|
`void (*)(void *scheduler, int priority, void (^callback)())` — cast back
|
|
441
445
|
to the typed pointer inside `ExpoModulesJSI`. It's typed as `UnsafeRawPointer`
|
|
@@ -51,17 +51,20 @@ public final class ClassDefinition: ObjectDefinition {
|
|
|
51
51
|
|
|
52
52
|
@JavaScriptActor
|
|
53
53
|
public override func build(appContext: AppContext) throws -> JavaScriptObject {
|
|
54
|
+
// The concrete `SharedObject` subclass backing this class, used to dispatch to the
|
|
55
|
+
// `@SharedObject` macro's `_constructSharedObject` / `_decorateSharedObject` overrides.
|
|
56
|
+
let sharedObjectType = ((associatedType as? DynamicSharedObjectType)?.innerType) as? SharedObject.Type
|
|
57
|
+
|
|
54
58
|
let constructorClosure: JavaScriptRuntime.SyncFunctionClosure = { [weak self, weak appContext] this, arguments in
|
|
55
59
|
guard let self, let appContext else {
|
|
56
60
|
throw Exceptions.AppContextLost()
|
|
57
61
|
}
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
if let
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
// a different JS object would replace `this` and drop that prototype chain.
|
|
62
|
+
// Build the native instance and pair it with `this` (returning a different object would drop
|
|
63
|
+
// the prototype chain `new` set up). Prefer the macro-synthesized `_constructSharedObject`,
|
|
64
|
+
// falling back to the DSL `Constructor` body.
|
|
65
|
+
if let sharedObject = try sharedObjectType?._constructSharedObject(this: this, arguments: arguments, in: appContext.runtime) {
|
|
66
|
+
appContext.sharedObjectRegistry.add(native: sharedObject, javaScript: this.getObject())
|
|
67
|
+
} else if let constructor {
|
|
65
68
|
let result = try constructor.runBody(appContext, in: appContext.runtime, this: this, arguments: arguments)
|
|
66
69
|
|
|
67
70
|
if let sharedObject = result as? SharedObject {
|
|
@@ -75,6 +78,12 @@ public final class ClassDefinition: ObjectDefinition {
|
|
|
75
78
|
|
|
76
79
|
try decorate(object: klass, appContext: appContext)
|
|
77
80
|
|
|
81
|
+
// Bind the macro's `@JS` members onto the prototype.
|
|
82
|
+
if let sharedObjectType {
|
|
83
|
+
let prototype = klass.getProperty("prototype").getObject()
|
|
84
|
+
try sharedObjectType._decorateSharedObject(prototype: prototype, in: appContext.runtime)
|
|
85
|
+
}
|
|
86
|
+
|
|
78
87
|
// Register the JS class and its associated native type.
|
|
79
88
|
if let sharedObjectType = associatedType as? DynamicSharedObjectType {
|
|
80
89
|
appContext.classRegistry.register(nativeClassId: sharedObjectType.typeIdentifier, javaScriptClass: klass)
|
|
@@ -122,6 +131,10 @@ public final class ClassDefinition: ObjectDefinition {
|
|
|
122
131
|
proto.setProperty(fn.name, value: try syncFn.build(appContext: appContext, in: runtime))
|
|
123
132
|
}
|
|
124
133
|
}
|
|
134
|
+
// Bind the macro's `@JS` members, which aren't in the DSL `properties`/`functions` dictionaries.
|
|
135
|
+
if let sharedObjectType = (associatedType as? DynamicSharedObjectType)?.innerType as? SharedObject.Type {
|
|
136
|
+
try sharedObjectType._decorateSharedObject(prototype: proto, in: runtime)
|
|
137
|
+
}
|
|
125
138
|
return proto
|
|
126
139
|
}
|
|
127
140
|
}
|