11#include " VariableContext.hpp"
2+ #include " Rules.hpp"
23
34namespace margelo ::nitro::cssnitro {
45
56 using AnyValue = ::margelo::nitro::AnyValue;
7+ using AnyMap = ::margelo::nitro::AnyMap;
8+ using AnyObject = ::margelo::nitro::AnyObject;
69
710 // Initialize the static contexts map
811 std::unordered_map<std::string, VariableContext::Context> VariableContext::contexts;
@@ -43,6 +46,11 @@ namespace margelo::nitro::cssnitro {
4346 std::optional<AnyValue> VariableContext::checkContext (const std::string &contextKey,
4447 const std::string &name,
4548 reactnativecss::Effect::GetProxy &get) {
49+ // If this is a root or universal context, ensure it exists
50+ if (contextKey == " root" || contextKey == " universal" ) {
51+ createContext (contextKey, " root" );
52+ }
53+
4654 auto contextIt = contexts.find (contextKey);
4755 if (contextIt != contexts.end ()) {
4856 auto &valueMap = contextIt->second .values ;
@@ -54,12 +62,27 @@ namespace margelo::nitro::cssnitro {
5462 return result;
5563 }
5664 } else {
57- // Variable doesn't exist in this context, create a new Observable with nullptr
58- auto observable = reactnativecss::Observable<AnyValue>::create (AnyValue ());
59- valueMap[name] = observable;
65+ // Variable doesn't exist in this context
66+ // Check if this is a root or universal context
67+ if (contextKey == " root" || contextKey == " universal" ) {
68+ // For root/universal, create a top-level computed
69+ auto &targetMap = (contextKey == " root" ) ? root_values : universal_values;
70+ auto computed = createTopLevelVariableComputed (targetMap, name);
71+ valueMap[name] = computed;
72+
73+ // Get the initial value from the computed
74+ auto result = get (*computed);
75+ if (!std::holds_alternative<std::monostate>(result)) {
76+ return result;
77+ }
78+ } else {
79+ // For other contexts, create a new Observable with nullptr
80+ auto observable = reactnativecss::Observable<AnyValue>::create (AnyValue ());
81+ valueMap[name] = observable;
6082
61- // Subscribe to the observable by calling get()
62- get (*observable);
83+ // Subscribe to the observable by calling get()
84+ get (*observable);
85+ }
6386 }
6487 }
6588 return std::nullopt ;
@@ -116,7 +139,8 @@ namespace margelo::nitro::cssnitro {
116139 auto contextIt = contexts.find (key);
117140 if (contextIt == contexts.end ()) {
118141 // Context doesn't exist, create it with empty parent
119- createContext (key, " " );
142+ // This couldn't happen in normal usage, but just in case
143+ createContext (key, " root" );
120144 contextIt = contexts.find (key);
121145 }
122146
@@ -196,25 +220,92 @@ namespace margelo::nitro::cssnitro {
196220 auto varIt = valueMap.find (name);
197221
198222 if (varIt == valueMap.end ()) {
199- // Variable doesn't exist in context, create a Computed that reads from the target map
200- auto computed = reactnativecss::Computed<AnyValue>::create (
201- [&targetMap, name](const AnyValue &prev,
202- reactnativecss::Effect::GetProxy &get) -> AnyValue {
203- (void ) prev;
204-
205- // Read from the target map
206- auto it = targetMap.find (name);
207- if (it != targetMap.end ()) {
208- return get (*it->second );
209- }
210- return AnyValue ();
211- },
212- AnyValue () // Initial value
213- );
214-
223+ // Variable doesn't exist in context, create a Computed using the factory
224+ auto computed = createTopLevelVariableComputed (targetMap, name);
215225 valueMap[name] = computed;
216226 }
217227 }
218228 }
219229
230+ std::shared_ptr<reactnativecss::Computed<AnyValue>>
231+ VariableContext::createTopLevelVariableComputed (
232+ std::unordered_map<std::string, std::shared_ptr<reactnativecss::Observable<AnyValue>>> &targetMap,
233+ const std::string &name) {
234+ return reactnativecss::Computed<AnyValue>::create (
235+ [&targetMap, name](const AnyValue &prev,
236+ reactnativecss::Effect::GetProxy &get) -> AnyValue {
237+ (void ) prev;
238+
239+ // Read from the target map
240+ auto it = targetMap.find (name);
241+ if (it != targetMap.end ()) {
242+ auto value = get (*it->second );
243+
244+ // Check if value is an array
245+ if (!std::holds_alternative<AnyArray>(value)) {
246+ return AnyValue ();
247+ }
248+
249+ const auto &arr = std::get<AnyArray>(value);
250+
251+ // Loop over the array
252+ for (const auto &item: arr) {
253+ // Each item should be an object with "v" and "m" keys
254+ if (!std::holds_alternative<AnyObject>(item)) {
255+ continue ;
256+ }
257+
258+ const auto &obj = std::get<AnyObject>(item);
259+
260+ // Check if "m" is set
261+ auto mIt = obj.find (" m" );
262+ if (mIt != obj.end () &&
263+ !std::holds_alternative<std::monostate>(mIt ->second )) {
264+ // "m" is set, test the media query/condition
265+ const auto &mValue = mIt ->second ;
266+
267+ // Convert AnyValue to AnyMap if it's an object
268+ if (std::holds_alternative<AnyObject>(mValue )) {
269+ const auto &mediaObj = std::get<AnyObject>(mValue );
270+ auto mediaMap = AnyMap::make (mediaObj.size ());
271+
272+ // Copy the object into an AnyMap
273+ for (const auto &kv: mediaObj) {
274+ mediaMap->setAny (kv.first , kv.second );
275+ }
276+
277+ // Test the rule - if it doesn't pass, continue to next item
278+ if (!Rules::testRule (mediaMap, get)) {
279+ continue ;
280+ }
281+ // If it passes, fall through to return the "v" value
282+ } else {
283+ // "m" exists but is not an AnyObject, skip this item
284+ continue ;
285+ }
286+ }
287+
288+ // "m" is not set or the media query passed, return the value of "v"
289+ auto vIt = obj.find (" v" );
290+ if (vIt != obj.end ()) {
291+ return vIt->second ;
292+ }
293+ }
294+
295+ return AnyValue ();
296+ } else {
297+ // Observable doesn't exist, create it and subscribe
298+ auto observable = reactnativecss::Observable<AnyValue>::create (AnyValue ());
299+ targetMap[name] = observable;
300+
301+ // Subscribe to the observable
302+ get (*observable);
303+
304+ return AnyValue ();
305+ }
306+ },
307+ AnyValue () // Initial value
308+ );
309+ }
310+
220311} // namespace margelo::nitro::cssnitro
0 commit comments