diff --git a/crates/hypertext-macros/src/html/component.rs b/crates/hypertext-macros/src/html/component.rs
index 071810b..ae0eb9c 100644
--- a/crates/hypertext-macros/src/html/component.rs
+++ b/crates/hypertext-macros/src/html/component.rs
@@ -1,12 +1,12 @@
use proc_macro2::TokenStream;
-use quote::{ToTokens, quote};
+use quote::{ToTokens, format_ident, quote};
use syn::{
Ident, Lit, Token,
parse::{Parse, ParseStream},
- token::{Brace, Paren},
+ token::{Brace, Bracket, Paren},
};
-use super::{AttributeValue, ElementBody, Generate, Generator, ParenExpr, Syntax};
+use super::{AttributeValue, ElementBody, Generate, Generator, ParenExpr, Syntax, Toggle};
use crate::html::Node;
pub struct Component {
@@ -21,8 +21,15 @@ impl Generate for Component {
fn generate(&self, g: &mut Generator) {
let props = self.attrs.iter().map(|attr| {
let name = &attr.name;
- attr.value_expr()
- .map_or_else(|| quote!(.#name(#name)), |value| quote!(.#name(#value)))
+
+ match attr.value_expr() {
+ Some(value) if let Some(ComponentAttributeValue::Toggle(_)) = attr.value => {
+ let maybe_name = format_ident!("maybe_{name}");
+ quote!(.#maybe_name(#value))
+ }
+ Some(value) => quote!(.#name(#value)),
+ None => quote!(.#name(#name)),
+ }
});
let children = match &self.body {
@@ -86,6 +93,15 @@ impl ComponentAttribute {
}
}
}
+ ComponentAttributeValue::Toggle(toggle) => {
+ let expr = &toggle.expr;
+ quote! {
+ {
+ #[allow(unused_parens)]
+ #expr
+ }
+ }
+ }
})
}
}
@@ -111,6 +127,7 @@ pub enum ComponentAttributeValue {
Literal(Lit),
Ident(Ident),
Expr(ParenExpr),
+ Toggle(Toggle),
}
impl Parse for ComponentAttributeValue {
@@ -123,6 +140,8 @@ impl Parse for ComponentAttributeValue {
input.parse().map(Self::Ident)
} else if lookahead.peek(Paren) {
input.parse().map(Self::Expr)
+ } else if lookahead.peek(Bracket) {
+ input.parse().map(Self::Toggle)
} else {
Err(lookahead.error())
}
diff --git a/crates/hypertext/tests/components.rs b/crates/hypertext/tests/components.rs
index 8d13a49..4944ff5 100644
--- a/crates/hypertext/tests/components.rs
+++ b/crates/hypertext/tests/components.rs
@@ -211,6 +211,38 @@ fn component_optional_field_both_variants() {
);
}
+#[test]
+fn component_optional_field_toggle_none() {
+ let maud_result = maud! {
+ Header title=("Hello".into()) subtitle=[None];
+ }
+ .render();
+ let rsx_result = rsx! {
+
+ }
+ .render();
+
+ for result in [maud_result, rsx_result] {
+ assert_eq!(result.as_inner(), "Hello
");
+ }
+}
+
+#[test]
+fn component_optional_field_toggle_some() {
+ let maud_result = maud! {
+ Header title=("Hello".into()) subtitle=[Some("World".to_string())];
+ }
+ .render();
+ let rsx_result = rsx! {
+
+ }
+ .render();
+
+ for result in [maud_result, rsx_result] {
+ assert_eq!(result.as_inner(), "Hello
World
");
+ }
+}
+
#[renderable]
fn nav_bar<'a>(title: &'a str, subtitle: &String, add_smiley: bool) -> impl Renderable {
maud! {