ui: Add `text_ellipsis` method to `Label`s (#22118)

Marshall Bowers created

This PR adds a `text_ellipsis` method to `Label`s.

This can be used to truncate the text with an ellipsis without needing
to wrap the `Label` in another element.

Release Notes:

- N/A

Change summary

crates/assistant/src/slash_command_picker.rs        |  9 -
crates/extensions_ui/src/extensions_ui.rs           | 64 +++++++-------
crates/ui/src/components/label/highlighted_label.rs |  5 +
crates/ui/src/components/label/label.rs             |  5 +
crates/ui/src/components/label/label_like.rs        | 13 +++
5 files changed, 57 insertions(+), 39 deletions(-)

Detailed changes

crates/assistant/src/slash_command_picker.rs 🔗

@@ -217,11 +217,10 @@ impl PickerDelegate for SlashCommandDelegate {
                                     )),
                             )
                             .child(
-                                div().overflow_hidden().text_ellipsis().child(
-                                    Label::new(info.description.clone())
-                                        .size(LabelSize::Small)
-                                        .color(Color::Muted),
-                                ),
+                                Label::new(info.description.clone())
+                                    .size(LabelSize::Small)
+                                    .color(Color::Muted)
+                                    .text_ellipsis(),
                             ),
                     ),
             ),

crates/extensions_ui/src/extensions_ui.rs 🔗

@@ -449,18 +449,17 @@ impl ExtensionsPage {
                     .gap_2()
                     .justify_between()
                     .child(
-                        div().overflow_x_hidden().text_ellipsis().child(
-                            Label::new(format!(
-                                "{}: {}",
-                                if extension.authors.len() > 1 {
-                                    "Authors"
-                                } else {
-                                    "Author"
-                                },
-                                extension.authors.join(", ")
-                            ))
-                            .size(LabelSize::Small),
-                        ),
+                        Label::new(format!(
+                            "{}: {}",
+                            if extension.authors.len() > 1 {
+                                "Authors"
+                            } else {
+                                "Author"
+                            },
+                            extension.authors.join(", ")
+                        ))
+                        .size(LabelSize::Small)
+                        .text_ellipsis(),
                     )
                     .child(Label::new("<>").size(LabelSize::Small)),
             )
@@ -469,11 +468,10 @@ impl ExtensionsPage {
                     .gap_2()
                     .justify_between()
                     .children(extension.description.as_ref().map(|description| {
-                        div().overflow_x_hidden().text_ellipsis().child(
-                            Label::new(description.clone())
-                                .size(LabelSize::Small)
-                                .color(Color::Default),
-                        )
+                        Label::new(description.clone())
+                            .size(LabelSize::Small)
+                            .color(Color::Default)
+                            .text_ellipsis()
                     }))
                     .children(repository_url.map(|repository_url| {
                         IconButton::new(
@@ -550,18 +548,17 @@ impl ExtensionsPage {
                     .gap_2()
                     .justify_between()
                     .child(
-                        div().overflow_x_hidden().text_ellipsis().child(
-                            Label::new(format!(
-                                "{}: {}",
-                                if extension.manifest.authors.len() > 1 {
-                                    "Authors"
-                                } else {
-                                    "Author"
-                                },
-                                extension.manifest.authors.join(", ")
-                            ))
-                            .size(LabelSize::Small),
-                        ),
+                        Label::new(format!(
+                            "{}: {}",
+                            if extension.manifest.authors.len() > 1 {
+                                "Authors"
+                            } else {
+                                "Author"
+                            },
+                            extension.manifest.authors.join(", ")
+                        ))
+                        .size(LabelSize::Small)
+                        .text_ellipsis(),
                     )
                     .child(
                         Label::new(format!(
@@ -576,11 +573,10 @@ impl ExtensionsPage {
                     .gap_2()
                     .justify_between()
                     .children(extension.manifest.description.as_ref().map(|description| {
-                        div().overflow_x_hidden().text_ellipsis().child(
-                            Label::new(description.clone())
-                                .size(LabelSize::Small)
-                                .color(Color::Default),
-                        )
+                        Label::new(description.clone())
+                            .size(LabelSize::Small)
+                            .color(Color::Default)
+                            .text_ellipsis()
                     }))
                     .child(
                         h_flex()

crates/ui/src/components/label/highlighted_label.rs 🔗

@@ -66,6 +66,11 @@ impl LabelCommon for HighlightedLabel {
         self
     }
 
+    fn text_ellipsis(mut self) -> Self {
+        self.base = self.base.text_ellipsis();
+        self
+    }
+
     fn single_line(mut self) -> Self {
         self.base = self.base.single_line();
         self

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

@@ -164,6 +164,11 @@ impl LabelCommon for Label {
         self
     }
 
+    fn text_ellipsis(mut self) -> Self {
+        self.base = self.base.text_ellipsis();
+        self
+    }
+
     fn single_line(mut self) -> Self {
         self.single_line = true;
         self.base = self.base.single_line();

crates/ui/src/components/label/label_like.rs 🔗

@@ -50,6 +50,9 @@ pub trait LabelCommon {
     /// Sets the alpha property of the label, overwriting the alpha value of the color.
     fn alpha(self, alpha: f32) -> Self;
 
+    /// Truncates overflowing text with an ellipsis (`…`) if needed.
+    fn text_ellipsis(self) -> Self;
+
     /// Sets the label to render as a single line.
     fn single_line(self) -> Self;
 }
@@ -67,6 +70,7 @@ pub struct LabelLike {
     alpha: Option<f32>,
     underline: bool,
     single_line: bool,
+    text_ellipsis: bool,
 }
 
 impl Default for LabelLike {
@@ -89,6 +93,7 @@ impl LabelLike {
             alpha: None,
             underline: false,
             single_line: false,
+            text_ellipsis: false,
         }
     }
 }
@@ -145,6 +150,11 @@ impl LabelCommon for LabelLike {
         self
     }
 
+    fn text_ellipsis(mut self) -> Self {
+        self.text_ellipsis = true;
+        self
+    }
+
     fn single_line(mut self) -> Self {
         self.single_line = true;
         self
@@ -189,6 +199,9 @@ impl RenderOnce for LabelLike {
             })
             .when(self.strikethrough, |this| this.line_through())
             .when(self.single_line, |this| this.whitespace_nowrap())
+            .when(self.text_ellipsis, |this| {
+                this.overflow_x_hidden().text_ellipsis()
+            })
             .text_color(color)
             .font_weight(self.weight.unwrap_or(settings.ui_font.weight))
             .children(self.children)