react-native-unistyles 3.1.1 → 3.2.1

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 (58) hide show
  1. package/README.md +3 -2
  2. package/android/src/main/cxx/NativeUnistylesModule.cpp +2 -5
  3. package/android/src/main/cxx/NativeUnistylesModule.h +1 -7
  4. package/android/src/main/java/com/unistyles/Equatable.kt +5 -1
  5. package/android/src/main/java/com/unistyles/NativePlatform+android.kt +6 -1
  6. package/android/src/main/java/com/unistyles/NativePlatform+listener.kt +21 -3
  7. package/cxx/core/UnistyleWrapper.h +2 -2
  8. package/cxx/core/UnistylesRegistry.cpp +57 -48
  9. package/cxx/core/UnistylesRegistry.h +16 -14
  10. package/cxx/core/UnistylesState.cpp +22 -20
  11. package/cxx/core/UnistylesState.h +5 -6
  12. package/cxx/hybridObjects/HybridShadowRegistry.cpp +14 -3
  13. package/cxx/hybridObjects/HybridShadowRegistry.h +5 -0
  14. package/cxx/hybridObjects/HybridStyleSheet.cpp +71 -45
  15. package/cxx/hybridObjects/HybridUnistylesRuntime.cpp +22 -32
  16. package/cxx/hybridObjects/HybridUnistylesRuntime.h +3 -4
  17. package/cxx/parser/Parser.cpp +14 -14
  18. package/cxx/shadowTree/ShadowTreeManager.cpp +10 -7
  19. package/ios/UnistylesModuleOnLoad.mm +3 -10
  20. package/lib/commonjs/core/useProxifiedUnistyles/useProxifiedUnistyles.js +4 -1
  21. package/lib/commonjs/core/useProxifiedUnistyles/useProxifiedUnistyles.js.map +1 -1
  22. package/lib/commonjs/specs/ShadowRegistry/index.js +20 -1
  23. package/lib/commonjs/specs/ShadowRegistry/index.js.map +1 -1
  24. package/lib/commonjs/web/convert/style.js +6 -6
  25. package/lib/commonjs/web/convert/style.js.map +1 -1
  26. package/lib/commonjs/web/listener.js +6 -0
  27. package/lib/commonjs/web/listener.js.map +1 -1
  28. package/lib/commonjs/web/utils/createUnistylesRef.js +1 -1
  29. package/lib/commonjs/web/utils/createUnistylesRef.js.map +1 -1
  30. package/lib/module/core/useProxifiedUnistyles/useProxifiedUnistyles.js +4 -1
  31. package/lib/module/core/useProxifiedUnistyles/useProxifiedUnistyles.js.map +1 -1
  32. package/lib/module/specs/ShadowRegistry/index.js +20 -1
  33. package/lib/module/specs/ShadowRegistry/index.js.map +1 -1
  34. package/lib/module/web/convert/style.js +6 -6
  35. package/lib/module/web/convert/style.js.map +1 -1
  36. package/lib/module/web/listener.js +6 -0
  37. package/lib/module/web/listener.js.map +1 -1
  38. package/lib/module/web/utils/createUnistylesRef.js +1 -1
  39. package/lib/module/web/utils/createUnistylesRef.js.map +1 -1
  40. package/lib/typescript/src/core/useProxifiedUnistyles/useProxifiedUnistyles.d.ts.map +1 -1
  41. package/lib/typescript/src/specs/ShadowRegistry/index.d.ts +2 -1
  42. package/lib/typescript/src/specs/ShadowRegistry/index.d.ts.map +1 -1
  43. package/lib/typescript/src/web/listener.d.ts.map +1 -1
  44. package/nitrogen/generated/android/c++/JColorScheme.hpp +1 -1
  45. package/nitrogen/generated/android/c++/JDimensions.hpp +1 -1
  46. package/nitrogen/generated/android/c++/JFunc_void_UnistylesNativeMiniRuntime.hpp +2 -2
  47. package/nitrogen/generated/android/c++/JFunc_void_std__vector_UnistyleDependency__UnistylesNativeMiniRuntime.hpp +2 -2
  48. package/nitrogen/generated/android/c++/JHybridNativePlatformSpec.hpp +2 -2
  49. package/nitrogen/generated/android/c++/JInsets.hpp +1 -1
  50. package/nitrogen/generated/android/c++/JOrientation.hpp +1 -1
  51. package/nitrogen/generated/android/c++/JUnistyleDependency.hpp +1 -1
  52. package/nitrogen/generated/android/c++/JUnistylesNativeMiniRuntime.hpp +1 -1
  53. package/package.json +3 -3
  54. package/src/core/useProxifiedUnistyles/useProxifiedUnistyles.ts +4 -1
  55. package/src/specs/ShadowRegistry/index.ts +36 -2
  56. package/src/web/convert/style.ts +6 -6
  57. package/src/web/listener.ts +6 -0
  58. package/src/web/utils/createUnistylesRef.ts +1 -1
package/README.md CHANGED
@@ -24,10 +24,11 @@ Install dependencies:
24
24
  yarn add react-native-nitro-modules
25
25
  ```
26
26
 
27
- | react-native-unistyles | Minimum react-native-nitro-modules |
28
- |------------------------|-------------------------------------|
27
+ | react-native-unistyles | Minimum react-native-nitro-modules |
28
+ |------------------------|----------------------------------------|
29
29
  | >= 3.0.0 | >= 0.33.9 |
30
30
  | >= 3.1.0 | >= 0.35.0 |
31
+ | >= 3.2.0 | >= 0.35.2 |
31
32
 
32
33
  > **Note:** Since v3.1.0, `react-native-edge-to-edge` is an **optional** dependency. We strongly recommend setting `edgeToEdgeEnabled=true` in your `android/gradle.properties` — it enforces translucent system bars on modals, disables legacy StatusBar hacks, and enables additional React Native core fixes. **Expo SDK 54+** enables this automatically. You can still install `react-native-edge-to-edge` for ecosystem compatibility with libraries like `react-native-bootsplash` or `react-native-permissions`.
33
34
 
@@ -33,11 +33,8 @@ void UnistylesModule::registerNatives() {
33
33
  jni::local_ref<BindingsInstallerHolder::javaobject> UnistylesModule::getBindingsInstaller(jni::alias_ref<UnistylesModule::javaobject> jobj) {
34
34
  auto& runtimeExecutor = jobj->cthis()->_runtimeExecutor;
35
35
  auto& nativePlatform = jobj->cthis()->_nativePlatform;
36
- auto* self = jobj->cthis();
37
-
38
- return BindingsInstallerHolder::newObjectCxxArgs([&runtimeExecutor, &nativePlatform, self](jsi::Runtime& rt) {
39
- self->_runtime = &rt;
40
36
 
37
+ return BindingsInstallerHolder::newObjectCxxArgs([&runtimeExecutor, &nativePlatform](jsi::Runtime& rt) {
41
38
  // function is called on: first init and every live reload
42
39
  // check if this is live reload, if so let's replace UnistylesRuntime with new runtime
43
40
  auto hasUnistylesRuntime = HybridObjectRegistry::hasHybridObject("UnistylesRuntime");
@@ -55,7 +52,7 @@ jni::local_ref<BindingsInstallerHolder::javaobject> UnistylesModule::getBindings
55
52
  };
56
53
 
57
54
  // init hybrids
58
- auto unistylesRuntime = std::make_shared<HybridUnistylesRuntime>(nativePlatform, rt, runOnJSThread);
55
+ auto unistylesRuntime = std::make_shared<HybridUnistylesRuntime>(nativePlatform, runOnJSThread);
59
56
  auto styleSheet = std::make_shared<HybridStyleSheet>(unistylesRuntime);
60
57
 
61
58
  HybridObjectRegistry::registerHybridObjectConstructor("UnistylesRuntime", [unistylesRuntime]() -> std::shared_ptr<HybridObject>{
@@ -29,12 +29,7 @@ struct UnistylesModule : public jni::HybridClass<UnistylesModule> {
29
29
  jni::alias_ref<JHybridNativePlatformSpec::JavaPart> nativePlatform
30
30
  );
31
31
  static void invalidateNative(jni::alias_ref<jhybridobject> jThis) {
32
- auto* self = jThis->cthis();
33
-
34
- if (self->_runtime) {
35
- core::UnistylesRegistry::get().destroyState(self->_runtime);
36
- self->_runtime = nullptr;
37
- }
32
+ core::UnistylesRegistry::get().destroy();
38
33
  }
39
34
 
40
35
  static jni::local_ref<BindingsInstallerHolder::javaobject> getBindingsInstaller(jni::alias_ref<UnistylesModule::javaobject> jThis);
@@ -42,7 +37,6 @@ struct UnistylesModule : public jni::HybridClass<UnistylesModule> {
42
37
  private:
43
38
  RuntimeExecutor _runtimeExecutor;
44
39
  std::shared_ptr<HybridNativePlatformSpec> _nativePlatform;
45
- jsi::Runtime* _runtime = nullptr;
46
40
  };
47
41
 
48
42
  }
@@ -54,7 +54,11 @@ fun NativePlatformAndroid.diffMiniRuntimes(lhs: UnistylesNativeMiniRuntime, rhs:
54
54
  dependencies.add(UnistyleDependency.NAVIGATIONBAR)
55
55
  }
56
56
 
57
- // rtl and pixel ratio are not dynamic
57
+ if (lhs.rtl != rhs.rtl) {
58
+ dependencies.add(UnistyleDependency.RTL)
59
+ }
60
+
61
+ // pixel ratio is not dynamic
58
62
 
59
63
  return dependencies.toTypedArray()
60
64
  }
@@ -37,6 +37,8 @@ class NativePlatformAndroid(private val reactContext: ReactApplicationContext):
37
37
  }
38
38
 
39
39
  fun onDestroy() {
40
+ _listener.onDestroy()
41
+ _insets.onDestroy()
40
42
  reactContext.removeLifecycleEventListener(this)
41
43
  }
42
44
 
@@ -155,11 +157,14 @@ class NativePlatformAndroid(private val reactContext: ReactApplicationContext):
155
157
  "com.facebook.react.modules.i18nmanager.I18nUtil",
156
158
  Context.MODE_PRIVATE
157
159
  )
160
+ val resourcesLocale = reactContext.resources.configuration.locales[0]
158
161
  val hasForcedRtl = sharedPrefs.getBoolean("RCTI18nUtil_forceRTL", false)
159
162
  // user preferences
160
163
  val isRtl = TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault()) == ViewCompat.LAYOUT_DIRECTION_RTL
164
+ val isResourcesRtl = TextUtilsCompat.getLayoutDirectionFromLocale(resourcesLocale) == ViewCompat.LAYOUT_DIRECTION_RTL
161
165
 
162
- return hasForcedRtl || isRtl
166
+
167
+ return hasForcedRtl || isRtl || isResourcesRtl
163
168
  }
164
169
 
165
170
  override fun setRootViewBackgroundColor(color: Double) {
@@ -4,6 +4,7 @@ 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.SharedPreferences
7
8
  import android.os.Handler
8
9
  import android.os.Looper
9
10
  import androidx.annotation.Keep
@@ -23,21 +24,38 @@ class NativePlatformListener(
23
24
  ) {
24
25
  private val _dependencyListeners: MutableList<CxxDependencyListener> = mutableListOf()
25
26
 
27
+ private fun notifyConfigChangedWithDelay() {
28
+ Handler(Looper.getMainLooper()).postDelayed({
29
+ this@NativePlatformListener.onConfigChange()
30
+ }, 25)
31
+ }
32
+
26
33
  private val configurationChangeReceiver = object : BroadcastReceiver() {
27
34
  override fun onReceive(context: Context, intent: Intent) {
28
- Handler(Looper.getMainLooper()).postDelayed({
29
- this@NativePlatformListener.onConfigChange()
30
- }, 25)
35
+ notifyConfigChangedWithDelay()
36
+ }
37
+ }
38
+
39
+ private val rtlPreferenceListener = SharedPreferences.OnSharedPreferenceChangeListener { prefs, key ->
40
+ if (key == "RCTI18nUtil_forceRTL") {
41
+ notifyConfigChangedWithDelay()
31
42
  }
32
43
  }
33
44
 
45
+ private val i18nUtilSharedPrefs = reactContext.getSharedPreferences(
46
+ "com.facebook.react.modules.i18nmanager.I18nUtil",
47
+ Context.MODE_PRIVATE
48
+ )
49
+
34
50
  init {
35
51
  reactContext.registerReceiver(configurationChangeReceiver, IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED))
52
+ i18nUtilSharedPrefs.registerOnSharedPreferenceChangeListener(rtlPreferenceListener)
36
53
  }
37
54
 
38
55
  fun onDestroy() {
39
56
  this.removePlatformListeners()
40
57
  reactContext.unregisterReceiver(configurationChangeReceiver)
58
+ i18nUtilSharedPrefs.unregisterOnSharedPreferenceChangeListener(rtlPreferenceListener)
41
59
  }
42
60
 
43
61
  fun addPlatformListener(listener: CxxDependencyListener) {
@@ -57,7 +57,7 @@ inline static std::vector<Unistyle::Shared> unistylesFromHashKeys(jsi::Runtime&
57
57
  auto& registry = UnistylesRegistry::get();
58
58
 
59
59
  for (auto& key: keys) {
60
- unistyles.emplace_back(registry.getUnistyleById(rt, key));
60
+ unistyles.emplace_back(registry.getUnistyleById(key));
61
61
  }
62
62
 
63
63
  return unistyles;
@@ -157,7 +157,7 @@ inline static jsi::Value objectFromUnistyle(jsi::Runtime& rt, std::shared_ptr<Hy
157
157
  [unistyleID = unistyle->unid, unistylesRuntime, variants, parsedArguments](jsi::Runtime &rt, const jsi::Value &thisValue, const jsi::Value *args, size_t count
158
158
  ) {
159
159
  auto& registry = UnistylesRegistry::get();
160
- auto unistyle = registry.getUnistyleById(rt, unistyleID);
160
+ auto unistyle = registry.getUnistyleById(unistyleID);
161
161
 
162
162
  parser::Parser(unistylesRuntime).rebuildUnistyle(rt, unistyle, variants, parsedArguments);
163
163
 
@@ -9,50 +9,44 @@ using namespace facebook::react;
9
9
  std::atomic<int> core::UnistylesRegistry::_nextStyleSheetTag{0};
10
10
 
11
11
  void core::UnistylesRegistry::registerTheme(jsi::Runtime& rt, std::string name, jsi::Value& theme) {
12
- auto& state = this->getState(rt);
12
+ auto& state = this->getState();
13
13
 
14
14
  state._jsThemes.emplace(name, std::move(theme));
15
15
  state._registeredThemeNames.push_back(name);
16
16
  }
17
17
 
18
- void core::UnistylesRegistry::registerBreakpoints(jsi::Runtime& rt, std::vector<std::pair<std::string, double>>& sortedBreakpoints) {
19
- auto& state = this->getState(rt);
18
+ void core::UnistylesRegistry::registerBreakpoints(std::vector<std::pair<std::string, double>>& sortedBreakpoints) {
19
+ auto& state = this->getState();
20
20
 
21
21
  state._sortedBreakpointPairs = std::move(sortedBreakpoints);
22
22
  }
23
23
 
24
- void core::UnistylesRegistry::setPrefersAdaptiveThemes(jsi::Runtime& rt, bool prefersAdaptiveThemes) {
25
- auto& state = this->getState(rt);
24
+ void core::UnistylesRegistry::setPrefersAdaptiveThemes(bool prefersAdaptiveThemes) {
25
+ auto& state = this->getState();
26
26
 
27
27
  state._prefersAdaptiveThemes = prefersAdaptiveThemes;
28
28
  }
29
29
 
30
- void core::UnistylesRegistry::setInitialThemeName(jsi::Runtime& rt, std::string themeName) {
31
- auto& state = this->getState(rt);
30
+ void core::UnistylesRegistry::setInitialThemeName(std::string themeName) {
31
+ auto& state = this->getState();
32
32
 
33
33
  state._initialThemeName = themeName;
34
34
  }
35
35
 
36
- core::UnistylesState& core::UnistylesRegistry::getState(jsi::Runtime& rt) {
37
- auto it = this->_states.find(&rt);
38
-
39
- helpers::assertThat(rt, it != this->_states.end(), "Unistyles was loaded, but it's not configured. Did you forget to call StyleSheet.configure? If you don't want to use any themes or breakpoints, simply call it with an empty object {}.");
36
+ core::UnistylesState& core::UnistylesRegistry::getState() {
37
+ if (!this->_state) {
38
+ throw std::runtime_error("Unistyles was loaded, but it's not configured. Did you forget to call StyleSheet.configure? If you don't want to use any themes or breakpoints, simply call it with an empty object {}.");
39
+ }
40
40
 
41
- return it->second;
41
+ return *this->_state;
42
42
  }
43
43
 
44
- void core::UnistylesRegistry::createState(jsi::Runtime& rt) {
45
- auto it = this->_states.find(&rt);
46
-
47
- this->_states.emplace(
48
- std::piecewise_construct,
49
- std::forward_as_tuple(&rt),
50
- std::forward_as_tuple(rt)
51
- );
44
+ void core::UnistylesRegistry::createState() {
45
+ this->_state = std::make_unique<UnistylesState>();
52
46
  }
53
47
 
54
48
  void core::UnistylesRegistry::updateTheme(jsi::Runtime& rt, std::string& themeName, jsi::Function&& callback) {
55
- auto& state = this->getState(rt);
49
+ auto& state = this->getState();
56
50
  auto it = state._jsThemes.find(themeName);
57
51
 
58
52
  helpers::assertThat(rt, it != state._jsThemes.end(), "Unistyles: You're trying to update theme '" + themeName + "' but it wasn't registered.");
@@ -70,22 +64,36 @@ void core::UnistylesRegistry::linkShadowNodeWithUnistyle(
70
64
  std::vector<std::shared_ptr<UnistyleData>>& unistylesData
71
65
  ) {
72
66
  this->trafficController.withLock([this, &rt, &unistylesData, shadowNodeFamily](){
67
+ // Clear suspension state if this family was previously suspended
68
+ if (_suspendedFamilies.erase(shadowNodeFamily) > 0) {
69
+ auto* mutableFamily = const_cast<ShadowNodeFamily*>(shadowNodeFamily);
70
+ mutableFamily->nativeProps_DEPRECATED.reset();
71
+ }
72
+
73
73
  shadow::ShadowLeafUpdates updates;
74
74
  auto parser = parser::Parser(nullptr);
75
75
 
76
- std::for_each(unistylesData.begin(), unistylesData.end(), [this, &rt, shadowNodeFamily](std::shared_ptr<UnistyleData> unistyleData){
77
- this->_shadowRegistry[&rt][shadowNodeFamily].emplace_back(unistyleData);
76
+ std::for_each(unistylesData.begin(), unistylesData.end(), [this, shadowNodeFamily](std::shared_ptr<UnistyleData> unistyleData){
77
+ this->_shadowRegistry[shadowNodeFamily].emplace_back(unistyleData);
78
78
  });
79
79
 
80
80
  updates[shadowNodeFamily] = parser.parseStylesToShadowTreeStyles(rt, unistylesData);
81
81
 
82
+ auto* mutableFamily = const_cast<ShadowNodeFamily*>(shadowNodeFamily);
83
+
84
+ if (mutableFamily->nativeProps_DEPRECATED) {
85
+ mutableFamily->nativeProps_DEPRECATED->update(updates[shadowNodeFamily]);
86
+ } else {
87
+ mutableFamily->nativeProps_DEPRECATED = std::make_unique<folly::dynamic>(updates[shadowNodeFamily]);
88
+ }
89
+
82
90
  this->trafficController.setUpdates(updates);
83
91
  this->trafficController.resumeUnistylesTraffic();
84
92
  });
85
93
  }
86
94
 
87
- void core::UnistylesRegistry::removeDuplicatedUnistyles(jsi::Runtime& rt, const ShadowNodeFamily *shadowNodeFamily, std::vector<core::Unistyle::Shared>& unistyles) {
88
- auto targetFamilyUnistyles = this->_shadowRegistry[&rt][shadowNodeFamily];
95
+ void core::UnistylesRegistry::removeDuplicatedUnistyles(const ShadowNodeFamily *shadowNodeFamily, std::vector<core::Unistyle::Shared>& unistyles) {
96
+ auto targetFamilyUnistyles = this->_shadowRegistry[shadowNodeFamily];
89
97
 
90
98
  unistyles.erase(
91
99
  std::remove_if(
@@ -105,32 +113,41 @@ void core::UnistylesRegistry::removeDuplicatedUnistyles(jsi::Runtime& rt, const
105
113
  );
106
114
  }
107
115
 
108
- void core::UnistylesRegistry::unlinkShadowNodeWithUnistyles(jsi::Runtime& rt, const ShadowNodeFamily* shadowNodeFamily) {
109
- this->trafficController.withLock([this, &rt, shadowNodeFamily](){
110
- this->_shadowRegistry[&rt].erase(shadowNodeFamily);
116
+ void core::UnistylesRegistry::unlinkShadowNodeWithUnistyles(const ShadowNodeFamily* shadowNodeFamily) {
117
+ this->trafficController.withLock([this, shadowNodeFamily](){
118
+ this->_shadowRegistry.erase(shadowNodeFamily);
119
+ this->_suspendedFamilies.erase(shadowNodeFamily);
111
120
  this->trafficController.removeShadowNode(shadowNodeFamily);
121
+ });
122
+ }
112
123
 
113
- if (this->_shadowRegistry[&rt].empty()) {
114
- this->_shadowRegistry.erase(&rt);
124
+ void core::UnistylesRegistry::suspendShadowNode(const ShadowNodeFamily* shadowNodeFamily) {
125
+ this->trafficController.withLock([this, shadowNodeFamily](){
126
+ if (this->_shadowRegistry.contains(shadowNodeFamily)) {
127
+ this->_suspendedFamilies.insert(shadowNodeFamily);
115
128
  }
116
129
  });
117
130
  }
118
131
 
132
+ bool core::UnistylesRegistry::isSuspended(const ShadowNodeFamily* family) const noexcept {
133
+ return _suspendedFamilies.count(family) > 0;
134
+ }
135
+
119
136
  std::shared_ptr<core::StyleSheet> core::UnistylesRegistry::addStyleSheet(jsi::Runtime& rt, core::StyleSheetType type, jsi::Object&& rawValue) {
120
137
  int tag = _nextStyleSheetTag.fetch_add(1);
121
138
 
122
139
  auto sheet = std::make_shared<core::StyleSheet>(tag, type, std::move(rawValue));
123
- this->_styleSheetRegistry[&rt][tag] = sheet;
140
+ this->_styleSheetRegistry[tag] = sheet;
124
141
 
125
142
  return sheet;
126
143
  }
127
144
 
128
- core::DependencyMap core::UnistylesRegistry::buildDependencyMap(jsi::Runtime& rt, std::vector<UnistyleDependency>& deps) {
145
+ core::DependencyMap core::UnistylesRegistry::buildDependencyMap(std::vector<UnistyleDependency>& deps) {
129
146
  core::DependencyMap dependencyMap;
130
147
 
131
148
  std::unordered_set<UnistyleDependency> uniqueDependencies(deps.begin(), deps.end());
132
149
 
133
- for (const auto& [family, unistyles] : this->_shadowRegistry[&rt]) {
150
+ for (const auto& [family, unistyles] : this->_shadowRegistry) {
134
151
  bool hasAnyOfDependencies = false;
135
152
 
136
153
  // Check if any dependency matches
@@ -171,7 +188,7 @@ void core::UnistylesRegistry::shadowLeafUpdateFromUnistyle(jsi::Runtime& rt, Uni
171
188
  ? std::make_optional(maybePressableId.asString(rt).utf8(rt))
172
189
  : std::nullopt;
173
190
 
174
- for (const auto& [family, unistyles] : this->_shadowRegistry[&rt]) {
191
+ for (const auto& [family, unistyles] : this->_shadowRegistry) {
175
192
  for (const auto& unistyleData : unistyles) {
176
193
  if (unistyleData->unistyle == unistyle) {
177
194
  updates[family] = parser.parseStylesToShadowTreeStyles(rt, { unistyleData });
@@ -183,7 +200,7 @@ void core::UnistylesRegistry::shadowLeafUpdateFromUnistyle(jsi::Runtime& rt, Uni
183
200
  });
184
201
  }
185
202
 
186
- std::vector<std::shared_ptr<core::StyleSheet>>core::UnistylesRegistry::getStyleSheetsToRefresh(jsi::Runtime& rt, std::vector<UnistyleDependency>& unistylesDependencies) {
203
+ std::vector<std::shared_ptr<core::StyleSheet>>core::UnistylesRegistry::getStyleSheetsToRefresh(std::vector<UnistyleDependency>& unistylesDependencies) {
187
204
  std::vector<std::shared_ptr<core::StyleSheet>> stylesheetsToRefresh;
188
205
  std::unordered_set<UnistyleDependency> depSet(
189
206
  unistylesDependencies.begin(),
@@ -197,8 +214,6 @@ std::vector<std::shared_ptr<core::StyleSheet>>core::UnistylesRegistry::getStyleS
197
214
  return stylesheetsToRefresh;
198
215
  }
199
216
 
200
- auto& styleSheets = this->_styleSheetRegistry[&rt];
201
-
202
217
  auto hasMatchingDependency = [&depSet](const auto& unistyles) {
203
218
  for (const auto& [_, unistyle] : unistyles) {
204
219
  for (const auto& dep : unistyle->dependencies) {
@@ -211,7 +226,7 @@ std::vector<std::shared_ptr<core::StyleSheet>>core::UnistylesRegistry::getStyleS
211
226
  return false;
212
227
  };
213
228
 
214
- for (const auto& [_, styleSheet] : styleSheets) {
229
+ for (const auto& [_, styleSheet] : this->_styleSheetRegistry) {
215
230
  if (styleSheet->type == StyleSheetType::ThemableWithMiniRuntime || styleSheet->type == StyleSheetType::Static) {
216
231
  if (hasMatchingDependency(styleSheet->unistyles)) {
217
232
  stylesheetsToRefresh.emplace_back(styleSheet);
@@ -226,8 +241,8 @@ std::vector<std::shared_ptr<core::StyleSheet>>core::UnistylesRegistry::getStyleS
226
241
  return stylesheetsToRefresh;
227
242
  }
228
243
 
229
- core::Unistyle::Shared core::UnistylesRegistry::getUnistyleById(jsi::Runtime& rt, std::string unistyleID) {
230
- for (auto& pair: this->_styleSheetRegistry[&rt]) {
244
+ core::Unistyle::Shared core::UnistylesRegistry::getUnistyleById(std::string unistyleID) {
245
+ for (auto& pair: this->_styleSheetRegistry) {
231
246
  auto [_, stylesheet] = pair;
232
247
 
233
248
  for (auto unistylePair: stylesheet->unistyles) {
@@ -251,16 +266,10 @@ void core::UnistylesRegistry::setScopedTheme(std::optional<std::string> themeNam
251
266
  }
252
267
 
253
268
  void core::UnistylesRegistry::destroy() {
254
- this->_states.clear();
269
+ this->_state.reset();
255
270
  this->_styleSheetRegistry.clear();
256
271
  this->_shadowRegistry.clear();
272
+ this->_suspendedFamilies.clear();
257
273
  this->_scopedTheme = std::nullopt;
258
274
  _nextStyleSheetTag.store(0);
259
275
  }
260
-
261
- void core::UnistylesRegistry::destroyState(jsi::Runtime* rt) {
262
- this->_states.erase(rt);
263
- this->_styleSheetRegistry.erase(rt);
264
- this->_shadowRegistry.erase(rt);
265
- this->_scopedTheme = std::nullopt;
266
- }
@@ -32,35 +32,37 @@ struct UnistylesRegistry: public StyleSheetRegistry {
32
32
  bool shouldUsePointsForBreakpoints = false;
33
33
 
34
34
  void registerTheme(jsi::Runtime& rt, std::string name, jsi::Value& theme);
35
- void registerBreakpoints(jsi::Runtime& rt, std::vector<std::pair<std::string, double>>& sortedBreakpoints);
36
- void setPrefersAdaptiveThemes(jsi::Runtime& rt, bool prefersAdaptiveThemes);
37
- void setInitialThemeName(jsi::Runtime& rt, std::string themeName);
35
+ void registerBreakpoints(std::vector<std::pair<std::string, double>>& sortedBreakpoints);
36
+ void setPrefersAdaptiveThemes(bool prefersAdaptiveThemes);
37
+ void setInitialThemeName(std::string themeName);
38
38
  void updateTheme(jsi::Runtime& rt, std::string& themeName, jsi::Function&& callback);
39
39
 
40
- UnistylesState& getState(jsi::Runtime& rt);
41
- void createState(jsi::Runtime& rt);
42
- std::vector<std::shared_ptr<core::StyleSheet>> getStyleSheetsToRefresh(jsi::Runtime& rt, std::vector<UnistyleDependency>& unistylesDependencies);
40
+ UnistylesState& getState();
41
+ void createState();
42
+ std::vector<std::shared_ptr<core::StyleSheet>> getStyleSheetsToRefresh(std::vector<UnistyleDependency>& unistylesDependencies);
43
43
  void linkShadowNodeWithUnistyle(jsi::Runtime& rt, const ShadowNodeFamily*, std::vector<std::shared_ptr<UnistyleData>>& unistylesData);
44
- void unlinkShadowNodeWithUnistyles(jsi::Runtime& rt, const ShadowNodeFamily*);
44
+ void unlinkShadowNodeWithUnistyles(const ShadowNodeFamily*);
45
+ void suspendShadowNode(const ShadowNodeFamily*);
46
+ bool isSuspended(const ShadowNodeFamily*) const noexcept;
45
47
  std::shared_ptr<core::StyleSheet> addStyleSheet(jsi::Runtime& rt, core::StyleSheetType type, jsi::Object&& rawValue);
46
- DependencyMap buildDependencyMap(jsi::Runtime& rt, std::vector<UnistyleDependency>& deps);
48
+ DependencyMap buildDependencyMap(std::vector<UnistyleDependency>& deps);
47
49
  void shadowLeafUpdateFromUnistyle(jsi::Runtime& rt, Unistyle::Shared unistyle, jsi::Value& maybePressableId);
48
50
  shadow::ShadowTrafficController trafficController{};
49
51
  const std::optional<std::string> getScopedTheme();
50
- void removeDuplicatedUnistyles(jsi::Runtime& rt, const ShadowNodeFamily* shadowNodeFamily, std::vector<core::Unistyle::Shared>& unistyles);
52
+ void removeDuplicatedUnistyles(const ShadowNodeFamily* shadowNodeFamily, std::vector<core::Unistyle::Shared>& unistyles);
51
53
  void setScopedTheme(std::optional<std::string> themeName);
52
- core::Unistyle::Shared getUnistyleById(jsi::Runtime& rt, std::string unistyleID);
54
+ core::Unistyle::Shared getUnistyleById(std::string unistyleID);
53
55
  void destroy();
54
- void destroyState(jsi::Runtime* rt);
55
56
 
56
57
  private:
57
58
  UnistylesRegistry() = default;
58
59
 
59
60
  static std::atomic<int> _nextStyleSheetTag;
60
61
  std::optional<std::string> _scopedTheme{};
61
- std::unordered_map<jsi::Runtime*, UnistylesState> _states{};
62
- std::unordered_map<jsi::Runtime*, std::unordered_map<int, std::shared_ptr<core::StyleSheet>>> _styleSheetRegistry{};
63
- std::unordered_map<jsi::Runtime*, std::unordered_map<const ShadowNodeFamily*, std::vector<std::shared_ptr<UnistyleData>>>> _shadowRegistry{};
62
+ std::unique_ptr<UnistylesState> _state{};
63
+ std::unordered_map<int, std::shared_ptr<core::StyleSheet>> _styleSheetRegistry{};
64
+ std::unordered_map<const ShadowNodeFamily*, std::vector<std::shared_ptr<UnistyleData>>> _shadowRegistry{};
65
+ std::unordered_set<const ShadowNodeFamily*> _suspendedFamilies{};
64
66
  };
65
67
 
66
68
  inline UnistylesRegistry& UnistylesRegistry::get() {
@@ -12,7 +12,9 @@ bool core::UnistylesState::hasAdaptiveThemes() {
12
12
  }
13
13
 
14
14
  void core::UnistylesState::setTheme(std::string themeName) {
15
- helpers::assertThat(*_rt, helpers::vecContainsKeys(this->_registeredThemeNames, {themeName}), "Unistyles: You're trying to set theme to: '" + std::string(themeName) + "', but it wasn't registered.");
15
+ if (!helpers::vecContainsKeys(this->_registeredThemeNames, {themeName})) {
16
+ throw std::runtime_error("Unistyles: You're trying to set theme to: '" + std::string(themeName) + "', but it wasn't registered.");
17
+ }
16
18
 
17
19
  if (themeName != this->_currentThemeName) {
18
20
  this->_currentThemeName = themeName;
@@ -23,33 +25,33 @@ std::optional<std::string>& core::UnistylesState::getCurrentThemeName() {
23
25
  return this->_currentThemeName;
24
26
  }
25
27
 
26
- jsi::Object core::UnistylesState::getCurrentJSTheme() {
28
+ jsi::Object core::UnistylesState::getCurrentJSTheme(jsi::Runtime& rt) {
27
29
  auto hasSomeThemes = _registeredThemeNames.size() > 0;
28
30
 
29
31
  if (!hasSomeThemes && !this->hasUserConfig) {
30
- helpers::assertThat(*_rt, false, "Unistyles: One of your stylesheets is trying to get the theme, but no theme has been selected yet. Did you forget to call StyleSheet.configure? If you called it, make sure you did so before any StyleSheet.create.");
32
+ helpers::assertThat(rt, false, "Unistyles: One of your stylesheets is trying to get the theme, but no theme has been selected yet. Did you forget to call StyleSheet.configure? If you called it, make sure you did so before any StyleSheet.create.");
31
33
  }
32
34
 
33
35
  // return empty object, if user didn't register any themes
34
36
  if (!hasSomeThemes) {
35
- return jsi::Object(*_rt);
37
+ return jsi::Object(rt);
36
38
  }
37
39
 
38
- helpers::assertThat(*_rt, _currentThemeName.has_value(), "Unistyles: One of your stylesheets is trying to get the theme, but no theme has been selected yet. Did you forget to select an initial theme?");
40
+ helpers::assertThat(rt, _currentThemeName.has_value(), "Unistyles: One of your stylesheets is trying to get the theme, but no theme has been selected yet. Did you forget to select an initial theme?");
39
41
 
40
42
  auto it = this->_jsThemes.find(_currentThemeName.value());
41
43
 
42
- helpers::assertThat(*_rt, it != this->_jsThemes.end(), "Unistyles: You're trying to get theme '" + _currentThemeName.value() + "', but it was not registered. Did you forget to register it with StyleSheet.configure?");
44
+ helpers::assertThat(rt, it != this->_jsThemes.end(), "Unistyles: You're trying to get theme '" + _currentThemeName.value() + "', but it was not registered. Did you forget to register it with StyleSheet.configure?");
43
45
 
44
- return it->second.asObject(*_rt);
46
+ return it->second.asObject(rt);
45
47
  }
46
48
 
47
- jsi::Object core::UnistylesState::getJSThemeByName(std::string& themeName) {
49
+ jsi::Object core::UnistylesState::getJSThemeByName(jsi::Runtime& rt, std::string& themeName) {
48
50
  auto it = this->_jsThemes.find(themeName);
49
51
 
50
- helpers::assertThat(*_rt, it != this->_jsThemes.end(), "Unistyles: You're trying to get theme '" + themeName + "', but it was not registered. Did you forget to register it with StyleSheet.configure?");
52
+ helpers::assertThat(rt, it != this->_jsThemes.end(), "Unistyles: You're trying to get theme '" + themeName + "', but it was not registered. Did you forget to register it with StyleSheet.configure?");
51
53
 
52
- return it->second.asObject(*_rt);
54
+ return it->second.asObject(rt);
53
55
  }
54
56
 
55
57
  void core::UnistylesState::computeCurrentBreakpoint(int screenWidth) {
@@ -99,28 +101,28 @@ void core::UnistylesState::registerParseBoxShadowString(jsi::Function&& fn) {
99
101
  this->_parseBoxShadowStringFn = std::make_shared<jsi::Function>(std::move(fn));
100
102
  }
101
103
 
102
- int core::UnistylesState::parseColor(jsi::Value& maybeColor) {
104
+ int core::UnistylesState::parseColor(jsi::Runtime& rt, jsi::Value& maybeColor) {
103
105
  if (!maybeColor.isString()) {
104
106
  return 0;
105
107
  }
106
108
 
107
- auto colorString = maybeColor.asString(*_rt);
109
+ auto colorString = maybeColor.asString(rt);
108
110
 
109
- if (!this->_colorCache.contains(colorString.utf8(*_rt).c_str())) {
111
+ if (!this->_colorCache.contains(colorString.utf8(rt).c_str())) {
110
112
  #ifdef ANDROID
111
- int color = this->_processColorFn.get()->call(*_rt, colorString).asNumber();
113
+ int color = this->_processColorFn.get()->call(rt, colorString).asNumber();
112
114
  #else
113
- uint32_t color = this->_processColorFn.get()->call(*_rt, colorString).asNumber();
115
+ uint32_t color = this->_processColorFn.get()->call(rt, colorString).asNumber();
114
116
  #endif
115
117
 
116
- this->_colorCache[colorString.utf8(*_rt).c_str()] = color ? color : 0;
118
+ this->_colorCache[colorString.utf8(rt).c_str()] = color ? color : 0;
117
119
  }
118
120
 
119
- return this->_colorCache[colorString.utf8(*_rt).c_str()];
121
+ return this->_colorCache[colorString.utf8(rt).c_str()];
120
122
  }
121
123
 
122
- jsi::Array core::UnistylesState::parseBoxShadowString(std::string&& boxShadowString) {
123
- jsi::Value result = this->_parseBoxShadowStringFn.get()->call(*_rt, boxShadowString);
124
+ jsi::Array core::UnistylesState::parseBoxShadowString(jsi::Runtime& rt, std::string&& boxShadowString) {
125
+ jsi::Value result = this->_parseBoxShadowStringFn.get()->call(rt, boxShadowString);
124
126
 
125
- return result.asObject(*_rt).asArray(*_rt);
127
+ return result.asObject(rt).asArray(rt);
126
128
  }
@@ -13,7 +13,7 @@ struct UnistylesRegistry;
13
13
  using namespace facebook;
14
14
 
15
15
  struct UnistylesState {
16
- UnistylesState(jsi::Runtime& rt): _rt{&rt} {}
16
+ UnistylesState() = default;
17
17
  UnistylesState(const UnistylesState&) = delete;
18
18
  UnistylesState(const UnistylesState&&) = delete;
19
19
 
@@ -29,16 +29,15 @@ struct UnistylesState {
29
29
  std::optional<std::string> getCurrentBreakpointName();
30
30
  std::vector<std::pair<std::string, double>> getSortedBreakpointPairs();
31
31
 
32
- jsi::Object getCurrentJSTheme();
33
- jsi::Object getJSThemeByName(std::string& themeName);
34
- int parseColor(jsi::Value& color);
35
- jsi::Array parseBoxShadowString(std::string&& boxShadowString);
32
+ jsi::Object getCurrentJSTheme(jsi::Runtime& rt);
33
+ jsi::Object getJSThemeByName(jsi::Runtime& rt, std::string& themeName);
34
+ int parseColor(jsi::Runtime& rt, jsi::Value& color);
35
+ jsi::Array parseBoxShadowString(jsi::Runtime& rt, std::string&& boxShadowString);
36
36
  void computeCurrentBreakpoint(int screenWidth);
37
37
  void registerProcessColorFunction(jsi::Function&& fn);
38
38
  void registerParseBoxShadowString(jsi::Function&& fn);
39
39
 
40
40
  private:
41
- jsi::Runtime* _rt;
42
41
  std::unordered_map<std::string, jsi::Value> _jsThemes{};
43
42
  std::optional<bool> _prefersAdaptiveThemes = std::nullopt;
44
43
  std::optional<std::string> _initialThemeName = std::nullopt;
@@ -13,7 +13,7 @@ jsi::Value HybridShadowRegistry::link(jsi::Runtime &rt, const jsi::Value &thisVa
13
13
  auto& registry = core::UnistylesRegistry::get();
14
14
 
15
15
  // this is special case for Animated, and prevents appending same unistyles to node
16
- registry.removeDuplicatedUnistyles(rt, &shadowNodeWrapper->getFamily(), unistyleWrappers);
16
+ registry.removeDuplicatedUnistyles(&shadowNodeWrapper->getFamily(), unistyleWrappers);
17
17
 
18
18
  if (unistyleWrappers.empty()) {
19
19
  return jsi::Value::undefined();
@@ -45,7 +45,7 @@ jsi::Value HybridShadowRegistry::link(jsi::Runtime &rt, const jsi::Value &thisVa
45
45
  if (scopedTheme.has_value()) {
46
46
  auto themeName = scopedTheme.value();
47
47
 
48
- helpers::assertThat(rt, registry.getState(rt).hasTheme(themeName), "Unistyles: You're trying to use scoped theme '" + themeName + "' but it wasn't registered.");
48
+ helpers::assertThat(rt, registry.getState().hasTheme(themeName), "Unistyles: You're trying to use scoped theme '" + themeName + "' but it wasn't registered.");
49
49
  }
50
50
 
51
51
  auto parser = parser::Parser(this->_unistylesRuntime);
@@ -107,7 +107,18 @@ jsi::Value HybridShadowRegistry::unlink(jsi::Runtime &rt, const jsi::Value &this
107
107
 
108
108
  auto& registry = core::UnistylesRegistry::get();
109
109
 
110
- registry.unlinkShadowNodeWithUnistyles(rt, &shadowNodeWrapper->getFamily());
110
+ registry.unlinkShadowNodeWithUnistyles(&shadowNodeWrapper->getFamily());
111
+
112
+ return jsi::Value::undefined();
113
+ }
114
+
115
+ jsi::Value HybridShadowRegistry::suspend(jsi::Runtime &rt, const jsi::Value &thisValue, const jsi::Value *args, size_t count) {
116
+ helpers::assertThat(rt, count == 1, "Unistyles: Invalid babel transform 'ShadowRegistry suspend' expected 1 argument.");
117
+
118
+ auto shadowNodeWrapper = getShadowNodeFromRef(rt, args[0]);
119
+ auto& registry = core::UnistylesRegistry::get();
120
+
121
+ registry.suspendShadowNode(&shadowNodeWrapper->getFamily());
111
122
 
112
123
  return jsi::Value::undefined();
113
124
  }
@@ -22,6 +22,10 @@ struct HybridShadowRegistry: public HybridUnistylesShadowRegistrySpec {
22
22
  const jsi::Value& thisValue,
23
23
  const jsi::Value* args,
24
24
  size_t count);
25
+ jsi::Value suspend(jsi::Runtime& rt,
26
+ const jsi::Value& thisValue,
27
+ const jsi::Value* args,
28
+ size_t count);
25
29
  jsi::Value flush(jsi::Runtime& rt,
26
30
  const jsi::Value& thisValue,
27
31
  const jsi::Value* args,
@@ -41,6 +45,7 @@ struct HybridShadowRegistry: public HybridUnistylesShadowRegistrySpec {
41
45
  registerHybrids(this, [](Prototype& prototype) {
42
46
  prototype.registerRawHybridMethod("link", 2, &HybridShadowRegistry::link);
43
47
  prototype.registerRawHybridMethod("unlink", 1, &HybridShadowRegistry::unlink);
48
+ prototype.registerRawHybridMethod("suspend", 1, &HybridShadowRegistry::suspend);
44
49
  prototype.registerRawHybridMethod("flush", 0, &HybridShadowRegistry::flush);
45
50
  prototype.registerRawHybridMethod("setScopedTheme", 1, &HybridShadowRegistry::setScopedTheme);
46
51
  prototype.registerRawHybridMethod("getScopedTheme", 0, &HybridShadowRegistry::getScopedTheme);