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