|
5 | 5 | __RELEASE = True |
6 | 6 | component_func = declare_component("element_renderer", release=__RELEASE) |
7 | 7 |
|
| 8 | +def init_default_state(key: str = None, default_value: Any = None, **component_state): |
| 9 | + return { |
| 10 | + "st_key": key, |
| 11 | + "value": default_value, |
| 12 | + "event_id": f"{key}_init", |
| 13 | + **component_state, |
| 14 | + } |
| 15 | + |
8 | 16 | class UIElement: |
9 | | - def __init__(self, name: str, props: Optional[Dict[str, Any]] = None, key: Optional[str] = None): |
| 17 | + def __init__(self, name: str, props: Optional[Dict[str, Any]] = None, key: Optional[str] = None, default_value: Any = None, default_component_state: Any = None): |
10 | 18 | self.key = key |
11 | 19 | self.props = props if props is not None else {} |
12 | 20 | self.name = name |
13 | 21 | self.children: List['UIElement'] = [] |
14 | | - self.is_root = False |
| 22 | + self.parent = None |
| 23 | + default_state = init_default_state(key, default_value, default_component_state) |
| 24 | + self.state = default_state |
| 25 | + self.default_state = default_state |
| 26 | + ctx = get_context() |
| 27 | + current_element = ctx.get("current_element") |
| 28 | + if current_element: |
| 29 | + current_element.add_child(self) |
| 30 | + self.parent = current_element |
15 | 31 |
|
16 | 32 | def render_tree(self, tree: Dict[str, Any]) -> Any: |
17 | | - return component_func(comp="element_renderer", props={"tree": tree}, key=self.key, default=None) |
| 33 | + self.state = component_func(comp="element_renderer", props={"tree": tree}, key=self.key, default=self.default_state) |
| 34 | + return self.state |
18 | 35 |
|
19 | | - def render(self) -> Dict[str, Any]: |
| 36 | + def render_props(self) -> Dict[str, Any]: |
20 | 37 | return { |
21 | 38 | "name": self.name, |
22 | 39 | "props": self.props, |
23 | | - "children": [child.render() for child in self.children] |
| 40 | + "children": [child.render_props() for child in self.children] |
24 | 41 | } |
| 42 | + |
| 43 | + def render(self) -> Any: |
| 44 | + return self.render_tree(self.render_props()) |
25 | 45 |
|
26 | 46 | def __enter__(self) -> 'UIElement': |
27 | 47 | ctx = get_context() |
28 | | - if not ctx["in_render"]: |
29 | | - ctx["in_render"] = True |
30 | | - self.is_root = True |
| 48 | + ctx["current_element"] = self |
31 | 49 | return self |
32 | 50 |
|
33 | 51 | def __exit__(self, exc_type, exc_val, exc_tb) -> None: |
34 | | - if self.is_root: |
35 | | - get_context()["in_render"] = False |
36 | | - self.render_tree(self.render()) |
| 52 | + ctx = get_context() |
| 53 | + if self.parent is None: |
| 54 | + self.render_tree(self.render_props()) |
| 55 | + |
| 56 | + # Reset the current element to this element's parent |
| 57 | + ctx["current_element"] = self.parent |
37 | 58 |
|
38 | 59 | def add_child(self, child: 'UIElement') -> None: |
| 60 | + child.parent = self |
39 | 61 | self.children.append(child) |
| 62 | + |
| 63 | + def __getattr__(self, item: str) -> Any: |
| 64 | + if item in self.props: |
| 65 | + return self.props[item] |
| 66 | + raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{item}'") |
| 67 | + |
| 68 | + @property |
| 69 | + def value(self) -> Any: |
| 70 | + return self.state["value"] |
40 | 71 |
|
41 | | -def element(name: str, key: Optional[str] = None, **props) -> UIElement: |
42 | | - return UIElement(name=name, props=props, key=key) |
| 72 | +def element(name: str, key: Optional[str] = None , default_value: Any = None, default_component_state: Any = None, **props) -> UIElement: |
| 73 | + return UIElement(name=name, props=props, key=key, default_value=default_value, default_component_state=default_component_state) |
0 commit comments