From 0c0f0e96df9266d56b6c740637cc43f9882904e1 Mon Sep 17 00:00:00 2001 From: pandarrr Date: Wed, 7 May 2025 15:34:05 -0500 Subject: [PATCH] Use SuperInto and correct Owner for props defaults (#3959) --- packages/core-macro/src/props/mod.rs | 9 +++++- packages/core-macro/tests/rsx.rs | 42 ++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/packages/core-macro/src/props/mod.rs b/packages/core-macro/src/props/mod.rs index 7cde3ee5a..6d8197c16 100644 --- a/packages/core-macro/src/props/mod.rs +++ b/packages/core-macro/src/props/mod.rs @@ -1416,10 +1416,15 @@ Finally, call `.build()` to create the instance of `{name}`. // If field has `into`, apply it to the default value. // Ignore any blank defaults as it causes type inference errors. let is_default = *default == parse_quote!(::core::default::Default::default()); + // If this is a signal type, we use super_into and the props struct as the owner + let is_child_owned_type = child_owned_type(field.ty); + let mut into = quote!{}; if !is_default { - if field.builder_attr.auto_into { + if is_child_owned_type { + into = quote!{ .super_into() } + } else if field.builder_attr.auto_into { into = quote!{ .into() } } else if field.builder_attr.auto_to_string { into = quote!{ .to_string() } @@ -1428,6 +1433,8 @@ Finally, call `.build()` to create the instance of `{name}`. if field.builder_attr.skip { quote!(let #name = #default #into;) + } else if is_child_owned_type { + quote!(let #name = #helper_trait_name::into_value(#name, || with_owner(self.owner.clone(), move || (#default) #into));) } else { quote!(let #name = #helper_trait_name::into_value(#name, || #default #into);) } diff --git a/packages/core-macro/tests/rsx.rs b/packages/core-macro/tests/rsx.rs index 5f6eaadd8..2246534be 100644 --- a/packages/core-macro/tests/rsx.rs +++ b/packages/core-macro/tests/rsx.rs @@ -49,8 +49,50 @@ mod test_default_into { pub some_data: bool, pub some_other_data: bool, + + // Test default values for signals + #[props(default)] + read_only_w_default: ReadOnlySignal, + + #[props(default = true)] + read_only_w_default_val: ReadOnlySignal, + + #[props(default = ReadOnlySignal::new(Signal::new(true)))] + read_only_w_default_val_explicit: ReadOnlySignal, + + // Test default values for callbacks/event handlers + #[props(default)] + callback_w_default: Callback, + + #[props(default = move |_| {})] + callback_w_default_val_closure: Callback, + + #[props(default = { + fn test(_: ()) {} + test + })] + callback_w_default_val_expr_fn: Callback, + + #[props(default = Callback::new(move |_: ()| {}))] + callback_w_default_val_explicit: Callback, + + #[props(default)] + event_handler_w_default: EventHandler, + + #[props(default = move |_| {})] + event_handler_w_default_val_closure: EventHandler, + + #[props(default = { + fn test(_: KeyboardEvent) {} + test + })] + event_handler_w_default_val_expr_fn: EventHandler, + + #[props(default = EventHandler::new(move |_: KeyboardEvent| {}))] + event_handler_w_default_val_explicit: EventHandler, } } + /// This test ensures that read-only signals that contain an option (`Signal>`) /// are correctly created as default when not provided. ///