From 8b51fdc17b56d6ef9d97f0214c9fd60c6d536082 Mon Sep 17 00:00:00 2001 From: rorychatt Date: Thu, 16 Apr 2026 17:11:42 +0200 Subject: [PATCH] [00238] Add footer_mut() to WidgetData trait for Card and Dialog footer ID assignment --- rusty/src/views/view.rs | 57 +++++++++++++++++++++++++++++++++++++ rusty/src/widgets/card.rs | 4 +++ rusty/src/widgets/dialog.rs | 4 +++ 3 files changed, 65 insertions(+) diff --git a/rusty/src/views/view.rs b/rusty/src/views/view.rs index b42e588..b0ce575 100644 --- a/rusty/src/views/view.rs +++ b/rusty/src/views/view.rs @@ -60,6 +60,12 @@ pub trait WidgetData: Send + Sync + Debug + 'static { fn single_child_mut(&mut self) -> Option<&mut Element> { None } + + /// Return mutable references to footer elements for recursive tree walking. + /// Card and Dialog override this. + fn footer_mut(&mut self) -> Option<&mut Vec> { + None + } } impl Clone for Box { @@ -103,6 +109,11 @@ impl Element { if let Some(child) = widget.single_child_mut() { child.assign_ids(ctx); } + if let Some(footer) = widget.footer_mut() { + for child in footer { + child.assign_ids(ctx); + } + } } Element::Fragment(children) => { for child in children { @@ -572,4 +583,50 @@ mod tests { "on_click handler should have fired" ); } + + #[test] + fn test_assign_ids_recurses_into_card_footer() { + let mut store = HookStore::default(); + let mut ctx = BuildContext::new(&mut store, None); + + let mut element: Element = Card::new() + .footer(vec![Button::new("Footer action").into()]) + .into(); + + element.assign_ids(&mut ctx); + + if let Element::Widget(card) = &element { + assert_eq!(card.get_id(), Some("w-0")); + if let Some(footer) = card.to_json().get("footer") { + let footer_arr = footer.as_array().unwrap(); + let btn_id = footer_arr[0]["id"].as_str().unwrap(); + assert_eq!(btn_id, "w-1"); + } else { + panic!("Expected Card to have a footer"); + } + } + } + + #[test] + fn test_assign_ids_recurses_into_dialog_footer() { + let mut store = HookStore::default(); + let mut ctx = BuildContext::new(&mut store, None); + + let mut element: Element = Dialog::new(true) + .footer(vec![Button::new("OK").into()]) + .into(); + + element.assign_ids(&mut ctx); + + if let Element::Widget(dialog) = &element { + assert_eq!(dialog.get_id(), Some("w-0")); + if let Some(footer) = dialog.to_json().get("footer") { + let footer_arr = footer.as_array().unwrap(); + let btn_id = footer_arr[0]["id"].as_str().unwrap(); + assert_eq!(btn_id, "w-1"); + } else { + panic!("Expected Dialog to have a footer"); + } + } + } } diff --git a/rusty/src/widgets/card.rs b/rusty/src/widgets/card.rs index f7a973c..3674a8a 100644 --- a/rusty/src/widgets/card.rs +++ b/rusty/src/widgets/card.rs @@ -109,6 +109,10 @@ impl WidgetData for Card { fn children_mut(&mut self) -> Option<&mut Vec> { Some(&mut self.children) } + + fn footer_mut(&mut self) -> Option<&mut Vec> { + self.footer.as_mut() + } } impl From for Element { diff --git a/rusty/src/widgets/dialog.rs b/rusty/src/widgets/dialog.rs index f9303ba..086de17 100644 --- a/rusty/src/widgets/dialog.rs +++ b/rusty/src/widgets/dialog.rs @@ -88,6 +88,10 @@ impl WidgetData for Dialog { fn children_mut(&mut self) -> Option<&mut Vec> { Some(&mut self.children) } + + fn footer_mut(&mut self) -> Option<&mut Vec> { + self.footer.as_mut() + } } impl From for Element {