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