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