react-native-unistyles 3.6.0 → 3.7.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 +4 -9
- package/android/build.gradle +42 -0
- package/android/src/legacy/java/com/unistyles/NativePlatform+extraWindows.kt +16 -0
- package/android/src/main/cxx/NativeUnistylesModule.cpp +5 -11
- package/android/src/main/cxx/NativeUnistylesModule.h +0 -4
- package/android/src/main/java/com/unistyles/NativePlatform+android.kt +82 -39
- package/android/src/main/java/com/unistyles/NativePlatform+insets.kt +73 -0
- package/android/src/main/java/com/unistyles/UnistylesModule.kt +2 -13
- package/android/src/rn86/java/com/unistyles/NativePlatform+extraWindows.kt +28 -0
- package/cxx/common/PerformanceTracing.h +85 -0
- package/cxx/converters/BackgroundLayerConverter.cpp +523 -0
- package/cxx/converters/BackgroundLayerConverter.h +14 -0
- package/cxx/converters/FontVariationSettingsConverter.cpp +104 -0
- package/cxx/converters/FontVariationSettingsConverter.h +17 -0
- package/cxx/core/UnistyleWrapper.h +16 -1
- package/cxx/hybridObjects/HybridShadowRegistry.cpp +8 -0
- package/cxx/hybridObjects/HybridStyleSheet.cpp +11 -0
- package/cxx/hybridObjects/HybridStyleSheet.h +1 -0
- package/cxx/hybridObjects/HybridUnistylesRuntime.cpp +10 -30
- package/cxx/hybridObjects/HybridUnistylesRuntime.h +2 -2
- package/cxx/parser/Parser.cpp +75 -10
- package/cxx/shadowTree/ShadowTreeDiagnostics.cpp +74 -0
- package/cxx/shadowTree/ShadowTreeManager.cpp +3 -0
- package/lib/commonjs/components/NamedTheme.js +4 -4
- package/lib/commonjs/components/NamedTheme.js.map +1 -1
- package/lib/commonjs/components/ScopedThemeContext.js +3 -1
- package/lib/commonjs/components/ScopedThemeContext.js.map +1 -1
- package/lib/commonjs/core/createUnistylesImageBackground.js +6 -2
- package/lib/commonjs/core/createUnistylesImageBackground.js.map +1 -1
- package/lib/commonjs/core/withUnistyles/withUnistyles.js +10 -7
- package/lib/commonjs/core/withUnistyles/withUnistyles.js.map +1 -1
- package/lib/commonjs/core/withUnistyles/withUnistyles.native.js +22 -3
- package/lib/commonjs/core/withUnistyles/withUnistyles.native.js.map +1 -1
- package/lib/commonjs/mocks.js +27 -3
- package/lib/commonjs/mocks.js.map +1 -1
- package/lib/commonjs/specs/ShadowRegistry/index.js +13 -3
- package/lib/commonjs/specs/ShadowRegistry/index.js.map +1 -1
- package/lib/commonjs/specs/ShadowRegistry/tracing.js +26 -0
- package/lib/commonjs/specs/ShadowRegistry/tracing.js.map +1 -0
- package/lib/commonjs/utils.js +52 -1
- package/lib/commonjs/utils.js.map +1 -1
- package/lib/commonjs/web/convert/index.js +19 -1
- package/lib/commonjs/web/convert/index.js.map +1 -1
- package/lib/commonjs/web/convert/module.d.ts +3 -0
- package/lib/commonjs/web/convert/object/backgroundLayers.js +30 -0
- package/lib/commonjs/web/convert/object/backgroundLayers.js.map +1 -0
- package/lib/commonjs/web/convert/object/fontVariationSettings.js +12 -0
- package/lib/commonjs/web/convert/object/fontVariationSettings.js.map +1 -0
- package/lib/commonjs/web/convert/object/index.js +22 -0
- package/lib/commonjs/web/convert/object/index.js.map +1 -1
- package/lib/commonjs/web/convert/utils.js +7 -1
- package/lib/commonjs/web/convert/utils.js.map +1 -1
- package/lib/commonjs/web/registry.js +6 -4
- package/lib/commonjs/web/registry.js.map +1 -1
- package/lib/commonjs/web/runtime.js +9 -6
- package/lib/commonjs/web/runtime.js.map +1 -1
- package/lib/commonjs/web/utils/unistyle.js +1 -3
- package/lib/commonjs/web/utils/unistyle.js.map +1 -1
- package/lib/module/components/NamedTheme.js +4 -4
- package/lib/module/components/NamedTheme.js.map +1 -1
- package/lib/module/components/ScopedThemeContext.js +3 -1
- package/lib/module/components/ScopedThemeContext.js.map +1 -1
- package/lib/module/core/createUnistylesImageBackground.js +6 -2
- package/lib/module/core/createUnistylesImageBackground.js.map +1 -1
- package/lib/module/core/withUnistyles/withUnistyles.js +9 -6
- package/lib/module/core/withUnistyles/withUnistyles.js.map +1 -1
- package/lib/module/core/withUnistyles/withUnistyles.native.js +24 -5
- package/lib/module/core/withUnistyles/withUnistyles.native.js.map +1 -1
- package/lib/module/mocks.js +27 -3
- package/lib/module/mocks.js.map +1 -1
- package/lib/module/specs/ShadowRegistry/index.js +13 -3
- package/lib/module/specs/ShadowRegistry/index.js.map +1 -1
- package/lib/module/specs/ShadowRegistry/tracing.js +21 -0
- package/lib/module/specs/ShadowRegistry/tracing.js.map +1 -0
- package/lib/module/utils.js +50 -0
- package/lib/module/utils.js.map +1 -1
- package/lib/module/web/convert/index.js +22 -3
- package/lib/module/web/convert/index.js.map +1 -1
- package/lib/module/web/convert/module.d.ts +3 -0
- package/lib/module/web/convert/object/backgroundLayers.js +25 -0
- package/lib/module/web/convert/object/backgroundLayers.js.map +1 -0
- package/lib/module/web/convert/object/fontVariationSettings.js +7 -0
- package/lib/module/web/convert/object/fontVariationSettings.js.map +1 -0
- package/lib/module/web/convert/object/index.js +2 -0
- package/lib/module/web/convert/object/index.js.map +1 -1
- package/lib/module/web/convert/utils.js +4 -0
- package/lib/module/web/convert/utils.js.map +1 -1
- package/lib/module/web/registry.js +6 -4
- package/lib/module/web/registry.js.map +1 -1
- package/lib/module/web/runtime.js +9 -6
- package/lib/module/web/runtime.js.map +1 -1
- package/lib/module/web/utils/unistyle.js +2 -4
- package/lib/module/web/utils/unistyle.js.map +1 -1
- package/lib/typescript/src/components/ScopedThemeContext.d.ts +2 -1
- package/lib/typescript/src/components/ScopedThemeContext.d.ts.map +1 -1
- package/lib/typescript/src/core/createUnistylesImageBackground.d.ts.map +1 -1
- package/lib/typescript/src/core/withUnistyles/withUnistyles.d.ts +6 -3
- package/lib/typescript/src/core/withUnistyles/withUnistyles.d.ts.map +1 -1
- package/lib/typescript/src/core/withUnistyles/withUnistyles.native.d.ts +7 -4
- package/lib/typescript/src/core/withUnistyles/withUnistyles.native.d.ts.map +1 -1
- package/lib/typescript/src/specs/ShadowRegistry/index.d.ts.map +1 -1
- package/lib/typescript/src/specs/ShadowRegistry/tracing.d.ts +2 -0
- package/lib/typescript/src/specs/ShadowRegistry/tracing.d.ts.map +1 -0
- package/lib/typescript/src/utils.d.ts +1 -0
- package/lib/typescript/src/utils.d.ts.map +1 -1
- package/lib/typescript/src/web/convert/index.d.ts.map +1 -1
- package/lib/typescript/src/web/convert/object/backgroundLayers.d.ts +4 -0
- package/lib/typescript/src/web/convert/object/backgroundLayers.d.ts.map +1 -0
- package/lib/typescript/src/web/convert/object/fontVariationSettings.d.ts +4 -0
- package/lib/typescript/src/web/convert/object/fontVariationSettings.d.ts.map +1 -0
- package/lib/typescript/src/web/convert/object/index.d.ts +2 -0
- package/lib/typescript/src/web/convert/object/index.d.ts.map +1 -1
- package/lib/typescript/src/web/convert/utils.d.ts +2 -0
- package/lib/typescript/src/web/convert/utils.d.ts.map +1 -1
- package/lib/typescript/src/web/registry.d.ts.map +1 -1
- package/lib/typescript/src/web/runtime.d.ts +1 -0
- package/lib/typescript/src/web/runtime.d.ts.map +1 -1
- package/lib/typescript/src/web/utils/unistyle.d.ts.map +1 -1
- package/metro/babel-transformer.js +79 -17
- package/package.json +26 -26
- package/plugin/index.js +79 -17
- package/src/components/NamedTheme.tsx +5 -5
- package/src/components/ScopedThemeContext.ts +6 -2
- package/src/core/createUnistylesImageBackground.tsx +6 -2
- package/src/core/withUnistyles/withUnistyles.native.tsx +28 -6
- package/src/core/withUnistyles/withUnistyles.tsx +6 -6
- package/src/mocks.ts +14 -5
- package/src/specs/ShadowRegistry/index.ts +14 -3
- package/src/specs/ShadowRegistry/tracing.ts +23 -0
- package/src/utils.ts +51 -0
- package/src/web/convert/index.ts +39 -3
- package/src/web/convert/object/backgroundLayers.ts +33 -0
- package/src/web/convert/object/fontVariationSettings.ts +7 -0
- package/src/web/convert/object/index.ts +2 -0
- package/src/web/convert/utils.ts +11 -0
- package/src/web/registry.ts +7 -8
- package/src/web/runtime.ts +7 -7
- package/src/web/utils/unistyle.ts +2 -4
- package/lib/commonjs/web/convert/module.d.js +0 -2
- package/lib/commonjs/web/convert/module.d.js.map +0 -1
- package/lib/module/web/convert/module.d.js +0 -2
- package/lib/module/web/convert/module.d.js.map +0 -1
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
#include "BackgroundLayerConverter.h"
|
|
2
|
+
|
|
3
|
+
#include <algorithm>
|
|
4
|
+
#include <cctype>
|
|
5
|
+
#include <cmath>
|
|
6
|
+
#include <cstdlib>
|
|
7
|
+
#include <limits>
|
|
8
|
+
#include <optional>
|
|
9
|
+
#include <vector>
|
|
10
|
+
|
|
11
|
+
// React Native processes background size, position and repeat strings in JS
|
|
12
|
+
// (processBackgroundSize.js, processBackgroundPosition.js and
|
|
13
|
+
// processBackgroundRepeat.js). Its native props parser only reads the processed
|
|
14
|
+
// arrays, even with enableNativeCSSParsing, so shadow tree updates convert the
|
|
15
|
+
// strings here with the same output.
|
|
16
|
+
namespace margelo::nitro::unistyles::converters {
|
|
17
|
+
|
|
18
|
+
namespace {
|
|
19
|
+
|
|
20
|
+
bool isWhitespace(char character) {
|
|
21
|
+
return std::isspace(static_cast<unsigned char>(character)) != 0;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
bool isDigit(const std::string &value, size_t index) {
|
|
25
|
+
return index < value.size() &&
|
|
26
|
+
std::isdigit(static_cast<unsigned char>(value[index])) != 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
std::string toLower(std::string value) {
|
|
30
|
+
std::transform(value.begin(), value.end(), value.begin(),
|
|
31
|
+
[](unsigned char c) { return std::tolower(c); });
|
|
32
|
+
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
bool endsWith(const std::string &value, const std::string &suffix) {
|
|
37
|
+
return value.size() >= suffix.size() &&
|
|
38
|
+
value.compare(value.size() - suffix.size(), suffix.size(), suffix) ==
|
|
39
|
+
0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
std::string trim(const std::string &value) {
|
|
43
|
+
auto start = std::find_if_not(value.begin(), value.end(), isWhitespace);
|
|
44
|
+
auto end = std::find_if_not(value.rbegin(), value.rend(), isWhitespace).base();
|
|
45
|
+
|
|
46
|
+
return start < end ? std::string(start, end) : std::string();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// value.split(',').map(s => s.trim())
|
|
50
|
+
std::vector<std::string> splitLayers(const std::string &value) {
|
|
51
|
+
std::vector<std::string> layers;
|
|
52
|
+
size_t start = 0;
|
|
53
|
+
|
|
54
|
+
while (true) {
|
|
55
|
+
auto end = value.find(',', start);
|
|
56
|
+
|
|
57
|
+
layers.push_back(trim(value.substr(start, end - start)));
|
|
58
|
+
|
|
59
|
+
if (end == std::string::npos) {
|
|
60
|
+
return layers;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
start = end + 1;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// value.split(/\s+/).filter(p => p.length > 0)
|
|
68
|
+
std::vector<std::string> splitParts(const std::string &value) {
|
|
69
|
+
std::vector<std::string> parts;
|
|
70
|
+
std::string part;
|
|
71
|
+
|
|
72
|
+
for (auto character : value) {
|
|
73
|
+
if (!isWhitespace(character)) {
|
|
74
|
+
part.push_back(character);
|
|
75
|
+
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!part.empty()) {
|
|
80
|
+
parts.push_back(part);
|
|
81
|
+
part.clear();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (!part.empty()) {
|
|
86
|
+
parts.push_back(part);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return parts;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// JS parseFloat: the longest decimal prefix after leading whitespace, NaN
|
|
93
|
+
// without one
|
|
94
|
+
double parseFloat(const std::string &value) {
|
|
95
|
+
size_t index = 0;
|
|
96
|
+
|
|
97
|
+
while (index < value.size() && isWhitespace(value[index])) {
|
|
98
|
+
index++;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
auto start = index;
|
|
102
|
+
|
|
103
|
+
if (index < value.size() && (value[index] == '+' || value[index] == '-')) {
|
|
104
|
+
index++;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (value.compare(index, 8, "Infinity") == 0) {
|
|
108
|
+
return value[start] == '-' ? -std::numeric_limits<double>::infinity()
|
|
109
|
+
: std::numeric_limits<double>::infinity();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
size_t digits = 0;
|
|
113
|
+
|
|
114
|
+
while (isDigit(value, index)) {
|
|
115
|
+
index++;
|
|
116
|
+
digits++;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (index < value.size() && value[index] == '.') {
|
|
120
|
+
index++;
|
|
121
|
+
|
|
122
|
+
while (isDigit(value, index)) {
|
|
123
|
+
index++;
|
|
124
|
+
digits++;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (digits == 0) {
|
|
129
|
+
return std::numeric_limits<double>::quiet_NaN();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (index < value.size() && (value[index] == 'e' || value[index] == 'E')) {
|
|
133
|
+
auto exponentIndex = index + 1;
|
|
134
|
+
|
|
135
|
+
if (exponentIndex < value.size() &&
|
|
136
|
+
(value[exponentIndex] == '+' || value[exponentIndex] == '-')) {
|
|
137
|
+
exponentIndex++;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
auto exponentStart = exponentIndex;
|
|
141
|
+
|
|
142
|
+
while (isDigit(value, exponentIndex)) {
|
|
143
|
+
exponentIndex++;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (exponentIndex > exponentStart) {
|
|
147
|
+
index = exponentIndex;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return std::strtod(value.substr(start, index - start).c_str(), nullptr);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// [ <length-percentage [0,∞]> | auto ]
|
|
155
|
+
std::optional<folly::dynamic> toBackgroundSizeValue(const std::string &size) {
|
|
156
|
+
if (endsWith(size, "px")) {
|
|
157
|
+
auto number = parseFloat(size);
|
|
158
|
+
|
|
159
|
+
if (!std::isnan(number) && number >= 0) {
|
|
160
|
+
return folly::dynamic(number);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (endsWith(size, "%") && parseFloat(size) >= 0) {
|
|
165
|
+
return folly::dynamic(size);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (size == "auto") {
|
|
169
|
+
return folly::dynamic(size);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return std::nullopt;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// https://www.w3.org/TR/css-backgrounds-3/#typedef-bg-size
|
|
176
|
+
folly::dynamic parseBackgroundSize(const std::string &value) {
|
|
177
|
+
folly::dynamic result = folly::dynamic::array();
|
|
178
|
+
|
|
179
|
+
for (const auto &size : splitLayers(value)) {
|
|
180
|
+
if (size.empty()) {
|
|
181
|
+
return folly::dynamic::array();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
auto parts = splitParts(size);
|
|
185
|
+
|
|
186
|
+
if (parts.size() == 2) {
|
|
187
|
+
auto x = toBackgroundSizeValue(toLower(parts[0]));
|
|
188
|
+
auto y = toBackgroundSizeValue(toLower(parts[1]));
|
|
189
|
+
|
|
190
|
+
if (!x.has_value() || !y.has_value()) {
|
|
191
|
+
return folly::dynamic::array();
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
result.push_back(folly::dynamic::object("x", x.value())("y", y.value()));
|
|
195
|
+
} else if (parts.size() == 1) {
|
|
196
|
+
auto x = toBackgroundSizeValue(toLower(parts[0]));
|
|
197
|
+
|
|
198
|
+
if (!x.has_value()) {
|
|
199
|
+
return folly::dynamic::array();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
result.push_back(folly::dynamic::object("x", x.value())("y", "auto"));
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return result;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
bool isValidPosition(const std::string &position) {
|
|
210
|
+
return endsWith(position, "px") || endsWith(position, "%") ||
|
|
211
|
+
position == "0";
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
std::optional<folly::dynamic>
|
|
215
|
+
getPositionFromCSSValue(const std::string &position) {
|
|
216
|
+
if (endsWith(position, "px")) {
|
|
217
|
+
return folly::dynamic(parseFloat(position));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (endsWith(position, "%")) {
|
|
221
|
+
return folly::dynamic(position);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// CSS length allows 0 as a valid value
|
|
225
|
+
if (position == "0") {
|
|
226
|
+
return folly::dynamic(0);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return std::nullopt;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// https://www.w3.org/TR/css-backgrounds-3/#typedef-bg-position
|
|
233
|
+
folly::dynamic parseBackgroundPosition(const std::string &value) {
|
|
234
|
+
folly::dynamic result = folly::dynamic::array();
|
|
235
|
+
|
|
236
|
+
for (const auto &position : splitLayers(value)) {
|
|
237
|
+
std::optional<folly::dynamic> top;
|
|
238
|
+
std::optional<folly::dynamic> left;
|
|
239
|
+
std::optional<folly::dynamic> right;
|
|
240
|
+
std::optional<folly::dynamic> bottom;
|
|
241
|
+
auto parts = splitParts(position);
|
|
242
|
+
|
|
243
|
+
// 1. Single value syntax [ left | center | right | top | bottom |
|
|
244
|
+
// <length-percentage> ]
|
|
245
|
+
if (parts.size() == 1) {
|
|
246
|
+
auto token1 = toLower(parts[0]);
|
|
247
|
+
|
|
248
|
+
if (token1 == "left") {
|
|
249
|
+
left = "0%";
|
|
250
|
+
top = "50%";
|
|
251
|
+
} else if (token1 == "center") {
|
|
252
|
+
left = "50%";
|
|
253
|
+
top = "50%";
|
|
254
|
+
} else if (token1 == "right") {
|
|
255
|
+
left = "100%";
|
|
256
|
+
top = "50%";
|
|
257
|
+
} else if (token1 == "top") {
|
|
258
|
+
left = "50%";
|
|
259
|
+
top = "0%";
|
|
260
|
+
} else if (token1 == "bottom") {
|
|
261
|
+
left = "50%";
|
|
262
|
+
top = "100%";
|
|
263
|
+
} else if (isValidPosition(token1)) {
|
|
264
|
+
auto positionValue = getPositionFromCSSValue(token1);
|
|
265
|
+
|
|
266
|
+
if (!positionValue.has_value()) {
|
|
267
|
+
return folly::dynamic::array();
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
left = positionValue;
|
|
271
|
+
top = "50%";
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// 2. Two value syntax [ left | center | right | <length-percentage> ] [
|
|
276
|
+
// top | center | bottom | <length-percentage> ]
|
|
277
|
+
if (parts.size() == 2) {
|
|
278
|
+
auto token1 = toLower(parts[0]);
|
|
279
|
+
|
|
280
|
+
if (token1 == "left") {
|
|
281
|
+
left = "0%";
|
|
282
|
+
} else if (token1 == "center") {
|
|
283
|
+
left = "50%";
|
|
284
|
+
} else if (token1 == "right") {
|
|
285
|
+
left = "100%";
|
|
286
|
+
} else if (token1 == "top") {
|
|
287
|
+
top = "0%";
|
|
288
|
+
} else if (token1 == "bottom") {
|
|
289
|
+
top = "100%";
|
|
290
|
+
} else if (isValidPosition(token1)) {
|
|
291
|
+
auto positionValue = getPositionFromCSSValue(token1);
|
|
292
|
+
|
|
293
|
+
if (!positionValue.has_value()) {
|
|
294
|
+
return folly::dynamic::array();
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
left = positionValue;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
auto token2 = toLower(parts[1]);
|
|
301
|
+
|
|
302
|
+
if (token2 == "top") {
|
|
303
|
+
top = "0%";
|
|
304
|
+
} else if (token2 == "center") {
|
|
305
|
+
top = "50%";
|
|
306
|
+
} else if (token2 == "bottom") {
|
|
307
|
+
top = "100%";
|
|
308
|
+
} else if (token2 == "left") {
|
|
309
|
+
left = "0%";
|
|
310
|
+
} else if (token2 == "right") {
|
|
311
|
+
left = "100%";
|
|
312
|
+
} else if (isValidPosition(token2)) {
|
|
313
|
+
auto positionValue = getPositionFromCSSValue(token2);
|
|
314
|
+
|
|
315
|
+
if (!positionValue.has_value()) {
|
|
316
|
+
return folly::dynamic::array();
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
top = positionValue;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// 3. Three value syntax [ center | [ left | right ] <length-percentage>? ]
|
|
324
|
+
// && [ center | [ top | bottom ] <length-percentage>? ]
|
|
325
|
+
if (parts.size() == 3) {
|
|
326
|
+
auto token1 = toLower(parts[0]);
|
|
327
|
+
auto token2 = toLower(parts[1]);
|
|
328
|
+
auto token3 = toLower(parts[2]);
|
|
329
|
+
|
|
330
|
+
if (token1 == "center") {
|
|
331
|
+
// e.g. center top 40%
|
|
332
|
+
left = "50%";
|
|
333
|
+
auto positionValue = getPositionFromCSSValue(token3);
|
|
334
|
+
|
|
335
|
+
if (!positionValue.has_value()) {
|
|
336
|
+
return folly::dynamic::array();
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (token2 == "top") {
|
|
340
|
+
top = positionValue;
|
|
341
|
+
} else if (token2 == "bottom") {
|
|
342
|
+
bottom = positionValue;
|
|
343
|
+
} else {
|
|
344
|
+
return folly::dynamic::array();
|
|
345
|
+
}
|
|
346
|
+
} else if (token3 == "center") {
|
|
347
|
+
// e.g. left 40% center
|
|
348
|
+
top = "50%";
|
|
349
|
+
auto positionValue = getPositionFromCSSValue(token2);
|
|
350
|
+
|
|
351
|
+
if (!positionValue.has_value()) {
|
|
352
|
+
return folly::dynamic::array();
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
if (token1 == "left") {
|
|
356
|
+
left = positionValue;
|
|
357
|
+
} else if (token1 == "right") {
|
|
358
|
+
right = positionValue;
|
|
359
|
+
} else {
|
|
360
|
+
return folly::dynamic::array();
|
|
361
|
+
}
|
|
362
|
+
} else {
|
|
363
|
+
// e.g. left 40% top, left top 10%
|
|
364
|
+
std::vector<std::string> tokens = {token1, token2, token3};
|
|
365
|
+
|
|
366
|
+
for (size_t i = 0; i < tokens.size(); i++) {
|
|
367
|
+
const auto &token = tokens[i];
|
|
368
|
+
|
|
369
|
+
if (isValidPosition(token)) {
|
|
370
|
+
auto positionValue = getPositionFromCSSValue(token);
|
|
371
|
+
|
|
372
|
+
if (!positionValue.has_value()) {
|
|
373
|
+
return folly::dynamic::array();
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (i == 0) {
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
const auto &previousToken = tokens[i - 1];
|
|
381
|
+
|
|
382
|
+
if (previousToken == "left") {
|
|
383
|
+
left = positionValue;
|
|
384
|
+
} else if (previousToken == "right") {
|
|
385
|
+
right = positionValue;
|
|
386
|
+
} else if (previousToken == "top") {
|
|
387
|
+
top = positionValue;
|
|
388
|
+
} else if (previousToken == "bottom") {
|
|
389
|
+
bottom = positionValue;
|
|
390
|
+
}
|
|
391
|
+
} else if (token == "left") {
|
|
392
|
+
left = "0%";
|
|
393
|
+
} else if (token == "right") {
|
|
394
|
+
right = "0%";
|
|
395
|
+
} else if (token == "top") {
|
|
396
|
+
top = "0%";
|
|
397
|
+
} else if (token == "bottom") {
|
|
398
|
+
bottom = "0%";
|
|
399
|
+
} else {
|
|
400
|
+
return folly::dynamic::array();
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// 4. Four value syntax [ center | [ left | right ] <length-percentage>? ]
|
|
407
|
+
// && [ center | [ top | bottom ] <length-percentage>? ]
|
|
408
|
+
if (parts.size() == 4) {
|
|
409
|
+
auto keyword1 = toLower(parts[0]);
|
|
410
|
+
auto value1 = getPositionFromCSSValue(toLower(parts[1]));
|
|
411
|
+
auto keyword2 = toLower(parts[2]);
|
|
412
|
+
auto value2 = getPositionFromCSSValue(toLower(parts[3]));
|
|
413
|
+
|
|
414
|
+
if (!value1.has_value() || !value2.has_value()) {
|
|
415
|
+
return folly::dynamic::array();
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
if (keyword1 == "left") {
|
|
419
|
+
left = value1;
|
|
420
|
+
} else if (keyword1 == "right") {
|
|
421
|
+
right = value1;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
if (keyword2 == "top") {
|
|
425
|
+
top = value2;
|
|
426
|
+
} else if (keyword2 == "bottom") {
|
|
427
|
+
bottom = value2;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (top.has_value() && left.has_value()) {
|
|
432
|
+
result.push_back(
|
|
433
|
+
folly::dynamic::object("top", top.value())("left", left.value()));
|
|
434
|
+
} else if (bottom.has_value() && right.has_value()) {
|
|
435
|
+
result.push_back(folly::dynamic::object("bottom", bottom.value())(
|
|
436
|
+
"right", right.value()));
|
|
437
|
+
} else if (top.has_value() && right.has_value()) {
|
|
438
|
+
result.push_back(
|
|
439
|
+
folly::dynamic::object("top", top.value())("right", right.value()));
|
|
440
|
+
} else if (bottom.has_value() && left.has_value()) {
|
|
441
|
+
result.push_back(folly::dynamic::object("bottom", bottom.value())(
|
|
442
|
+
"left", left.value()));
|
|
443
|
+
} else {
|
|
444
|
+
return folly::dynamic::array();
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
return result;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
bool isBackgroundRepeatKeyword(const std::string &value) {
|
|
452
|
+
return value == "repeat" || value == "space" || value == "round" ||
|
|
453
|
+
value == "no-repeat";
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// https://www.w3.org/TR/css-backgrounds-3/#typedef-repeat-style
|
|
457
|
+
folly::dynamic parseBackgroundRepeat(const std::string &value) {
|
|
458
|
+
folly::dynamic result = folly::dynamic::array();
|
|
459
|
+
|
|
460
|
+
for (const auto &repeat : splitLayers(value)) {
|
|
461
|
+
if (repeat.empty()) {
|
|
462
|
+
return folly::dynamic::array();
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
auto parts = splitParts(repeat);
|
|
466
|
+
|
|
467
|
+
if (parts.size() == 1) {
|
|
468
|
+
auto token1 = toLower(parts[0]);
|
|
469
|
+
|
|
470
|
+
if (token1 == "repeat-x") {
|
|
471
|
+
result.push_back(folly::dynamic::object("x", "repeat")("y", "no-repeat"));
|
|
472
|
+
} else if (token1 == "repeat-y") {
|
|
473
|
+
result.push_back(folly::dynamic::object("x", "no-repeat")("y", "repeat"));
|
|
474
|
+
} else if (isBackgroundRepeatKeyword(token1)) {
|
|
475
|
+
result.push_back(folly::dynamic::object("x", token1)("y", token1));
|
|
476
|
+
} else {
|
|
477
|
+
return folly::dynamic::array();
|
|
478
|
+
}
|
|
479
|
+
} else if (parts.size() == 2) {
|
|
480
|
+
auto token1 = toLower(parts[0]);
|
|
481
|
+
auto token2 = toLower(parts[1]);
|
|
482
|
+
|
|
483
|
+
if (!isBackgroundRepeatKeyword(token1) ||
|
|
484
|
+
!isBackgroundRepeatKeyword(token2)) {
|
|
485
|
+
return folly::dynamic::array();
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
result.push_back(folly::dynamic::object("x", token1)("y", token2));
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
return result;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
} // namespace
|
|
496
|
+
|
|
497
|
+
bool isBackgroundLayerPropName(const std::string &propertyName) {
|
|
498
|
+
return propertyName == "backgroundSize" ||
|
|
499
|
+
propertyName == "experimental_backgroundSize" ||
|
|
500
|
+
propertyName == "backgroundPosition" ||
|
|
501
|
+
propertyName == "experimental_backgroundPosition" ||
|
|
502
|
+
propertyName == "backgroundRepeat" ||
|
|
503
|
+
propertyName == "experimental_backgroundRepeat";
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
folly::dynamic parseBackgroundLayerString(const std::string &propertyName,
|
|
507
|
+
const std::string &value) {
|
|
508
|
+
std::string singleLineValue = value;
|
|
509
|
+
|
|
510
|
+
std::replace(singleLineValue.begin(), singleLineValue.end(), '\n', ' ');
|
|
511
|
+
|
|
512
|
+
if (endsWith(propertyName, "ackgroundSize")) {
|
|
513
|
+
return parseBackgroundSize(singleLineValue);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
if (endsWith(propertyName, "ackgroundPosition")) {
|
|
517
|
+
return parseBackgroundPosition(singleLineValue);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
return parseBackgroundRepeat(singleLineValue);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
} // namespace margelo::nitro::unistyles::converters
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <folly/dynamic.h>
|
|
4
|
+
#include <string>
|
|
5
|
+
|
|
6
|
+
namespace margelo::nitro::unistyles::converters {
|
|
7
|
+
|
|
8
|
+
// backgroundSize, backgroundPosition and backgroundRepeat (and their
|
|
9
|
+
// experimental_ aliases)
|
|
10
|
+
bool isBackgroundLayerPropName(const std::string &propertyName);
|
|
11
|
+
folly::dynamic parseBackgroundLayerString(const std::string &propertyName,
|
|
12
|
+
const std::string &value);
|
|
13
|
+
|
|
14
|
+
} // namespace margelo::nitro::unistyles::converters
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
#include "FontVariationSettingsConverter.h"
|
|
2
|
+
|
|
3
|
+
#include <algorithm>
|
|
4
|
+
#include <cmath>
|
|
5
|
+
#include <utility>
|
|
6
|
+
#include <vector>
|
|
7
|
+
|
|
8
|
+
// React Native converts the object form to a string in JS
|
|
9
|
+
// (processFontVariationSettings.js), and its native props only read strings,
|
|
10
|
+
// so shadow tree updates convert it here with the same output.
|
|
11
|
+
namespace margelo::nitro::unistyles::converters {
|
|
12
|
+
|
|
13
|
+
using namespace facebook;
|
|
14
|
+
|
|
15
|
+
namespace {
|
|
16
|
+
|
|
17
|
+
std::optional<std::string> quoteAxis(const std::string &axis) {
|
|
18
|
+
auto isPrintable = [](unsigned char character) {
|
|
19
|
+
return character >= 0x20 && character <= 0x7e;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
if (axis.size() != 4 || !std::all_of(axis.begin(), axis.end(), isPrintable)) {
|
|
23
|
+
return std::nullopt;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (axis.find('\'') == std::string::npos) {
|
|
27
|
+
return "'" + axis + "'";
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (axis.find('"') == std::string::npos) {
|
|
31
|
+
return "\"" + axis + "\"";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return std::nullopt;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
} // namespace
|
|
38
|
+
|
|
39
|
+
bool isFontVariationSettingsPropName(const std::string &propertyName) {
|
|
40
|
+
return propertyName == "fontVariationSettings";
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
bool isFontVariationSettingsObject(jsi::Runtime &rt, jsi::Object &value) {
|
|
44
|
+
if (value.isArray(rt) || value.isFunction(rt)) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
auto propertyNames = value.getPropertyNames(rt);
|
|
49
|
+
auto length = propertyNames.size(rt);
|
|
50
|
+
|
|
51
|
+
for (size_t i = 0; i < length; i++) {
|
|
52
|
+
auto propertyName = propertyNames.getValueAtIndex(rt, i).asString(rt);
|
|
53
|
+
|
|
54
|
+
if (!value.getProperty(rt, jsi::PropNameID::forString(rt, propertyName))
|
|
55
|
+
.isNumber()) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
std::optional<std::string> fontVariationSettingsToString(jsi::Runtime &rt,
|
|
64
|
+
jsi::Object &value) {
|
|
65
|
+
std::vector<std::pair<std::string, double>> axes;
|
|
66
|
+
auto propertyNames = value.getPropertyNames(rt);
|
|
67
|
+
auto length = propertyNames.size(rt);
|
|
68
|
+
|
|
69
|
+
for (size_t i = 0; i < length; i++) {
|
|
70
|
+
auto propertyName = propertyNames.getValueAtIndex(rt, i).asString(rt);
|
|
71
|
+
auto axisValue =
|
|
72
|
+
value.getProperty(rt, jsi::PropNameID::forString(rt, propertyName));
|
|
73
|
+
|
|
74
|
+
if (!axisValue.isNumber() || !std::isfinite(axisValue.asNumber())) {
|
|
75
|
+
return std::nullopt;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
axes.emplace_back(propertyName.utf8(rt), axisValue.asNumber());
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
std::sort(axes.begin(), axes.end());
|
|
82
|
+
|
|
83
|
+
std::string result;
|
|
84
|
+
|
|
85
|
+
for (const auto &[axis, axisValue] : axes) {
|
|
86
|
+
auto quotedAxis = quoteAxis(axis);
|
|
87
|
+
|
|
88
|
+
if (!quotedAxis.has_value()) {
|
|
89
|
+
return std::nullopt;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (!result.empty()) {
|
|
93
|
+
result += ", ";
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// String(value), so numbers are formatted like in JS
|
|
97
|
+
result += quotedAxis.value() + " " +
|
|
98
|
+
jsi::Value(axisValue).toString(rt).utf8(rt);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return result;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
} // namespace margelo::nitro::unistyles::converters
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <jsi/jsi.h>
|
|
4
|
+
#include <optional>
|
|
5
|
+
#include <string>
|
|
6
|
+
|
|
7
|
+
namespace margelo::nitro::unistyles::converters {
|
|
8
|
+
|
|
9
|
+
bool isFontVariationSettingsPropName(const std::string &propertyName);
|
|
10
|
+
// { wght: 700, slnt: -10 }, as opposed to a breakpoints object
|
|
11
|
+
bool isFontVariationSettingsObject(facebook::jsi::Runtime &rt,
|
|
12
|
+
facebook::jsi::Object &value);
|
|
13
|
+
std::optional<std::string>
|
|
14
|
+
fontVariationSettingsToString(facebook::jsi::Runtime &rt,
|
|
15
|
+
facebook::jsi::Object &value);
|
|
16
|
+
|
|
17
|
+
} // namespace margelo::nitro::unistyles::converters
|
|
@@ -44,7 +44,7 @@ inline static std::vector<std::string> getUnistylesHashKeys(jsi::Runtime& rt, js
|
|
|
44
44
|
auto propertyName = propertyNames.getValueAtIndex(rt, i).getString(rt);
|
|
45
45
|
std::string key = propertyName.utf8(rt);
|
|
46
46
|
|
|
47
|
-
if (key.compare(0, prefix.length(), prefix) == 0) {
|
|
47
|
+
if (key.compare(0, prefix.length(), prefix) == 0 && object.getProperty(rt, propertyName).isObject()) {
|
|
48
48
|
matchingKeys.push_back(key);
|
|
49
49
|
}
|
|
50
50
|
}
|
|
@@ -192,6 +192,21 @@ You likely accessed a style while the runtime was being torn down (eg. during a
|
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
+
if (unistyle->styleKey != helpers::EXOTIC_STYLE_KEY) {
|
|
196
|
+
std::vector<folly::dynamic> arguments = parsedArguments.has_value()
|
|
197
|
+
? parsedArguments.value()
|
|
198
|
+
: std::vector<folly::dynamic>{};
|
|
199
|
+
|
|
200
|
+
auto unistyleData = std::make_shared<UnistyleData>(unistyle, variants, arguments, std::nullopt);
|
|
201
|
+
|
|
202
|
+
parser.rebuildUnistyleWithVariants(rt, unistyleData);
|
|
203
|
+
|
|
204
|
+
if (unistyleData->parsedStyle.has_value()) {
|
|
205
|
+
return jsi::Value(rt, unistyleData->parsedStyle.value()).asObject(rt);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// exotic (unbound) styles have no unistyle data to rebuild into
|
|
195
210
|
parser.rebuildUnistyle(rt, unistyle, variants, parsedArguments);
|
|
196
211
|
|
|
197
212
|
return jsi::Value(rt, unistyle->parsedStyle.value()).asObject(rt);
|