ui: Fix wrapping in the banner component (#34516)

Danilo Leal created

Also removing the `icon` field as the banner component always renders
with an icon anyway. Hopefully, this fixes any weird text wrapping that
was happening before.

Release Notes:

- N/A

Change summary

crates/ui/src/components/banner.rs | 51 ++++++++++++++-----------------
1 file changed, 23 insertions(+), 28 deletions(-)

Detailed changes

crates/ui/src/components/banner.rs 🔗

@@ -19,8 +19,8 @@ pub enum Severity {
 /// use ui::{Banner};
 ///
 ///    Banner::new()
-///     .severity(Severity::Info)
-///     .children(Label::new("This is an informational message"))
+///     .severity(Severity::Success)
+///     .children(Label::new("This is a success message"))
 ///     .action_slot(
 ///         Button::new("learn-more", "Learn More")
 ///             .icon(IconName::ArrowUpRight)
@@ -32,7 +32,6 @@ pub enum Severity {
 pub struct Banner {
     severity: Severity,
     children: Vec<AnyElement>,
-    icon: Option<(IconName, Option<Color>)>,
     action_slot: Option<AnyElement>,
 }
 
@@ -42,7 +41,6 @@ impl Banner {
         Self {
             severity: Severity::Info,
             children: Vec::new(),
-            icon: None,
             action_slot: None,
         }
     }
@@ -53,12 +51,6 @@ impl Banner {
         self
     }
 
-    /// Sets an icon to display in the banner with an optional color.
-    pub fn icon(mut self, icon: IconName, color: Option<impl Into<Color>>) -> Self {
-        self.icon = Some((icon, color.map(|c| c.into())));
-        self
-    }
-
     /// A slot for actions, such as CTA or dismissal buttons.
     pub fn action_slot(mut self, element: impl IntoElement) -> Self {
         self.action_slot = Some(element.into_any_element());
@@ -73,12 +65,13 @@ impl ParentElement for Banner {
 }
 
 impl RenderOnce for Banner {
-    fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
-        let base = h_flex()
+    fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
+        let banner = h_flex()
             .py_0p5()
-            .rounded_sm()
+            .gap_1p5()
             .flex_wrap()
             .justify_between()
+            .rounded_sm()
             .border_1();
 
         let (icon, icon_color, bg_color, border_color) = match self.severity {
@@ -108,29 +101,31 @@ impl RenderOnce for Banner {
             ),
         };
 
-        let mut container = base.bg(bg_color).border_color(border_color);
-
-        let mut content_area = h_flex().id("content_area").gap_1p5().overflow_x_scroll();
-
-        if self.icon.is_none() {
-            content_area =
-                content_area.child(Icon::new(icon).size(IconSize::XSmall).color(icon_color));
-        }
+        let mut banner = banner.bg(bg_color).border_color(border_color);
 
-        content_area = content_area.children(self.children);
+        let icon_and_child = h_flex()
+            .items_start()
+            .min_w_0()
+            .gap_1p5()
+            .child(
+                h_flex()
+                    .h(window.line_height())
+                    .flex_shrink_0()
+                    .child(Icon::new(icon).size(IconSize::XSmall).color(icon_color)),
+            )
+            .child(div().min_w_0().children(self.children));
 
         if let Some(action_slot) = self.action_slot {
-            container = container
+            banner = banner
                 .pl_2()
-                .pr_0p5()
-                .gap_2()
-                .child(content_area)
+                .pr_1()
+                .child(icon_and_child)
                 .child(action_slot);
         } else {
-            container = container.px_2().child(div().w_full().child(content_area));
+            banner = banner.px_2().child(icon_and_child);
         }
 
-        container
+        banner
     }
 }