Skip to content

Commit abc4e94

Browse files
committed
feat: container query
1 parent eaa6ba1 commit abc4e94

File tree

13 files changed

+620
-108
lines changed

13 files changed

+620
-108
lines changed

android/src/main/cpp/StyledComputedFactory.cpp

Lines changed: 0 additions & 1 deletion
This file was deleted.

cpp/ContainerContext.cpp

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
///
2+
/// ContainerContext.cpp
3+
/// Container context management for layout tracking
4+
///
5+
6+
#include "ContainerContext.hpp"
7+
8+
namespace margelo::nitro::cssnitro {
9+
10+
// Static member initialization
11+
std::unordered_map<std::string, LayoutBounds> ContainerContext::_layoutMap;
12+
std::unordered_map<std::string, ScopeHierarchy> ContainerContext::_scopeMap;
13+
14+
std::optional<std::string> ContainerContext::findInScope(const std::string &containerScope,
15+
const std::optional<std::string> &name) {
16+
// If no name provided, return the container scope directly
17+
if (!name.has_value()) {
18+
return containerScope;
19+
}
20+
21+
// Check if the scope exists
22+
auto scopeIt = _scopeMap.find(containerScope);
23+
if (scopeIt == _scopeMap.end()) {
24+
return std::nullopt;
25+
}
26+
27+
const ScopeHierarchy &hierarchy = scopeIt->second;
28+
29+
// Check if name exists in current scope
30+
if (hierarchy.names.find(name.value()) != hierarchy.names.end()) {
31+
return containerScope;
32+
}
33+
34+
// If not found and parent is not "root", check parent scope
35+
if (!hierarchy.parent.empty() && hierarchy.parent != "root") {
36+
return findInScope(hierarchy.parent, name);
37+
}
38+
39+
// Not found and we've reached root
40+
return std::nullopt;
41+
}
42+
43+
void ContainerContext::setScope(const std::string &containerScope,
44+
const std::string &parent,
45+
const std::unordered_set<std::string> &names) {
46+
_scopeMap[containerScope] = ScopeHierarchy(parent, names);
47+
}
48+
49+
std::optional<double> ContainerContext::getX(const std::string &containerScope,
50+
const std::optional<std::string> &name,
51+
reactnativecss::Effect::GetProxy &get) {
52+
auto foundKey = findInScope(containerScope, name);
53+
if (!foundKey.has_value()) {
54+
return std::nullopt;
55+
}
56+
57+
// Get layout bounds
58+
auto it = _layoutMap.find(foundKey.value());
59+
if (it == _layoutMap.end()) {
60+
return std::nullopt;
61+
}
62+
63+
// Track the observable through the proxy
64+
return get(*it->second.x);
65+
}
66+
67+
std::optional<double> ContainerContext::getY(const std::string &containerScope,
68+
const std::optional<std::string> &name,
69+
reactnativecss::Effect::GetProxy &get) {
70+
auto foundKey = findInScope(containerScope, name);
71+
if (!foundKey.has_value()) {
72+
return std::nullopt;
73+
}
74+
75+
auto it = _layoutMap.find(foundKey.value());
76+
if (it == _layoutMap.end()) {
77+
return std::nullopt;
78+
}
79+
80+
return get(*it->second.y);
81+
}
82+
83+
std::optional<double> ContainerContext::getWidth(const std::string &containerScope,
84+
const std::optional<std::string> &name,
85+
reactnativecss::Effect::GetProxy &get) {
86+
auto foundKey = findInScope(containerScope, name);
87+
if (!foundKey.has_value()) {
88+
return std::nullopt;
89+
}
90+
91+
auto it = _layoutMap.find(foundKey.value());
92+
if (it == _layoutMap.end()) {
93+
return std::nullopt;
94+
}
95+
96+
return get(*it->second.width);
97+
}
98+
99+
std::optional<double> ContainerContext::getHeight(const std::string &containerScope,
100+
const std::optional<std::string> &name,
101+
reactnativecss::Effect::GetProxy &get) {
102+
auto foundKey = findInScope(containerScope, name);
103+
if (!foundKey.has_value()) {
104+
return std::nullopt;
105+
}
106+
107+
auto it = _layoutMap.find(foundKey.value());
108+
if (it == _layoutMap.end()) {
109+
return std::nullopt;
110+
}
111+
112+
return get(*it->second.height);
113+
}
114+
115+
void ContainerContext::setLayout(const std::string &key,
116+
double x, double y,
117+
double width, double height) {
118+
LayoutBounds &bounds = _layoutMap[key];
119+
bounds.x->set(x);
120+
bounds.y->set(y);
121+
bounds.width->set(width);
122+
bounds.height->set(height);
123+
}
124+
125+
} // namespace margelo::nitro::cssnitro

cpp/ContainerContext.hpp

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
///
2+
/// ContainerContext.hpp
3+
/// Container context management for layout tracking
4+
///
5+
6+
#pragma once
7+
8+
#include <unordered_map>
9+
#include <unordered_set>
10+
#include <string>
11+
#include <memory>
12+
#include <optional>
13+
#include "Effect.hpp"
14+
#include "Observable.hpp"
15+
16+
namespace margelo::nitro::cssnitro {
17+
18+
// Layout bounds structure
19+
struct LayoutBounds {
20+
std::shared_ptr<reactnativecss::Observable<double>> x;
21+
std::shared_ptr<reactnativecss::Observable<double>> y;
22+
std::shared_ptr<reactnativecss::Observable<double>> width;
23+
std::shared_ptr<reactnativecss::Observable<double>> height;
24+
25+
LayoutBounds()
26+
: x(reactnativecss::Observable<double>::create(0.0)),
27+
y(reactnativecss::Observable<double>::create(0.0)),
28+
width(reactnativecss::Observable<double>::create(0.0)),
29+
height(reactnativecss::Observable<double>::create(0.0)) {}
30+
};
31+
32+
// Scope hierarchy structure
33+
struct ScopeHierarchy {
34+
std::string parent;
35+
std::unordered_set<std::string> names;
36+
37+
ScopeHierarchy() : parent(""), names() {}
38+
39+
ScopeHierarchy(std::string p, std::unordered_set<std::string> n)
40+
: parent(std::move(p)), names(std::move(n)) {}
41+
};
42+
43+
/**
44+
* ContainerContext manages layout bounds and scope hierarchies for containers
45+
*/
46+
class ContainerContext {
47+
private:
48+
static std::unordered_map<std::string, LayoutBounds> _layoutMap;
49+
static std::unordered_map<std::string, ScopeHierarchy> _scopeMap;
50+
51+
public:
52+
// Helper to find a name in scope hierarchy
53+
static std::optional<std::string>
54+
findInScope(const std::string &containerScope, const std::optional<std::string> &name);
55+
56+
/**
57+
* Set the scope hierarchy for a container
58+
*/
59+
static void setScope(const std::string &containerScope,
60+
const std::string &parent,
61+
const std::unordered_set<std::string> &names);
62+
63+
/**
64+
* Get X coordinate for a container/element
65+
* Returns nullptr if not found and parent is "root"
66+
*/
67+
static std::optional<double> getX(const std::string &containerScope,
68+
const std::optional<std::string> &name,
69+
reactnativecss::Effect::GetProxy &get);
70+
71+
/**
72+
* Get Y coordinate for a container/element
73+
* Returns nullptr if not found and parent is "root"
74+
*/
75+
static std::optional<double> getY(const std::string &containerScope,
76+
const std::optional<std::string> &name,
77+
reactnativecss::Effect::GetProxy &get);
78+
79+
/**
80+
* Get width for a container/element
81+
* Returns nullptr if not found and parent is "root"
82+
*/
83+
static std::optional<double> getWidth(const std::string &containerScope,
84+
const std::optional<std::string> &name,
85+
reactnativecss::Effect::GetProxy &get);
86+
87+
/**
88+
* Get height for a container/element
89+
* Returns nullptr if not found and parent is "root"
90+
*/
91+
static std::optional<double> getHeight(const std::string &containerScope,
92+
const std::optional<std::string> &name,
93+
reactnativecss::Effect::GetProxy &get);
94+
95+
static void
96+
setLayout(const std::string &key, double x, double y, double width, double height);
97+
};
98+
99+
} // namespace margelo::nitro::cssnitro

cpp/HybridStyleRegistry.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "HybridStyleRegistry.hpp"
22
#include "Computed.hpp"
3+
#include "ContainerContext.hpp"
34
#include "Observable.hpp"
45
#include "ShadowTreeUpdateManager.hpp"
56
#include "StyledComputedFactory.hpp"
@@ -174,7 +175,8 @@ namespace margelo::nitro::cssnitro {
174175
auto computed = ::margelo::nitro::cssnitro::makeStyledComputed(styleRuleMap_, classNames,
175176
componentId,
176177
*shadowUpdates_,
177-
variableScope);
178+
variableScope,
179+
containerScope);
178180

179181
computedMap_[componentId] = computed;
180182

@@ -196,6 +198,12 @@ namespace margelo::nitro::cssnitro {
196198
PseudoClasses::set(componentId, type, value);
197199
}
198200

201+
void HybridStyleRegistry::updateComponentLayout(const std::string &componentId,
202+
const margelo::nitro::cssnitro::LayoutRectangle &value) {
203+
204+
ContainerContext::setLayout(componentId, value.x, value.y, value.width, value.height);
205+
}
206+
199207
void HybridStyleRegistry::unlinkComponent(const std::string &componentId) {
200208
shadowUpdates_->unlinkComponent(componentId);
201209
}

cpp/HybridStyleRegistry.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ namespace margelo::nitro::cssnitro {
6161
void updateComponentState(const std::string &componentId, PseudoClassType type,
6262
bool value) override;
6363

64+
void updateComponentLayout(const std::string &componentId,
65+
const LayoutRectangle &value) override;
66+
6467
void unlinkComponent(const std::string &componentId) override;
6568

6669
void updateComponentInlineStyleKeys(const std::string &componentId,

0 commit comments

Comments
 (0)