|
2 | 2 |
|
3 | 3 | namespace margelo::nitro::cssnitro { |
4 | 4 |
|
| 5 | + using AnyValue = ::margelo::nitro::AnyValue; |
| 6 | + |
5 | 7 | // Initialize the static contexts map |
6 | | - std::unordered_map<std::string, std::unordered_map<std::string, std::shared_ptr<reactnativecss::Observable<AnyValue>>>> VariableContext::contexts; |
| 8 | + std::unordered_map<std::string, VariableContext::Context> VariableContext::contexts; |
7 | 9 |
|
8 | | - void VariableContext::createContext(const std::string &key) { |
9 | | - // Create a new empty map for this context |
10 | | - contexts[key] = std::unordered_map<std::string, std::shared_ptr<reactnativecss::Observable<AnyValue>>>(); |
| 10 | + void VariableContext::createContext(const std::string &key, const std::string &parent) { |
| 11 | + // Create a new context with the specified parent |
| 12 | + Context ctx; |
| 13 | + ctx.parent = parent; |
| 14 | + ctx.values = std::unordered_map<std::string, VariableValue>(); |
| 15 | + contexts[key] = ctx; |
11 | 16 | } |
12 | 17 |
|
13 | 18 | void VariableContext::deleteContext(const std::string &key) { |
14 | 19 | // Remove the context from the map |
15 | 20 | contexts.erase(key); |
16 | 21 | } |
17 | 22 |
|
18 | | - const AnyValue &VariableContext::getVariable(const std::string &key, const std::string &name, |
19 | | - reactnativecss::Effect::GetProxy &get) { |
20 | | - // Find the context |
21 | | - auto contextIt = contexts.find(key); |
22 | | - if (contextIt == contexts.end()) { |
23 | | - // Context doesn't exist, throw or return a default value |
24 | | - static AnyValue defaultValue; |
25 | | - return defaultValue; |
| 23 | + AnyValue VariableContext::getValue(const VariableValue &varValue, |
| 24 | + reactnativecss::Effect::GetProxy &get) { |
| 25 | + if (std::holds_alternative<std::shared_ptr<reactnativecss::Observable<AnyValue>>>( |
| 26 | + varValue)) { |
| 27 | + auto obs = std::get<std::shared_ptr<reactnativecss::Observable<AnyValue>>>(varValue); |
| 28 | + return get(*obs); |
| 29 | + } else { |
| 30 | + auto comp = std::get<std::shared_ptr<reactnativecss::Computed<AnyValue>>>(varValue); |
| 31 | + return get(*comp); |
| 32 | + } |
| 33 | + } |
| 34 | + |
| 35 | + std::optional<AnyValue> VariableContext::checkContext(const std::string &contextKey, |
| 36 | + const std::string &name, |
| 37 | + reactnativecss::Effect::GetProxy &get) { |
| 38 | + auto contextIt = contexts.find(contextKey); |
| 39 | + if (contextIt != contexts.end()) { |
| 40 | + auto &valueMap = contextIt->second.values; |
| 41 | + auto varIt = valueMap.find(name); |
| 42 | + if (varIt != valueMap.end()) { |
| 43 | + auto result = getValue(varIt->second, get); |
| 44 | + // If the value is not nullopt, return it |
| 45 | + if (!std::holds_alternative<std::monostate>(result)) { |
| 46 | + return result; |
| 47 | + } |
| 48 | + } |
| 49 | + } |
| 50 | + return std::nullopt; |
| 51 | + } |
| 52 | + |
| 53 | + std::optional<AnyValue> |
| 54 | + VariableContext::getVariable(const std::string &key, const std::string &name, |
| 55 | + reactnativecss::Effect::GetProxy &get) { |
| 56 | + // 1. Check current key |
| 57 | + auto result = checkContext(key, name, get); |
| 58 | + if (result.has_value()) { |
| 59 | + return result; |
26 | 60 | } |
27 | 61 |
|
28 | | - // Find the variable in the context |
29 | | - auto &variableMap = contextIt->second; |
30 | | - auto varIt = variableMap.find(name); |
31 | | - if (varIt == variableMap.end()) { |
32 | | - // Variable doesn't exist, return a default value |
33 | | - static AnyValue defaultValue; |
34 | | - return defaultValue; |
| 62 | + // 2. Check "universal" context (if we're not already in it) |
| 63 | + if (key != "universal") { |
| 64 | + result = checkContext("universal", name, get); |
| 65 | + if (result.has_value()) { |
| 66 | + return result; |
| 67 | + } |
| 68 | + |
| 69 | + // 3. Walk up the parent chain from the original key |
| 70 | + std::string currentKey = key; |
| 71 | + auto contextIt = contexts.find(currentKey); |
| 72 | + if (contextIt != contexts.end()) { |
| 73 | + std::string parentKey = contextIt->second.parent; |
| 74 | + |
| 75 | + // Walk up parent chain until we hit root (parent points to itself) |
| 76 | + while (parentKey != currentKey && !parentKey.empty()) { |
| 77 | + result = checkContext(parentKey, name, get); |
| 78 | + if (result.has_value()) { |
| 79 | + return result; |
| 80 | + } |
| 81 | + |
| 82 | + // Move to next parent |
| 83 | + auto parentIt = contexts.find(parentKey); |
| 84 | + if (parentIt != contexts.end()) { |
| 85 | + currentKey = parentKey; |
| 86 | + parentKey = parentIt->second.parent; |
| 87 | + } else { |
| 88 | + break; |
| 89 | + } |
| 90 | + } |
| 91 | + } |
35 | 92 | } |
36 | 93 |
|
37 | | - // Get the observable and subscribe the effect to it |
38 | | - auto &observable = varIt->second; |
39 | | - return get(*observable); |
| 94 | + // Variable doesn't exist in any context |
| 95 | + return std::nullopt; |
40 | 96 | } |
41 | 97 |
|
42 | 98 | void VariableContext::setVariable(const std::string &key, const std::string &name, |
43 | 99 | const AnyValue &value) { |
44 | 100 | // Find or create the context |
45 | 101 | auto contextIt = contexts.find(key); |
46 | 102 | if (contextIt == contexts.end()) { |
47 | | - // Context doesn't exist, create it |
48 | | - createContext(key); |
| 103 | + // Context doesn't exist, create it with empty parent |
| 104 | + createContext(key, ""); |
49 | 105 | contextIt = contexts.find(key); |
50 | 106 | } |
51 | 107 |
|
52 | | - auto &variableMap = contextIt->second; |
| 108 | + auto &valueMap = contextIt->second.values; |
53 | 109 |
|
54 | | - // Find or create the observable for this variable |
55 | | - auto varIt = variableMap.find(name); |
56 | | - if (varIt == variableMap.end()) { |
57 | | - // Variable doesn't exist, create a new Observable with the value |
58 | | - auto observable = reactnativecss::Observable<AnyValue>::create(value); |
59 | | - variableMap[name] = observable; |
60 | | - } else { |
61 | | - // Variable exists, update its value |
62 | | - varIt->second->set(value); |
| 110 | + // Find the variable |
| 111 | + auto varIt = valueMap.find(name); |
| 112 | + if (varIt != valueMap.end()) { |
| 113 | + // Variable exists, check if it's an Observable or Computed |
| 114 | + if (std::holds_alternative<std::shared_ptr<reactnativecss::Observable<AnyValue>>>( |
| 115 | + varIt->second)) { |
| 116 | + // It's an Observable, just update its value |
| 117 | + auto obs = std::get<std::shared_ptr<reactnativecss::Observable<AnyValue>>>( |
| 118 | + varIt->second); |
| 119 | + obs->set(value); |
| 120 | + return; |
| 121 | + } else { |
| 122 | + // It's a Computed, dispose it and create a new Observable |
| 123 | + auto comp = std::get<std::shared_ptr<reactnativecss::Computed<AnyValue>>>( |
| 124 | + varIt->second); |
| 125 | + comp->dispose(); |
| 126 | + } |
63 | 127 | } |
| 128 | + |
| 129 | + // Create a new Observable with the value |
| 130 | + auto observable = reactnativecss::Observable<AnyValue>::create(value); |
| 131 | + valueMap[name] = observable; |
64 | 132 | } |
65 | 133 |
|
66 | 134 | void VariableContext::setVariable(const std::string &key, const std::string &name, |
67 | | - std::shared_ptr<reactnativecss::Observable<AnyValue>> observable) { |
| 135 | + std::shared_ptr<reactnativecss::Computed<AnyValue>> computed) { |
68 | 136 | // Find or create the context |
69 | 137 | auto contextIt = contexts.find(key); |
70 | 138 | if (contextIt == contexts.end()) { |
71 | | - // Context doesn't exist, create it |
72 | | - createContext(key); |
| 139 | + // Context doesn't exist, create it with empty parent |
| 140 | + createContext(key, ""); |
73 | 141 | contextIt = contexts.find(key); |
74 | 142 | } |
75 | 143 |
|
76 | | - auto &variableMap = contextIt->second; |
| 144 | + auto &valueMap = contextIt->second.values; |
| 145 | + |
| 146 | + // Check if variable already exists and dispose if it's a Computed |
| 147 | + auto varIt = valueMap.find(name); |
| 148 | + if (varIt != valueMap.end()) { |
| 149 | + if (std::holds_alternative<std::shared_ptr<reactnativecss::Computed<AnyValue>>>( |
| 150 | + varIt->second)) { |
| 151 | + auto existingComp = std::get<std::shared_ptr<reactnativecss::Computed<AnyValue>>>( |
| 152 | + varIt->second); |
| 153 | + existingComp->dispose(); |
| 154 | + } |
| 155 | + } |
| 156 | + |
| 157 | + // Set the variable to use the provided Computed directly |
| 158 | + valueMap[name] = computed; |
| 159 | + } |
| 160 | + |
| 161 | + void VariableContext::setTopLevelVariable(const std::string &key, const std::string &name, |
| 162 | + const std::vector<HybridRootVariableRule> &value) { |
| 163 | + // Create a new Computed that returns "yellow" for now |
| 164 | + auto computed = reactnativecss::Computed<AnyValue>::create( |
| 165 | + [](const AnyValue &prev, reactnativecss::Effect::GetProxy &get) -> AnyValue { |
| 166 | + (void) prev; |
| 167 | + (void) get; |
| 168 | + return AnyValue("yellow"); |
| 169 | + }, |
| 170 | + AnyValue() // Initial value |
| 171 | + ); |
77 | 172 |
|
78 | | - // Set the variable to use the provided Observable directly |
79 | | - variableMap[name] = observable; |
| 173 | + // Use the Computed overload to set the variable |
| 174 | + setVariable(key, name, computed); |
80 | 175 | } |
81 | 176 |
|
82 | 177 | } // namespace margelo::nitro::cssnitro |
0 commit comments