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

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,241 @@
1
+ #include "UnistylesRuntime.h"
2
+ #include <jsi/jsi.h>
3
+
4
+ using namespace facebook;
5
+
6
+ jsi::Value UnistylesRuntime::getScreenWidth(jsi::Runtime& rt, std::string fnName) {
7
+ return jsi::Value(this->screen.width);
8
+ }
9
+
10
+ jsi::Value UnistylesRuntime::getScreenHeight(jsi::Runtime& rt, std::string fnName) {
11
+ return jsi::Value(this->screen.height);
12
+ }
13
+
14
+ jsi::Value UnistylesRuntime::getContentSizeCategory(jsi::Runtime & rt, std::string fnName) {
15
+ return jsi::Value(jsi::String::createFromUtf8(rt, this->contentSizeCategory));
16
+ }
17
+
18
+ jsi::Value UnistylesRuntime::hasEnabledAdaptiveThemes(jsi::Runtime& rt, std::string fnName) {
19
+ return jsi::Value(this->hasAdaptiveThemes);
20
+ }
21
+
22
+ jsi::Value UnistylesRuntime::getThemeName(jsi::Runtime& rt, std::string fnName) {
23
+ return !this->themeName.empty()
24
+ ? jsi::Value(jsi::String::createFromUtf8(rt, this->themeName))
25
+ : this->getThemeOrFail(rt);
26
+ }
27
+
28
+ jsi::Value UnistylesRuntime::getCurrentBreakpoint(jsi::Runtime& rt, std::string fnName) {
29
+ return !this->breakpoint.empty()
30
+ ? jsi::Value(jsi::String::createFromUtf8(rt, this->breakpoint))
31
+ : jsi::Value::undefined();
32
+ }
33
+
34
+ jsi::Value UnistylesRuntime::getColorScheme(jsi::Runtime& rt, std::string fnName) {
35
+ return jsi::Value(jsi::String::createFromUtf8(rt, this->colorScheme));
36
+ }
37
+
38
+ jsi::Value UnistylesRuntime::getSortedBreakpointPairs(jsi::Runtime& rt, std::string fnName) {
39
+ std::unique_ptr<jsi::Array> sortedBreakpointEntriesArray = std::make_unique<jsi::Array>(rt, this->sortedBreakpointPairs.size());
40
+
41
+ for (size_t i = 0; i < this->sortedBreakpointPairs.size(); ++i) {
42
+ std::unique_ptr<jsi::Array> pairArray = std::make_unique<jsi::Array>(rt, 2);
43
+ jsi::String nameValue = jsi::String::createFromUtf8(rt, this->sortedBreakpointPairs[i].first);
44
+
45
+ pairArray->setValueAtIndex(rt, 0, nameValue);
46
+ pairArray->setValueAtIndex(rt, 1, jsi::Value(this->sortedBreakpointPairs[i].second));
47
+ sortedBreakpointEntriesArray->setValueAtIndex(rt, i, *pairArray);
48
+ }
49
+
50
+ return jsi::Value(rt, *sortedBreakpointEntriesArray);
51
+ }
52
+
53
+ jsi::Value UnistylesRuntime::setBreakpoints(jsi::Runtime& rt, std::string fnName) {
54
+ return HOST_FN(fnName, 1, {
55
+ jsi::Object breakpointsObj = arguments[0].asObject(rt);
56
+ auto sortedBreakpoints = this->toSortedBreakpointPairs(rt, breakpointsObj);
57
+
58
+ if (sortedBreakpoints.size() == 0) {
59
+ throw jsi::JSError(rt, UnistylesErrorBreakpointsCannotBeEmpty);
60
+ }
61
+
62
+ if (sortedBreakpoints.at(0).second != 0) {
63
+ throw jsi::JSError(rt, UnistylesErrorBreakpointsMustStartFromZero);
64
+ }
65
+
66
+ this->sortedBreakpointPairs = sortedBreakpoints;
67
+
68
+ std::string breakpoint = this->getBreakpointFromScreenWidth(this->screen.width, sortedBreakpoints);
69
+
70
+ this->breakpoint = breakpoint;
71
+
72
+ return jsi::Value::undefined();
73
+ });
74
+ }
75
+
76
+ jsi::Value UnistylesRuntime::setActiveTheme(jsi::Runtime& rt, std::string fnName) {
77
+ return HOST_FN(fnName, 1, {
78
+ std::string themeName = arguments[0].asString(rt).utf8(rt);
79
+
80
+ if (this->themeName != themeName) {
81
+ this->themeName = themeName;
82
+ this->onThemeChange(themeName);
83
+ }
84
+
85
+ return jsi::Value::undefined();
86
+ });
87
+ }
88
+
89
+ jsi::Value UnistylesRuntime::updateTheme(jsi::Runtime& rt, std::string fnName) {
90
+ return HOST_FN(fnName, 1, {
91
+ std::string themeName = arguments[0].asString(rt).utf8(rt);
92
+
93
+ if (this->themeName == themeName) {
94
+ this->onThemeChange(themeName);
95
+ }
96
+
97
+ return jsi::Value::undefined();
98
+ });
99
+ }
100
+
101
+ jsi::Value UnistylesRuntime::useAdaptiveThemes(jsi::Runtime& rt, std::string fnName) {
102
+ return HOST_FN(fnName, 1, {
103
+ bool enableAdaptiveThemes = arguments[0].asBool();
104
+
105
+ if (enableAdaptiveThemes && this->colorScheme == UnistylesUnspecifiedScheme) {
106
+ throw jsi::JSError(rt, UnistylesErrorAdaptiveThemesNotSupported);
107
+ }
108
+
109
+ this->hasAdaptiveThemes = enableAdaptiveThemes;
110
+
111
+ if (!enableAdaptiveThemes || !this->supportsAutomaticColorScheme) {
112
+ return jsi::Value::undefined();
113
+ }
114
+
115
+ if (this->themeName != this->colorScheme) {
116
+ this->themeName = this->colorScheme;
117
+ this->onThemeChange(this->themeName);
118
+ }
119
+
120
+ return jsi::Value::undefined();
121
+ });
122
+ }
123
+
124
+ jsi::Value UnistylesRuntime::addPlugin(jsi::Runtime& rt, std::string fnName) {
125
+ return HOST_FN(fnName, 1, {
126
+ std::string pluginName = arguments[0].asString(rt).utf8(rt);
127
+ bool notify = arguments[1].asBool();
128
+
129
+ this->pluginNames.push_back(pluginName);
130
+
131
+ // registry enabled plugins won't notify listeners
132
+ if (notify) {
133
+ this->onPluginChange();
134
+ }
135
+
136
+ return jsi::Value::undefined();
137
+ });
138
+ }
139
+
140
+ jsi::Value UnistylesRuntime::removePlugin(jsi::Runtime& rt, std::string fnName) {
141
+ return HOST_FN(fnName, 1, {
142
+ std::string pluginName = arguments[0].asString(rt).utf8(rt);
143
+
144
+ auto it = std::find(this->pluginNames.begin(), this->pluginNames.end(), pluginName);
145
+
146
+ if (it != this->pluginNames.end()) {
147
+ this->pluginNames.erase(it);
148
+ this->onPluginChange();
149
+ }
150
+
151
+ return jsi::Value::undefined();
152
+ });
153
+ }
154
+
155
+ jsi::Value UnistylesRuntime::getEnabledPlugins(jsi::Runtime& rt, std::string fnName) {
156
+ auto jsiArray = facebook::jsi::Array(rt, this->pluginNames.size());
157
+
158
+ for (size_t i = 0; i < this->pluginNames.size(); i++) {
159
+ jsiArray.setValueAtIndex(rt, i, facebook::jsi::String::createFromUtf8(rt, this->pluginNames[i]));
160
+ }
161
+
162
+ return jsiArray;
163
+ }
164
+
165
+ jsi::Value UnistylesRuntime::getInsets(jsi::Runtime& rt, std::string fnName) {
166
+ auto insets = jsi::Object(rt);
167
+
168
+ insets.setProperty(rt, "top", this->insets.top);
169
+ insets.setProperty(rt, "bottom", this->insets.bottom);
170
+ insets.setProperty(rt, "left", this->insets.left);
171
+ insets.setProperty(rt, "right", this->insets.right);
172
+
173
+ return insets;
174
+ }
175
+
176
+ jsi::Value UnistylesRuntime::getStatusBar(jsi::Runtime& rt, std::string fnName) {
177
+ auto statusBar = jsi::Object(rt);
178
+ auto setStatusBarColorFunction = HOST_FN("setColor", 1, {
179
+ std::string color = arguments[0].asString(rt).utf8(rt);
180
+
181
+ if (this->setStatusBarColor.has_value()) {
182
+ this->setStatusBarColor.value()(color);
183
+ }
184
+
185
+ return jsi::Value::undefined();
186
+ });
187
+
188
+ statusBar.setProperty(rt, "width", this->statusBar.width);
189
+ statusBar.setProperty(rt, "height", this->statusBar.height);
190
+ statusBar.setProperty(rt, "setColor", setStatusBarColorFunction);
191
+
192
+ return statusBar;
193
+ }
194
+
195
+ jsi::Value UnistylesRuntime::getNavigationBar(jsi::Runtime& rt, std::string fnName) {
196
+ auto navigationBarValue = jsi::Object(rt);
197
+ auto setNavigationBarColorFunction = HOST_FN("setColor", 1, {
198
+ std::string color = arguments[0].asString(rt).utf8(rt);
199
+
200
+ if (this->setNavigationBarColor.has_value()) {
201
+ this->setNavigationBarColor.value()(color);
202
+ }
203
+
204
+ return jsi::Value::undefined();
205
+ });
206
+
207
+ navigationBarValue.setProperty(rt, "width", this->navigationBar.width);
208
+ navigationBarValue.setProperty(rt, "height", this->navigationBar.height);
209
+ navigationBarValue.setProperty(rt, "setColor", setNavigationBarColorFunction);
210
+
211
+ return navigationBarValue;
212
+ }
213
+
214
+ std::optional<jsi::Value> UnistylesRuntime::setThemes(jsi::Runtime& rt, const jsi::Value& value) {
215
+ jsi::Array themes = value.asObject(rt).asArray(rt);
216
+ std::vector<std::string> themesVector;
217
+ size_t length = themes.size(rt);
218
+
219
+ for (size_t i = 0; i < length; ++i) {
220
+ jsi::Value element = themes.getValueAtIndex(rt, i);
221
+
222
+ if (element.isString()) {
223
+ std::string theme = element.asString(rt).utf8(rt);
224
+ themesVector.push_back(theme);
225
+ }
226
+ }
227
+
228
+ if (themesVector.size() == 0) {
229
+ throw jsi::JSError(rt, UnistylesErrorThemesCannotBeEmpty);
230
+ }
231
+
232
+ this->themes = themesVector;
233
+ this->themeName = "";
234
+
235
+ bool hasLightTheme = std::find(themesVector.begin(), themesVector.end(), "light") != themesVector.end();
236
+ bool hasDarkTheme = std::find(themesVector.begin(), themesVector.end(), "dark") != themesVector.end();
237
+
238
+ this->supportsAutomaticColorScheme = hasLightTheme && hasDarkTheme;
239
+
240
+ return std::nullopt;
241
+ }
@@ -0,0 +1,230 @@
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
+ this->contentSizeCategory = contentSizeCategory;
62
+ this->onContentSizeCategoryChange(contentSizeCategory);
63
+ }
64
+
65
+ jsi::Value UnistylesModel::getThemeOrFail(jsi::Runtime& runtime) {
66
+ if (this->themes.size() == 1) {
67
+ std::string themeName = this->themes.at(0);
68
+
69
+ this->themeName = themeName;
70
+
71
+ return jsi::String::createFromUtf8(runtime, themeName);
72
+ }
73
+
74
+ return jsi::Value().undefined();
75
+ }
76
+
77
+ std::vector<std::pair<std::string, double>> UnistylesModel::toSortedBreakpointPairs(jsi::Runtime& rt, jsi::Object& breakpointsObj) {
78
+ jsi::Array propertyNames = breakpointsObj.getPropertyNames(rt);
79
+ std::vector<std::pair<std::string, double>> sortedBreakpointEntriesVec;
80
+
81
+ for (size_t i = 0; i < propertyNames.size(rt); ++i) {
82
+ jsi::Value propNameValue = propertyNames.getValueAtIndex(rt, i);
83
+ std::string name = propNameValue.asString(rt).utf8(rt);
84
+ jsi::PropNameID propNameID = jsi::PropNameID::forUtf8(rt, name);
85
+ jsi::Value value = breakpointsObj.getProperty(rt, propNameID);
86
+
87
+ if (value.isNumber()) {
88
+ double breakpointValue = value.asNumber();
89
+
90
+ sortedBreakpointEntriesVec.push_back(std::make_pair(name, breakpointValue));
91
+ }
92
+ }
93
+
94
+ std::sort(sortedBreakpointEntriesVec.begin(), sortedBreakpointEntriesVec.end(), [](const std::pair<std::string, double>& a, const std::pair<std::string, double>& b) {
95
+ return a.second < b.second;
96
+ });
97
+
98
+ return sortedBreakpointEntriesVec;
99
+ }
100
+
101
+ // a little bit hacky, but works like Turbo Module emitDeviceEvent
102
+ // it will be super easy to refactor for Unistyles 3.0
103
+ // ref: https://github.com/facebook/react-native/pull/43375
104
+ // ref: https://github.com/facebook/react-native/blob/b5fd041917d197f256433a41a126f0dff767c429/packages/react-native/ReactCommon/react/nativemodule/core/ReactCommon/TurboModule.cpp#L42
105
+ void UnistylesModel::emitDeviceEvent(const std::string eventType, EventPayload payload) {
106
+ this->callInvoker->invokeAsync([eventType, payload, this](){
107
+ jsi::Value emitter = this->runtime.global().getProperty(this->runtime, "__rctDeviceEventEmitter");
108
+
109
+ if (emitter.isUndefined()) {
110
+ return;
111
+ }
112
+
113
+ jsi::Object emitterObject = emitter.asObject(runtime);
114
+ jsi::Function emitFunction = emitterObject.getPropertyAsFunction(runtime, "emit");
115
+
116
+ std::vector<jsi::Value> arguments;
117
+ jsi::Object event = jsi::Object(this->runtime);
118
+
119
+ event.setProperty(this->runtime, "type", jsi::String::createFromUtf8(this->runtime, eventType));
120
+
121
+ jsi::Object eventPayload = this->parseEventPayload(payload);
122
+
123
+ event.setProperty(this->runtime, "payload", eventPayload);
124
+
125
+ arguments.emplace_back(jsi::String::createFromAscii(runtime, "__unistylesOnChange"));
126
+ arguments.emplace_back(std::move(event));
127
+
128
+ emitFunction.callWithThis(runtime, emitterObject, (const jsi::Value*)arguments.data(), arguments.size());
129
+ });
130
+ }
131
+
132
+ void UnistylesModel::onThemeChange(std::string themeName) {
133
+ EventPayload payload;
134
+ payload["themeName"] = themeName;
135
+
136
+ this->emitDeviceEvent("theme", payload);
137
+ }
138
+
139
+ void UnistylesModel::onContentSizeCategoryChange(std::string contentSizeCategory) {
140
+ EventPayload payload;
141
+ payload["contentSizeCategory"] = contentSizeCategory;
142
+
143
+ this->emitDeviceEvent("dynamicTypeSize", payload);
144
+ }
145
+
146
+ void UnistylesModel::onPluginChange() {
147
+ this->emitDeviceEvent("plugin", {});
148
+ }
149
+
150
+ void UnistylesModel::onLayoutChange() {
151
+ EventPayload payload;
152
+ std::string orientation = screen.width > screen.height
153
+ ? UnistylesOrientationLandscape
154
+ : UnistylesOrientationPortrait;
155
+
156
+ payload["breakpoint"] = this->breakpoint;
157
+ payload["orientation"] = orientation;
158
+
159
+ EventNestedValue screenPayload;
160
+ auto screen = this->screen;
161
+
162
+ screenPayload["width"] = screen.width;
163
+ screenPayload["height"] = screen.height;
164
+
165
+ payload["screen"] = screenPayload;
166
+
167
+ EventNestedValue statusBarPayload;
168
+ auto statusBar = this->statusBar;
169
+
170
+ statusBarPayload["width"] = statusBar.width;
171
+ statusBarPayload["height"] = statusBar.height;
172
+
173
+ payload["statusBar"] = statusBarPayload;
174
+
175
+ EventNestedValue navigationBarPayload;
176
+ auto navigationBar = this->navigationBar;
177
+
178
+ navigationBarPayload["width"] = navigationBar.width;
179
+ navigationBarPayload["height"] = navigationBar.height;
180
+
181
+ payload["navigationBar"] = navigationBarPayload;
182
+
183
+ EventNestedValue insetsPayload;
184
+ auto insets = this->insets;
185
+
186
+ insetsPayload["top"] = insets.top;
187
+ insetsPayload["bottom"] = insets.bottom;
188
+ insetsPayload["left"] = insets.left;
189
+ insetsPayload["right"] = insets.right;
190
+
191
+ payload["insets"] = insetsPayload;
192
+
193
+ this->emitDeviceEvent("layout", payload);
194
+ }
195
+
196
+ jsi::Object UnistylesModel::parseEventPayload(EventPayload payload) {
197
+ jsi::Object eventPayload = jsi::Object(this->runtime);
198
+
199
+ for (const auto& [key, value] : payload) {
200
+ if (std::holds_alternative<std::string>(value)) {
201
+ eventPayload.setProperty(this->runtime, key.c_str(), jsi::String::createFromUtf8(this->runtime, std::get<std::string>(value)));
202
+ }
203
+
204
+ if (std::holds_alternative<int>(value)) {
205
+ eventPayload.setProperty(this->runtime, key.c_str(), std::get<int>(value));
206
+ }
207
+
208
+ if (std::holds_alternative<EventNestedValue>(value)) {
209
+ eventPayload.setProperty(this->runtime, key.c_str(), this->parseEventNestedPayload(std::get<EventNestedValue>(value)));
210
+ }
211
+ }
212
+
213
+ return eventPayload;
214
+ }
215
+
216
+ jsi::Object UnistylesModel::parseEventNestedPayload(EventNestedValue payload) {
217
+ jsi::Object eventPayload = jsi::Object(this->runtime);
218
+
219
+ for (const auto& [key, value] : payload) {
220
+ if (std::holds_alternative<std::string>(value)) {
221
+ eventPayload.setProperty(this->runtime, key.c_str(), jsi::String::createFromUtf8(this->runtime, std::get<std::string>(value)));
222
+ }
223
+
224
+ if (std::holds_alternative<int>(value)) {
225
+ eventPayload.setProperty(this->runtime, key.c_str(), std::get<int>(value));
226
+ }
227
+ }
228
+
229
+ return eventPayload;
230
+ }
@@ -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
+ };