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