1use crate::TextStyleRefinement;
2use crate::{
3 self as gpui, px, relative, rems, AbsoluteLength, AlignItems, CursorStyle, DefiniteLength,
4 Fill, FlexDirection, FlexWrap, Font, FontStyle, FontWeight, Hsla, JustifyContent, Length,
5 SharedString, StrikethroughStyle, StyleRefinement, TextOverflow, WhiteSpace,
6};
7pub use gpui_macros::{
8 border_style_methods, box_shadow_style_methods, cursor_style_methods, margin_style_methods,
9 overflow_style_methods, padding_style_methods, position_style_methods,
10 visibility_style_methods,
11};
12use taffy::style::{AlignContent, Display};
13
14const ELLIPSIS: &str = "…";
15
16/// A trait for elements that can be styled.
17/// Use this to opt-in to a utility CSS-like styling API.
18pub trait Styled: Sized {
19 /// Returns a reference to the style memory of this element.
20 fn style(&mut self) -> &mut StyleRefinement;
21
22 gpui_macros::style_helpers!();
23 gpui_macros::visibility_style_methods!();
24 gpui_macros::margin_style_methods!();
25 gpui_macros::padding_style_methods!();
26 gpui_macros::position_style_methods!();
27 gpui_macros::overflow_style_methods!();
28 gpui_macros::cursor_style_methods!();
29 gpui_macros::border_style_methods!();
30 gpui_macros::box_shadow_style_methods!();
31
32 /// Sets the display type of the element to `block`.
33 /// [Docs](https://tailwindcss.com/docs/display)
34 fn block(mut self) -> Self {
35 self.style().display = Some(Display::Block);
36 self
37 }
38
39 /// Sets the display type of the element to `flex`.
40 /// [Docs](https://tailwindcss.com/docs/display)
41 fn flex(mut self) -> Self {
42 self.style().display = Some(Display::Flex);
43 self
44 }
45
46 /// Sets the whitespace of the element to `normal`.
47 /// [Docs](https://tailwindcss.com/docs/whitespace#normal)
48 fn whitespace_normal(mut self) -> Self {
49 self.text_style()
50 .get_or_insert_with(Default::default)
51 .white_space = Some(WhiteSpace::Normal);
52 self
53 }
54
55 /// Sets the whitespace of the element to `nowrap`.
56 /// [Docs](https://tailwindcss.com/docs/whitespace#nowrap)
57 fn whitespace_nowrap(mut self) -> Self {
58 self.text_style()
59 .get_or_insert_with(Default::default)
60 .white_space = Some(WhiteSpace::Nowrap);
61 self
62 }
63
64 /// Sets the truncate overflowing text with an ellipsis (…) if needed.
65 /// [Docs](https://tailwindcss.com/docs/text-overflow#ellipsis)
66 fn text_ellipsis(mut self) -> Self {
67 self.text_style()
68 .get_or_insert_with(Default::default)
69 .text_overflow = Some(TextOverflow::Ellipsis(ELLIPSIS));
70 self
71 }
72
73 /// Sets the text overflow behavior of the element.
74 fn text_overflow(mut self, overflow: TextOverflow) -> Self {
75 self.text_style()
76 .get_or_insert_with(Default::default)
77 .text_overflow = Some(overflow);
78 self
79 }
80
81 /// Sets the truncate to prevent text from wrapping and truncate overflowing text with an ellipsis (…) if needed.
82 /// [Docs](https://tailwindcss.com/docs/text-overflow#truncate)
83 fn truncate(mut self) -> Self {
84 self.overflow_hidden().whitespace_nowrap().text_ellipsis()
85 }
86
87 /// Sets number of lines to show before truncating the text.
88 /// [Docs](https://tailwindcss.com/docs/line-clamp)
89 fn line_clamp(mut self, lines: usize) -> Self {
90 let mut text_style = self.text_style().get_or_insert_with(Default::default);
91 text_style.line_clamp = Some(lines);
92 self.overflow_hidden()
93 }
94
95 /// Sets the flex direction of the element to `column`.
96 /// [Docs](https://tailwindcss.com/docs/flex-direction#column)
97 fn flex_col(mut self) -> Self {
98 self.style().flex_direction = Some(FlexDirection::Column);
99 self
100 }
101
102 /// Sets the flex direction of the element to `column-reverse`.
103 /// [Docs](https://tailwindcss.com/docs/flex-direction#column-reverse)
104 fn flex_col_reverse(mut self) -> Self {
105 self.style().flex_direction = Some(FlexDirection::ColumnReverse);
106 self
107 }
108
109 /// Sets the flex direction of the element to `row`.
110 /// [Docs](https://tailwindcss.com/docs/flex-direction#row)
111 fn flex_row(mut self) -> Self {
112 self.style().flex_direction = Some(FlexDirection::Row);
113 self
114 }
115
116 /// Sets the flex direction of the element to `row-reverse`.
117 /// [Docs](https://tailwindcss.com/docs/flex-direction#row-reverse)
118 fn flex_row_reverse(mut self) -> Self {
119 self.style().flex_direction = Some(FlexDirection::RowReverse);
120 self
121 }
122
123 /// Sets the element to allow a flex item to grow and shrink as needed, ignoring its initial size.
124 /// [Docs](https://tailwindcss.com/docs/flex#flex-1)
125 fn flex_1(mut self) -> Self {
126 self.style().flex_grow = Some(1.);
127 self.style().flex_shrink = Some(1.);
128 self.style().flex_basis = Some(relative(0.).into());
129 self
130 }
131
132 /// Sets the element to allow a flex item to grow and shrink, taking into account its initial size.
133 /// [Docs](https://tailwindcss.com/docs/flex#auto)
134 fn flex_auto(mut self) -> Self {
135 self.style().flex_grow = Some(1.);
136 self.style().flex_shrink = Some(1.);
137 self.style().flex_basis = Some(Length::Auto);
138 self
139 }
140
141 /// Sets the element to allow a flex item to shrink but not grow, taking into account its initial size.
142 /// [Docs](https://tailwindcss.com/docs/flex#initial)
143 fn flex_initial(mut self) -> Self {
144 self.style().flex_grow = Some(0.);
145 self.style().flex_shrink = Some(1.);
146 self.style().flex_basis = Some(Length::Auto);
147 self
148 }
149
150 /// Sets the element to prevent a flex item from growing or shrinking.
151 /// [Docs](https://tailwindcss.com/docs/flex#none)
152 fn flex_none(mut self) -> Self {
153 self.style().flex_grow = Some(0.);
154 self.style().flex_shrink = Some(0.);
155 self
156 }
157
158 /// Sets the initial size of flex items for this element.
159 /// [Docs](https://tailwindcss.com/docs/flex-basis)
160 fn flex_basis(mut self, basis: impl Into<Length>) -> Self {
161 self.style().flex_basis = Some(basis.into());
162 self
163 }
164
165 /// Sets the element to allow a flex item to grow to fill any available space.
166 /// [Docs](https://tailwindcss.com/docs/flex-grow)
167 fn flex_grow(mut self) -> Self {
168 self.style().flex_grow = Some(1.);
169 self
170 }
171
172 /// Sets the element to allow a flex item to shrink if needed.
173 /// [Docs](https://tailwindcss.com/docs/flex-shrink)
174 fn flex_shrink(mut self) -> Self {
175 self.style().flex_shrink = Some(1.);
176 self
177 }
178
179 /// Sets the element to prevent a flex item from shrinking.
180 /// [Docs](https://tailwindcss.com/docs/flex-shrink#dont-shrink)
181 fn flex_shrink_0(mut self) -> Self {
182 self.style().flex_shrink = Some(0.);
183 self
184 }
185
186 /// Sets the element to allow flex items to wrap.
187 /// [Docs](https://tailwindcss.com/docs/flex-wrap#wrap-normally)
188 fn flex_wrap(mut self) -> Self {
189 self.style().flex_wrap = Some(FlexWrap::Wrap);
190 self
191 }
192
193 /// Sets the element wrap flex items in the reverse direction.
194 /// [Docs](https://tailwindcss.com/docs/flex-wrap#wrap-reversed)
195 fn flex_wrap_reverse(mut self) -> Self {
196 self.style().flex_wrap = Some(FlexWrap::WrapReverse);
197 self
198 }
199
200 /// Sets the element to prevent flex items from wrapping, causing inflexible items to overflow the container if necessary.
201 /// [Docs](https://tailwindcss.com/docs/flex-wrap#dont-wrap)
202 fn flex_nowrap(mut self) -> Self {
203 self.style().flex_wrap = Some(FlexWrap::NoWrap);
204 self
205 }
206
207 /// Sets the element to align flex items to the start of the container's cross axis.
208 /// [Docs](https://tailwindcss.com/docs/align-items#start)
209 fn items_start(mut self) -> Self {
210 self.style().align_items = Some(AlignItems::FlexStart);
211 self
212 }
213
214 /// Sets the element to align flex items to the end of the container's cross axis.
215 /// [Docs](https://tailwindcss.com/docs/align-items#end)
216 fn items_end(mut self) -> Self {
217 self.style().align_items = Some(AlignItems::FlexEnd);
218 self
219 }
220
221 /// Sets the element to align flex items along the center of the container's cross axis.
222 /// [Docs](https://tailwindcss.com/docs/align-items#center)
223 fn items_center(mut self) -> Self {
224 self.style().align_items = Some(AlignItems::Center);
225 self
226 }
227
228 /// Sets the element to align flex items along the baseline of the container's cross axis.
229 /// [Docs](https://tailwindcss.com/docs/align-items#baseline)
230 fn items_baseline(mut self) -> Self {
231 self.style().align_items = Some(AlignItems::Baseline);
232 self
233 }
234
235 /// Sets the element to justify flex items against the start of the container's main axis.
236 /// [Docs](https://tailwindcss.com/docs/justify-content#start)
237 fn justify_start(mut self) -> Self {
238 self.style().justify_content = Some(JustifyContent::Start);
239 self
240 }
241
242 /// Sets the element to justify flex items against the end of the container's main axis.
243 /// [Docs](https://tailwindcss.com/docs/justify-content#end)
244 fn justify_end(mut self) -> Self {
245 self.style().justify_content = Some(JustifyContent::End);
246 self
247 }
248
249 /// Sets the element to justify flex items along the center of the container's main axis.
250 /// [Docs](https://tailwindcss.com/docs/justify-content#center)
251 fn justify_center(mut self) -> Self {
252 self.style().justify_content = Some(JustifyContent::Center);
253 self
254 }
255
256 /// Sets the element to justify flex items along the container's main axis
257 /// such that there is an equal amount of space between each item.
258 /// [Docs](https://tailwindcss.com/docs/justify-content#space-between)
259 fn justify_between(mut self) -> Self {
260 self.style().justify_content = Some(JustifyContent::SpaceBetween);
261 self
262 }
263
264 /// Sets the element to justify items along the container's main axis such
265 /// that there is an equal amount of space on each side of each item.
266 /// [Docs](https://tailwindcss.com/docs/justify-content#space-around)
267 fn justify_around(mut self) -> Self {
268 self.style().justify_content = Some(JustifyContent::SpaceAround);
269 self
270 }
271
272 /// Sets the element to pack content items in their default position as if no align-content value was set.
273 /// [Docs](https://tailwindcss.com/docs/align-content#normal)
274 fn content_normal(mut self) -> Self {
275 self.style().align_content = None;
276 self
277 }
278
279 /// Sets the element to pack content items in the center of the container's cross axis.
280 /// [Docs](https://tailwindcss.com/docs/align-content#center)
281 fn content_center(mut self) -> Self {
282 self.style().align_content = Some(AlignContent::Center);
283 self
284 }
285
286 /// Sets the element to pack content items against the start of the container's cross axis.
287 /// [Docs](https://tailwindcss.com/docs/align-content#start)
288 fn content_start(mut self) -> Self {
289 self.style().align_content = Some(AlignContent::FlexStart);
290 self
291 }
292
293 /// Sets the element to pack content items against the end of the container's cross axis.
294 /// [Docs](https://tailwindcss.com/docs/align-content#end)
295 fn content_end(mut self) -> Self {
296 self.style().align_content = Some(AlignContent::FlexEnd);
297 self
298 }
299
300 /// Sets the element to pack content items along the container's cross axis
301 /// such that there is an equal amount of space between each item.
302 /// [Docs](https://tailwindcss.com/docs/align-content#space-between)
303 fn content_between(mut self) -> Self {
304 self.style().align_content = Some(AlignContent::SpaceBetween);
305 self
306 }
307
308 /// Sets the element to pack content items along the container's cross axis
309 /// such that there is an equal amount of space on each side of each item.
310 /// [Docs](https://tailwindcss.com/docs/align-content#space-around)
311 fn content_around(mut self) -> Self {
312 self.style().align_content = Some(AlignContent::SpaceAround);
313 self
314 }
315
316 /// Sets the element to pack content items along the container's cross axis
317 /// such that there is an equal amount of space between each item.
318 /// [Docs](https://tailwindcss.com/docs/align-content#space-evenly)
319 fn content_evenly(mut self) -> Self {
320 self.style().align_content = Some(AlignContent::SpaceEvenly);
321 self
322 }
323
324 /// Sets the element to allow content items to fill the available space along the container's cross axis.
325 /// [Docs](https://tailwindcss.com/docs/align-content#stretch)
326 fn content_stretch(mut self) -> Self {
327 self.style().align_content = Some(AlignContent::Stretch);
328 self
329 }
330
331 /// Sets the background color of the element.
332 fn bg<F>(mut self, fill: F) -> Self
333 where
334 F: Into<Fill>,
335 Self: Sized,
336 {
337 self.style().background = Some(fill.into());
338 self
339 }
340
341 /// Returns a mutable reference to the text style that has been configured on this element.
342 fn text_style(&mut self) -> &mut Option<TextStyleRefinement> {
343 let style: &mut StyleRefinement = self.style();
344 &mut style.text
345 }
346
347 /// Sets the text color of this element.
348 ///
349 /// This value cascades to its child elements.
350 fn text_color(mut self, color: impl Into<Hsla>) -> Self {
351 self.text_style().get_or_insert_with(Default::default).color = Some(color.into());
352 self
353 }
354
355 /// Sets the font weight of this element
356 ///
357 /// This value cascades to its child elements.
358 fn font_weight(mut self, weight: FontWeight) -> Self {
359 self.text_style()
360 .get_or_insert_with(Default::default)
361 .font_weight = Some(weight);
362 self
363 }
364
365 /// Sets the background color of this element.
366 ///
367 /// This value cascades to its child elements.
368 fn text_bg(mut self, bg: impl Into<Hsla>) -> Self {
369 self.text_style()
370 .get_or_insert_with(Default::default)
371 .background_color = Some(bg.into());
372 self
373 }
374
375 /// Sets the text size of this element.
376 ///
377 /// This value cascades to its child elements.
378 fn text_size(mut self, size: impl Into<AbsoluteLength>) -> Self {
379 self.text_style()
380 .get_or_insert_with(Default::default)
381 .font_size = Some(size.into());
382 self
383 }
384
385 /// Sets the text size to 'extra small'.
386 /// [Docs](https://tailwindcss.com/docs/font-size#setting-the-font-size)
387 fn text_xs(mut self) -> Self {
388 self.text_style()
389 .get_or_insert_with(Default::default)
390 .font_size = Some(rems(0.75).into());
391 self
392 }
393
394 /// Sets the text size to 'small'.
395 /// [Docs](https://tailwindcss.com/docs/font-size#setting-the-font-size)
396 fn text_sm(mut self) -> Self {
397 self.text_style()
398 .get_or_insert_with(Default::default)
399 .font_size = Some(rems(0.875).into());
400 self
401 }
402
403 /// Sets the text size to 'base'.
404 /// [Docs](https://tailwindcss.com/docs/font-size#setting-the-font-size)
405 fn text_base(mut self) -> Self {
406 self.text_style()
407 .get_or_insert_with(Default::default)
408 .font_size = Some(rems(1.0).into());
409 self
410 }
411
412 /// Sets the text size to 'large'.
413 /// [Docs](https://tailwindcss.com/docs/font-size#setting-the-font-size)
414 fn text_lg(mut self) -> Self {
415 self.text_style()
416 .get_or_insert_with(Default::default)
417 .font_size = Some(rems(1.125).into());
418 self
419 }
420
421 /// Sets the text size to 'extra large'.
422 /// [Docs](https://tailwindcss.com/docs/font-size#setting-the-font-size)
423 fn text_xl(mut self) -> Self {
424 self.text_style()
425 .get_or_insert_with(Default::default)
426 .font_size = Some(rems(1.25).into());
427 self
428 }
429
430 /// Sets the text size to 'extra extra large'.
431 /// [Docs](https://tailwindcss.com/docs/font-size#setting-the-font-size)
432 fn text_2xl(mut self) -> Self {
433 self.text_style()
434 .get_or_insert_with(Default::default)
435 .font_size = Some(rems(1.5).into());
436 self
437 }
438
439 /// Sets the text size to 'extra extra extra large'.
440 /// [Docs](https://tailwindcss.com/docs/font-size#setting-the-font-size)
441 fn text_3xl(mut self) -> Self {
442 self.text_style()
443 .get_or_insert_with(Default::default)
444 .font_size = Some(rems(1.875).into());
445 self
446 }
447
448 /// Sets the font style of the element to italic.
449 /// [Docs](https://tailwindcss.com/docs/font-style#italicizing-text)
450 fn italic(mut self) -> Self {
451 self.text_style()
452 .get_or_insert_with(Default::default)
453 .font_style = Some(FontStyle::Italic);
454 self
455 }
456
457 /// Sets the font style of the element to normal (not italic).
458 /// [Docs](https://tailwindcss.com/docs/font-style#italicizing-text)
459 fn not_italic(mut self) -> Self {
460 self.text_style()
461 .get_or_insert_with(Default::default)
462 .font_style = Some(FontStyle::Normal);
463 self
464 }
465
466 /// Sets the decoration of the text to have a line through it.
467 /// [Docs](https://tailwindcss.com/docs/text-decoration#setting-the-text-decoration)
468 fn line_through(mut self) -> Self {
469 let style = self.text_style().get_or_insert_with(Default::default);
470 style.strikethrough = Some(StrikethroughStyle {
471 thickness: px(1.),
472 ..Default::default()
473 });
474 self
475 }
476
477 /// Removes the text decoration on this element.
478 ///
479 /// This value cascades to its child elements.
480 fn text_decoration_none(mut self) -> Self {
481 self.text_style()
482 .get_or_insert_with(Default::default)
483 .underline = None;
484 self
485 }
486
487 /// Sets the color for the underline on this element
488 fn text_decoration_color(mut self, color: impl Into<Hsla>) -> Self {
489 let style = self.text_style().get_or_insert_with(Default::default);
490 let underline = style.underline.get_or_insert_with(Default::default);
491 underline.color = Some(color.into());
492 self
493 }
494
495 /// Sets the text decoration style to a solid line.
496 /// [Docs](https://tailwindcss.com/docs/text-decoration-style)
497 fn text_decoration_solid(mut self) -> Self {
498 let style = self.text_style().get_or_insert_with(Default::default);
499 let underline = style.underline.get_or_insert_with(Default::default);
500 underline.wavy = false;
501 self
502 }
503
504 /// Sets the text decoration style to a wavy line.
505 /// [Docs](https://tailwindcss.com/docs/text-decoration-style)
506 fn text_decoration_wavy(mut self) -> Self {
507 let style = self.text_style().get_or_insert_with(Default::default);
508 let underline = style.underline.get_or_insert_with(Default::default);
509 underline.wavy = true;
510 self
511 }
512
513 /// Sets the text decoration to be 0px thick.
514 /// [Docs](https://tailwindcss.com/docs/text-decoration-thickness)
515 fn text_decoration_0(mut self) -> Self {
516 let style = self.text_style().get_or_insert_with(Default::default);
517 let underline = style.underline.get_or_insert_with(Default::default);
518 underline.thickness = px(0.);
519 self
520 }
521
522 /// Sets the text decoration to be 1px thick.
523 /// [Docs](https://tailwindcss.com/docs/text-decoration-thickness)
524 fn text_decoration_1(mut self) -> Self {
525 let style = self.text_style().get_or_insert_with(Default::default);
526 let underline = style.underline.get_or_insert_with(Default::default);
527 underline.thickness = px(1.);
528 self
529 }
530
531 /// Sets the text decoration to be 2px thick.
532 /// [Docs](https://tailwindcss.com/docs/text-decoration-thickness)
533 fn text_decoration_2(mut self) -> Self {
534 let style = self.text_style().get_or_insert_with(Default::default);
535 let underline = style.underline.get_or_insert_with(Default::default);
536 underline.thickness = px(2.);
537 self
538 }
539
540 /// Sets the text decoration to be 4px thick.
541 /// [Docs](https://tailwindcss.com/docs/text-decoration-thickness)
542 fn text_decoration_4(mut self) -> Self {
543 let style = self.text_style().get_or_insert_with(Default::default);
544 let underline = style.underline.get_or_insert_with(Default::default);
545 underline.thickness = px(4.);
546 self
547 }
548
549 /// Sets the text decoration to be 8px thick.
550 /// [Docs](https://tailwindcss.com/docs/text-decoration-thickness)
551 fn text_decoration_8(mut self) -> Self {
552 let style = self.text_style().get_or_insert_with(Default::default);
553 let underline = style.underline.get_or_insert_with(Default::default);
554 underline.thickness = px(8.);
555 self
556 }
557
558 /// Sets the font family of this element and its children.
559 fn font_family(mut self, family_name: impl Into<SharedString>) -> Self {
560 self.text_style()
561 .get_or_insert_with(Default::default)
562 .font_family = Some(family_name.into());
563 self
564 }
565
566 /// Sets the font of this element and its children.
567 fn font(mut self, font: Font) -> Self {
568 let Font {
569 family,
570 features,
571 fallbacks,
572 weight,
573 style,
574 } = font;
575
576 let text_style = self.text_style().get_or_insert_with(Default::default);
577 text_style.font_family = Some(family);
578 text_style.font_features = Some(features);
579 text_style.font_weight = Some(weight);
580 text_style.font_style = Some(style);
581 text_style.font_fallbacks = fallbacks;
582
583 self
584 }
585
586 /// Sets the line height of this element and its children.
587 fn line_height(mut self, line_height: impl Into<DefiniteLength>) -> Self {
588 self.text_style()
589 .get_or_insert_with(Default::default)
590 .line_height = Some(line_height.into());
591 self
592 }
593
594 /// Sets the opacity of this element and its children.
595 fn opacity(mut self, opacity: f32) -> Self {
596 self.style().opacity = Some(opacity);
597 self
598 }
599
600 /// Draws a debug border around this element.
601 #[cfg(debug_assertions)]
602 fn debug(mut self) -> Self {
603 self.style().debug = Some(true);
604 self
605 }
606
607 /// Draws a debug border on all conforming elements below this element.
608 #[cfg(debug_assertions)]
609 fn debug_below(mut self) -> Self {
610 self.style().debug_below = Some(true);
611 self
612 }
613}