expo-modules-core 58.0.11 → 58.0.13
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 +24 -0
- package/android/build.gradle +3 -3
- package/android/cmake/common.cmake +13 -1
- package/android/cmake/jsi.cmake +1 -1
- package/android/cmake/main.cmake +1 -1
- package/android/cmake/pch-ccache.cmake +139 -0
- package/android/cmake/tests.cmake +1 -1
- package/android/cmake/worklets.cmake +1 -1
- package/android/prebuilt/metadata.json +2 -2
- package/android/prebuilt/native-libs.tar.xz +0 -0
- package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +3 -2
- package/android/src/main/java/expo/modules/kotlin/jni/PromiseImpl.kt +14 -5
- package/android/src/main/java/expo/modules/v2/ExpoModulesV2Host.kt +10 -4
- package/build/NativeViewManagerAdapter.native.js +46 -1
- package/build/NativeViewManagerAdapter.native.js.map +1 -1
- package/common/cpp/SharedObject.cpp +7 -2
- package/expo-module-gradle-plugin/build.gradle.kts +1 -1
- package/expo-module-gradle-plugin/src/main/kotlin/expo/modules/plugin/android/MavenPublicationExtension.kt +1 -1
- package/ios/Core/AppContext.swift +2 -1
- package/ios/Core/ArrayBuffers/ArrayBuffer.swift +5 -0
- package/ios/Core/Coding/JavaScriptCodable+Enumerable.swift +15 -0
- package/ios/Core/Coding/JavaScriptCodable+Record.swift +19 -3
- package/ios/Core/Coding/JavaScriptCodable+SharedObject.swift +5 -0
- package/ios/Core/Coding/JavaScriptCodable+TypedArray.swift +5 -0
- package/ios/Core/ExpoModulesMacros.swift +1 -1
- package/ios/Core/SharedObjects/SharedObject.swift +3 -3
- package/ios/Core/SharedObjects/SharedObjectNativeState.swift +8 -0
- package/ios/Core/SharedObjects/SharedObjectRegistry.swift +14 -3
- package/ios/Core/Views/SwiftUI/SwiftUIHostingView.swift +26 -17
- package/package.json +5 -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/src/NativeViewManagerAdapter.native.tsx +81 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 58.0.13
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [macOS] Attach SwiftUI hosting views even when no `NSViewController` is in the responder chain, such as a React root view set directly as `NSWindow.contentView`. Previously, `@expo/ui` content in such windows rendered nothing. ([#50995](https://github.com/expo/expo/pull/50995) by [@gabrieldonadel](https://github.com/gabrieldonadel))
|
|
8
|
+
- [iOS] Update `expo-modules-macros` to 0.15.0, which generates only the unowned decode for `@Union` and skips cases whose `decodableKinds` can't match. ([#50894](https://github.com/expo/expo/pull/50894) by [@tsapeta](https://github.com/tsapeta))
|
|
9
|
+
- [Internal] Make `AppContext` non-final, so that `TestAppContext` from `expo-modules-test-core` can subclass it. ([#51015](https://github.com/expo/expo/pull/51015) by [@tsapeta](https://github.com/tsapeta))
|
|
10
|
+
- [Android] Fixed a race where a promise resolved and rejected from different threads at the same time could settle twice and throw on the JavaScript thread. ([#51052](https://github.com/expo/expo/pull/51052) by [@alanjhughes](https://github.com/alanjhughes))
|
|
11
|
+
- [Android] An Expo Modules API 2.0 module that throws a `CodedException` now reports its `code` to JavaScript. ([#51036](https://github.com/expo/expo/pull/51036) by [@lukmccall](https://github.com/lukmccall))
|
|
12
|
+
- Updated dependencies. ([#50859](https://github.com/expo/expo/pull/50859), [#51015](https://github.com/expo/expo/pull/51015), [#51004](https://github.com/expo/expo/pull/51004), [#51040](https://github.com/expo/expo/pull/51040), [#51055](https://github.com/expo/expo/pull/51055))
|
|
13
|
+
- expo-modules-jsi@58.0.9
|
|
14
|
+
|
|
15
|
+
## 58.0.12
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- [Internal][Android] `expoPublish` now formats the updated `expo-module.config.json` with `oxfmt` instead of `prettier`. ([#47438](https://github.com/expo/expo/pull/47438) by [@hassankhan](https://github.com/hassankhan))
|
|
20
|
+
- [iOS] Add `decodableKinds` to `JavaScriptDecodable`: the kinds of JavaScript value (`JavaScriptValueKinds`) that `decode` can accept, so code that picks between several types can skip the ones that can't match. ([#50905](https://github.com/expo/expo/pull/50905) by [@tsapeta](https://github.com/tsapeta))
|
|
21
|
+
- [iOS] Add `JavaScriptValue.withUnownedValue(in:_:)`, and give the owning `JavaScriptDecodable.decode` a default that borrows the value and decodes it through the `JavaScriptUnownedValue` overload, so a conformer can implement only that one. Arrays, dictionaries, dates, records and enums now decode unowned values without copying them first. ([#50960](https://github.com/expo/expo/pull/50960) by [@tsapeta](https://github.com/tsapeta))
|
|
22
|
+
- Fixed native views ignoring `aria-*`, `id` and `tabIndex` props such as `aria-hidden` and `aria-label` ([#50782](https://github.com/expo/expo/issues/50782)). ([#50959](https://github.com/expo/expo/pull/50959) by [@alanjhughes](https://github.com/alanjhughes))
|
|
23
|
+
- Fixed `release()` throwing on a shared object whose JS object is frozen, for example an `ImageRef` passed as a view prop in development ([#50962](https://github.com/expo/expo/issues/50962)). ([#50970](https://github.com/expo/expo/pull/50970) by [@tsapeta](https://github.com/tsapeta))
|
|
24
|
+
- Updated dependencies. ([#50905](https://github.com/expo/expo/pull/50905), [#50698](https://github.com/expo/expo/pull/50698), [#50937](https://github.com/expo/expo/pull/50937), [#50888](https://github.com/expo/expo/pull/50888), [#50960](https://github.com/expo/expo/pull/50960), [#50980](https://github.com/expo/expo/pull/50980), [#50354](https://github.com/expo/expo/pull/50354))
|
|
25
|
+
- expo-modules-jsi@58.0.8
|
|
26
|
+
|
|
3
27
|
## 58.0.11
|
|
4
28
|
|
|
5
29
|
### Patch Changes
|
package/android/build.gradle
CHANGED
|
@@ -46,7 +46,7 @@ if (shouldIncludeCompose) {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
group = 'host.exp.exponent'
|
|
49
|
-
version = '58.0.
|
|
49
|
+
version = '58.0.13'
|
|
50
50
|
|
|
51
51
|
def isExpoModulesCoreTests = {
|
|
52
52
|
Gradle gradle = getGradle()
|
|
@@ -97,7 +97,7 @@ if (workletsProject != null) {
|
|
|
97
97
|
|
|
98
98
|
def reactNativeWorkletsRootDir = workletsProject?.projectDir?.parentFile
|
|
99
99
|
|
|
100
|
-
def expoModulesV2Version = "0.2.
|
|
100
|
+
def expoModulesV2Version = "0.2.4"
|
|
101
101
|
|
|
102
102
|
configurations {
|
|
103
103
|
// Artifact-only: the C++ sources, not something to put on any classpath.
|
|
@@ -175,7 +175,7 @@ android {
|
|
|
175
175
|
defaultConfig {
|
|
176
176
|
consumerProguardFiles 'proguard-rules.pro'
|
|
177
177
|
versionCode 1
|
|
178
|
-
versionName "58.0.
|
|
178
|
+
versionName "58.0.13"
|
|
179
179
|
buildConfigField "String", "EXPO_MODULES_CORE_VERSION", "\"${versionName}\""
|
|
180
180
|
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", "true"
|
|
181
181
|
|
|
@@ -27,6 +27,8 @@ target_link_libraries(
|
|
|
27
27
|
ReactAndroid::reactnative
|
|
28
28
|
)
|
|
29
29
|
|
|
30
|
+
include(${CMAKE_SOURCE_DIR}/cmake/pch-ccache.cmake)
|
|
31
|
+
|
|
30
32
|
function(use_expo_common target_name)
|
|
31
33
|
target_link_libraries(${target_name} PRIVATE EXPO_COMMON)
|
|
32
34
|
endfunction()
|
|
@@ -47,10 +49,12 @@ target_include_directories(
|
|
|
47
49
|
"${REACT_NATIVE_DIR}/ReactAndroid/src/main/jni"
|
|
48
50
|
)
|
|
49
51
|
|
|
52
|
+
set(EXPO_PCH_INCLUDE_OPTION "$<$<COMPILE_LANGUAGE:CXX>:-idirafter${CMAKE_SOURCE_DIR}/src/main/cpp>")
|
|
53
|
+
target_compile_options(expo-modules-pch PRIVATE ${EXPO_PCH_INCLUDE_OPTION})
|
|
50
54
|
target_precompile_headers(
|
|
51
55
|
expo-modules-pch
|
|
52
56
|
PRIVATE
|
|
53
|
-
|
|
57
|
+
"<ExpoHeader.pch>"
|
|
54
58
|
)
|
|
55
59
|
|
|
56
60
|
# Drop the timestamp embedded in the .pch so it stays bit-for-bit stable across
|
|
@@ -60,3 +64,11 @@ target_compile_options(
|
|
|
60
64
|
PRIVATE
|
|
61
65
|
"$<$<COMPILE_LANGUAGE:CXX>:-Xclang;-fno-pch-timestamp>"
|
|
62
66
|
)
|
|
67
|
+
|
|
68
|
+
pch_ccache_owner(expo-modules-pch)
|
|
69
|
+
|
|
70
|
+
function(use_expo_pch target_name)
|
|
71
|
+
target_precompile_headers(${target_name} REUSE_FROM expo-modules-pch)
|
|
72
|
+
target_compile_options(${target_name} PRIVATE ${EXPO_PCH_INCLUDE_OPTION})
|
|
73
|
+
pch_ccache_consumer(${target_name} expo-modules-pch)
|
|
74
|
+
endfunction()
|
package/android/cmake/jsi.cmake
CHANGED
package/android/cmake/main.cmake
CHANGED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Run as custom command
|
|
2
|
+
if(CMAKE_SCRIPT_MODE_FILE)
|
|
3
|
+
set(target_option)
|
|
4
|
+
if(COMPILER_TARGET)
|
|
5
|
+
set(target_option "--target=${COMPILER_TARGET}")
|
|
6
|
+
endif()
|
|
7
|
+
|
|
8
|
+
execute_process(
|
|
9
|
+
COMMAND "${COMPILER}" ${target_option} -module-file-info "${PCH}"
|
|
10
|
+
OUTPUT_VARIABLE info
|
|
11
|
+
RESULT_VARIABLE result
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
if(NOT result EQUAL 0)
|
|
15
|
+
# Hash the .pch itself, which is what ccache does without a .sum. The build stays correct, but
|
|
16
|
+
# checkouts at different paths don't share the results of the users of this PCH.
|
|
17
|
+
message(WARNING "`${COMPILER} -module-file-info ${PCH}` failed, so ccache can't share the results "
|
|
18
|
+
"of the users of this PCH between checkouts at different paths.")
|
|
19
|
+
file(SHA256 "${PCH}" digest)
|
|
20
|
+
file(WRITE "${PCH}.sum" "${digest}\n")
|
|
21
|
+
return()
|
|
22
|
+
endif()
|
|
23
|
+
|
|
24
|
+
# Remove `ShowColors` and `PCH_CCACHE_BUILD_DIR`
|
|
25
|
+
string(REGEX REPLACE "PCH_CCACHE_BUILD_DIR=[^\n]*|ShowColors: [^\n]*" "" info "${info}")
|
|
26
|
+
|
|
27
|
+
# Get all input files
|
|
28
|
+
string(REGEX MATCHALL "Input file: [^\n]*" input_files "${info}")
|
|
29
|
+
foreach(input_file IN LISTS input_files)
|
|
30
|
+
string(REGEX REPLACE "^Input file: | \\[[A-Za-z, ]+\\]$" "" path "${input_file}")
|
|
31
|
+
if(EXISTS "${path}")
|
|
32
|
+
file(SHA256 "${path}" digest)
|
|
33
|
+
string(APPEND info "${digest}\n")
|
|
34
|
+
endif()
|
|
35
|
+
endforeach()
|
|
36
|
+
|
|
37
|
+
# Remove base dir
|
|
38
|
+
if(BASE_DIR)
|
|
39
|
+
string(REGEX REPLACE "(.)/+$" "\\1" base_dir "${BASE_DIR}")
|
|
40
|
+
string(REGEX REPLACE "([][+.*()^$?|\\\\])" "\\\\\\1" base_dir_regex "${base_dir}")
|
|
41
|
+
# The directory itself or a path in it, followed by a space, a quote or a line break. A directory whose
|
|
42
|
+
# name only starts with the same text doesn't match.
|
|
43
|
+
string(REGEX MATCHALL "${base_dir_regex}(/[^ '\n]*)?[ '\n]" paths "${info}")
|
|
44
|
+
list(REMOVE_DUPLICATES paths)
|
|
45
|
+
foreach(path IN LISTS paths)
|
|
46
|
+
string(REGEX REPLACE "[ '\n]$" "" path "${path}")
|
|
47
|
+
file(RELATIVE_PATH relative_path "${BUILD_DIR}" "${path}")
|
|
48
|
+
string(REGEX REPLACE "([][+.*()^$?|\\\\])" "\\\\\\1" path_regex "${path}")
|
|
49
|
+
string(REGEX REPLACE "${path_regex}([ '\n])" "${relative_path}\\1" info "${info}")
|
|
50
|
+
endforeach()
|
|
51
|
+
endif()
|
|
52
|
+
|
|
53
|
+
string(SHA256 digest "${info}")
|
|
54
|
+
file(WRITE "${PCH}.sum" "${digest}\n")
|
|
55
|
+
return()
|
|
56
|
+
endif()
|
|
57
|
+
|
|
58
|
+
set(PCH_CCACHE_FILE "${CMAKE_CURRENT_LIST_FILE}")
|
|
59
|
+
|
|
60
|
+
# Find ccache program if it's used by the target
|
|
61
|
+
function(_pch_ccache_program target out_var)
|
|
62
|
+
get_target_property(launcher ${target} CXX_COMPILER_LAUNCHER)
|
|
63
|
+
get_property(global_rule GLOBAL PROPERTY RULE_LAUNCH_COMPILE)
|
|
64
|
+
get_property(directory_rule DIRECTORY PROPERTY RULE_LAUNCH_COMPILE)
|
|
65
|
+
separate_arguments(rules UNIX_COMMAND "${global_rule} ${directory_rule}")
|
|
66
|
+
get_filename_component(compiler "${CMAKE_CXX_COMPILER}" REALPATH)
|
|
67
|
+
foreach(program IN LISTS launcher rules compiler)
|
|
68
|
+
get_filename_component(name "${program}" NAME_WE)
|
|
69
|
+
if(name STREQUAL "ccache")
|
|
70
|
+
find_program(PCH_CCACHE_PROGRAM NAMES "${program}")
|
|
71
|
+
set(${out_var} "${PCH_CCACHE_PROGRAM}" PARENT_SCOPE)
|
|
72
|
+
return()
|
|
73
|
+
endif()
|
|
74
|
+
endforeach()
|
|
75
|
+
set(${out_var} "" PARENT_SCOPE)
|
|
76
|
+
endfunction()
|
|
77
|
+
|
|
78
|
+
function(pch_ccache_owner owner)
|
|
79
|
+
# CMake's location of the PCH for the Ninja and Makefile generators.
|
|
80
|
+
set(pch_dir "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${owner}.dir")
|
|
81
|
+
set(pch "${pch_dir}/cmake_pch.hxx.pch")
|
|
82
|
+
|
|
83
|
+
# Used by the custom command
|
|
84
|
+
set_property(SOURCE "${pch_dir}/cmake_pch.hxx.cxx" APPEND PROPERTY
|
|
85
|
+
COMPILE_DEFINITIONS "PCH_CCACHE_BUILD_DIR=${CMAKE_CURRENT_BINARY_DIR}"
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
set(pch_external_checksum "")
|
|
89
|
+
set(base_dir "")
|
|
90
|
+
_pch_ccache_program(${owner} ccache)
|
|
91
|
+
if(NOT ccache AND "$ENV{EXPO_FORCE_PCH_CCACHE_SUM}")
|
|
92
|
+
# ccache runs through a wrapper, so take its configuration from the ccache on PATH
|
|
93
|
+
find_program(PCH_CCACHE_PATH_PROGRAM ccache)
|
|
94
|
+
set(ccache "${PCH_CCACHE_PATH_PROGRAM}")
|
|
95
|
+
endif()
|
|
96
|
+
if(ccache)
|
|
97
|
+
foreach(option IN ITEMS pch_external_checksum base_dir)
|
|
98
|
+
execute_process(
|
|
99
|
+
COMMAND "${ccache}" --get-config ${option}
|
|
100
|
+
OUTPUT_VARIABLE ${option}
|
|
101
|
+
OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
102
|
+
ERROR_QUIET
|
|
103
|
+
)
|
|
104
|
+
endforeach()
|
|
105
|
+
endif()
|
|
106
|
+
|
|
107
|
+
if("$ENV{EXPO_FORCE_PCH_CCACHE_SUM}")
|
|
108
|
+
set(pch_external_checksum "true")
|
|
109
|
+
endif()
|
|
110
|
+
|
|
111
|
+
if(NOT pch_external_checksum STREQUAL "true")
|
|
112
|
+
# Remove the .sum of an earlier configuration: it can belong to an older PCH, and ccache would hash it
|
|
113
|
+
# if `pch_external_checksum` is enabled later.
|
|
114
|
+
file(REMOVE "${pch}.sum")
|
|
115
|
+
return()
|
|
116
|
+
endif()
|
|
117
|
+
|
|
118
|
+
add_custom_command(
|
|
119
|
+
OUTPUT "${pch}.sum"
|
|
120
|
+
COMMAND "${CMAKE_COMMAND}"
|
|
121
|
+
"-DCOMPILER=${CMAKE_CXX_COMPILER}"
|
|
122
|
+
"-DCOMPILER_TARGET=${CMAKE_CXX_COMPILER_TARGET}"
|
|
123
|
+
"-DPCH=${pch}"
|
|
124
|
+
"-DBASE_DIR=${base_dir}"
|
|
125
|
+
"-DBUILD_DIR=${CMAKE_BINARY_DIR}"
|
|
126
|
+
-P "${PCH_CCACHE_FILE}"
|
|
127
|
+
DEPENDS "${pch}" "${PCH_CCACHE_FILE}"
|
|
128
|
+
COMMENT "Writing the ccache checksum of the ${owner} PCH"
|
|
129
|
+
VERBATIM
|
|
130
|
+
)
|
|
131
|
+
add_custom_target(${owner}-pch-ccache-sum DEPENDS "${pch}.sum")
|
|
132
|
+
endfunction()
|
|
133
|
+
|
|
134
|
+
function(pch_ccache_consumer consumer owner)
|
|
135
|
+
# ccache reads the .sum when it compiles a source of <consumer>, so it must be written before.
|
|
136
|
+
if(TARGET ${owner}-pch-ccache-sum)
|
|
137
|
+
add_dependencies(${consumer} ${owner}-pch-ccache-sum)
|
|
138
|
+
endif()
|
|
139
|
+
endfunction()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"reactNativeVersion": "0.88.0",
|
|
3
|
-
"sourceHash": "
|
|
3
|
+
"sourceHash": "6f9421c9afcc3239b0995cea1757806a",
|
|
4
4
|
"variants": [
|
|
5
5
|
"debug",
|
|
6
6
|
"release"
|
|
@@ -16,5 +16,5 @@
|
|
|
16
16
|
"libexpo-modules-jsi.so"
|
|
17
17
|
],
|
|
18
18
|
"stripped": true,
|
|
19
|
-
"createdAt": "2026-
|
|
19
|
+
"createdAt": "2026-10-05T21:13:27.466871505Z"
|
|
20
20
|
}
|
|
Binary file
|
|
@@ -3,6 +3,7 @@ package expo.modules.kotlin.exception
|
|
|
3
3
|
import com.facebook.react.bridge.ReadableType
|
|
4
4
|
import expo.modules.core.interfaces.DoNotStrip
|
|
5
5
|
import expo.modules.kotlin.types.descriptors.TypeDescriptor
|
|
6
|
+
import io.github.expo.modules.v2.JavaScriptThrowable
|
|
6
7
|
import java.util.*
|
|
7
8
|
import kotlin.reflect.KClass
|
|
8
9
|
import kotlin.reflect.KProperty1
|
|
@@ -23,13 +24,13 @@ inline fun Throwable?.toCodedException() = when (this) {
|
|
|
23
24
|
open class CodedException(
|
|
24
25
|
message: String?,
|
|
25
26
|
cause: Throwable? = null
|
|
26
|
-
) :
|
|
27
|
+
) : JavaScriptThrowable(message, cause) {
|
|
27
28
|
// We need that secondary property, cause we can't access
|
|
28
29
|
// the javaClass property in the constructor.
|
|
29
30
|
private var providedCode: String? = null
|
|
30
31
|
|
|
31
32
|
@get:DoNotStrip
|
|
32
|
-
val code
|
|
33
|
+
final override val code: String
|
|
33
34
|
get() = providedCode ?: inferCode(javaClass)
|
|
34
35
|
|
|
35
36
|
constructor(code: String?, message: String?, cause: Throwable?) : this(message = message, cause = cause) {
|
|
@@ -4,13 +4,15 @@ import expo.modules.core.interfaces.DoNotStrip
|
|
|
4
4
|
import expo.modules.kotlin.AppContext
|
|
5
5
|
import expo.modules.kotlin.Promise
|
|
6
6
|
import java.lang.ref.WeakReference
|
|
7
|
+
import java.util.concurrent.atomic.AtomicBoolean
|
|
7
8
|
|
|
8
9
|
@DoNotStrip
|
|
9
10
|
class PromiseImpl @DoNotStrip internal constructor(
|
|
10
11
|
@DoNotStrip internal val callback: JavaCallback
|
|
11
12
|
) : Promise {
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
private val settled = AtomicBoolean(false)
|
|
14
|
+
internal val wasSettled: Boolean
|
|
15
|
+
get() = settled.get()
|
|
14
16
|
private var appContextHolder: WeakReference<AppContext>? = null
|
|
15
17
|
private var fullFunctionName: String? = null
|
|
16
18
|
|
|
@@ -57,12 +59,19 @@ class PromiseImpl @DoNotStrip internal constructor(
|
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
private inline fun checkIfWasSettled(body: () -> Unit) {
|
|
60
|
-
if (
|
|
62
|
+
if (!settled.compareAndSet(false, true)) {
|
|
61
63
|
return
|
|
62
64
|
}
|
|
63
65
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
+
var didSettle = false
|
|
67
|
+
try {
|
|
68
|
+
body()
|
|
69
|
+
didSettle = true
|
|
70
|
+
} finally {
|
|
71
|
+
if (!didSettle) {
|
|
72
|
+
settled.set(false)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
66
75
|
}
|
|
67
76
|
|
|
68
77
|
fun decorateWithDebugInformation(
|
|
@@ -3,7 +3,6 @@ package expo.modules.v2
|
|
|
3
3
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
4
4
|
import expo.modules.kotlin.logger
|
|
5
5
|
import io.github.expo.modules.v2.Module
|
|
6
|
-
import io.github.expo.modules.v2.modules.ModuleRegistry
|
|
7
6
|
import io.github.expo.modules.v2.react.ReactRuntime
|
|
8
7
|
import java.lang.reflect.Modifier
|
|
9
8
|
|
|
@@ -31,9 +30,16 @@ object ExpoModulesV2Host {
|
|
|
31
30
|
}
|
|
32
31
|
|
|
33
32
|
try {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
// The runtime creates a context of its own, and serves the modules of that context.
|
|
34
|
+
val attached = ReactRuntime.attach(reactContext)
|
|
35
|
+
try {
|
|
36
|
+
modules.forEach(attached.moduleRegistry::register)
|
|
37
|
+
} catch (e: Throwable) {
|
|
38
|
+
// Closing the runtime closes its context, so no module stays bound to it.
|
|
39
|
+
attached.close()
|
|
40
|
+
throw e
|
|
41
|
+
}
|
|
42
|
+
runtime = attached
|
|
37
43
|
logger.info("✅ Expo Modules v2 installed ${modules.size} module(s) on globalThis.expo.modules")
|
|
38
44
|
} catch (e: Throwable) {
|
|
39
45
|
logger.error("❌ Cannot install Expo Modules v2: $e", e)
|
|
@@ -84,6 +84,51 @@ import { requireNativeModule } from './requireNativeModule';
|
|
|
84
84
|
}
|
|
85
85
|
return cachedNativeComponent;
|
|
86
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* Maps `aria-*`, `id` and `tabIndex` props to native props.
|
|
89
|
+
* Mirrors `Libraries/Components/View/View.js` in React Native 0.88.
|
|
90
|
+
*/ function mapAriaProps(props) {
|
|
91
|
+
const { accessibilityState, accessibilityValue, 'aria-busy': ariaBusy, 'aria-checked': ariaChecked, 'aria-disabled': ariaDisabled, 'aria-expanded': ariaExpanded, 'aria-hidden': ariaHidden, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, 'aria-live': ariaLive, 'aria-selected': ariaSelected, 'aria-valuemax': ariaValueMax, 'aria-valuemin': ariaValueMin, 'aria-valuenow': ariaValueNow, 'aria-valuetext': ariaValueText, id, tabIndex, ...resolvedProps } = props;
|
|
92
|
+
if (ariaLabelledBy !== undefined) {
|
|
93
|
+
resolvedProps.accessibilityLabelledBy = ariaLabelledBy.split(/\s*,\s*/g);
|
|
94
|
+
}
|
|
95
|
+
if (ariaLabel !== undefined) {
|
|
96
|
+
resolvedProps.accessibilityLabel = ariaLabel;
|
|
97
|
+
}
|
|
98
|
+
if (ariaLive !== undefined) {
|
|
99
|
+
resolvedProps.accessibilityLiveRegion = ariaLive === 'off' ? 'none' : ariaLive;
|
|
100
|
+
}
|
|
101
|
+
if (ariaHidden !== undefined) {
|
|
102
|
+
resolvedProps.accessibilityElementsHidden = ariaHidden;
|
|
103
|
+
if (ariaHidden === true) {
|
|
104
|
+
resolvedProps.importantForAccessibility = 'no-hide-descendants';
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (id !== undefined) {
|
|
108
|
+
resolvedProps.nativeID = id;
|
|
109
|
+
}
|
|
110
|
+
if (tabIndex !== undefined) {
|
|
111
|
+
resolvedProps.focusable = !tabIndex;
|
|
112
|
+
}
|
|
113
|
+
if (accessibilityState != null || ariaBusy != null || ariaChecked != null || ariaDisabled != null || ariaExpanded != null || ariaSelected != null) {
|
|
114
|
+
resolvedProps.accessibilityState = {
|
|
115
|
+
busy: ariaBusy ?? accessibilityState?.busy,
|
|
116
|
+
checked: ariaChecked ?? accessibilityState?.checked,
|
|
117
|
+
disabled: ariaDisabled ?? accessibilityState?.disabled,
|
|
118
|
+
expanded: ariaExpanded ?? accessibilityState?.expanded,
|
|
119
|
+
selected: ariaSelected ?? accessibilityState?.selected
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
if (accessibilityValue != null || ariaValueMax != null || ariaValueMin != null || ariaValueNow != null || ariaValueText != null) {
|
|
123
|
+
resolvedProps.accessibilityValue = {
|
|
124
|
+
max: ariaValueMax ?? accessibilityValue?.max,
|
|
125
|
+
min: ariaValueMin ?? accessibilityValue?.min,
|
|
126
|
+
now: ariaValueNow ?? accessibilityValue?.now,
|
|
127
|
+
text: ariaValueText ?? accessibilityValue?.text
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
return resolvedProps;
|
|
131
|
+
}
|
|
87
132
|
/**
|
|
88
133
|
* A drop-in replacement for `requireNativeComponent`.
|
|
89
134
|
*/ export function requireNativeViewManager(moduleName, viewName) {
|
|
@@ -104,7 +149,7 @@ import { requireNativeModule } from './requireNativeModule';
|
|
|
104
149
|
}
|
|
105
150
|
render() {
|
|
106
151
|
return /*#__PURE__*/ _jsx(ReactNativeComponent, {
|
|
107
|
-
...this.props,
|
|
152
|
+
...mapAriaProps(this.props),
|
|
108
153
|
ref: this.nativeRef
|
|
109
154
|
});
|
|
110
155
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["NativeViewManagerAdapter.native.tsx"],"sourcesContent":[null],"names":["createRef","PureComponent","findNodeHandle","get","componentRegistryGet","SharedObject","requireNativeModule","nativeComponentsCache","Map","requireNativeComponent","moduleName","viewName","appIdentifier","globalThis","expo","viewNameSuffix","nativeViewName","expoViewConfig","getViewConfig","console","warn","uiViewClassName","directEventTypes","validAttributes","addAttributeProcessing","processPropValue","value","sharedObjectId","__expo_shared_object_id__","descriptor","process","attributes","key","Object","keys","requireCachedNativeComponent","cacheKey","cachedNativeComponent","nativeComponent","set","requireNativeViewManager","ReactNativeComponent","NativeComponent","displayName","nativeRef","nativeTag","componentDidMount","current","getNativeRef","render","
|
|
1
|
+
{"version":3,"sources":["NativeViewManagerAdapter.native.tsx"],"sourcesContent":[null],"names":["createRef","PureComponent","findNodeHandle","get","componentRegistryGet","SharedObject","requireNativeModule","nativeComponentsCache","Map","requireNativeComponent","moduleName","viewName","appIdentifier","globalThis","expo","viewNameSuffix","nativeViewName","expoViewConfig","getViewConfig","console","warn","uiViewClassName","directEventTypes","validAttributes","addAttributeProcessing","processPropValue","value","sharedObjectId","__expo_shared_object_id__","descriptor","process","attributes","key","Object","keys","requireCachedNativeComponent","cacheKey","cachedNativeComponent","nativeComponent","set","mapAriaProps","props","accessibilityState","accessibilityValue","ariaBusy","ariaChecked","ariaDisabled","ariaExpanded","ariaHidden","ariaLabel","ariaLabelledBy","ariaLive","ariaSelected","ariaValueMax","ariaValueMin","ariaValueNow","ariaValueText","id","tabIndex","resolvedProps","undefined","accessibilityLabelledBy","split","accessibilityLabel","accessibilityLiveRegion","accessibilityElementsHidden","importantForAccessibility","nativeID","focusable","busy","checked","disabled","expanded","selected","max","min","now","text","requireNativeViewManager","ReactNativeComponent","NativeComponent","displayName","nativeRef","nativeTag","componentDidMount","current","getNativeRef","render","ref","nativeModule","nativeViewPrototype","ViewPrototypes","assign","prototype"],"mappings":"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"}
|
|
@@ -38,8 +38,13 @@ void installBaseClass(jsi::Runtime &runtime, const ObjectReleaser& releaser) {
|
|
|
38
38
|
|
|
39
39
|
releaser(nativeState->objectId);
|
|
40
40
|
|
|
41
|
-
//
|
|
42
|
-
|
|
41
|
+
// Resetting the native state throws when the object is frozen, for example a shared object
|
|
42
|
+
// passed as a view prop, which React Native deep-freezes in development. The native object
|
|
43
|
+
// is already released, so the native state can stay.
|
|
44
|
+
try {
|
|
45
|
+
thisObject.setNativeState(runtime, nullptr);
|
|
46
|
+
} catch (const jsi::JSIException &) {
|
|
47
|
+
}
|
|
43
48
|
}
|
|
44
49
|
return jsi::Value::undefined();
|
|
45
50
|
});
|
|
@@ -33,7 +33,7 @@ dependencies {
|
|
|
33
33
|
implementation("com.facebook.react:react-native-gradle-plugin")
|
|
34
34
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
|
|
35
35
|
implementation("io.github.expo.pika:pika-gradle:1.1.0")
|
|
36
|
-
implementation("io.github.expo:expo-modules-v2-gradle-plugin:0.2.
|
|
36
|
+
implementation("io.github.expo:expo-modules-v2-gradle-plugin:0.2.4")
|
|
37
37
|
|
|
38
38
|
if (isExpoAutolinkingSettingsPluginAvailable) {
|
|
39
39
|
implementation("expo.modules:expo-autolinking-plugin-shared")
|
|
@@ -204,7 +204,7 @@ private fun Project.expoPublishBody(publicationInfo: PublicationInfo, expoModule
|
|
|
204
204
|
providers.exec { env ->
|
|
205
205
|
env.workingDir(layout.projectDirectory.file(".."))
|
|
206
206
|
// TODO(@lukmccall): support other package managers
|
|
207
|
-
env.commandLine("pnpm", "
|
|
207
|
+
env.commandLine("pnpm", "oxfmt", "--write", "expo-module.config.json")
|
|
208
208
|
}.result.get()
|
|
209
209
|
}
|
|
210
210
|
|
|
@@ -3,9 +3,10 @@ import ExpoModulesJSI
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
The app context is an interface to a single Expo app.
|
|
6
|
+
Not `final` so that `TestAppContext` from `ExpoModulesTestCore` can subclass it.
|
|
6
7
|
*/
|
|
7
8
|
@objc(EXAppContext)
|
|
8
|
-
public
|
|
9
|
+
public class AppContext: NSObject, EXAppContextProtocol, @unchecked Sendable {
|
|
9
10
|
internal static func create() -> AppContext {
|
|
10
11
|
let appContext = AppContext()
|
|
11
12
|
|
|
@@ -225,6 +225,11 @@ public final class ArrayBuffer: AnyArrayBuffer, Sendable {
|
|
|
225
225
|
}
|
|
226
226
|
|
|
227
227
|
extension ArrayBuffer: JavaScriptDecodable, JavaScriptEncodable {
|
|
228
|
+
@inlinable
|
|
229
|
+
public static var decodableKinds: JavaScriptValueKinds {
|
|
230
|
+
return .object
|
|
231
|
+
}
|
|
232
|
+
|
|
228
233
|
// MARK: - JavaScriptDecodable
|
|
229
234
|
@JavaScriptActor
|
|
230
235
|
@inlinable
|
|
@@ -7,6 +7,12 @@ import ExpoModulesJSI
|
|
|
7
7
|
// `String` or an integer type), delegating the actual conversion to that raw value's conformance.
|
|
8
8
|
|
|
9
9
|
extension Enumerable where Self: RawRepresentable, RawValue: JavaScriptCodable {
|
|
10
|
+
// An enum decodes through its raw value, so it accepts what the raw value accepts.
|
|
11
|
+
@inlinable
|
|
12
|
+
public static var decodableKinds: JavaScriptValueKinds {
|
|
13
|
+
return RawValue.decodableKinds
|
|
14
|
+
}
|
|
15
|
+
|
|
10
16
|
@JavaScriptActor
|
|
11
17
|
@inlinable
|
|
12
18
|
public static func decode(_ value: borrowing JavaScriptValue, in runtime: borrowing JavaScriptRuntime) throws -> Self
|
|
@@ -15,6 +21,15 @@ extension Enumerable where Self: RawRepresentable, RawValue: JavaScriptCodable {
|
|
|
15
21
|
return try create(fromRawValue: rawValue)
|
|
16
22
|
}
|
|
17
23
|
|
|
24
|
+
@JavaScriptActor
|
|
25
|
+
@inlinable
|
|
26
|
+
public static func decode(_ value: borrowing JavaScriptUnownedValue, in runtime: borrowing JavaScriptRuntime) throws
|
|
27
|
+
-> Self
|
|
28
|
+
{
|
|
29
|
+
let rawValue = try RawValue.decode(value, in: runtime)
|
|
30
|
+
return try create(fromRawValue: rawValue)
|
|
31
|
+
}
|
|
32
|
+
|
|
18
33
|
@JavaScriptActor
|
|
19
34
|
@inlinable
|
|
20
35
|
public static func encode(_ value: Self, in runtime: borrowing JavaScriptRuntime) throws -> JavaScriptValue {
|
|
@@ -14,11 +14,16 @@ import ExpoModulesJSI
|
|
|
14
14
|
// context never prepared has no such state, so recovery returns `nil` and the conversion throws
|
|
15
15
|
// `Exceptions.AppContextNotFound`.
|
|
16
16
|
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
// the defaulted overload materializes an owning value and forwards.
|
|
17
|
+
// Both `decode` overloads read the object and hand it to `from(object:appContext:)`. The unowned one
|
|
18
|
+
// reads it straight from the borrowed value, so a record argument isn't copied first.
|
|
20
19
|
|
|
21
20
|
extension Record {
|
|
21
|
+
// A record decodes only from an object.
|
|
22
|
+
@inlinable
|
|
23
|
+
public static var decodableKinds: JavaScriptValueKinds {
|
|
24
|
+
return .object
|
|
25
|
+
}
|
|
26
|
+
|
|
22
27
|
@JavaScriptActor
|
|
23
28
|
@inlinable
|
|
24
29
|
public static func decode(_ value: borrowing JavaScriptValue, in runtime: borrowing JavaScriptRuntime) throws -> Self
|
|
@@ -29,6 +34,17 @@ extension Record {
|
|
|
29
34
|
return try from(object: value.asObject(), appContext: appContext)
|
|
30
35
|
}
|
|
31
36
|
|
|
37
|
+
@JavaScriptActor
|
|
38
|
+
@inlinable
|
|
39
|
+
public static func decode(_ value: borrowing JavaScriptUnownedValue, in runtime: borrowing JavaScriptRuntime) throws
|
|
40
|
+
-> Self
|
|
41
|
+
{
|
|
42
|
+
guard let appContext = AppContext.from(runtime: runtime) else {
|
|
43
|
+
throw Exceptions.AppContextNotFound()
|
|
44
|
+
}
|
|
45
|
+
return try from(object: value.asObject(in: runtime), appContext: appContext)
|
|
46
|
+
}
|
|
47
|
+
|
|
32
48
|
@JavaScriptActor
|
|
33
49
|
@inlinable
|
|
34
50
|
public static func encode(_ value: Self, in runtime: borrowing JavaScriptRuntime) throws -> JavaScriptValue {
|
|
@@ -7,6 +7,11 @@ import ExpoModulesJSI
|
|
|
7
7
|
// object's structure like `Record`.
|
|
8
8
|
|
|
9
9
|
extension SharedObject: JavaScriptDecodable, JavaScriptEncodable {
|
|
10
|
+
@inlinable
|
|
11
|
+
public static var decodableKinds: JavaScriptValueKinds {
|
|
12
|
+
return .object
|
|
13
|
+
}
|
|
14
|
+
|
|
10
15
|
@JavaScriptActor
|
|
11
16
|
@inlinable
|
|
12
17
|
public static func decode(_ value: borrowing JavaScriptValue, in runtime: borrowing JavaScriptRuntime) throws -> Self
|
|
@@ -8,6 +8,11 @@ import ExpoModulesJSI
|
|
|
8
8
|
// `TypedArray.swift` / `ConcreteTypedArrays.swift`.
|
|
9
9
|
|
|
10
10
|
extension TypedArray: JavaScriptDecodable, JavaScriptEncodable {
|
|
11
|
+
@inlinable
|
|
12
|
+
public static var decodableKinds: JavaScriptValueKinds {
|
|
13
|
+
return .object
|
|
14
|
+
}
|
|
15
|
+
|
|
11
16
|
@JavaScriptActor
|
|
12
17
|
@inlinable
|
|
13
18
|
public static func encode(_ value: TypedArray, in runtime: borrowing JavaScriptRuntime) throws -> JavaScriptValue {
|
|
@@ -216,7 +216,7 @@ public macro Record() =
|
|
|
216
216
|
/// }
|
|
217
217
|
@attached(
|
|
218
218
|
member,
|
|
219
|
-
names: named(decode), named(encode), named(`as`), named(_payloadTypeName),
|
|
219
|
+
names: named(decode), named(encode), named(decodableKinds), named(`as`), named(_payloadTypeName),
|
|
220
220
|
named(_assertTypesConformance))
|
|
221
221
|
@attached(extension, conformances: JavaScriptDecodable, JavaScriptEncodable)
|
|
222
222
|
public macro Union() =
|
|
@@ -119,13 +119,13 @@ extension SharedObject {
|
|
|
119
119
|
/// Returns the base `SharedObject`. Callers wanting a concrete subclass use the `as:` overload, which
|
|
120
120
|
/// performs a checked downcast.
|
|
121
121
|
///
|
|
122
|
-
/// Throws `NotFoundException` when the object carries no native state.
|
|
122
|
+
/// Throws `NotFoundException` when the object carries no native state or its native object was released.
|
|
123
123
|
@JavaScriptActor
|
|
124
124
|
public static func native(from jsObject: borrowing JavaScriptObject) throws -> SharedObject {
|
|
125
|
-
guard let
|
|
125
|
+
guard let nativeState = jsObject.getNativeState(as: SharedObjectNativeState.self), !nativeState.isReleased else {
|
|
126
126
|
throw NotFoundException()
|
|
127
127
|
}
|
|
128
|
-
return native
|
|
128
|
+
return nativeState.native
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
/// Recovers the native shared object and casts it to the given subclass, e.g.
|
|
@@ -13,6 +13,10 @@ import ExpoModulesJSI
|
|
|
13
13
|
internal final class SharedObjectNativeState: JavaScriptNativeState {
|
|
14
14
|
internal let native: SharedObject
|
|
15
15
|
|
|
16
|
+
/// Whether the native object was released. A JS object can keep its native state after the release
|
|
17
|
+
/// (for example a frozen one, whose native state can't be reset), so lookups check this flag.
|
|
18
|
+
internal private(set) var isReleased = false
|
|
19
|
+
|
|
16
20
|
/// The JS object paired with the native object in each runtime, keyed by runtime identity and held
|
|
17
21
|
/// weakly. One native object can be exposed to several runtimes (e.g. the main and UI runtimes, or
|
|
18
22
|
/// worklet contexts), each with its own JS counterpart.
|
|
@@ -23,6 +27,10 @@ internal final class SharedObjectNativeState: JavaScriptNativeState {
|
|
|
23
27
|
super.init(factory: factory)
|
|
24
28
|
}
|
|
25
29
|
|
|
30
|
+
internal func markReleased() {
|
|
31
|
+
isReleased = true
|
|
32
|
+
}
|
|
33
|
+
|
|
26
34
|
/// Records `jsObject` as the native object's JS counterpart in `runtime`. The caller is responsible
|
|
27
35
|
/// for having attached this native state to `jsObject` (`jsObject.setNativeState(self)`), which reuses
|
|
28
36
|
/// the shared C++ pointee across runtimes.
|
|
@@ -96,7 +96,8 @@ public final class SharedObjectRegistry: Sendable {
|
|
|
96
96
|
// A native object that already carries a native state was paired in an earlier runtime. Reuse its
|
|
97
97
|
// id rather than minting a new one: the C++ `NativeState.objectId` is immutable and drives the
|
|
98
98
|
// releaser/`delete`, so a fresh id would disagree with it and leak this object's registry entry.
|
|
99
|
-
let
|
|
99
|
+
let existingNativeState = unreleasedNativeState(of: nativeObject)
|
|
100
|
+
let id = existingNativeState != nil ? nativeObject.sharedObjectId : pullNextId()
|
|
100
101
|
|
|
101
102
|
// Assign the ID and the app context to the object.
|
|
102
103
|
nativeObject.sharedObjectId = id
|
|
@@ -124,7 +125,7 @@ public final class SharedObjectRegistry: Sendable {
|
|
|
124
125
|
// Reuse it so all runtimes share one native state (and one underlying C++ pointee, via
|
|
125
126
|
// `acquireShared`); a fresh state per runtime would leave `nativeObject.nativeState` pointing at
|
|
126
127
|
// whichever ran last and lose the earlier runtimes' pairings.
|
|
127
|
-
let nativeState =
|
|
128
|
+
let nativeState = existingNativeState ?? {
|
|
128
129
|
let releaser: ObjectReleaser = { [weak self] id in
|
|
129
130
|
self?.delete(id)
|
|
130
131
|
}
|
|
@@ -169,6 +170,7 @@ public final class SharedObjectRegistry: Sendable {
|
|
|
169
170
|
state.withLock { state in
|
|
170
171
|
if let nativeState = state.pairs[id] {
|
|
171
172
|
let native = nativeState.native
|
|
173
|
+
nativeState.markReleased()
|
|
172
174
|
native.sharedObjectWillRelease()
|
|
173
175
|
// Reset an ID on the object.
|
|
174
176
|
native.sharedObjectId = 0
|
|
@@ -230,12 +232,21 @@ public final class SharedObjectRegistry: Sendable {
|
|
|
230
232
|
// The id table and the native object both resolve to the same `SharedObjectNativeState`, which
|
|
231
233
|
// owns the per-runtime JS counterparts, so a single lookup serves both. Prefer the native object's
|
|
232
234
|
// own back-pointer and fall back to the id table for objects whose back-pointer was cleared.
|
|
233
|
-
let nativeState = nativeObject
|
|
235
|
+
let nativeState = unreleasedNativeState(of: nativeObject) ?? state.withLock { state in
|
|
234
236
|
return state.pairs[nativeObject.sharedObjectId]
|
|
235
237
|
}
|
|
236
238
|
return nativeState?.javaScriptObject(in: runtime)
|
|
237
239
|
}
|
|
238
240
|
|
|
241
|
+
/// Returns the native object's native state, or `nil` if it was released. A released native state can
|
|
242
|
+
/// outlive the release on a JS object that couldn't drop it (for example a frozen one).
|
|
243
|
+
private func unreleasedNativeState(of nativeObject: SharedObject) -> SharedObjectNativeState? {
|
|
244
|
+
guard let nativeState = nativeObject.nativeState, !nativeState.isReleased else {
|
|
245
|
+
return nil
|
|
246
|
+
}
|
|
247
|
+
return nativeState
|
|
248
|
+
}
|
|
249
|
+
|
|
239
250
|
/**
|
|
240
251
|
Creates a plain JS object and pairs it with a given native object.
|
|
241
252
|
*/
|
|
@@ -223,26 +223,35 @@ extension ExpoSwiftUI {
|
|
|
223
223
|
}
|
|
224
224
|
#endif
|
|
225
225
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
hostingController.didMove(toParent: parentController)
|
|
240
|
-
#endif
|
|
241
|
-
setupHostingViewConstraints()
|
|
242
|
-
} else {
|
|
226
|
+
guard window != nil else {
|
|
227
|
+
hostingController.view.removeFromSuperview()
|
|
228
|
+
hostingController.removeFromParent()
|
|
229
|
+
return
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
let parentController = reactViewController()
|
|
233
|
+
#if os(macOS)
|
|
234
|
+
// An `NSHostingController` view renders without a parent controller, and a React root view used
|
|
235
|
+
// directly as `NSWindow.contentView` has none in its responder chain, so don't require one.
|
|
236
|
+
parentController?.addChild(hostingController)
|
|
237
|
+
#else
|
|
238
|
+
guard let parentController else {
|
|
243
239
|
hostingController.view.removeFromSuperview()
|
|
244
240
|
hostingController.removeFromParent()
|
|
241
|
+
return
|
|
242
|
+
}
|
|
243
|
+
if parentController as? UINavigationController == nil && parentController as? UITabBarController == nil {
|
|
244
|
+
// Swift automatically adds the hostingController in the correct place when the parentController
|
|
245
|
+
// is UINavigationController, since its children are supposed to be only screens.
|
|
246
|
+
// Similarly, for UITabBarController we expect its children to be only tabs.
|
|
247
|
+
parentController.addChild(hostingController)
|
|
245
248
|
}
|
|
249
|
+
#endif
|
|
250
|
+
addSubview(hostingController.view)
|
|
251
|
+
#if os(iOS) || os(tvOS)
|
|
252
|
+
hostingController.didMove(toParent: parentController)
|
|
253
|
+
#endif
|
|
254
|
+
setupHostingViewConstraints()
|
|
246
255
|
}
|
|
247
256
|
|
|
248
257
|
#if os(macOS)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-modules-core",
|
|
3
|
-
"version": "58.0.
|
|
3
|
+
"version": "58.0.13",
|
|
4
4
|
"description": "The core of Expo Modules architecture",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"expo",
|
|
@@ -64,8 +64,8 @@
|
|
|
64
64
|
"./package.json": "./package.json"
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"expo-modules-jsi": "~58.0.
|
|
68
|
-
"expo-modules-macros": "0.
|
|
67
|
+
"expo-modules-jsi": "~58.0.9",
|
|
68
|
+
"expo-modules-macros": "0.15.0",
|
|
69
69
|
"invariant": "^2.2.4"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"@types/invariant": "^2.2.33",
|
|
74
74
|
"@types/react": "~19.3.0",
|
|
75
75
|
"@types/react-dom": "^19.1.7",
|
|
76
|
-
"expo-module-scripts": "56.0.
|
|
76
|
+
"expo-module-scripts": "56.0.7",
|
|
77
77
|
"react-dom": "19.3.0"
|
|
78
78
|
},
|
|
79
79
|
"peerDependencies": {
|
|
@@ -89,6 +89,7 @@
|
|
|
89
89
|
"scripts": {
|
|
90
90
|
"build": "expo-build src",
|
|
91
91
|
"precompile-ios": "et prebuild-package-for-publish",
|
|
92
|
+
"precompile-android": "et prebuild-android-package-for-publish",
|
|
92
93
|
"clean": "expo-module clean",
|
|
93
94
|
"lint": "oxlint --config oxlint.config.mjs .",
|
|
94
95
|
"format": "expo-module format",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -128,6 +128,86 @@ function requireCachedNativeComponent<Props>(
|
|
|
128
128
|
return cachedNativeComponent;
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
/**
|
|
132
|
+
* Maps `aria-*`, `id` and `tabIndex` props to native props.
|
|
133
|
+
* Mirrors `Libraries/Components/View/View.js` in React Native 0.88.
|
|
134
|
+
*/
|
|
135
|
+
function mapAriaProps(props: Record<string, any>): Record<string, any> {
|
|
136
|
+
const {
|
|
137
|
+
accessibilityState,
|
|
138
|
+
accessibilityValue,
|
|
139
|
+
'aria-busy': ariaBusy,
|
|
140
|
+
'aria-checked': ariaChecked,
|
|
141
|
+
'aria-disabled': ariaDisabled,
|
|
142
|
+
'aria-expanded': ariaExpanded,
|
|
143
|
+
'aria-hidden': ariaHidden,
|
|
144
|
+
'aria-label': ariaLabel,
|
|
145
|
+
'aria-labelledby': ariaLabelledBy,
|
|
146
|
+
'aria-live': ariaLive,
|
|
147
|
+
'aria-selected': ariaSelected,
|
|
148
|
+
'aria-valuemax': ariaValueMax,
|
|
149
|
+
'aria-valuemin': ariaValueMin,
|
|
150
|
+
'aria-valuenow': ariaValueNow,
|
|
151
|
+
'aria-valuetext': ariaValueText,
|
|
152
|
+
id,
|
|
153
|
+
tabIndex,
|
|
154
|
+
...resolvedProps
|
|
155
|
+
} = props;
|
|
156
|
+
|
|
157
|
+
if (ariaLabelledBy !== undefined) {
|
|
158
|
+
resolvedProps.accessibilityLabelledBy = ariaLabelledBy.split(/\s*,\s*/g);
|
|
159
|
+
}
|
|
160
|
+
if (ariaLabel !== undefined) {
|
|
161
|
+
resolvedProps.accessibilityLabel = ariaLabel;
|
|
162
|
+
}
|
|
163
|
+
if (ariaLive !== undefined) {
|
|
164
|
+
resolvedProps.accessibilityLiveRegion = ariaLive === 'off' ? 'none' : ariaLive;
|
|
165
|
+
}
|
|
166
|
+
if (ariaHidden !== undefined) {
|
|
167
|
+
resolvedProps.accessibilityElementsHidden = ariaHidden;
|
|
168
|
+
if (ariaHidden === true) {
|
|
169
|
+
resolvedProps.importantForAccessibility = 'no-hide-descendants';
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if (id !== undefined) {
|
|
173
|
+
resolvedProps.nativeID = id;
|
|
174
|
+
}
|
|
175
|
+
if (tabIndex !== undefined) {
|
|
176
|
+
resolvedProps.focusable = !tabIndex;
|
|
177
|
+
}
|
|
178
|
+
if (
|
|
179
|
+
accessibilityState != null ||
|
|
180
|
+
ariaBusy != null ||
|
|
181
|
+
ariaChecked != null ||
|
|
182
|
+
ariaDisabled != null ||
|
|
183
|
+
ariaExpanded != null ||
|
|
184
|
+
ariaSelected != null
|
|
185
|
+
) {
|
|
186
|
+
resolvedProps.accessibilityState = {
|
|
187
|
+
busy: ariaBusy ?? accessibilityState?.busy,
|
|
188
|
+
checked: ariaChecked ?? accessibilityState?.checked,
|
|
189
|
+
disabled: ariaDisabled ?? accessibilityState?.disabled,
|
|
190
|
+
expanded: ariaExpanded ?? accessibilityState?.expanded,
|
|
191
|
+
selected: ariaSelected ?? accessibilityState?.selected,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
if (
|
|
195
|
+
accessibilityValue != null ||
|
|
196
|
+
ariaValueMax != null ||
|
|
197
|
+
ariaValueMin != null ||
|
|
198
|
+
ariaValueNow != null ||
|
|
199
|
+
ariaValueText != null
|
|
200
|
+
) {
|
|
201
|
+
resolvedProps.accessibilityValue = {
|
|
202
|
+
max: ariaValueMax ?? accessibilityValue?.max,
|
|
203
|
+
min: ariaValueMin ?? accessibilityValue?.min,
|
|
204
|
+
now: ariaValueNow ?? accessibilityValue?.now,
|
|
205
|
+
text: ariaValueText ?? accessibilityValue?.text,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
return resolvedProps;
|
|
209
|
+
}
|
|
210
|
+
|
|
131
211
|
/**
|
|
132
212
|
* A drop-in replacement for `requireNativeComponent`.
|
|
133
213
|
*/
|
|
@@ -158,7 +238,7 @@ export function requireNativeViewManager<P>(
|
|
|
158
238
|
}
|
|
159
239
|
|
|
160
240
|
render() {
|
|
161
|
-
return <ReactNativeComponent {...this.props} ref={this.nativeRef} />;
|
|
241
|
+
return <ReactNativeComponent {...mapAriaProps(this.props)} ref={this.nativeRef} />;
|
|
162
242
|
}
|
|
163
243
|
}
|
|
164
244
|
|