-
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 container-level #[props(default)] to generate a Default implementation
for the props type. Every field must either have a default field attribute or be
an Option<T>.
#[props(default)]
pub struct PanelProps {
#[props(default)]
title: String,
subtitle: Option<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)]
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.
Use #[props(nested)] to embed another props type without wrapping that field
in PropValue<T>. The macro also generates a hidden field_builder method on
the generated builder for recursive builder syntax. Use
#[props(nested(args...))] when the nested props type has positional start
fields.
#[props]
pub struct ViewProps {
#[props(start)]
x: i32,
#[props(start)]
y: f32,
#[props(default)]
margin: f32,
}
#[props]
pub struct ButtonProps {
#[props(nested(x: i32, y: f32))]
view_props: ViewProps,
#[props(default)]
title: String,
}
let props = build_props!(ButtonProps(
.view_props(
10,
20.0,
.margin = 3.0,
),
.title = "Click".to_string(),
));Nested fields cannot be #[props(start)] fields or grouped 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.
For #[props(nested)] fields, replace = with parentheses to recursively
build the nested props. Positional values inside the parentheses are passed to
the generated nested builder helper:
let props = build_props!(ButtonProps(
.view_props(
10,
20.0,
.margin = 3.0,
),
));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()));