react-native-unistyles 2.8.0-beta.1 → 2.8.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/android/CMakeLists.txt +8 -1
  2. package/android/build.gradle +4 -1
  3. package/android/src/main/cxx/cpp-adapter.cpp +10 -100
  4. package/android/src/main/cxx/helpers.h +2 -0
  5. package/android/src/main/cxx/platform.cpp +126 -0
  6. package/android/src/main/cxx/platform.h +15 -0
  7. package/android/src/main/java/com/unistyles/Models.kt +14 -35
  8. package/android/src/main/java/com/unistyles/Platform.kt +91 -10
  9. package/android/src/main/java/com/unistyles/UnistylesModule.kt +84 -139
  10. package/cxx/Macros.h +11 -0
  11. package/cxx/UnistylesImpl.cpp +241 -0
  12. package/cxx/UnistylesModel.cpp +234 -0
  13. package/cxx/UnistylesModel.h +112 -0
  14. package/cxx/UnistylesRuntime.cpp +17 -388
  15. package/cxx/UnistylesRuntime.h +56 -95
  16. package/ios/UnistylesModule.h +8 -0
  17. package/ios/UnistylesModule.mm +12 -89
  18. package/ios/platform/Platform_Shared.h +5 -0
  19. package/ios/platform/Platform_Shared.mm +69 -0
  20. package/ios/platform/Platform_iOS.h +2 -9
  21. package/ios/platform/Platform_iOS.mm +47 -94
  22. package/ios/platform/Platform_macOS.h +1 -6
  23. package/ios/platform/Platform_macOS.mm +29 -29
  24. package/ios/platform/Platform_tvOS.h +2 -9
  25. package/ios/platform/Platform_tvOS.mm +30 -92
  26. package/ios/platform/Platform_visionOS.h +2 -8
  27. package/ios/platform/Platform_visionOS.mm +28 -83
  28. package/package.json +1 -1
  29. package/react-native-unistyles.podspec +3 -0
  30. package/android/src/main/java/com/unistyles/Config.kt +0 -116
  31. package/android/src/main/java/com/unistyles/Insets.kt +0 -141
  32. package/ios/UnistylesHelpers.h +0 -3
  33. package/ios/UnistylesHelpers.mm +0 -5
@@ -4,44 +4,45 @@ import android.content.BroadcastReceiver
4
4
  import android.content.Context
5
5
  import android.content.Intent
6
6
  import android.content.IntentFilter
7
+ import android.content.res.Configuration
7
8
  import android.graphics.Color
8
9
  import android.os.Handler
9
10
  import android.os.Looper
10
11
  import android.util.Log
11
- import android.view.ViewTreeObserver
12
- import com.facebook.react.bridge.Arguments
12
+ import android.view.View
13
+ import androidx.core.view.ViewCompat
14
+ import androidx.core.view.WindowCompat
13
15
  import com.facebook.react.bridge.LifecycleEventListener
14
16
  import com.facebook.react.bridge.ReactApplicationContext
15
17
  import com.facebook.react.bridge.ReactContextBaseJavaModule
16
18
  import com.facebook.react.bridge.ReactMethod
17
- import com.facebook.react.modules.core.DeviceEventManagerModule
19
+ import com.facebook.react.turbomodule.core.interfaces.CallInvokerHolder
18
20
 
19
21
  class UnistylesModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext), LifecycleEventListener {
20
- private val drawHandler = Handler(Looper.getMainLooper())
21
- private val debounceDuration = 250L
22
- private var runnable: Runnable? = null
23
-
24
22
  private var isCxxReady: Boolean = false
25
23
  private lateinit var platform: Platform
26
- private val layoutListener = ViewTreeObserver.OnGlobalLayoutListener {
27
- if (this.isCxxReady) {
28
- runnable?.let { drawHandler.removeCallbacks(it) }
29
-
30
- runnable = Runnable {
31
- this@UnistylesModule.onLayoutConfigChange()
32
- }.also {
33
- drawHandler.postDelayed(it, debounceDuration)
34
- }
35
- }
36
- }
37
24
 
38
25
  private val configurationChangeReceiver = object : BroadcastReceiver() {
39
26
  override fun onReceive(context: Context, intent: Intent) {
40
- if (intent.action == Intent.ACTION_CONFIGURATION_CHANGED && this@UnistylesModule.isCxxReady) {
27
+ if (!this@UnistylesModule.isCxxReady) {
28
+ return
29
+ }
30
+
31
+ if (intent.action == Intent.ACTION_CONFIGURATION_CHANGED) {
41
32
  Handler(Looper.getMainLooper()).postDelayed({
42
33
  this@UnistylesModule.onConfigChange()
43
34
  }, 10)
44
35
  }
36
+
37
+ val newConfig = context.resources.configuration
38
+
39
+ if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
40
+ this@UnistylesModule.onLayoutConfigChange()
41
+ }
42
+
43
+ if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
44
+ this@UnistylesModule.onLayoutConfigChange()
45
+ }
45
46
  }
46
47
  }
47
48
 
@@ -56,21 +57,8 @@ class UnistylesModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
56
57
  reactApplicationContext.addLifecycleEventListener(this)
57
58
  }
58
59
 
59
- private fun setupLayoutListener() {
60
- val activity = currentActivity ?: return
61
- activity.window.decorView.rootView.viewTreeObserver.addOnGlobalLayoutListener(layoutListener)
62
- }
63
-
64
- private fun stopLayoutListener() {
65
- val activity = currentActivity ?: return
66
- activity.window.decorView.rootView.viewTreeObserver.removeOnGlobalLayoutListener(layoutListener)
67
- }
68
-
69
- @Deprecated("Deprecated in Java")
70
- override fun onCatalystInstanceDestroy() {
71
- this.stopLayoutListener()
60
+ override fun invalidate() {
72
61
  reactApplicationContext.unregisterReceiver(configurationChangeReceiver)
73
- runnable?.let { drawHandler.removeCallbacks(it) }
74
62
  reactApplicationContext.removeLifecycleEventListener(this)
75
63
 
76
64
  if (this.isCxxReady) {
@@ -81,36 +69,27 @@ class UnistylesModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
81
69
  //endregion
82
70
  //region Event handlers
83
71
  private fun onConfigChange() {
84
- if (!platform.hasNewConfig()) {
85
- return
86
- }
87
-
88
- val config = platform.getConfig()
72
+ val colorScheme = this.platform.getColorScheme()
73
+ val contentSizeCategory = this.platform.getContentSizeCategory()
89
74
 
90
75
  reactApplicationContext.runOnJSQueueThread {
91
- if (config.hasNewColorScheme) {
92
- this.nativeOnAppearanceChange(config.colorScheme)
93
- }
94
-
95
- if (config.hasNewContentSizeCategory) {
96
- this.nativeOnContentSizeCategoryChange(config.contentSizeCategory)
97
- }
76
+ this.nativeOnAppearanceChange(colorScheme)
77
+ this.nativeOnContentSizeCategoryChange(contentSizeCategory)
98
78
  }
99
79
  }
100
80
 
101
81
  private fun onLayoutConfigChange() {
102
- if (!platform.hasNewLayoutConfig()) {
103
- return
104
- }
105
-
106
- val config = platform.getLayoutConfig()
82
+ val screen = this.getScreenDimensions()
83
+ val insets = this.getInsets()
84
+ val statusBar = this.getStatusBarDimensions()
85
+ val navigationBar = this.getNavigationBarDimensions()
107
86
 
108
87
  reactApplicationContext.runOnJSQueueThread {
109
88
  this.nativeOnOrientationChange(
110
- config.screen,
111
- config.insets,
112
- config.statusBar,
113
- config.navigationBar
89
+ screen,
90
+ insets,
91
+ statusBar,
92
+ navigationBar
114
93
  )
115
94
  }
116
95
  }
@@ -123,25 +102,17 @@ class UnistylesModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
123
102
  System.loadLibrary("unistyles")
124
103
 
125
104
  this.platform = Platform(reactApplicationContext)
105
+ this.enableEdgeToEdge()
126
106
 
127
- val config = platform.getConfig()
128
- val layoutConfig = platform.getLayoutConfig()
129
-
130
- this.reactApplicationContext.javaScriptContextHolder?.let {
131
- this.nativeInstall(
132
- it.get(),
133
- layoutConfig.screen,
134
- config.colorScheme,
135
- config.contentSizeCategory,
136
- layoutConfig.insets,
137
- layoutConfig.statusBar,
138
- layoutConfig.navigationBar
139
- )
140
- this.isCxxReady = true
107
+ this.reactApplicationContext.javaScriptContextHolder?.let { contextHolder ->
108
+ this.reactApplicationContext.catalystInstance.jsCallInvokerHolder?.let { callInvokerHolder: CallInvokerHolder ->
109
+ this.nativeInstall(contextHolder.get(), callInvokerHolder)
110
+ this.isCxxReady = true
141
111
 
142
- Log.i(NAME, "Installed Unistyles \uD83E\uDD84!")
112
+ Log.i(NAME, "Installed Unistyles \uD83E\uDD84!")
143
113
 
144
- return true
114
+ return true
115
+ }
145
116
  }
146
117
 
147
118
  false
@@ -152,88 +123,36 @@ class UnistylesModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
152
123
  }
153
124
  }
154
125
 
155
- private external fun nativeInstall(
156
- jsi: Long,
157
- screen: Dimensions,
158
- colorScheme: String,
159
- contentSizeCategory: String,
160
- insets: Insets,
161
- statusBar: Dimensions,
162
- navigationBar: Dimensions
163
- )
126
+ private external fun nativeInstall(jsi: Long, callInvoker: CallInvokerHolder)
164
127
  private external fun nativeDestroy()
165
128
  private external fun nativeOnOrientationChange(screen: Dimensions, insets: Insets, statusBar: Dimensions, navigationBar: Dimensions)
166
129
  private external fun nativeOnAppearanceChange(colorScheme: String)
167
130
  private external fun nativeOnContentSizeCategoryChange(contentSizeCategory: String)
168
131
 
169
132
  //endregion
170
- //region Event emitter
171
- private fun onLayoutChange(breakpoint: String, orientation: String, screen: Dimensions, statusBar: Dimensions, insets: Insets, navigationBar: Dimensions) {
172
- val body = Arguments.createMap().apply {
173
- putString("type", "layout")
174
- putMap("payload", Arguments.createMap().apply {
175
- putString("breakpoint", breakpoint)
176
- putString("orientation", orientation)
177
- putMap("screen", Arguments.createMap().apply {
178
- putInt("width", screen.width)
179
- putInt("height", screen.height)
180
- })
181
- putMap("statusBar", Arguments.createMap().apply {
182
- putInt("width", statusBar.width)
183
- putInt("height", statusBar.height)
184
- })
185
- putMap("insets", Arguments.createMap().apply {
186
- putInt("top", insets.top)
187
- putInt("bottom", insets.bottom)
188
- putInt("left", insets.left)
189
- putInt("right", insets.right)
190
- })
191
- putMap("navigationBar", Arguments.createMap().apply {
192
- putInt("width", navigationBar.width)
193
- putInt("height", navigationBar.height)
194
- })
195
- })
196
- }
197
133
 
198
- reactApplicationContext
199
- .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
200
- .emit("__unistylesOnChange", body)
134
+ private fun getScreenDimensions(): Dimensions {
135
+ return platform.getScreenDimensions()
201
136
  }
202
137
 
203
- private fun onThemeChange(themeName: String) {
204
- val body = Arguments.createMap().apply {
205
- putString("type", "theme")
206
- putMap("payload", Arguments.createMap().apply {
207
- putString("themeName", themeName)
208
- })
209
- }
210
-
211
- reactApplicationContext
212
- .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
213
- .emit("__unistylesOnChange", body)
138
+ private fun getColorScheme(): String {
139
+ return platform.getColorScheme()
214
140
  }
215
141
 
216
- private fun onPluginChange() {
217
- val body = Arguments.createMap().apply {
218
- putString("type", "plugin")
219
- }
142
+ private fun getStatusBarDimensions(): Dimensions {
143
+ return platform.getStatusBarDimensions()
144
+ }
220
145
 
221
- reactApplicationContext
222
- .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
223
- .emit("__unistylesOnChange", body)
146
+ private fun getNavigationBarDimensions(): Dimensions {
147
+ return platform.getNavigationBarDimensions()
224
148
  }
225
149
 
226
- private fun onContentSizeCategoryChange(contentSizeCategory: String) {
227
- val body = Arguments.createMap().apply {
228
- putString("type", "dynamicTypeSize")
229
- putMap("payload", Arguments.createMap().apply {
230
- putString("contentSizeCategory", contentSizeCategory)
231
- })
232
- }
150
+ private fun getContentSizeCategory(): String {
151
+ return platform.getContentSizeCategory()
152
+ }
233
153
 
234
- reactApplicationContext
235
- .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
236
- .emit("__unistylesOnChange", body)
154
+ private fun getInsets(): Insets {
155
+ return platform.getInsets()
237
156
  }
238
157
 
239
158
  private fun onSetNavigationBarColor(color: String) {
@@ -268,6 +187,14 @@ class UnistylesModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
268
187
  }
269
188
  }
270
189
 
190
+ private fun enableEdgeToEdge() {
191
+ this.reactApplicationContext.currentActivity?.let { activity ->
192
+ activity.runOnUiThread {
193
+ WindowCompat.setDecorFitsSystemWindows(activity.window, false)
194
+ }
195
+ }
196
+ }
197
+
271
198
  @ReactMethod
272
199
  fun addListener(eventName: String?) = Unit
273
200
 
@@ -278,11 +205,29 @@ class UnistylesModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
278
205
  this.onConfigChange()
279
206
  }
280
207
 
281
- this.setupLayoutListener()
208
+ this.reactApplicationContext.currentActivity?.let { activity ->
209
+ activity.findViewById<View>(android.R.id.content)?.let { mainView ->
210
+ activity.window?.decorView?.let { decorView ->
211
+ ViewCompat.setOnApplyWindowInsetsListener(mainView) { _, insets ->
212
+ this.platform.setInsetsCompat(insets, decorView)
213
+
214
+ if (this.isCxxReady) {
215
+ this.onLayoutConfigChange()
216
+ }
217
+
218
+ insets
219
+ }
220
+ }
221
+ }
222
+ }
282
223
  }
283
224
 
284
225
  override fun onHostPause() {
285
- this.stopLayoutListener()
226
+ this.reactApplicationContext.currentActivity?.let { activity ->
227
+ activity.window?.decorView?.let { view ->
228
+ ViewCompat.setOnApplyWindowInsetsListener(view, null)
229
+ }
230
+ }
286
231
  }
287
232
 
288
233
  override fun onHostDestroy() {}
package/cxx/Macros.h ADDED
@@ -0,0 +1,11 @@
1
+ #pragma once
2
+
3
+ #define HOST_FN(name, args, fn_body) \
4
+ jsi::Function::createFromHostFunction(rt, \
5
+ jsi::PropNameID::forAscii(rt, name), \
6
+ args, \
7
+ [this, &fnName](jsi::Runtime &rt, const jsi::Value &thisVal, const jsi::Value *arguments, size_t count) -> jsi::Value \
8
+ fn_body \
9
+ ); \
10
+
11
+ #define BIND_FN(fn) std::bind(&UnistylesRuntime::fn, this, std::placeholders::_1, std::placeholders::_2)
@@ -0,0 +1,241 @@
1
+ #include "UnistylesRuntime.h"
2
+ #include <jsi/jsi.h>
3
+
4
+ using namespace facebook;
5
+
6
+ jsi::Value UnistylesRuntime::getScreenWidth(jsi::Runtime& rt, std::string fnName) {
7
+ return jsi::Value(this->screen.width);
8
+ }
9
+
10
+ jsi::Value UnistylesRuntime::getScreenHeight(jsi::Runtime& rt, std::string fnName) {
11
+ return jsi::Value(this->screen.height);
12
+ }
13
+
14
+ jsi::Value UnistylesRuntime::getContentSizeCategory(jsi::Runtime & rt, std::string fnName) {
15
+ return jsi::Value(jsi::String::createFromUtf8(rt, this->contentSizeCategory));
16
+ }
17
+
18
+ jsi::Value UnistylesRuntime::hasEnabledAdaptiveThemes(jsi::Runtime& rt, std::string fnName) {
19
+ return jsi::Value(this->hasAdaptiveThemes);
20
+ }
21
+
22
+ jsi::Value UnistylesRuntime::getThemeName(jsi::Runtime& rt, std::string fnName) {
23
+ return !this->themeName.empty()
24
+ ? jsi::Value(jsi::String::createFromUtf8(rt, this->themeName))
25
+ : this->getThemeOrFail(rt);
26
+ }
27
+
28
+ jsi::Value UnistylesRuntime::getCurrentBreakpoint(jsi::Runtime& rt, std::string fnName) {
29
+ return !this->breakpoint.empty()
30
+ ? jsi::Value(jsi::String::createFromUtf8(rt, this->breakpoint))
31
+ : jsi::Value::undefined();
32
+ }
33
+
34
+ jsi::Value UnistylesRuntime::getColorScheme(jsi::Runtime& rt, std::string fnName) {
35
+ return jsi::Value(jsi::String::createFromUtf8(rt, this->colorScheme));
36
+ }
37
+
38
+ jsi::Value UnistylesRuntime::getSortedBreakpointPairs(jsi::Runtime& rt, std::string fnName) {
39
+ std::unique_ptr<jsi::Array> sortedBreakpointEntriesArray = std::make_unique<jsi::Array>(rt, this->sortedBreakpointPairs.size());
40
+
41
+ for (size_t i = 0; i < this->sortedBreakpointPairs.size(); ++i) {
42
+ std::unique_ptr<jsi::Array> pairArray = std::make_unique<jsi::Array>(rt, 2);
43
+ jsi::String nameValue = jsi::String::createFromUtf8(rt, this->sortedBreakpointPairs[i].first);
44
+
45
+ pairArray->setValueAtIndex(rt, 0, nameValue);
46
+ pairArray->setValueAtIndex(rt, 1, jsi::Value(this->sortedBreakpointPairs[i].second));
47
+ sortedBreakpointEntriesArray->setValueAtIndex(rt, i, *pairArray);
48
+ }
49
+
50
+ return jsi::Value(rt, *sortedBreakpointEntriesArray);
51
+ }
52
+
53
+ jsi::Value UnistylesRuntime::setBreakpoints(jsi::Runtime& rt, std::string fnName) {
54
+ return HOST_FN(fnName, 1, {
55
+ jsi::Object breakpointsObj = arguments[0].asObject(rt);
56
+ auto sortedBreakpoints = this->toSortedBreakpointPairs(rt, breakpointsObj);
57
+
58
+ if (sortedBreakpoints.size() == 0) {
59
+ throw jsi::JSError(rt, UnistylesErrorBreakpointsCannotBeEmpty);
60
+ }
61
+
62
+ if (sortedBreakpoints.at(0).second != 0) {
63
+ throw jsi::JSError(rt, UnistylesErrorBreakpointsMustStartFromZero);
64
+ }
65
+
66
+ this->sortedBreakpointPairs = sortedBreakpoints;
67
+
68
+ std::string breakpoint = this->getBreakpointFromScreenWidth(this->screen.width, sortedBreakpoints);
69
+
70
+ this->breakpoint = breakpoint;
71
+
72
+ return jsi::Value::undefined();
73
+ });
74
+ }
75
+
76
+ jsi::Value UnistylesRuntime::setActiveTheme(jsi::Runtime& rt, std::string fnName) {
77
+ return HOST_FN(fnName, 1, {
78
+ std::string themeName = arguments[0].asString(rt).utf8(rt);
79
+
80
+ if (this->themeName != themeName) {
81
+ this->themeName = themeName;
82
+ this->onThemeChange(themeName);
83
+ }
84
+
85
+ return jsi::Value::undefined();
86
+ });
87
+ }
88
+
89
+ jsi::Value UnistylesRuntime::updateTheme(jsi::Runtime& rt, std::string fnName) {
90
+ return HOST_FN(fnName, 1, {
91
+ std::string themeName = arguments[0].asString(rt).utf8(rt);
92
+
93
+ if (this->themeName == themeName) {
94
+ this->onThemeChange(themeName);
95
+ }
96
+
97
+ return jsi::Value::undefined();
98
+ });
99
+ }
100
+
101
+ jsi::Value UnistylesRuntime::useAdaptiveThemes(jsi::Runtime& rt, std::string fnName) {
102
+ return HOST_FN(fnName, 1, {
103
+ bool enableAdaptiveThemes = arguments[0].asBool();
104
+
105
+ if (enableAdaptiveThemes && this->colorScheme == UnistylesUnspecifiedScheme) {
106
+ throw jsi::JSError(rt, UnistylesErrorAdaptiveThemesNotSupported);
107
+ }
108
+
109
+ this->hasAdaptiveThemes = enableAdaptiveThemes;
110
+
111
+ if (!enableAdaptiveThemes || !this->supportsAutomaticColorScheme) {
112
+ return jsi::Value::undefined();
113
+ }
114
+
115
+ if (this->themeName != this->colorScheme) {
116
+ this->themeName = this->colorScheme;
117
+ this->onThemeChange(this->themeName);
118
+ }
119
+
120
+ return jsi::Value::undefined();
121
+ });
122
+ }
123
+
124
+ jsi::Value UnistylesRuntime::addPlugin(jsi::Runtime& rt, std::string fnName) {
125
+ return HOST_FN(fnName, 1, {
126
+ std::string pluginName = arguments[0].asString(rt).utf8(rt);
127
+ bool notify = arguments[1].asBool();
128
+
129
+ this->pluginNames.push_back(pluginName);
130
+
131
+ // registry enabled plugins won't notify listeners
132
+ if (notify) {
133
+ this->onPluginChange();
134
+ }
135
+
136
+ return jsi::Value::undefined();
137
+ });
138
+ }
139
+
140
+ jsi::Value UnistylesRuntime::removePlugin(jsi::Runtime& rt, std::string fnName) {
141
+ return HOST_FN(fnName, 1, {
142
+ std::string pluginName = arguments[0].asString(rt).utf8(rt);
143
+
144
+ auto it = std::find(this->pluginNames.begin(), this->pluginNames.end(), pluginName);
145
+
146
+ if (it != this->pluginNames.end()) {
147
+ this->pluginNames.erase(it);
148
+ this->onPluginChange();
149
+ }
150
+
151
+ return jsi::Value::undefined();
152
+ });
153
+ }
154
+
155
+ jsi::Value UnistylesRuntime::getEnabledPlugins(jsi::Runtime& rt, std::string fnName) {
156
+ auto jsiArray = facebook::jsi::Array(rt, this->pluginNames.size());
157
+
158
+ for (size_t i = 0; i < this->pluginNames.size(); i++) {
159
+ jsiArray.setValueAtIndex(rt, i, facebook::jsi::String::createFromUtf8(rt, this->pluginNames[i]));
160
+ }
161
+
162
+ return jsiArray;
163
+ }
164
+
165
+ jsi::Value UnistylesRuntime::getInsets(jsi::Runtime& rt, std::string fnName) {
166
+ auto insets = jsi::Object(rt);
167
+
168
+ insets.setProperty(rt, "top", this->insets.top);
169
+ insets.setProperty(rt, "bottom", this->insets.bottom);
170
+ insets.setProperty(rt, "left", this->insets.left);
171
+ insets.setProperty(rt, "right", this->insets.right);
172
+
173
+ return insets;
174
+ }
175
+
176
+ jsi::Value UnistylesRuntime::getStatusBar(jsi::Runtime& rt, std::string fnName) {
177
+ auto statusBar = jsi::Object(rt);
178
+ auto setStatusBarColorFunction = HOST_FN("setColor", 1, {
179
+ std::string color = arguments[0].asString(rt).utf8(rt);
180
+
181
+ if (this->setStatusBarColor.has_value()) {
182
+ this->setStatusBarColor.value()(color);
183
+ }
184
+
185
+ return jsi::Value::undefined();
186
+ });
187
+
188
+ statusBar.setProperty(rt, "width", this->statusBar.width);
189
+ statusBar.setProperty(rt, "height", this->statusBar.height);
190
+ statusBar.setProperty(rt, "setColor", setStatusBarColorFunction);
191
+
192
+ return statusBar;
193
+ }
194
+
195
+ jsi::Value UnistylesRuntime::getNavigationBar(jsi::Runtime& rt, std::string fnName) {
196
+ auto navigationBarValue = jsi::Object(rt);
197
+ auto setNavigationBarColorFunction = HOST_FN("setColor", 1, {
198
+ std::string color = arguments[0].asString(rt).utf8(rt);
199
+
200
+ if (this->setNavigationBarColor.has_value()) {
201
+ this->setNavigationBarColor.value()(color);
202
+ }
203
+
204
+ return jsi::Value::undefined();
205
+ });
206
+
207
+ navigationBarValue.setProperty(rt, "width", this->navigationBar.width);
208
+ navigationBarValue.setProperty(rt, "height", this->navigationBar.height);
209
+ navigationBarValue.setProperty(rt, "setColor", setNavigationBarColorFunction);
210
+
211
+ return navigationBarValue;
212
+ }
213
+
214
+ std::optional<jsi::Value> UnistylesRuntime::setThemes(jsi::Runtime& rt, const jsi::Value& value) {
215
+ jsi::Array themes = value.asObject(rt).asArray(rt);
216
+ std::vector<std::string> themesVector;
217
+ size_t length = themes.size(rt);
218
+
219
+ for (size_t i = 0; i < length; ++i) {
220
+ jsi::Value element = themes.getValueAtIndex(rt, i);
221
+
222
+ if (element.isString()) {
223
+ std::string theme = element.asString(rt).utf8(rt);
224
+ themesVector.push_back(theme);
225
+ }
226
+ }
227
+
228
+ if (themesVector.size() == 0) {
229
+ throw jsi::JSError(rt, UnistylesErrorThemesCannotBeEmpty);
230
+ }
231
+
232
+ this->themes = themesVector;
233
+ this->themeName = "";
234
+
235
+ bool hasLightTheme = std::find(themesVector.begin(), themesVector.end(), "light") != themesVector.end();
236
+ bool hasDarkTheme = std::find(themesVector.begin(), themesVector.end(), "dark") != themesVector.end();
237
+
238
+ this->supportsAutomaticColorScheme = hasLightTheme && hasDarkTheme;
239
+
240
+ return std::nullopt;
241
+ }