Add explicit fragment support (JSX-like syntax), and support Components returning iterables.
We now explicitly support JSX-like fragment syntax. This is useful when implementing component functions:
def Items() -> Node:
return html(t"<><li>Item 1</li><li>Item 2</li></>")
result = html(t"<ul><{Items} /></ul>")
# <ul><li>Item 1</li><li>Item 2</li></ul>As an alternative, we also support returning typing.Iterables from components as well; these are treated as implicitly creating a tdom.nodes.Fragment:
def Items() -> Iterable[Node]:
for i in range(2):
yield t"<li>Item {i + 1}</li>"
result = html(t"<ul><{Items} /></ul>")
# <ul><li>Item 1</li><li>Item 2</li></ul>In practice, component functions can return any value and it will be converted to a Node in exactly the same way that any value substituted in children context would be normally (aka html(t"<div>{child_value}</div>")). The fallback case if a value isn't a special type is always simply to create a Text node from str(value).