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}