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

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. package/android/CMakeLists.txt +8 -1
  2. package/android/build.gradle +4 -1
  3. package/android/src/main/cxx/cpp-adapter.cpp +10 -100
  4. package/android/src/main/cxx/helpers.h +2 -0
  5. package/android/src/main/cxx/platform.cpp +126 -0
  6. package/android/src/main/cxx/platform.h +15 -0
  7. package/android/src/main/java/com/unistyles/Models.kt +14 -35
  8. package/android/src/main/java/com/unistyles/Platform.kt +91 -10
  9. package/android/src/main/java/com/unistyles/UnistylesModule.kt +84 -139
  10. package/cxx/Macros.h +11 -0
  11. package/cxx/UnistylesImpl.cpp +241 -0
  12. package/cxx/UnistylesModel.cpp +234 -0
  13. package/cxx/UnistylesModel.h +112 -0
  14. package/cxx/UnistylesRuntime.cpp +17 -388
  15. package/cxx/UnistylesRuntime.h +56 -95
  16. package/ios/UnistylesModule.h +8 -0
  17. package/ios/UnistylesModule.mm +12 -89
  18. package/ios/platform/Platform_Shared.h +5 -0
  19. package/ios/platform/Platform_Shared.mm +69 -0
  20. package/ios/platform/Platform_iOS.h +2 -9
  21. package/ios/platform/Platform_iOS.mm +47 -94
  22. package/ios/platform/Platform_macOS.h +1 -6
  23. package/ios/platform/Platform_macOS.mm +29 -29
  24. package/ios/platform/Platform_tvOS.h +2 -9
  25. package/ios/platform/Platform_tvOS.mm +30 -92
  26. package/ios/platform/Platform_visionOS.h +2 -8
  27. package/ios/platform/Platform_visionOS.mm +28 -83
  28. package/package.json +1 -1
  29. package/react-native-unistyles.podspec +3 -0
  30. package/android/src/main/java/com/unistyles/Config.kt +0 -116
  31. package/android/src/main/java/com/unistyles/Insets.kt +0 -141
  32. package/ios/UnistylesHelpers.h +0 -3
  33. package/ios/UnistylesHelpers.mm +0 -5
@@ -0,0 +1,234 @@
1
+ #include "UnistylesModel.h"
2
+
3
+ std::string UnistylesModel::getBreakpointFromScreenWidth(int width, const std::vector<std::pair<std::string, double>>& sortedBreakpointPairs) {
4
+ for (size_t i = 0; i < sortedBreakpointPairs.size(); ++i) {
5
+ const auto& [key, value] = sortedBreakpointPairs[i];
6
+ const double maxVal = (i + 1 < sortedBreakpointPairs.size()) ? sortedBreakpointPairs[i + 1].second : std::numeric_limits<double>::infinity();
7
+
8
+ if (width >= value && width < maxVal) {
9
+ return key;
10
+ }
11
+ }
12
+
13
+ return sortedBreakpointPairs.empty() ? "" : sortedBreakpointPairs.back().first;
14
+ }
15
+
16
+ void UnistylesModel::handleScreenSizeChange(Dimensions& screen, std::optional<Insets> insets, std::optional<Dimensions> statusBar, std::optional<Dimensions> navigationBar) {
17
+ std::string breakpoint = this->getBreakpointFromScreenWidth(screen.width, this->sortedBreakpointPairs);
18
+ bool hasDifferentBreakpoint = this->breakpoint != breakpoint;
19
+ bool hasDifferentScreenDimensions = this->screen.width != screen.width || this->screen.height != screen.height;
20
+ bool hasDifferentInsets = insets.has_value()
21
+ ? this->insets.top != insets->top || this->insets.bottom != insets->bottom || this->insets.left != insets->left || this->insets.right != insets->right
22
+ : false;
23
+
24
+ // we don't need to check statusBar/navigationBar as they will only change on orientation change witch is equal to hasDifferentScreenDimensions
25
+ bool shouldNotify = hasDifferentBreakpoint || hasDifferentScreenDimensions || hasDifferentInsets;
26
+
27
+ this->breakpoint = breakpoint;
28
+ this->screen = {screen.width, screen.height};
29
+
30
+ if (insets.has_value()) {
31
+ this->insets = {insets->top, insets->bottom, insets->left, insets->right};
32
+ }
33
+
34
+ if (statusBar.has_value()) {
35
+ this->statusBar = {statusBar->width, statusBar->height};
36
+ }
37
+
38
+ if (navigationBar.has_value()) {
39
+ this->navigationBar = {navigationBar->width, navigationBar->height};
40
+ }
41
+
42
+ if (shouldNotify) {
43
+ this->onLayoutChange();
44
+ }
45
+ }
46
+
47
+ void UnistylesModel::handleAppearanceChange(std::string colorScheme) {
48
+ this->colorScheme = colorScheme;
49
+
50
+ if (!this->supportsAutomaticColorScheme || !this->hasAdaptiveThemes) {
51
+ return;
52
+ }
53
+
54
+ if (this->themeName != this->colorScheme) {
55
+ this->onThemeChange(this->colorScheme);
56
+ this->themeName = this->colorScheme;
57
+ }
58
+ }
59
+
60
+ void UnistylesModel::handleContentSizeCategoryChange(std::string contentSizeCategory) {
61
+ if (this->contentSizeCategory == contentSizeCategory) {
62
+ return;
63
+ }
64
+
65
+ this->contentSizeCategory = contentSizeCategory;
66
+ this->onContentSizeCategoryChange(contentSizeCategory);
67
+ }
68
+
69
+ jsi::Value UnistylesModel::getThemeOrFail(jsi::Runtime& runtime) {
70
+ if (this->themes.size() == 1) {
71
+ std::string themeName = this->themes.at(0);
72
+
73
+ this->themeName = themeName;
74
+
75
+ return jsi::String::createFromUtf8(runtime, themeName);
76
+ }
77
+
78
+ return jsi::Value().undefined();
79
+ }
80
+
81
+ std::vector<std::pair<std::string, double>> UnistylesModel::toSortedBreakpointPairs(jsi::Runtime& rt, jsi::Object& breakpointsObj) {
82
+ jsi::Array propertyNames = breakpointsObj.getPropertyNames(rt);
83
+ std::vector<std::pair<std::string, double>> sortedBreakpointEntriesVec;
84
+
85
+ for (size_t i = 0; i < propertyNames.size(rt); ++i) {
86
+ jsi::Value propNameValue = propertyNames.getValueAtIndex(rt, i);
87
+ std::string name = propNameValue.asString(rt).utf8(rt);
88
+ jsi::PropNameID propNameID = jsi::PropNameID::forUtf8(rt, name);
89
+ jsi::Value value = breakpointsObj.getProperty(rt, propNameID);
90
+
91
+ if (value.isNumber()) {
92
+ double breakpointValue = value.asNumber();
93
+
94
+ sortedBreakpointEntriesVec.push_back(std::make_pair(name, breakpointValue));
95
+ }
96
+ }
97
+
98
+ std::sort(sortedBreakpointEntriesVec.begin(), sortedBreakpointEntriesVec.end(), [](const std::pair<std::string, double>& a, const std::pair<std::string, double>& b) {
99
+ return a.second < b.second;
100
+ });
101
+
102
+ return sortedBreakpointEntriesVec;
103
+ }
104
+
105
+ // a little bit hacky, but works like Turbo Module emitDeviceEvent
106
+ // it will be super easy to refactor for Unistyles 3.0
107
+ // ref: https://github.com/facebook/react-native/pull/43375
108
+ // ref: https://github.com/facebook/react-native/blob/b5fd041917d197f256433a41a126f0dff767c429/packages/react-native/ReactCommon/react/nativemodule/core/ReactCommon/TurboModule.cpp#L42
109
+ void UnistylesModel::emitDeviceEvent(const std::string eventType, EventPayload payload) {
110
+ this->callInvoker->invokeAsync([eventType, payload, this](){
111
+ jsi::Value emitter = this->runtime.global().getProperty(this->runtime, "__rctDeviceEventEmitter");
112
+
113
+ if (emitter.isUndefined()) {
114
+ return;
115
+ }
116
+
117
+ jsi::Object emitterObject = emitter.asObject(runtime);
118
+ jsi::Function emitFunction = emitterObject.getPropertyAsFunction(runtime, "emit");
119
+
120
+ std::vector<jsi::Value> arguments;
121
+ jsi::Object event = jsi::Object(this->runtime);
122
+
123
+ event.setProperty(this->runtime, "type", jsi::String::createFromUtf8(this->runtime, eventType));
124
+
125
+ jsi::Object eventPayload = this->parseEventPayload(payload);
126
+
127
+ event.setProperty(this->runtime, "payload", eventPayload);
128
+
129
+ arguments.emplace_back(jsi::String::createFromAscii(runtime, "__unistylesOnChange"));
130
+ arguments.emplace_back(std::move(event));
131
+
132
+ emitFunction.callWithThis(runtime, emitterObject, (const jsi::Value*)arguments.data(), arguments.size());
133
+ });
134
+ }
135
+
136
+ void UnistylesModel::onThemeChange(std::string themeName) {
137
+ EventPayload payload;
138
+ payload["themeName"] = themeName;
139
+
140
+ this->emitDeviceEvent("theme", payload);
141
+ }
142
+
143
+ void UnistylesModel::onContentSizeCategoryChange(std::string contentSizeCategory) {
144
+ EventPayload payload;
145
+ payload["contentSizeCategory"] = contentSizeCategory;
146
+
147
+ this->emitDeviceEvent("dynamicTypeSize", payload);
148
+ }
149
+
150
+ void UnistylesModel::onPluginChange() {
151
+ this->emitDeviceEvent("plugin", {});
152
+ }
153
+
154
+ void UnistylesModel::onLayoutChange() {
155
+ EventPayload payload;
156
+ std::string orientation = screen.width > screen.height
157
+ ? UnistylesOrientationLandscape
158
+ : UnistylesOrientationPortrait;
159
+
160
+ payload["breakpoint"] = this->breakpoint;
161
+ payload["orientation"] = orientation;
162
+
163
+ EventNestedValue screenPayload;
164
+ auto screen = this->screen;
165
+
166
+ screenPayload["width"] = screen.width;
167
+ screenPayload["height"] = screen.height;
168
+
169
+ payload["screen"] = screenPayload;
170
+
171
+ EventNestedValue statusBarPayload;
172
+ auto statusBar = this->statusBar;
173
+
174
+ statusBarPayload["width"] = statusBar.width;
175
+ statusBarPayload["height"] = statusBar.height;
176
+
177
+ payload["statusBar"] = statusBarPayload;
178
+
179
+ EventNestedValue navigationBarPayload;
180
+ auto navigationBar = this->navigationBar;
181
+
182
+ navigationBarPayload["width"] = navigationBar.width;
183
+ navigationBarPayload["height"] = navigationBar.height;
184
+
185
+ payload["navigationBar"] = navigationBarPayload;
186
+
187
+ EventNestedValue insetsPayload;
188
+ auto insets = this->insets;
189
+
190
+ insetsPayload["top"] = insets.top;
191
+ insetsPayload["bottom"] = insets.bottom;
192
+ insetsPayload["left"] = insets.left;
193
+ insetsPayload["right"] = insets.right;
194
+
195
+ payload["insets"] = insetsPayload;
196
+
197
+ this->emitDeviceEvent("layout", payload);
198
+ }
199
+
200
+ jsi::Object UnistylesModel::parseEventPayload(EventPayload payload) {
201
+ jsi::Object eventPayload = jsi::Object(this->runtime);
202
+
203
+ for (const auto& [key, value] : payload) {
204
+ if (std::holds_alternative<std::string>(value)) {
205
+ eventPayload.setProperty(this->runtime, key.c_str(), jsi::String::createFromUtf8(this->runtime, std::get<std::string>(value)));
206
+ }
207
+
208
+ if (std::holds_alternative<int>(value)) {
209
+ eventPayload.setProperty(this->runtime, key.c_str(), std::get<int>(value));
210
+ }
211
+
212
+ if (std::holds_alternative<EventNestedValue>(value)) {
213
+ eventPayload.setProperty(this->runtime, key.c_str(), this->parseEventNestedPayload(std::get<EventNestedValue>(value)));
214
+ }
215
+ }
216
+
217
+ return eventPayload;
218
+ }
219
+
220
+ jsi::Object UnistylesModel::parseEventNestedPayload(EventNestedValue payload) {
221
+ jsi::Object eventPayload = jsi::Object(this->runtime);
222
+
223
+ for (const auto& [key, value] : payload) {
224
+ if (std::holds_alternative<std::string>(value)) {
225
+ eventPayload.setProperty(this->runtime, key.c_str(), jsi::String::createFromUtf8(this->runtime, std::get<std::string>(value)));
226
+ }
227
+
228
+ if (std::holds_alternative<int>(value)) {
229
+ eventPayload.setProperty(this->runtime, key.c_str(), std::get<int>(value));
230
+ }
231
+ }
232
+
233
+ return eventPayload;
234
+ }
@@ -0,0 +1,112 @@
1
+ #pragma once
2
+
3
+ #include <jsi/jsi.h>
4
+ #include <ReactCommon/CallInvoker.h>
5
+ #include <vector>
6
+ #include <map>
7
+ #include <optional>
8
+ #include <variant>
9
+
10
+ using namespace facebook;
11
+
12
+ const std::string UnistylesOrientationPortrait = "portrait";
13
+ const std::string UnistylesOrientationLandscape = "landscape";
14
+
15
+ const std::string UnistylesDarkScheme = "dark";
16
+ const std::string UnistylesLightScheme = "light";
17
+ const std::string UnistylesUnspecifiedScheme = "unspecified";
18
+
19
+ const std::string UnistylesErrorBreakpointsCannotBeEmpty = "You are trying to register empty breakpoints object";
20
+ const std::string UnistylesErrorBreakpointsMustStartFromZero = "You are trying to register breakpoints that don't start from 0";
21
+ const std::string UnistylesErrorThemesCannotBeEmpty = "You are trying to register empty themes object";
22
+ const std::string UnistylesErrorAdaptiveThemesNotSupported = "Your platform doesn't support adaptive themes";
23
+
24
+ struct Dimensions {
25
+ int width;
26
+ int height;
27
+ };
28
+
29
+ struct Insets {
30
+ int top;
31
+ int bottom;
32
+ int left;
33
+ int right;
34
+ };
35
+
36
+ using EventNestedValue = std::map<std::string, std::variant<std::string, int>>;
37
+ using EventValue = std::variant<std::string, int>;
38
+ using EventPayload = std::map<std::string, std::variant<std::string, int, EventNestedValue>>;
39
+
40
+ struct UnistylesModel {
41
+ void emitDeviceEvent(const std::string eventType, EventPayload payload);
42
+ void onThemeChange(std::string themeName);
43
+ void onPluginChange();
44
+ void onContentSizeCategoryChange(std::string contentSizeCategory);
45
+ void onLayoutChange();
46
+ jsi::Object parseEventPayload(EventPayload payload);
47
+ jsi::Object parseEventNestedPayload(EventNestedValue payload);
48
+
49
+ std::function<Dimensions()> getScreenDimensions;
50
+ std::function<std::string()> getContentSizeCategory;
51
+ std::function<std::string()> getColorScheme;
52
+ std::function<Dimensions()> getStatusBarDimensions;
53
+ std::function<Dimensions()> getNavigationBarDimensions;
54
+ std::function<Insets()> getInsets;
55
+ std::optional<std::function<void(std::string)>> setStatusBarColor;
56
+ std::optional<std::function<void(std::string)>> setNavigationBarColor;
57
+
58
+ void setScreenDimensionsCallback(std::function<Dimensions()> callback) {
59
+ this->getScreenDimensions = callback;
60
+ }
61
+ void setContentSizeCategoryCallback(std::function<std::string()> callback) {
62
+ this->getContentSizeCategory = callback;
63
+ }
64
+ void setColorSchemeCallback(std::function<std::string()> callback) {
65
+ this->getColorScheme = callback;
66
+ }
67
+ void setStatusBarDimensionsCallback(std::function<Dimensions()> callback) {
68
+ this->getStatusBarDimensions = callback;
69
+ }
70
+ void setNavigationBarDimensionsCallback(std::function<Dimensions()> callback) {
71
+ this->getNavigationBarDimensions = callback;
72
+ }
73
+ void setInsetsCallback(std::function<Insets()> callback) {
74
+ this->getInsets = callback;
75
+ }
76
+ void setStatusBarColorCallback(std::function<void(std::string color)> callback) {
77
+ this->setStatusBarColor = callback;
78
+ }
79
+ void setNavigationBarColorCallback(std::function<void(std::string color)> callback) {
80
+ this->setNavigationBarColor = callback;
81
+ }
82
+
83
+ Dimensions screen = {0, 0};
84
+ Dimensions statusBar = {0, 0};
85
+ Dimensions navigationBar = {0, 0};
86
+ Insets insets = {0, 0, 0, 0};
87
+ std::string colorScheme = UnistylesUnspecifiedScheme;
88
+ std::string contentSizeCategory = UnistylesUnspecifiedScheme;
89
+
90
+ UnistylesModel(jsi::Runtime& rt, std::shared_ptr<react::CallInvoker> callInvoker): runtime(rt), callInvoker(callInvoker) {}
91
+
92
+ bool hasAdaptiveThemes;
93
+ bool supportsAutomaticColorScheme;
94
+
95
+ std::string themeName;
96
+ std::string breakpoint;
97
+ std::vector<std::string> pluginNames;
98
+ std::vector<std::string> themes;
99
+ std::vector<std::pair<std::string, double>> sortedBreakpointPairs;
100
+
101
+ void handleScreenSizeChange(Dimensions& screen, std::optional<Insets> insets, std::optional<Dimensions> statusBar, std::optional<Dimensions> navigationBar);
102
+ void handleAppearanceChange(std::string colorScheme);
103
+ void handleContentSizeCategoryChange(std::string contentSizeCategory);
104
+
105
+ jsi::Value getThemeOrFail(jsi::Runtime&);
106
+ std::string getBreakpointFromScreenWidth(int width, const std::vector<std::pair<std::string, double>>& sortedBreakpointEntries);
107
+ std::vector<std::pair<std::string, double>> toSortedBreakpointPairs(jsi::Runtime&, jsi::Object&);
108
+
109
+ private:
110
+ jsi::Runtime& runtime;
111
+ std::shared_ptr<react::CallInvoker> callInvoker;
112
+ };