-
Notifications
You must be signed in to change notification settings - Fork 0
Layout Macro
layout! is Nestix's component tree syntax. It expands to normal calls to
create_element, generated prop builders, computed, and built-in list
helpers.
Create an element by naming a component type.
layout! {
App
}Add props with parentheses:
layout! {
Button(.disabled = false)
}Pass an existing props value with $ before the parentheses:
let props = build_props!(ButtonProps(.title = "Click".to_string()));
layout! {
Button$(props)
}Add children with braces:
layout! {
Div {
Text("Hello")
Button { Text("Click") }
}
}If a component has children, layout! sets a .children prop automatically.
The component's props type must include a compatible children field.
Use $(expr) to splice an existing element or iterable of elements into a
layout.
layout! {
Fragment {
$(props.children.clone())
}
}The expression is converted through ToElements when the surrounding layout
contains multiple items.
Use normal if and else branches.
layout! {
if count.get() % 2 == 0 {
Text("Even")
} else {
Text("Odd")
}
}Conditionals are reactive when they read signals. The generated output uses a computed value so the branch updates when dependencies change.
Branches can contain one or many elements:
layout! {
Div {
if logged_in.get() {
Header
Dashboard
} else {
LoginForm
}
}
}Use for item in data to render a signal-backed list. If no key is supplied,
the item itself is used as the key.
layout! {
for item in items.clone() {
Text(item)
}
}For non-identity keys, add where key = ....
layout! {
for item in items.clone() where key = |item| item.0.clone() {
TodoListItem(.data = item)
}
}The generated child closure receives each item as a Readonly<Item>, so child
props can react when an existing keyed item changes.
List data must be a signal whose output is cloneable and iterable. Keys must be
stable, Eq, and Hash.
Prefix an element or splice with yield when that item must be created inside
the generated computed closure.
layout! {
yield Text(computed!([label] || label.get()))
}This is an advanced escape hatch for cases where pre-creating an element outside the computed output would capture stale values or produce the wrong identity.
An element can bind its host handle into a state using name @ Component.
let input_handle = create_state(None);
layout! {
input_handle @ Input(.value = "Hello".to_string())
}The generated code creates an effect that writes element.handle() into the
state. This is useful when renderer components expose host handles.
Some components accept a child factory rather than a static Layout. The layout
parser supports closure arguments after an element's optional capture list.
layout! {
SomeComponent [items] |item| {
Text(item.get())
}
}The generated .children value is a callback! returning a PropValue of the
nested layout.
For child layout closures, bracketed captures clone values into the closure.
layout! {
Menu [selected, label: props.label] |item| {
MenuItem(.selected = selected.clone(), .label = label.clone())
}
}Capture syntax matches closure! and callback!:
-
[name]clonesname; -
[alias: expr]clonesexprinto a local namedalias.
Depending on its contents, layout! may return:
-
(); - a single
Element; -
Vec<Element>; - a computed signal that produces an element or vector of elements.
Components usually return the macro expression directly and let the
ComponentOutput machinery mount it.