react-native-unistyles 3.3.0 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -10
- package/android/build.gradle +12 -1
- package/android/src/main/cxx/NativeUnistylesModule.cpp +8 -4
- package/android/src/main/cxx/NativeUnistylesModule.h +5 -1
- package/components/native/ActivityIndicator/package.json +1 -1
- package/cxx/common/UnistylesConstants.h +1 -0
- package/cxx/converters/TransformOriginConverter.cpp +106 -0
- package/cxx/core/StyleSheetRegistry.cpp +9 -9
- package/cxx/core/StyleSheetRegistry.h +3 -3
- package/cxx/core/UnistyleWrapper.h +13 -1
- package/cxx/core/UnistylesRegistry.cpp +226 -54
- package/cxx/core/UnistylesRegistry.h +64 -7
- package/cxx/hybridObjects/HybridShadowRegistry.cpp +128 -11
- package/cxx/hybridObjects/HybridShadowRegistry.h +20 -0
- package/cxx/hybridObjects/HybridStyleSheet.cpp +20 -12
- package/cxx/hybridObjects/HybridUnistylesRuntime.cpp +11 -1
- package/cxx/hybridObjects/HybridUnistylesRuntime.h +4 -2
- package/cxx/parser/Parser.cpp +30 -3
- package/cxx/parser/Parser.h +1 -0
- package/cxx/shadowTree/NativeProps.h +88 -0
- package/cxx/shadowTree/ShadowLeafUpdate.h +8 -0
- package/cxx/shadowTree/ShadowTrafficController.h +18 -35
- package/cxx/shadowTree/ShadowTreeDiagnostics.cpp +339 -0
- package/cxx/shadowTree/ShadowTreeDiagnostics.h +18 -0
- package/cxx/shadowTree/ShadowTreeManager.cpp +14 -148
- package/cxx/shadowTree/ShadowTreeManager.h +2 -6
- package/diagnostics/package.json +6 -0
- package/ios/UnistylesModuleOnLoad.mm +9 -3
- package/lib/commonjs/components/native/ActivityIndicator.native.js +10 -0
- package/lib/commonjs/components/native/ActivityIndicator.native.js.map +1 -0
- package/lib/commonjs/components/native/Animated.js +2 -0
- package/lib/commonjs/components/native/Animated.js.map +1 -1
- package/lib/commonjs/components/native/NativeText.js +6 -0
- package/lib/commonjs/components/native/NativeText.js.map +1 -1
- package/lib/commonjs/components/native/NativeText.native.js +17 -1
- package/lib/commonjs/components/native/NativeText.native.js.map +1 -1
- package/lib/commonjs/components/native/NativeView.js +6 -0
- package/lib/commonjs/components/native/NativeView.js.map +1 -1
- package/lib/commonjs/components/native/NativeView.native.js +22 -3
- package/lib/commonjs/components/native/NativeView.native.js.map +1 -1
- package/lib/commonjs/components/native/Pressable.js +9 -3
- package/lib/commonjs/components/native/Pressable.js.map +1 -1
- package/lib/commonjs/components/native/Pressable.native.js +2 -0
- package/lib/commonjs/components/native/Pressable.native.js.map +1 -1
- package/lib/commonjs/components/native/TouchableHighlight.native.js +10 -0
- package/lib/commonjs/components/native/TouchableHighlight.native.js.map +1 -0
- package/lib/commonjs/core/createUnistylesActivityIndicator.js +41 -0
- package/lib/commonjs/core/createUnistylesActivityIndicator.js.map +1 -0
- package/lib/commonjs/core/createUnistylesElement.js +59 -14
- package/lib/commonjs/core/createUnistylesElement.js.map +1 -1
- package/lib/commonjs/core/createUnistylesTouchableHighlight.js +58 -0
- package/lib/commonjs/core/createUnistylesTouchableHighlight.js.map +1 -0
- package/lib/commonjs/core/index.js +14 -0
- package/lib/commonjs/core/index.js.map +1 -1
- package/lib/commonjs/diagnostics/index.js +13 -0
- package/lib/commonjs/diagnostics/index.js.map +1 -0
- package/lib/commonjs/diagnostics/types.js +2 -0
- package/lib/commonjs/diagnostics/types.js.map +1 -0
- package/lib/commonjs/diagnostics/verify.js +19 -0
- package/lib/commonjs/diagnostics/verify.js.map +1 -0
- package/lib/commonjs/diagnostics/verify.native.js +12 -0
- package/lib/commonjs/diagnostics/verify.native.js.map +1 -0
- package/lib/commonjs/index.js +38 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/mocks.js +41 -0
- package/lib/commonjs/mocks.js.map +1 -1
- package/lib/commonjs/reanimated/variant/useUpdateVariantColor.native.js +8 -0
- package/lib/commonjs/reanimated/variant/useUpdateVariantColor.native.js.map +1 -1
- package/lib/commonjs/specs/ShadowRegistry/index.js +97 -1
- package/lib/commonjs/specs/ShadowRegistry/index.js.map +1 -1
- package/lib/commonjs/specs/StyleSheet/index.js +5 -1
- package/lib/commonjs/specs/StyleSheet/index.js.map +1 -1
- package/lib/commonjs/specs/UnistylesRuntime/index.js.map +1 -1
- package/lib/commonjs/web/convert/object/boxShadow.js +2 -2
- package/lib/commonjs/web/convert/object/boxShadow.js.map +1 -1
- package/lib/commonjs/web/index.js.map +1 -1
- package/lib/commonjs/web/registry.js +3 -0
- package/lib/commonjs/web/registry.js.map +1 -1
- package/lib/module/components/native/ActivityIndicator.native.js +6 -0
- package/lib/module/components/native/ActivityIndicator.native.js.map +1 -0
- package/lib/module/components/native/Animated.js +3 -0
- package/lib/module/components/native/Animated.js.map +1 -1
- package/lib/module/components/native/NativeText.js +1 -1
- package/lib/module/components/native/NativeText.js.map +1 -1
- package/lib/module/components/native/NativeText.native.js +15 -1
- package/lib/module/components/native/NativeText.native.js.map +1 -1
- package/lib/module/components/native/NativeView.js +1 -0
- package/lib/module/components/native/NativeView.js.map +1 -1
- package/lib/module/components/native/NativeView.native.js +19 -2
- package/lib/module/components/native/NativeView.native.js.map +1 -1
- package/lib/module/components/native/Pressable.js +9 -3
- package/lib/module/components/native/Pressable.js.map +1 -1
- package/lib/module/components/native/Pressable.native.js +2 -0
- package/lib/module/components/native/Pressable.native.js.map +1 -1
- package/lib/module/components/native/TouchableHighlight.native.js +6 -0
- package/lib/module/components/native/TouchableHighlight.native.js.map +1 -0
- package/lib/module/core/createUnistylesActivityIndicator.js +35 -0
- package/lib/module/core/createUnistylesActivityIndicator.js.map +1 -0
- package/lib/module/core/createUnistylesElement.js +58 -13
- package/lib/module/core/createUnistylesElement.js.map +1 -1
- package/lib/module/core/createUnistylesTouchableHighlight.js +52 -0
- package/lib/module/core/createUnistylesTouchableHighlight.js.map +1 -0
- package/lib/module/core/index.js +2 -0
- package/lib/module/core/index.js.map +1 -1
- package/lib/module/diagnostics/index.js +5 -0
- package/lib/module/diagnostics/index.js.map +1 -0
- package/lib/module/diagnostics/types.js +2 -0
- package/lib/module/diagnostics/types.js.map +1 -0
- package/lib/module/diagnostics/verify.js +14 -0
- package/lib/module/diagnostics/verify.js.map +1 -0
- package/lib/module/diagnostics/verify.native.js +8 -0
- package/lib/module/diagnostics/verify.native.js.map +1 -0
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/mocks.js +41 -0
- package/lib/module/mocks.js.map +1 -1
- package/lib/module/reanimated/variant/useUpdateVariantColor.native.js +9 -1
- package/lib/module/reanimated/variant/useUpdateVariantColor.native.js.map +1 -1
- package/lib/module/specs/ShadowRegistry/index.js +97 -1
- package/lib/module/specs/ShadowRegistry/index.js.map +1 -1
- package/lib/module/specs/StyleSheet/index.js +6 -1
- package/lib/module/specs/StyleSheet/index.js.map +1 -1
- package/lib/module/specs/UnistylesRuntime/index.js.map +1 -1
- package/lib/module/web/convert/object/boxShadow.js +2 -2
- package/lib/module/web/convert/object/boxShadow.js.map +1 -1
- package/lib/module/web/index.js.map +1 -1
- package/lib/module/web/registry.js +3 -0
- package/lib/module/web/registry.js.map +1 -1
- package/lib/typescript/src/components/native/ActivityIndicator.native.d.ts +2 -0
- package/lib/typescript/src/components/native/ActivityIndicator.native.d.ts.map +1 -0
- package/lib/typescript/src/components/native/Animated.d.ts +16 -36
- package/lib/typescript/src/components/native/Animated.d.ts.map +1 -1
- package/lib/typescript/src/components/native/NativeText.d.ts +1 -1
- package/lib/typescript/src/components/native/NativeText.d.ts.map +1 -1
- package/lib/typescript/src/components/native/NativeText.native.d.ts.map +1 -1
- package/lib/typescript/src/components/native/NativeView.d.ts +1 -0
- package/lib/typescript/src/components/native/NativeView.d.ts.map +1 -1
- package/lib/typescript/src/components/native/NativeView.native.d.ts +2 -2
- package/lib/typescript/src/components/native/NativeView.native.d.ts.map +1 -1
- package/lib/typescript/src/components/native/Pressable.d.ts +4 -2
- package/lib/typescript/src/components/native/Pressable.d.ts.map +1 -1
- package/lib/typescript/src/components/native/Pressable.native.d.ts +5 -2
- package/lib/typescript/src/components/native/Pressable.native.d.ts.map +1 -1
- package/lib/typescript/src/components/native/TouchableHighlight.native.d.ts +2 -0
- package/lib/typescript/src/components/native/TouchableHighlight.native.d.ts.map +1 -0
- package/lib/typescript/src/core/createUnistylesActivityIndicator.d.ts +3 -0
- package/lib/typescript/src/core/createUnistylesActivityIndicator.d.ts.map +1 -0
- package/lib/typescript/src/core/createUnistylesElement.d.ts.map +1 -1
- package/lib/typescript/src/core/createUnistylesTouchableHighlight.d.ts +3 -0
- package/lib/typescript/src/core/createUnistylesTouchableHighlight.d.ts.map +1 -0
- package/lib/typescript/src/core/index.d.ts +2 -0
- package/lib/typescript/src/core/index.d.ts.map +1 -1
- package/lib/typescript/src/core/useUnistyles.d.ts +1 -1
- package/lib/typescript/src/diagnostics/index.d.ts +3 -0
- package/lib/typescript/src/diagnostics/index.d.ts.map +1 -0
- package/lib/typescript/src/diagnostics/types.d.ts +19 -0
- package/lib/typescript/src/diagnostics/types.d.ts.map +1 -0
- package/lib/typescript/src/diagnostics/verify.d.ts +3 -0
- package/lib/typescript/src/diagnostics/verify.d.ts.map +1 -0
- package/lib/typescript/src/diagnostics/verify.native.d.ts +3 -0
- package/lib/typescript/src/diagnostics/verify.native.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +4 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/reanimated/variant/useUpdateVariantColor.native.d.ts.map +1 -1
- package/lib/typescript/src/specs/ShadowRegistry/index.d.ts +5 -1
- package/lib/typescript/src/specs/ShadowRegistry/index.d.ts.map +1 -1
- package/lib/typescript/src/specs/ShadowRegistry/types.d.ts +3 -0
- package/lib/typescript/src/specs/ShadowRegistry/types.d.ts.map +1 -1
- package/lib/typescript/src/specs/StyleSheet/index.d.ts +4 -1
- package/lib/typescript/src/specs/StyleSheet/index.d.ts.map +1 -1
- package/lib/typescript/src/specs/UnistylesRuntime/index.d.ts +2 -2
- package/lib/typescript/src/specs/UnistylesRuntime/index.d.ts.map +1 -1
- package/lib/typescript/src/types/breakpoints.d.ts +1 -1
- package/lib/typescript/src/types/breakpoints.d.ts.map +1 -1
- package/lib/typescript/src/types/core.d.ts +7 -2
- package/lib/typescript/src/types/core.d.ts.map +1 -1
- package/lib/typescript/src/types/stylesheet.d.ts +3 -3
- package/lib/typescript/src/types/stylesheet.d.ts.map +1 -1
- package/lib/typescript/src/web/index.d.ts.map +1 -1
- package/lib/typescript/src/web/registry.d.ts.map +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/unistyles/Func_void_UnistylesNativeMiniRuntime.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/unistyles/Func_void_std__vector_UnistyleDependency__UnistylesNativeMiniRuntime.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/unistyles/HybridNativePlatformSpec.kt +2 -0
- package/package.json +35 -26
- package/plugin/index.d.ts +4 -4
- package/plugin/index.js +21 -5
- package/src/components/native/ActivityIndicator.native.tsx +5 -0
- package/src/components/native/Animated.tsx +18 -1
- package/src/components/native/NativeText.native.tsx +18 -1
- package/src/components/native/NativeText.tsx +1 -1
- package/src/components/native/NativeView.native.tsx +22 -2
- package/src/components/native/NativeView.tsx +2 -0
- package/src/components/native/Pressable.native.tsx +10 -2
- package/src/components/native/Pressable.tsx +15 -4
- package/src/components/native/TouchableHighlight.native.tsx +5 -0
- package/src/core/createUnistylesActivityIndicator.tsx +47 -0
- package/src/core/createUnistylesElement.tsx +45 -14
- package/src/core/createUnistylesTouchableHighlight.tsx +69 -0
- package/src/core/index.ts +2 -0
- package/src/diagnostics/index.ts +3 -0
- package/src/diagnostics/types.ts +25 -0
- package/src/diagnostics/verify.native.ts +7 -0
- package/src/diagnostics/verify.ts +13 -0
- package/src/index.ts +4 -1
- package/src/mocks.ts +41 -0
- package/src/reanimated/variant/useUpdateVariantColor.native.ts +7 -1
- package/src/specs/ShadowRegistry/index.ts +128 -1
- package/src/specs/ShadowRegistry/types.ts +3 -0
- package/src/specs/StyleSheet/index.ts +10 -2
- package/src/specs/UnistylesRuntime/index.ts +7 -2
- package/src/types/breakpoints.ts +5 -3
- package/src/types/core.ts +7 -28
- package/src/types/stylesheet.ts +3 -3
- package/src/web/convert/object/boxShadow.ts +2 -2
- package/src/web/index.ts +2 -1
- package/src/web/registry.ts +3 -0
|
@@ -6,6 +6,11 @@ using namespace facebook::react;
|
|
|
6
6
|
jsi::Value HybridShadowRegistry::link(jsi::Runtime &rt, const jsi::Value &thisValue, const jsi::Value *args, size_t count) {
|
|
7
7
|
helpers::assertThat(rt, count == 2, "Unistyles: Invalid babel transform 'ShadowRegistry link' expected 2 arguments.");
|
|
8
8
|
|
|
9
|
+
// runtime was replaced, registry belongs to the next one
|
|
10
|
+
if (!this->_unistylesRuntime->ownsRegistry()) {
|
|
11
|
+
return jsi::Value::undefined();
|
|
12
|
+
}
|
|
13
|
+
|
|
9
14
|
auto shadowNodeWrapper = getShadowNodeFromRef(rt, args[0]);
|
|
10
15
|
|
|
11
16
|
std::vector<core::Unistyle::Shared> unistyleWrappers = core::unistyleFromValue(rt, args[1]);
|
|
@@ -87,37 +92,79 @@ jsi::Value HybridShadowRegistry::link(jsi::Runtime &rt, const jsi::Value &thisVa
|
|
|
87
92
|
parser.rebuildUnistyleWithScopedTheme(rt, parsedStyleSheet, unistyleData);
|
|
88
93
|
}
|
|
89
94
|
|
|
90
|
-
//
|
|
95
|
+
// The shared cache can belong to another view by the time React attaches refs.
|
|
96
|
+
// Restore this view's arguments and variants before saving its native styles.
|
|
91
97
|
if (!unistyleData->parsedStyle.has_value() && unistyle->parsedStyle.has_value()) {
|
|
92
|
-
|
|
98
|
+
parser.rebuildUnistyleWithVariants(rt, unistyleData);
|
|
93
99
|
}
|
|
94
100
|
|
|
95
101
|
unistylesData.emplace_back(unistyleData);
|
|
96
102
|
}
|
|
97
103
|
|
|
98
104
|
std::optional<folly::dynamic> initialScopedUpdate;
|
|
105
|
+
bool shouldCommit = false;
|
|
99
106
|
|
|
100
|
-
if (scopedTheme.has_value()
|
|
101
|
-
initialScopedUpdate = parser.
|
|
107
|
+
if (scopedTheme.has_value()) {
|
|
108
|
+
initialScopedUpdate = parser.parseStylesToShadowTreeUpdates(rt, unistylesData);
|
|
109
|
+
shouldCommit = shadow::hasNativeProps(&shadowNodeWrapper->getFamily());
|
|
110
|
+
} else if (shadow::hasNativeProps(&shadowNodeWrapper->getFamily())) {
|
|
111
|
+
auto update = parser.parseStylesToShadowTreeUpdates(rt, unistylesData);
|
|
112
|
+
|
|
113
|
+
if (shadow::hasOutdatedNativeProps(&shadowNodeWrapper->getFamily(), update)) {
|
|
114
|
+
initialScopedUpdate = std::move(update);
|
|
115
|
+
shouldCommit = true;
|
|
116
|
+
}
|
|
102
117
|
}
|
|
103
118
|
|
|
104
119
|
registry.linkShadowNodeWithUnistyle(
|
|
105
120
|
rt,
|
|
106
|
-
|
|
121
|
+
this->_unistylesRuntime->generation,
|
|
122
|
+
shadowNodeWrapper->getFamilyShared(),
|
|
107
123
|
unistylesData,
|
|
108
124
|
std::move(initialScopedUpdate)
|
|
109
125
|
);
|
|
110
126
|
|
|
111
|
-
if (
|
|
112
|
-
|
|
127
|
+
if (shouldCommit) {
|
|
128
|
+
this->scheduleShadowTreeUpdate(rt);
|
|
113
129
|
}
|
|
114
130
|
|
|
115
131
|
return jsi::Value::undefined();
|
|
116
132
|
}
|
|
117
133
|
|
|
134
|
+
void HybridShadowRegistry::scheduleShadowTreeUpdate(jsi::Runtime& rt) {
|
|
135
|
+
if (this->_isShadowTreeUpdateScheduled->exchange(true)) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
auto isShadowTreeUpdateScheduled = this->_isShadowTreeUpdateScheduled;
|
|
140
|
+
auto unistylesRuntime = this->_unistylesRuntime;
|
|
141
|
+
|
|
142
|
+
rt.queueMicrotask(jsi::Function::createFromHostFunction(
|
|
143
|
+
rt,
|
|
144
|
+
jsi::PropNameID::forAscii(rt, "unistylesUpdateShadowTree"),
|
|
145
|
+
0,
|
|
146
|
+
[isShadowTreeUpdateScheduled, unistylesRuntime](jsi::Runtime& rt, const jsi::Value&, const jsi::Value*, size_t) {
|
|
147
|
+
isShadowTreeUpdateScheduled->store(false);
|
|
148
|
+
|
|
149
|
+
// pending updates belong to the runtime that replaced this one
|
|
150
|
+
if (!unistylesRuntime->ownsRegistry()) {
|
|
151
|
+
return jsi::Value::undefined();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
shadow::ShadowTreeManager::updateShadowTree(rt);
|
|
155
|
+
|
|
156
|
+
return jsi::Value::undefined();
|
|
157
|
+
}
|
|
158
|
+
));
|
|
159
|
+
}
|
|
160
|
+
|
|
118
161
|
jsi::Value HybridShadowRegistry::unlink(jsi::Runtime &rt, const jsi::Value &thisValue, const jsi::Value *args, size_t count) {
|
|
119
162
|
helpers::assertThat(rt, count == 1, "Unistyles: Invalid babel transform 'ShadowRegistry unlink' expected 1 argument.");
|
|
120
163
|
|
|
164
|
+
if (!this->_unistylesRuntime->ownsRegistry()) {
|
|
165
|
+
return jsi::Value::undefined();
|
|
166
|
+
}
|
|
167
|
+
|
|
121
168
|
auto shadowNodeWrapper = getShadowNodeFromRef(rt, args[0]);
|
|
122
169
|
|
|
123
170
|
auto& registry = core::UnistylesRegistry::get();
|
|
@@ -130,6 +177,10 @@ jsi::Value HybridShadowRegistry::unlink(jsi::Runtime &rt, const jsi::Value &this
|
|
|
130
177
|
jsi::Value HybridShadowRegistry::suspend(jsi::Runtime &rt, const jsi::Value &thisValue, const jsi::Value *args, size_t count) {
|
|
131
178
|
helpers::assertThat(rt, count == 1, "Unistyles: Invalid babel transform 'ShadowRegistry suspend' expected 1 argument.");
|
|
132
179
|
|
|
180
|
+
if (!this->_unistylesRuntime->ownsRegistry()) {
|
|
181
|
+
return jsi::Value::undefined();
|
|
182
|
+
}
|
|
183
|
+
|
|
133
184
|
auto shadowNodeWrapper = getShadowNodeFromRef(rt, args[0]);
|
|
134
185
|
auto& registry = core::UnistylesRegistry::get();
|
|
135
186
|
|
|
@@ -139,6 +190,10 @@ jsi::Value HybridShadowRegistry::suspend(jsi::Runtime &rt, const jsi::Value &thi
|
|
|
139
190
|
}
|
|
140
191
|
|
|
141
192
|
jsi::Value HybridShadowRegistry::flush(jsi::Runtime &rt, const jsi::Value &thisValue, const jsi::Value *args, size_t count) {
|
|
193
|
+
if (!this->_unistylesRuntime->ownsRegistry()) {
|
|
194
|
+
return jsi::Value::undefined();
|
|
195
|
+
}
|
|
196
|
+
|
|
142
197
|
shadow::ShadowTreeManager::updateShadowTree(rt);
|
|
143
198
|
|
|
144
199
|
return jsi::Value::undefined();
|
|
@@ -147,6 +202,10 @@ jsi::Value HybridShadowRegistry::flush(jsi::Runtime &rt, const jsi::Value &thisV
|
|
|
147
202
|
jsi::Value HybridShadowRegistry::setScopedTheme(jsi::Runtime &rt, const jsi::Value &thisValue, const jsi::Value *args, size_t count) {
|
|
148
203
|
helpers::assertThat(rt, count == 1, "Unistyles: setScopedTheme expected 1 argument.");
|
|
149
204
|
|
|
205
|
+
if (!this->_unistylesRuntime->ownsRegistry()) {
|
|
206
|
+
return jsi::Value::undefined();
|
|
207
|
+
}
|
|
208
|
+
|
|
150
209
|
auto& registry = core::UnistylesRegistry::get();
|
|
151
210
|
|
|
152
211
|
if (args[0].isUndefined()) {
|
|
@@ -169,10 +228,68 @@ jsi::Value HybridShadowRegistry::getScopedTheme(jsi::Runtime &rt, const jsi::Val
|
|
|
169
228
|
: jsi::Value::undefined();
|
|
170
229
|
}
|
|
171
230
|
|
|
231
|
+
jsi::Value HybridShadowRegistry::verify(jsi::Runtime &rt, const jsi::Value &thisValue, const jsi::Value *args, size_t count) {
|
|
232
|
+
return shadow::ShadowTreeDiagnostics::verify(rt, this->_unistylesRuntime);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
jsi::Value HybridShadowRegistry::takeCommittedTags(jsi::Runtime &rt, const jsi::Value &thisValue, const jsi::Value *args, size_t count) {
|
|
236
|
+
auto tags = core::UnistylesRegistry::get().takeCommittedTags();
|
|
237
|
+
auto result = jsi::Array(rt, tags.size());
|
|
238
|
+
|
|
239
|
+
for (size_t i = 0; i < tags.size(); i++) {
|
|
240
|
+
result.setValueAtIndex(rt, i, jsi::Value(static_cast<double>(tags[i])));
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return result;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
jsi::Value HybridShadowRegistry::refreshReactNodes(jsi::Runtime &rt, const jsi::Value &thisValue, const jsi::Value *args, size_t count) {
|
|
247
|
+
helpers::assertThat(rt, count == 1 && args[0].isObject(), "Unistyles: refreshReactNodes expected to be called with an array of shadow nodes.");
|
|
248
|
+
|
|
249
|
+
auto nodes = args[0].asObject(rt).asArray(rt);
|
|
250
|
+
std::unordered_map<SurfaceId, std::shared_ptr<const RootShadowNode>> roots;
|
|
251
|
+
|
|
252
|
+
UIManagerBinding::getBinding(rt)->getUIManager().getShadowTreeRegistry().enumerate([&roots](const ShadowTree& shadowTree, bool&) {
|
|
253
|
+
roots.emplace(shadowTree.getSurfaceId(), shadowTree.getCurrentRevision().rootShadowNode);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
for (size_t i = 0; i < nodes.size(rt); i++) {
|
|
257
|
+
auto node = nodes.getValueAtIndex(rt, i);
|
|
258
|
+
|
|
259
|
+
if (!node.isObject() || !node.asObject(rt).hasNativeState<ShadowNodeWrapper>(rt)) {
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
auto wrapper = node.asObject(rt).getNativeState<ShadowNodeWrapper>(rt);
|
|
264
|
+
|
|
265
|
+
// never committed, React cloned it in a render that isn't committed yet (eg. a transition that yielded)
|
|
266
|
+
// it holds what React rendered since, pointing it at the committed node would drop that
|
|
267
|
+
if (!wrapper->shadowNode->getHasBeenPromoted()) {
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const auto& family = wrapper->shadowNode->getFamily();
|
|
272
|
+
auto rootIt = roots.find(family.getSurfaceId());
|
|
273
|
+
|
|
274
|
+
if (rootIt == roots.end()) {
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
auto ancestors = family.getAncestors(*rootIt->second);
|
|
279
|
+
|
|
280
|
+
// frozen nodes are not in the committed tree, nativeProps_DEPRECATED covers them
|
|
281
|
+
if (ancestors.empty()) {
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const auto& [parent, index] = ancestors.back();
|
|
286
|
+
|
|
287
|
+
wrapper->shadowNode = parent.get().getChildren().at(index);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return jsi::Value::undefined();
|
|
291
|
+
}
|
|
292
|
+
|
|
172
293
|
std::shared_ptr<const core::ShadowNode> HybridShadowRegistry::getShadowNodeFromRef(jsi::Runtime& rt, const jsi::Value& maybeRef) {
|
|
173
|
-
#if REACT_NATIVE_VERSION_MINOR >= 81
|
|
174
294
|
return Bridging<std::shared_ptr<const ShadowNode>>::fromJs(rt, maybeRef);
|
|
175
|
-
#else
|
|
176
|
-
return shadowNodeFromValue(rt, maybeRef);
|
|
177
|
-
#endif
|
|
178
295
|
}
|
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
#include "UnistylesState.h"
|
|
7
7
|
#include "UnistylesRegistry.h"
|
|
8
8
|
#include "ShadowTreeManager.h"
|
|
9
|
+
#include "ShadowTreeDiagnostics.h"
|
|
9
10
|
#include <cxxreact/ReactNativeVersion.h>
|
|
11
|
+
#include <atomic>
|
|
10
12
|
|
|
11
13
|
namespace margelo::nitro::unistyles {
|
|
12
14
|
|
|
@@ -38,6 +40,18 @@ struct HybridShadowRegistry: public HybridUnistylesShadowRegistrySpec {
|
|
|
38
40
|
const jsi::Value& thisValue,
|
|
39
41
|
const jsi::Value* args,
|
|
40
42
|
size_t count);
|
|
43
|
+
jsi::Value verify(jsi::Runtime& rt,
|
|
44
|
+
const jsi::Value& thisValue,
|
|
45
|
+
const jsi::Value* args,
|
|
46
|
+
size_t count);
|
|
47
|
+
jsi::Value takeCommittedTags(jsi::Runtime& rt,
|
|
48
|
+
const jsi::Value& thisValue,
|
|
49
|
+
const jsi::Value* args,
|
|
50
|
+
size_t count);
|
|
51
|
+
jsi::Value refreshReactNodes(jsi::Runtime& rt,
|
|
52
|
+
const jsi::Value& thisValue,
|
|
53
|
+
const jsi::Value* args,
|
|
54
|
+
size_t count);
|
|
41
55
|
|
|
42
56
|
void loadHybridMethods() override {
|
|
43
57
|
HybridUnistylesShadowRegistrySpec::loadHybridMethods();
|
|
@@ -49,13 +63,19 @@ struct HybridShadowRegistry: public HybridUnistylesShadowRegistrySpec {
|
|
|
49
63
|
prototype.registerRawHybridMethod("flush", 0, &HybridShadowRegistry::flush);
|
|
50
64
|
prototype.registerRawHybridMethod("setScopedTheme", 1, &HybridShadowRegistry::setScopedTheme);
|
|
51
65
|
prototype.registerRawHybridMethod("getScopedTheme", 0, &HybridShadowRegistry::getScopedTheme);
|
|
66
|
+
prototype.registerRawHybridMethod("verify", 0, &HybridShadowRegistry::verify);
|
|
67
|
+
prototype.registerRawHybridMethod("takeCommittedTags", 0, &HybridShadowRegistry::takeCommittedTags);
|
|
68
|
+
prototype.registerRawHybridMethod("refreshReactNodes", 1, &HybridShadowRegistry::refreshReactNodes);
|
|
52
69
|
});
|
|
53
70
|
};
|
|
54
71
|
|
|
55
72
|
std::shared_ptr<const core::ShadowNode> getShadowNodeFromRef(jsi::Runtime& rt, const jsi::Value& maybeRef);
|
|
56
73
|
|
|
57
74
|
private:
|
|
75
|
+
void scheduleShadowTreeUpdate(jsi::Runtime& rt);
|
|
76
|
+
|
|
58
77
|
std::shared_ptr<HybridUnistylesRuntime> _unistylesRuntime;
|
|
78
|
+
std::shared_ptr<std::atomic<bool>> _isShadowTreeUpdateScheduled = std::make_shared<std::atomic<bool>>(false);
|
|
59
79
|
};
|
|
60
80
|
|
|
61
81
|
}
|
|
@@ -16,12 +16,13 @@ double HybridStyleSheet::getHairlineWidth() {
|
|
|
16
16
|
jsi::Value HybridStyleSheet::create(jsi::Runtime& rt, const jsi::Value &thisVal, const jsi::Value *arguments, size_t count) {
|
|
17
17
|
helpers::assertThat(rt, count == 1, "StyleSheet.create expected to be called with one argument.");
|
|
18
18
|
helpers::assertThat(rt, arguments[0].isObject(), "StyleSheet.create expected to be called with object or function.");
|
|
19
|
+
helpers::assertThat(rt, this->_unistylesRuntime->ownsRegistry(), helpers::RUNTIME_REPLACED_ERROR);
|
|
19
20
|
|
|
20
21
|
auto thisStyleSheet = thisVal.asObject(rt);
|
|
21
22
|
auto& registry = core::UnistylesRegistry::get();
|
|
22
23
|
|
|
23
24
|
jsi::Object rawStyleSheet = arguments[0].asObject(rt);
|
|
24
|
-
auto registeredStyleSheet = registry.addStyleSheetFromValue(rt, std::move(rawStyleSheet));
|
|
25
|
+
auto registeredStyleSheet = registry.addStyleSheetFromValue(rt, this->_unistylesRuntime->generation, std::move(rawStyleSheet));
|
|
25
26
|
|
|
26
27
|
auto parser = parser::Parser(this->_unistylesRuntime);
|
|
27
28
|
|
|
@@ -34,6 +35,7 @@ jsi::Value HybridStyleSheet::create(jsi::Runtime& rt, const jsi::Value &thisVal,
|
|
|
34
35
|
jsi::Value HybridStyleSheet::configure(jsi::Runtime &rt, const jsi::Value &thisVal, const jsi::Value *arguments, size_t count) {
|
|
35
36
|
helpers::assertThat(rt, count == 1, "StyleSheet.configure expected to be called with one argument.");
|
|
36
37
|
helpers::assertThat(rt, arguments[0].isObject(), "StyleSheet.configure expected to be called with object.");
|
|
38
|
+
helpers::assertThat(rt, this->_unistylesRuntime->ownsRegistry(), helpers::RUNTIME_REPLACED_ERROR);
|
|
37
39
|
|
|
38
40
|
auto config = arguments[0].asObject(rt);
|
|
39
41
|
|
|
@@ -73,6 +75,8 @@ jsi::Value HybridStyleSheet::init(jsi::Runtime &rt, const jsi::Value &thisVal, c
|
|
|
73
75
|
return jsi::Value::undefined();
|
|
74
76
|
}
|
|
75
77
|
|
|
78
|
+
helpers::assertThat(rt, this->_unistylesRuntime->ownsRegistry(), helpers::RUNTIME_REPLACED_ERROR);
|
|
79
|
+
|
|
76
80
|
// create new state
|
|
77
81
|
auto& registry = core::UnistylesRegistry::get();
|
|
78
82
|
|
|
@@ -165,7 +169,7 @@ void HybridStyleSheet::parseThemes(jsi::Runtime &rt, jsi::Object themes) {
|
|
|
165
169
|
helpers::enumerateJSIObject(rt, themes, [&](const std::string& propertyName, jsi::Value& propertyValue){
|
|
166
170
|
helpers::assertThat(rt, propertyValue.isObject(), "StyleSheet.configure's registered theme '" + propertyName + "' must be an object.");
|
|
167
171
|
|
|
168
|
-
registry.registerTheme(rt, propertyName, propertyValue);
|
|
172
|
+
registry.registerTheme(rt, this->_unistylesRuntime->generation, propertyName, propertyValue);
|
|
169
173
|
});
|
|
170
174
|
}
|
|
171
175
|
|
|
@@ -267,7 +271,8 @@ void HybridStyleSheet::onPlatformDependenciesChange(std::vector<UnistyleDependen
|
|
|
267
271
|
this->_unistylesRuntime->runOnJSThread([weakSelf, dependencies](jsi::Runtime& rt) {
|
|
268
272
|
auto self = std::dynamic_pointer_cast<HybridStyleSheet>(weakSelf.lock());
|
|
269
273
|
|
|
270
|
-
|
|
274
|
+
// runtime was replaced in the meantime, registry belongs to the next one
|
|
275
|
+
if (!self || !self->_unistylesRuntime->ownsRegistry()) {
|
|
271
276
|
return;
|
|
272
277
|
}
|
|
273
278
|
|
|
@@ -288,7 +293,7 @@ void HybridStyleSheet::onPlatformNativeDependenciesChange(std::vector<UnistyleDe
|
|
|
288
293
|
this->_unistylesRuntime->runOnJSThread([weakSelf, dependencies, miniRuntime](jsi::Runtime& rt){
|
|
289
294
|
auto self = std::dynamic_pointer_cast<HybridStyleSheet>(weakSelf.lock());
|
|
290
295
|
|
|
291
|
-
if (!self) {
|
|
296
|
+
if (!self || !self->_unistylesRuntime->ownsRegistry()) {
|
|
292
297
|
return;
|
|
293
298
|
}
|
|
294
299
|
|
|
@@ -329,7 +334,7 @@ void HybridStyleSheet::onImeChange(UnistylesNativeMiniRuntime miniRuntime) {
|
|
|
329
334
|
this->_unistylesRuntime->runOnJSThread([weakSelf, miniRuntime](jsi::Runtime& rt){
|
|
330
335
|
auto self = std::dynamic_pointer_cast<HybridStyleSheet>(weakSelf.lock());
|
|
331
336
|
|
|
332
|
-
if (!self) {
|
|
337
|
+
if (!self || !self->_unistylesRuntime->ownsRegistry()) {
|
|
333
338
|
return;
|
|
334
339
|
}
|
|
335
340
|
|
|
@@ -348,22 +353,25 @@ void HybridStyleSheet::applyDependencyChanges(jsi::Runtime& rt, std::vector<Unis
|
|
|
348
353
|
// but their rawValue must still be refreshed so rerenders read fresh closures
|
|
349
354
|
auto dependentStyleSheets = registry.getStyleSheetsToRefresh(dependencies);
|
|
350
355
|
|
|
351
|
-
if (dependencyMap.empty() && dependentStyleSheets.empty()) {
|
|
352
|
-
return;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
356
|
// rebuild rawValue BEFORE notifying listeners so JS rerenders read fresh closures
|
|
356
|
-
|
|
357
|
+
if (!dependencyMap.empty() || !dependentStyleSheets.empty()) {
|
|
358
|
+
parser.rebuildUnistylesInDependencyMap(rt, dependencyMap, dependentStyleSheets, maybeMiniRuntime);
|
|
359
|
+
}
|
|
357
360
|
|
|
358
361
|
if (!dependencyMap.empty()) {
|
|
359
362
|
parser.rebuildShadowLeafUpdates(rt, dependencyMap);
|
|
360
363
|
}
|
|
361
364
|
|
|
362
|
-
|
|
365
|
+
std::vector<Tag> committedTags;
|
|
363
366
|
|
|
364
367
|
if (!dependencyMap.empty()) {
|
|
365
|
-
shadow::ShadowTreeManager::updateShadowTree(rt);
|
|
368
|
+
committedTags = shadow::ShadowTreeManager::updateShadowTree(rt);
|
|
366
369
|
}
|
|
370
|
+
|
|
371
|
+
// after the commit, so listeners can point React at the committed nodes
|
|
372
|
+
registry.setCommittedTags(std::move(committedTags));
|
|
373
|
+
// also when no StyleSheet depends on the change, hooks (useUnistyles, withUnistyles, Display, Hide) may
|
|
374
|
+
this->notifyJSListeners(dependencies);
|
|
367
375
|
}
|
|
368
376
|
|
|
369
377
|
void HybridStyleSheet::notifyJSListeners(std::vector<UnistyleDependency>& dependencies) {
|
|
@@ -4,9 +4,18 @@
|
|
|
4
4
|
using namespace margelo::nitro::unistyles;
|
|
5
5
|
|
|
6
6
|
core::UnistylesState& HybridUnistylesRuntime::getState() {
|
|
7
|
+
// state belongs to the runtime that replaced this one
|
|
8
|
+
if (!this->ownsRegistry()) {
|
|
9
|
+
throw std::runtime_error(helpers::RUNTIME_REPLACED_ERROR);
|
|
10
|
+
}
|
|
11
|
+
|
|
7
12
|
return core::UnistylesRegistry::get().getState();
|
|
8
13
|
}
|
|
9
14
|
|
|
15
|
+
bool HybridUnistylesRuntime::ownsRegistry() const {
|
|
16
|
+
return core::UnistylesRegistry::get().isCurrent(this->generation);
|
|
17
|
+
}
|
|
18
|
+
|
|
10
19
|
ColorScheme HybridUnistylesRuntime::getColorScheme() {
|
|
11
20
|
auto colorScheme = this->_nativePlatform->getColorScheme();
|
|
12
21
|
|
|
@@ -166,13 +175,14 @@ jsi::Value HybridUnistylesRuntime::updateTheme(jsi::Runtime &rt, const jsi::Valu
|
|
|
166
175
|
helpers::assertThat(rt, count == 2, "UnistylesRuntime.updateTheme expected to be called with 2 arguments.");
|
|
167
176
|
helpers::assertThat(rt, args[0].isString(), "UnistylesRuntime.updateTheme expected first argument to be a string.");
|
|
168
177
|
helpers::assertThat(rt, args[1].isObject(), "UnistylesRuntime.updateTheme expected first argument to be a function.");
|
|
178
|
+
helpers::assertThat(rt, this->ownsRegistry(), helpers::RUNTIME_REPLACED_ERROR);
|
|
169
179
|
|
|
170
180
|
auto& registry = core::UnistylesRegistry::get();
|
|
171
181
|
auto themeName = args[0].asString(rt).utf8(rt);
|
|
172
182
|
|
|
173
183
|
helpers::assertThat(rt, args[1].asObject(rt).isFunction(rt), "UnistylesRuntime.updateTheme expected second argument to be a function.");
|
|
174
184
|
|
|
175
|
-
registry.updateTheme(rt, themeName, args[1].asObject(rt).asFunction(rt));
|
|
185
|
+
registry.updateTheme(rt, this->generation, themeName, args[1].asObject(rt).asFunction(rt));
|
|
176
186
|
|
|
177
187
|
this->_onDependenciesChange({UnistyleDependency::THEME});
|
|
178
188
|
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
namespace margelo::nitro::unistyles {
|
|
14
14
|
|
|
15
15
|
struct HybridUnistylesRuntime: public HybridUnistylesRuntimeSpec {
|
|
16
|
-
HybridUnistylesRuntime(std::shared_ptr<HybridNativePlatformSpec> nativePlatform, std::function<void(std::function<void(jsi::Runtime&)>&&)> runOnJSThread)
|
|
17
|
-
: HybridObject(TAG), _nativePlatform{nativePlatform}, runOnJSThread(std::move(runOnJSThread)) {}
|
|
16
|
+
HybridUnistylesRuntime(std::shared_ptr<HybridNativePlatformSpec> nativePlatform, std::function<void(std::function<void(jsi::Runtime&)>&&)> runOnJSThread, uint64_t generation)
|
|
17
|
+
: HybridObject(TAG), _nativePlatform{nativePlatform}, runOnJSThread(std::move(runOnJSThread)), generation{generation} {}
|
|
18
18
|
|
|
19
19
|
jsi::Value getTheme(jsi::Runtime& rt,
|
|
20
20
|
const jsi::Value& thisValue,
|
|
@@ -70,11 +70,13 @@ struct HybridUnistylesRuntime: public HybridUnistylesRuntimeSpec {
|
|
|
70
70
|
std::unordered_map<std::string, double> getBreakpoints() override;
|
|
71
71
|
|
|
72
72
|
core::UnistylesState& getState();
|
|
73
|
+
bool ownsRegistry() const;
|
|
73
74
|
UnistylesCxxMiniRuntime buildMiniRuntimeFromNativeRuntime(UnistylesNativeMiniRuntime& nativeMiniRuntime);
|
|
74
75
|
jsi::Value getMiniRuntimeAsValue(jsi::Runtime& rt, std::optional<UnistylesNativeMiniRuntime> maybeMiniRuntime);
|
|
75
76
|
void includeDependenciesForColorSchemeChange(std::vector<UnistyleDependency>& deps);
|
|
76
77
|
void calculateNewThemeAndDependencies(std::vector<UnistyleDependency>& deps);
|
|
77
78
|
std::function<void(std::function<void(jsi::Runtime&)>&&)> runOnJSThread;
|
|
79
|
+
const uint64_t generation;
|
|
78
80
|
|
|
79
81
|
private:
|
|
80
82
|
std::shared_ptr<HybridNavigationBar> _navigationBar;
|
package/cxx/parser/Parser.cpp
CHANGED
|
@@ -439,13 +439,12 @@ void parser::Parser::rebuildShadowLeafUpdates(jsi::Runtime& rt, core::Dependency
|
|
|
439
439
|
|
|
440
440
|
for (const auto& [shadowNode, unistyles] : dependencyMap) {
|
|
441
441
|
// Parse string colors (e.g., "#000000") to int representation
|
|
442
|
-
auto rawProps = this->
|
|
442
|
+
auto rawProps = this->parseStylesToShadowTreeUpdates(rt, unistyles);
|
|
443
443
|
|
|
444
444
|
updates.emplace(shadowNode, std::move(rawProps));
|
|
445
445
|
}
|
|
446
446
|
|
|
447
|
-
registry.
|
|
448
|
-
registry.trafficController.resumeUnistylesTraffic();
|
|
447
|
+
registry.queueShadowLeafUpdatesUnsafe(updates);
|
|
449
448
|
});
|
|
450
449
|
}
|
|
451
450
|
|
|
@@ -1269,6 +1268,34 @@ folly::dynamic parser::Parser::parseStylesToShadowTreeStyles(jsi::Runtime& rt, c
|
|
|
1269
1268
|
return jsi::dynamicFromValue(rt, jsi::Value(rt, convertedStyles));
|
|
1270
1269
|
}
|
|
1271
1270
|
|
|
1271
|
+
// shadow tree updates skip the props an inline style sets last, React (or an animation) owns them
|
|
1272
|
+
// writing them would also leave them in nativeProps_DEPRECATED, which React Native applies to every later clone,
|
|
1273
|
+
// so a value captured at link time would undo what React rendered since
|
|
1274
|
+
folly::dynamic parser::Parser::parseStylesToShadowTreeUpdates(jsi::Runtime& rt, const std::vector<std::shared_ptr<UnistyleData>>& unistyles) {
|
|
1275
|
+
auto props = this->parseStylesToShadowTreeStyles(rt, unistyles);
|
|
1276
|
+
std::unordered_map<std::string, bool> isOwnedByInlineStyle;
|
|
1277
|
+
|
|
1278
|
+
for (const auto& unistyleData : unistyles) {
|
|
1279
|
+
if (!unistyleData->parsedStyle.has_value()) {
|
|
1280
|
+
continue;
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
bool isInlineStyle = unistyleData->unistyle->styleKey == helpers::EXOTIC_STYLE_KEY;
|
|
1284
|
+
|
|
1285
|
+
helpers::enumerateJSIObject(rt, unistyleData->parsedStyle.value(), [&isOwnedByInlineStyle, isInlineStyle](const std::string& propName, jsi::Value&) {
|
|
1286
|
+
isOwnedByInlineStyle[propName] = isInlineStyle;
|
|
1287
|
+
});
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
for (const auto& [propName, isInline] : isOwnedByInlineStyle) {
|
|
1291
|
+
if (isInline) {
|
|
1292
|
+
props.erase(propName);
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
return props;
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1272
1299
|
|
|
1273
1300
|
// check is styleKey contains color
|
|
1274
1301
|
bool parser::Parser::isColor(const std::string& propertyName) {
|
package/cxx/parser/Parser.h
CHANGED
|
@@ -28,6 +28,7 @@ struct Parser {
|
|
|
28
28
|
void rebuildUnistylesInDependencyMap(jsi::Runtime& rt, core::DependencyMap& dependencyMap, std::vector<std::shared_ptr<core::StyleSheet>>& styleSheets, std::optional<UnistylesNativeMiniRuntime> maybeMiniRuntime);
|
|
29
29
|
void rebuildShadowLeafUpdates(jsi::Runtime& rt, core::DependencyMap& dependencyMap);
|
|
30
30
|
folly::dynamic parseStylesToShadowTreeStyles(jsi::Runtime& rt, const std::vector<std::shared_ptr<UnistyleData>>& unistyles);
|
|
31
|
+
folly::dynamic parseStylesToShadowTreeUpdates(jsi::Runtime& rt, const std::vector<std::shared_ptr<UnistyleData>>& unistyles);
|
|
31
32
|
void rebuildUnistyle(jsi::Runtime& rt, Unistyle::Shared unistyle, const Variants& variants, std::optional<std::vector<folly::dynamic>>);
|
|
32
33
|
void rebuildUnistyleWithScopedTheme(jsi::Runtime& rt, jsi::Value& jsScopedTheme, std::shared_ptr<core::UnistyleData> unistyleData);
|
|
33
34
|
jsi::Value getParsedStyleSheetForScopedTheme(jsi::Runtime& rt, core::Unistyle::Shared unistyle, std::string& scopedTheme);
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <folly/dynamic.h>
|
|
4
|
+
#include <react/renderer/core/ShadowNodeFamily.h>
|
|
5
|
+
#include <cxxreact/ReactNativeVersion.h>
|
|
6
|
+
#include <algorithm>
|
|
7
|
+
#include <cstdint>
|
|
8
|
+
#include <memory>
|
|
9
|
+
#include <mutex>
|
|
10
|
+
#include <string>
|
|
11
|
+
|
|
12
|
+
// React Native reads ShadowNodeFamily::nativeProps_DEPRECATED from any thread
|
|
13
|
+
// (eg. ShadowNode::clone during main thread layout) and since 0.86.1 guards every access with nativePropsMutex
|
|
14
|
+
// we need to hold the same lock, otherwise mutating / replacing the folly::dynamic races with RN copying it
|
|
15
|
+
#if REACT_NATIVE_VERSION_MINOR > 86 || (REACT_NATIVE_VERSION_MINOR == 86 && REACT_NATIVE_VERSION_PATCH >= 1)
|
|
16
|
+
#define UNISTYLES_HAS_NATIVE_PROPS_MUTEX 1
|
|
17
|
+
#else
|
|
18
|
+
#define UNISTYLES_HAS_NATIVE_PROPS_MUTEX 0
|
|
19
|
+
#endif
|
|
20
|
+
|
|
21
|
+
namespace margelo::nitro::unistyles::shadow {
|
|
22
|
+
|
|
23
|
+
using namespace facebook::react;
|
|
24
|
+
|
|
25
|
+
inline void mergeNativeProps(const ShadowNodeFamily* family, const folly::dynamic& props) {
|
|
26
|
+
#if UNISTYLES_HAS_NATIVE_PROPS_MUTEX
|
|
27
|
+
std::lock_guard<std::mutex> lock(family->nativePropsMutex);
|
|
28
|
+
#endif
|
|
29
|
+
|
|
30
|
+
if (family->nativeProps_DEPRECATED && family->nativeProps_DEPRECATED->isObject()) {
|
|
31
|
+
family->nativeProps_DEPRECATED->update(props);
|
|
32
|
+
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
family->nativeProps_DEPRECATED = std::make_unique<folly::dynamic>(props);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
inline bool hasNativeProps(const ShadowNodeFamily* family) {
|
|
40
|
+
#if UNISTYLES_HAS_NATIVE_PROPS_MUTEX
|
|
41
|
+
std::lock_guard<std::mutex> lock(family->nativePropsMutex);
|
|
42
|
+
#endif
|
|
43
|
+
|
|
44
|
+
return family->nativeProps_DEPRECATED && family->nativeProps_DEPRECATED->isObject();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
inline bool isSamePropValue(const std::string& propName, const folly::dynamic& value, const folly::dynamic& otherValue) {
|
|
48
|
+
if (value == otherValue) {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (!value.isNumber() || !otherValue.isNumber()) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
std::string lowercasePropName = propName;
|
|
57
|
+
std::transform(lowercasePropName.begin(), lowercasePropName.end(), lowercasePropName.begin(), ::tolower);
|
|
58
|
+
|
|
59
|
+
if (lowercasePropName.find("color") == std::string::npos) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return static_cast<uint32_t>(static_cast<int64_t>(value.asDouble())) == static_cast<uint32_t>(static_cast<int64_t>(otherValue.asDouble()));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
inline bool hasOutdatedNativeProps(const ShadowNodeFamily* family, const folly::dynamic& props) {
|
|
67
|
+
#if UNISTYLES_HAS_NATIVE_PROPS_MUTEX
|
|
68
|
+
std::lock_guard<std::mutex> lock(family->nativePropsMutex);
|
|
69
|
+
#endif
|
|
70
|
+
|
|
71
|
+
if (!family->nativeProps_DEPRECATED || !family->nativeProps_DEPRECATED->isObject() || !props.isObject()) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
auto& nativeProps = *family->nativeProps_DEPRECATED;
|
|
76
|
+
|
|
77
|
+
for (const auto& [propName, propValue] : props.items()) {
|
|
78
|
+
auto it = nativeProps.find(propName);
|
|
79
|
+
|
|
80
|
+
if (it != nativeProps.items().end() && !isSamePropValue(propName.asString(), it->second, propValue)) {
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
#include <jsi/jsi.h>
|
|
4
4
|
#include <folly/dynamic.h>
|
|
5
|
+
#include <memory>
|
|
5
6
|
#include <react/renderer/uimanager/UIManager.h>
|
|
6
7
|
|
|
7
8
|
namespace margelo::nitro::unistyles::shadow {
|
|
@@ -12,4 +13,11 @@ using namespace facebook::react;
|
|
|
12
13
|
// translates Unistyles changes to unified shadow tree changes
|
|
13
14
|
using ShadowLeafUpdates = std::unordered_map<const ShadowNodeFamily*, folly::dynamic>;
|
|
14
15
|
|
|
16
|
+
struct PinnedShadowLeafUpdate {
|
|
17
|
+
std::shared_ptr<const ShadowNodeFamily> family;
|
|
18
|
+
folly::dynamic props;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
using PinnedShadowLeafUpdates = std::unordered_map<const ShadowNodeFamily*, PinnedShadowLeafUpdate>;
|
|
22
|
+
|
|
15
23
|
}
|
|
@@ -8,52 +8,36 @@ namespace margelo::nitro::unistyles::shadow {
|
|
|
8
8
|
// Like a traffic officer managing a jam, this struct ensures everything
|
|
9
9
|
// is synchronized within a set timeframe, controlling flow and preventing chaos.
|
|
10
10
|
struct ShadowTrafficController {
|
|
11
|
-
inline
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
inline void stopUnistylesTraffic() {
|
|
16
|
-
this->_canCommit = false;
|
|
17
|
-
}
|
|
11
|
+
inline void setUpdate(std::shared_ptr<const ShadowNodeFamily> family, folly::dynamic props) {
|
|
12
|
+
// call it only within withLock!
|
|
13
|
+
auto key = family.get();
|
|
18
14
|
|
|
19
|
-
|
|
20
|
-
this->_canCommit = true;
|
|
15
|
+
_unistylesUpdates.insert_or_assign(key, PinnedShadowLeafUpdate{std::move(family), std::move(props)});
|
|
21
16
|
}
|
|
22
17
|
|
|
23
|
-
inline
|
|
18
|
+
inline PinnedShadowLeafUpdates takeUpdates() {
|
|
24
19
|
// call it only within withLock!
|
|
25
|
-
return _unistylesUpdates;
|
|
20
|
+
return std::exchange(_unistylesUpdates, {});
|
|
26
21
|
}
|
|
27
22
|
|
|
28
|
-
inline
|
|
23
|
+
inline std::shared_ptr<const ShadowNodeFamily> removeShadowNode(const ShadowNodeFamily* shadowNodeFamily) {
|
|
29
24
|
// call it only within withLock!
|
|
30
|
-
|
|
25
|
+
// returns the pin, so the caller can release it after unlocking
|
|
26
|
+
auto it = _unistylesUpdates.find(shadowNodeFamily);
|
|
31
27
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if (targetUpdates.contains(pair.first)) {
|
|
36
|
-
targetUpdates[pair.first] = std::move(pair.second);
|
|
28
|
+
if (it == _unistylesUpdates.end()) {
|
|
29
|
+
return nullptr;
|
|
30
|
+
}
|
|
37
31
|
|
|
38
|
-
|
|
39
|
-
}
|
|
32
|
+
auto family = std::move(it->second.family);
|
|
40
33
|
|
|
41
|
-
|
|
42
|
-
});
|
|
43
|
-
}
|
|
34
|
+
_unistylesUpdates.erase(it);
|
|
44
35
|
|
|
45
|
-
|
|
46
|
-
// call it only within withLock!
|
|
47
|
-
if (_unistylesUpdates.contains(shadowNodeFamily)) {
|
|
48
|
-
_unistylesUpdates.erase(shadowNodeFamily);
|
|
49
|
-
}
|
|
36
|
+
return family;
|
|
50
37
|
}
|
|
51
38
|
|
|
52
|
-
inline
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
_unistylesUpdates = {};
|
|
56
|
-
_canCommit = false;
|
|
39
|
+
inline size_t getUpdatesCount() const {
|
|
40
|
+
return _unistylesUpdates.size();
|
|
57
41
|
}
|
|
58
42
|
|
|
59
43
|
template <typename F>
|
|
@@ -64,8 +48,7 @@ struct ShadowTrafficController {
|
|
|
64
48
|
}
|
|
65
49
|
|
|
66
50
|
private:
|
|
67
|
-
|
|
68
|
-
shadow::ShadowLeafUpdates _unistylesUpdates{};
|
|
51
|
+
PinnedShadowLeafUpdates _unistylesUpdates{};
|
|
69
52
|
|
|
70
53
|
// this struct should be accessed in thread-safe manner. Otherwise shadow tree updates
|
|
71
54
|
// from different threads will break it
|