label.rs

  1use crate::{LabelLike, prelude::*};
  2use gpui::StyleRefinement;
  3
  4/// A struct representing a label element in the UI.
  5///
  6/// The `Label` struct stores the label text and common properties for a label element.
  7/// It provides methods for modifying these properties.
  8///
  9/// # Examples
 10///
 11/// ```
 12/// use ui::prelude::*;
 13///
 14/// Label::new("Hello, World!");
 15/// ```
 16///
 17/// **A colored label**, for example labeling a dangerous action:
 18///
 19/// ```
 20/// use ui::prelude::*;
 21///
 22/// let my_label = Label::new("Delete").color(Color::Error);
 23/// ```
 24///
 25/// **A label with a strikethrough**, for example labeling something that has been deleted:
 26///
 27/// ```
 28/// use ui::prelude::*;
 29///
 30/// let my_label = Label::new("Deleted").strikethrough();
 31/// ```
 32#[derive(IntoElement, RegisterComponent)]
 33pub struct Label {
 34    base: LabelLike,
 35    label: SharedString,
 36}
 37
 38impl Label {
 39    /// Creates a new [`Label`] with the given text.
 40    ///
 41    /// # Examples
 42    ///
 43    /// ```
 44    /// use ui::prelude::*;
 45    ///
 46    /// let my_label = Label::new("Hello, World!");
 47    /// ```
 48    pub fn new(label: impl Into<SharedString>) -> Self {
 49        Self {
 50            base: LabelLike::new(),
 51            label: label.into(),
 52        }
 53    }
 54
 55    /// Sets the text of the [`Label`].
 56    pub fn set_text(&mut self, text: impl Into<SharedString>) {
 57        self.label = text.into();
 58    }
 59
 60    /// Truncates the label from the start, keeping the end visible.
 61    pub fn truncate_start(mut self) -> Self {
 62        self.base = self.base.truncate_start();
 63        self
 64    }
 65}
 66
 67// Style methods.
 68impl Label {
 69    fn style(&mut self) -> &mut StyleRefinement {
 70        self.base.base.style()
 71    }
 72
 73    gpui::margin_style_methods!({
 74        visibility: pub
 75    });
 76}
 77
 78impl LabelCommon for Label {
 79    /// Sets the size of the label using a [`LabelSize`].
 80    ///
 81    /// # Examples
 82    ///
 83    /// ```
 84    /// use ui::prelude::*;
 85    ///
 86    /// let my_label = Label::new("Hello, World!").size(LabelSize::Small);
 87    /// ```
 88    fn size(mut self, size: LabelSize) -> Self {
 89        self.base = self.base.size(size);
 90        self
 91    }
 92
 93    /// Sets the weight of the label using a [`FontWeight`].
 94    ///
 95    /// # Examples
 96    ///
 97    /// ```
 98    /// use gpui::FontWeight;
 99    /// use ui::prelude::*;
100    ///
101    /// let my_label = Label::new("Hello, World!").weight(FontWeight::BOLD);
102    /// ```
103    fn weight(mut self, weight: gpui::FontWeight) -> Self {
104        self.base = self.base.weight(weight);
105        self
106    }
107
108    /// Sets the line height style of the label using a [`LineHeightStyle`].
109    ///
110    /// # Examples
111    ///
112    /// ```
113    /// use ui::prelude::*;
114    ///
115    /// let my_label = Label::new("Hello, World!").line_height_style(LineHeightStyle::UiLabel);
116    /// ```
117    fn line_height_style(mut self, line_height_style: LineHeightStyle) -> Self {
118        self.base = self.base.line_height_style(line_height_style);
119        self
120    }
121
122    /// Sets the color of the label using a [`Color`].
123    ///
124    /// # Examples
125    ///
126    /// ```
127    /// use ui::prelude::*;
128    ///
129    /// let my_label = Label::new("Hello, World!").color(Color::Accent);
130    /// ```
131    fn color(mut self, color: Color) -> Self {
132        self.base = self.base.color(color);
133        self
134    }
135
136    /// Sets the strikethrough property of the label.
137    ///
138    /// # Examples
139    ///
140    /// ```
141    /// use ui::prelude::*;
142    ///
143    /// let my_label = Label::new("Hello, World!").strikethrough();
144    /// ```
145    fn strikethrough(mut self) -> Self {
146        self.base = self.base.strikethrough();
147        self
148    }
149
150    /// Sets the italic property of the label.
151    ///
152    /// # Examples
153    ///
154    /// ```
155    /// use ui::prelude::*;
156    ///
157    /// let my_label = Label::new("Hello, World!").italic();
158    /// ```
159    fn italic(mut self) -> Self {
160        self.base = self.base.italic();
161        self
162    }
163
164    /// Sets the alpha property of the color of label.
165    ///
166    /// # Examples
167    ///
168    /// ```
169    /// use ui::prelude::*;
170    ///
171    /// let my_label = Label::new("Hello, World!").alpha(0.5);
172    /// ```
173    fn alpha(mut self, alpha: f32) -> Self {
174        self.base = self.base.alpha(alpha);
175        self
176    }
177
178    fn underline(mut self) -> Self {
179        self.base = self.base.underline();
180        self
181    }
182
183    /// Truncates overflowing text with an ellipsis (`…`) if needed.
184    fn truncate(mut self) -> Self {
185        self.base = self.base.truncate();
186        self
187    }
188
189    fn single_line(mut self) -> Self {
190        self.label = SharedString::from(self.label.replace('\n', ""));
191        self.base = self.base.single_line();
192        self
193    }
194
195    fn buffer_font(mut self, cx: &App) -> Self {
196        self.base = self.base.buffer_font(cx);
197        self
198    }
199
200    /// Styles the label to look like inline code.
201    fn inline_code(mut self, cx: &App) -> Self {
202        self.base = self.base.inline_code(cx);
203        self
204    }
205}
206
207impl RenderOnce for Label {
208    fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
209        self.base.child(self.label)
210    }
211}
212
213impl Component for Label {
214    fn scope() -> ComponentScope {
215        ComponentScope::Typography
216    }
217
218    fn description() -> Option<&'static str> {
219        Some("A text label component that supports various styles, sizes, and formatting options.")
220    }
221
222    fn preview(_window: &mut Window, cx: &mut App) -> Option<AnyElement> {
223        Some(
224            v_flex()
225                .gap_6()
226                .children(vec![
227                    example_group_with_title(
228                        "Sizes",
229                        vec![
230                            single_example("Default", Label::new("Project Explorer").into_any_element()),
231                            single_example("Small", Label::new("File: main.rs").size(LabelSize::Small).into_any_element()),
232                            single_example("Large", Label::new("Welcome to Zed").size(LabelSize::Large).into_any_element()),
233                        ],
234                    ),
235                    example_group_with_title(
236                        "Colors",
237                        vec![
238                            single_example("Default", Label::new("Status: Ready").into_any_element()),
239                            single_example("Accent", Label::new("New Update Available").color(Color::Accent).into_any_element()),
240                            single_example("Error", Label::new("Build Failed").color(Color::Error).into_any_element()),
241                        ],
242                    ),
243                    example_group_with_title(
244                        "Styles",
245                        vec![
246                            single_example("Default", Label::new("Normal Text").into_any_element()),
247                            single_example("Bold", Label::new("Important Notice").weight(gpui::FontWeight::BOLD).into_any_element()),
248                            single_example("Italic", Label::new("Code Comment").italic().into_any_element()),
249                            single_example("Strikethrough", Label::new("Deprecated Feature").strikethrough().into_any_element()),
250                            single_example("Underline", Label::new("Clickable Link").underline().into_any_element()),
251                            single_example("Inline Code", Label::new("fn main() {}").inline_code(cx).into_any_element()),
252                        ],
253                    ),
254                    example_group_with_title(
255                        "Line Height Styles",
256                        vec![
257                            single_example("Default", Label::new("Multi-line\nText\nExample").into_any_element()),
258                            single_example("UI Label", Label::new("Compact\nUI\nLabel").line_height_style(LineHeightStyle::UiLabel).into_any_element()),
259                        ],
260                    ),
261                    example_group_with_title(
262                        "Special Cases",
263                        vec![
264                            single_example("Single Line", Label::new("Line 1\nLine 2\nLine 3").single_line().into_any_element()),
265                            single_example("Regular Truncation", div().max_w_24().child(Label::new("This is a very long file name that should be truncated: very_long_file_name_with_many_words.rs").truncate()).into_any_element()),
266                            single_example("Start Truncation", div().max_w_24().child(Label::new("zed/crates/ui/src/components/label/truncate/label/label.rs").truncate_start()).into_any_element()),
267                        ],
268                    ),
269                ])
270                .into_any_element()
271        )
272    }
273}