|
8 | 8 | from lxml import etree
|
9 | 9 | from lxml.html import fromstring, tostring
|
10 | 10 |
|
11 |
| -from reactpy.core.types import VdomDict |
| 11 | +from reactpy.core.types import ComponentType, VdomDict |
12 | 12 | from reactpy.core.vdom import vdom
|
13 | 13 |
|
14 | 14 | _RefValue = TypeVar("_RefValue")
|
@@ -156,42 +156,42 @@ def _etree_to_vdom(
|
156 | 156 | return el
|
157 | 157 |
|
158 | 158 |
|
159 |
| -def _add_vdom_to_etree(parent: etree._Element, vdom: VdomDict | dict[str, Any]) -> None: |
| 159 | +def _add_vdom_to_etree(parent: etree._Element, node: VdomDict | dict[str, Any]) -> None: |
160 | 160 | try:
|
161 |
| - tag = vdom["tagName"] |
| 161 | + tag = node["tagName"] |
162 | 162 | except KeyError as e:
|
163 |
| - msg = f"Expected a VDOM dict, not {vdom}" |
| 163 | + msg = f"Expected a VDOM dict, not {type(node)}" |
164 | 164 | raise TypeError(msg) from e
|
165 | 165 | else:
|
166 |
| - vdom = cast(VdomDict, vdom) |
| 166 | + node = cast(VdomDict, node) |
167 | 167 |
|
168 | 168 | if tag:
|
169 | 169 | element = etree.SubElement(parent, tag)
|
170 | 170 | element.attrib.update(
|
171 |
| - _vdom_attr_to_html_str(k, v) for k, v in vdom.get("attributes", {}).items() |
| 171 | + _vdom_attr_to_html_str(k, v) for k, v in node.get("attributes", {}).items() |
172 | 172 | )
|
173 | 173 | else:
|
174 | 174 | element = parent
|
175 | 175 |
|
176 |
| - for c in vdom.get("children", []): |
| 176 | + for c in node.get("children", []): |
| 177 | + if hasattr(c, "render"): |
| 178 | + c = _component_to_vdom(cast(ComponentType, c)) |
177 | 179 | if isinstance(c, dict):
|
178 | 180 | _add_vdom_to_etree(element, c)
|
179 | 181 | else:
|
180 |
| - """ |
181 |
| - LXML handles string children by storing them under `text` and `tail` |
182 |
| - attributes of Element objects. The `text` attribute, if present, effectively |
183 |
| - becomes that element's first child. Then the `tail` attribute, if present, |
184 |
| - becomes a sibling that follows that element. For example, consider the |
185 |
| - following HTML: |
186 |
| -
|
187 |
| - <p><a>hello</a>world</p> |
188 |
| -
|
189 |
| - In this code sample, "hello" is the `text` attribute of the `<a>` element |
190 |
| - and "world" is the `tail` attribute of that same `<a>` element. It's for |
191 |
| - this reason that, depending on whether the element being constructed has |
192 |
| - non-string a child element, we need to assign a `text` vs `tail` attribute |
193 |
| - to that element or the last non-string child respectively. |
194 |
| - """ |
| 182 | + # LXML handles string children by storing them under `text` and `tail` |
| 183 | + # attributes of Element objects. The `text` attribute, if present, effectively |
| 184 | + # becomes that element's first child. Then the `tail` attribute, if present, |
| 185 | + # becomes a sibling that follows that element. For example, consider the |
| 186 | + # following HTML: |
| 187 | + |
| 188 | + # <p><a>hello</a>world</p> |
| 189 | + |
| 190 | + # In this code sample, "hello" is the `text` attribute of the `<a>` element |
| 191 | + # and "world" is the `tail` attribute of that same `<a>` element. It's for |
| 192 | + # this reason that, depending on whether the element being constructed has |
| 193 | + # non-string a child element, we need to assign a `text` vs `tail` attribute |
| 194 | + # to that element or the last non-string child respectively. |
195 | 195 | if len(element):
|
196 | 196 | last_child = element[-1]
|
197 | 197 | last_child.tail = f"{last_child.tail or ''}{c}"
|
@@ -249,6 +249,14 @@ def _generate_vdom_children(
|
249 | 249 | )
|
250 | 250 |
|
251 | 251 |
|
| 252 | +def _component_to_vdom(component: ComponentType) -> VdomDict | str | None: |
| 253 | + """Convert a component to a VDOM dictionary""" |
| 254 | + result = component.render() |
| 255 | + if hasattr(result, "render"): |
| 256 | + result = _component_to_vdom(cast(ComponentType, result)) |
| 257 | + return cast(VdomDict, result) |
| 258 | + |
| 259 | + |
252 | 260 | def del_html_head_body_transform(vdom: VdomDict) -> VdomDict:
|
253 | 261 | """Transform intended for use with `html_to_vdom`.
|
254 | 262 |
|
|
0 commit comments