-
Notifications
You must be signed in to change notification settings - Fork 0
Props
The #[props] macro turns a named-field struct into a Nestix prop container and
typed builder.
#[props(debug)]
#[derive(Debug)]
pub struct ButtonProps {
#[props(default)]
disabled: bool,
on_click: Option<Shared<dyn Fn()>>,
}Every normal field is transformed into PropValue<T>. Component code reads the
current value with .get().
if props.disabled.get() {
// disabled
}Fields are required unless they are Option<T> or marked with
#[props(default)] or #[props(start)].
#[props]
pub struct TextProps {
text: String,
}
layout! {
Text(.text = "Hello".to_string())
}The generated builder tracks required fields at the type level.
Option<T> fields default to None automatically.
#[props]
pub struct LinkProps {
href: String,
target: Option<String>,
}Callers may omit .target.
Use #[props(default)] to default through Default::default().
#[props]
pub struct InputProps {
#[props(default)]
value: String,
}Use #[props(default = expr)] for a custom default.
#[props]
pub struct BadgeProps {
#[props(default = "neutral".to_string())]
tone: String,
}Use #[props(start)] for positional arguments in layout! and build_props!.
#[props(debug)]
#[derive(Debug)]
pub struct TextProps {
#[props(start)]
text: String,
}
layout! {
Text("Hello")
}Start fields are passed to the generated builder constructor before named properties.
#[props(debug)] makes the generated Props::debug_fmt implementation delegate
to the struct's Debug implementation.
#[props(debug)]
#[derive(Debug)]
pub struct PanelProps {
#[props(default)]
children: Layout,
}Without debug, type-erased props format as Props(..).
Use #[props(bounds(...))] to provide bounds for generated implementations.
#[props(bounds(I: IntoIterator + 'static, K: 'static))]
pub struct ForProps<I: IntoIterator, K> {
data: I,
key: Shared<dyn Fn(&I::Item) -> K>,
}Use #[props(group(name => [field_a, field_b]))] to generate a builder method
that sets several normal prop fields to the same value.
#[props(
group(margin => [margin_left, margin_right, margin_top, margin_bottom]),
group(margin_vertical => [margin_top, margin_bottom]),
)]
pub struct ViewProps {
#[props(default)]
margin_left: Dimension,
#[props(default)]
margin_right: Dimension,
#[props(default)]
margin_top: Dimension,
#[props(default)]
margin_bottom: Dimension,
}
layout! {
View(
.margin = Dimension::Points(8.0),
.width = Dimension::Points(200.0),
)
}Grouped fields must all have the same type. They cannot be #[props(start)] or
#[props(extends(...))] fields. The generated method follows the same typed
builder rules as field setters, so a grouped setter can set fields that are
unset or defaulted.
When the prop struct is extensible, group methods are also exposed through
generated builder extension traits, so extended prop structs can use the same
group syntax.
#[props(extensible(TraitName, WrapperTraitName))] generates a trait exposing
the prop struct and its fields, plus a builder wrapper trait used for prop
composition. Other prop structs can include an extension field with
#[props(extends(TraitName, WrapperTraitName))].
This is useful for component libraries that want prop inheritance or shared prop groups.
#[props(extensible(ViewPropsExt, ViewPropsWrapper))]
pub struct ViewProps {
#[props(default)]
class: String,
}
#[props]
pub struct ButtonProps {
#[props(extends(ViewPropsExt, ViewPropsWrapper))]
view: ViewProps,
on_click: Option<Shared<dyn Fn()>>,
}Extension fields are not wrapped in PropValue<T> and cannot also be start or
default fields.
build_props! drives the generated builder. This is what layout! uses for
component prop syntax.
let props = build_props!(ButtonProps(
.disabled = false,
.on_click = callback!(|| log::info!("clicked")),
));Positional arguments fill start fields:
let props = build_props!(TextProps("Hello"));Named values are converted with prop_value!, so plain values, signals, and
existing PropValue<T> values are accepted.
prop_value! converts:
- plain values to
PropValue::from_plain; - signals to
PropValue::from_signal; - existing
PropValue<T>values unchanged.
let plain = prop_value!("Hello".to_string());
let reactive = prop_value!(computed!([count] || count.get().to_string()));