diff --git a/leptos_macro/src/component.rs b/leptos_macro/src/component.rs index dbddd5462b..db122ab9eb 100644 --- a/leptos_macro/src/component.rs +++ b/leptos_macro/src/component.rs @@ -732,6 +732,34 @@ impl Docs { } } +#[derive(Clone, Debug)] +struct DefaultExpr(Option); + +impl DefaultExpr { + fn is_some(&self) -> bool { + self.0.is_some() + } +} + +impl attribute_derive::ConvertParsed for DefaultExpr { + type Type = syn::Expr; + fn convert(value: Self::Type) -> syn::Result { + Ok(Self(Some(value))) + } + + fn default_by_default() -> bool { + true + } + + fn default() -> Self { + Self(None) + } + + fn as_flag() -> Option { + Some(parse_quote!(Default::default())) + } +} + #[derive(Clone, Debug, AttributeDerive)] #[attribute(ident = prop)] struct PropOpt { @@ -742,14 +770,14 @@ struct PropOpt { #[attribute(conflicts = [optional, optional_no_strip])] strip_option: bool, #[attribute(example = "5 * 10")] - default: Option, + default: DefaultExpr, into: bool, attrs: bool, } struct TypedBuilderOpts { default: bool, - default_with_value: Option, + default_with_value: DefaultExpr, strip_option: bool, into: bool, } @@ -767,7 +795,7 @@ impl TypedBuilderOpts { impl TypedBuilderOpts { fn to_serde_tokens(&self) -> TokenStream { - let default = if let Some(v) = &self.default_with_value { + let default = if let Some(v) = &self.default_with_value.0 { let v = v.to_token_stream().to_string(); quote! { default=#v, } } else if self.default { @@ -786,7 +814,7 @@ impl TypedBuilderOpts { impl ToTokens for TypedBuilderOpts { fn to_tokens(&self, tokens: &mut TokenStream) { - let default = if let Some(v) = &self.default_with_value { + let default = if let Some(v) = &self.default_with_value.0 { let v = v.to_token_stream().to_string(); quote! { default_code=#v, } } else if self.default { diff --git a/leptos_macro/tests/component.rs b/leptos_macro/tests/component.rs index f156507c06..e1c4aa17d2 100644 --- a/leptos_macro/tests/component.rs +++ b/leptos_macro/tests/component.rs @@ -16,6 +16,11 @@ fn Component( _ = into; } +#[component] +fn ImplicitDefault(#[prop(default)] default: String) -> impl IntoView { + let _ = default; +} + #[test] fn component() { let cp = ComponentProps::builder().into("").strip_option(9).build(); @@ -24,4 +29,7 @@ fn component() { assert_eq!(cp.strip_option, Some(9)); assert_eq!(cp.default, NonZeroUsize::new(10).unwrap()); assert_eq!(cp.into, ""); + + let cp = ImplicitDefaultProps::builder().build(); + assert_eq!(cp.default, String::default()); } diff --git a/leptos_macro/tests/ui/component.rs b/leptos_macro/tests/ui/component.rs index d5ecf2cc3c..08ab8fcf02 100644 --- a/leptos_macro/tests/ui/component.rs +++ b/leptos_macro/tests/ui/component.rs @@ -35,14 +35,6 @@ fn optional_no_strip_and_strip_option( _ = conflicting; } -#[component] -fn default_without_value( - , - #[prop(default)] default: bool, -) -> impl IntoView { - _ = default; -} - #[component] fn default_with_invalid_value( , diff --git a/leptos_macro/tests/ui/component_absolute.rs b/leptos_macro/tests/ui/component_absolute.rs index fe629cfa0f..efb45d4881 100644 --- a/leptos_macro/tests/ui/component_absolute.rs +++ b/leptos_macro/tests/ui/component_absolute.rs @@ -27,13 +27,6 @@ fn optional_no_strip_and_strip_option( _ = conflicting; } -#[::leptos::component] -fn default_without_value( - #[prop(default)] default: bool, -) -> impl ::leptos::IntoView { - _ = default; -} - #[::leptos::component] fn default_with_invalid_value( #[prop(default= |)] default: bool,