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    pub fn flex_1(mut self) -> Self {
 78        self.style().flex_grow = Some(1.);
 79        self.style().flex_shrink = Some(1.);
 80        self.style().flex_basis = Some(gpui::relative(0.).into());
 81        self
 82    }
 83
 84    pub fn flex_none(mut self) -> Self {
 85        self.style().flex_grow = Some(0.);
 86        self.style().flex_shrink = Some(0.);
 87        self
 88    }
 89
 90    pub fn flex_grow(mut self) -> Self {
 91        self.style().flex_grow = Some(1.);
 92        self
 93    }
 94
 95    pub fn flex_shrink(mut self) -> Self {
 96        self.style().flex_shrink = Some(1.);
 97        self
 98    }
 99
100    pub fn flex_shrink_0(mut self) -> Self {
101        self.style().flex_shrink = Some(0.);
102        self
103    }
104}
105
106impl LabelCommon for Label {
107    /// Sets the size of the label using a [`LabelSize`].
108    ///
109    /// # Examples
110    ///
111    /// ```
112    /// use ui::prelude::*;
113    ///
114    /// let my_label = Label::new("Hello, World!").size(LabelSize::Small);
115    /// ```
116    fn size(mut self, size: LabelSize) -> Self {
117        self.base = self.base.size(size);
118        self
119    }
120
121    /// Sets the weight of the label using a [`FontWeight`].
122    ///
123    /// # Examples
124    ///
125    /// ```
126    /// use gpui::FontWeight;
127    /// use ui::prelude::*;
128    ///
129    /// let my_label = Label::new("Hello, World!").weight(FontWeight::BOLD);
130    /// ```
131    fn weight(mut self, weight: gpui::FontWeight) -> Self {
132        self.base = self.base.weight(weight);
133        self
134    }
135
136    /// Sets the line height style of the label using a [`LineHeightStyle`].
137    ///
138    /// # Examples
139    ///
140    /// ```
141    /// use ui::prelude::*;
142    ///
143    /// let my_label = Label::new("Hello, World!").line_height_style(LineHeightStyle::UiLabel);
144    /// ```
145    fn line_height_style(mut self, line_height_style: LineHeightStyle) -> Self {
146        self.base = self.base.line_height_style(line_height_style);
147        self
148    }
149
150    /// Sets the color of the label using a [`Color`].
151    ///
152    /// # Examples
153    ///
154    /// ```
155    /// use ui::prelude::*;
156    ///
157    /// let my_label = Label::new("Hello, World!").color(Color::Accent);
158    /// ```
159    fn color(mut self, color: Color) -> Self {
160        self.base = self.base.color(color);
161        self
162    }
163
164    /// Sets the strikethrough property of the label.
165    ///
166    /// # Examples
167    ///
168    /// ```
169    /// use ui::prelude::*;
170    ///
171    /// let my_label = Label::new("Hello, World!").strikethrough();
172    /// ```
173    fn strikethrough(mut self) -> Self {
174        self.base = self.base.strikethrough();
175        self
176    }
177
178    /// Sets the italic property of the label.
179    ///
180    /// # Examples
181    ///
182    /// ```
183    /// use ui::prelude::*;
184    ///
185    /// let my_label = Label::new("Hello, World!").italic();
186    /// ```
187    fn italic(mut self) -> Self {
188        self.base = self.base.italic();
189        self
190    }
191
192    /// Sets the alpha property of the color of label.
193    ///
194    /// # Examples
195    ///
196    /// ```
197    /// use ui::prelude::*;
198    ///
199    /// let my_label = Label::new("Hello, World!").alpha(0.5);
200    /// ```
201    fn alpha(mut self, alpha: f32) -> Self {
202        self.base = self.base.alpha(alpha);
203        self
204    }
205
206    fn underline(mut self) -> Self {
207        self.base = self.base.underline();
208        self
209    }
210
211    /// Truncates overflowing text with an ellipsis (`…`) if needed.
212    fn truncate(mut self) -> Self {
213        self.base = self.base.truncate();
214        self
215    }
216
217    fn single_line(mut self) -> Self {
218        self.label = SharedString::from(self.label.replace('\n', ""));
219        self.base = self.base.single_line();
220        self
221    }
222
223    fn buffer_font(mut self, cx: &App) -> Self {
224        self.base = self.base.buffer_font(cx);
225        self
226    }
227
228    /// Styles the label to look like inline code.
229    fn inline_code(mut self, cx: &App) -> Self {
230        self.base = self.base.inline_code(cx);
231        self
232    }
233}
234
235impl RenderOnce for Label {
236    fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
237        self.base.child(self.label)
238    }
239}
240
241impl Component for Label {
242    fn scope() -> ComponentScope {
243        ComponentScope::Typography
244    }
245
246    fn description() -> Option<&'static str> {
247        Some("A text label component that supports various styles, sizes, and formatting options.")
248    }
249
250    fn preview(_window: &mut Window, cx: &mut App) -> Option<AnyElement> {
251        Some(
252            v_flex()
253                .gap_6()
254                .children(vec![
255                    example_group_with_title(
256                        "Sizes",
257                        vec![
258                            single_example("Default", Label::new("Project Explorer").into_any_element()),
259                            single_example("Small", Label::new("File: main.rs").size(LabelSize::Small).into_any_element()),
260                            single_example("Large", Label::new("Welcome to Zed").size(LabelSize::Large).into_any_element()),
261                        ],
262                    ),
263                    example_group_with_title(
264                        "Colors",
265                        vec![
266                            single_example("Default", Label::new("Status: Ready").into_any_element()),
267                            single_example("Accent", Label::new("New Update Available").color(Color::Accent).into_any_element()),
268                            single_example("Error", Label::new("Build Failed").color(Color::Error).into_any_element()),
269                        ],
270                    ),
271                    example_group_with_title(
272                        "Styles",
273                        vec![
274                            single_example("Default", Label::new("Normal Text").into_any_element()),
275                            single_example("Bold", Label::new("Important Notice").weight(gpui::FontWeight::BOLD).into_any_element()),
276                            single_example("Italic", Label::new("Code Comment").italic().into_any_element()),
277                            single_example("Strikethrough", Label::new("Deprecated Feature").strikethrough().into_any_element()),
278                            single_example("Underline", Label::new("Clickable Link").underline().into_any_element()),
279                            single_example("Inline Code", Label::new("fn main() {}").inline_code(cx).into_any_element()),
280                        ],
281                    ),
282                    example_group_with_title(
283                        "Line Height Styles",
284                        vec![
285                            single_example("Default", Label::new("Multi-line\nText\nExample").into_any_element()),
286                            single_example("UI Label", Label::new("Compact\nUI\nLabel").line_height_style(LineHeightStyle::UiLabel).into_any_element()),
287                        ],
288                    ),
289                    example_group_with_title(
290                        "Special Cases",
291                        vec![
292                            single_example("Single Line", Label::new("Line 1\nLine 2\nLine 3").single_line().into_any_element()),
293                            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()),
294                            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()),
295                        ],
296                    ),
297                ])
298                .into_any_element()
299        )
300    }
301}