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, 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#italicizing-text)
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 decoration of the text to have a line through it.
490 /// [Docs](https://tailwindcss.com/docs/text-decoration#setting-the-text-decoration)
491 fn line_through(mut self) -> Self {
492 let style = self.text_style().get_or_insert_with(Default::default);
493 style.strikethrough = Some(StrikethroughStyle {
494 thickness: px(1.),
495 ..Default::default()
496 });
497 self
498 }
499
500 /// Removes the text decoration on this element.
501 ///
502 /// This value cascades to its child elements.
503 fn text_decoration_none(mut self) -> Self {
504 self.text_style()
505 .get_or_insert_with(Default::default)
506 .underline = None;
507 self
508 }
509
510 /// Sets the color for the underline on this element
511 fn text_decoration_color(mut self, color: impl Into<Hsla>) -> Self {
512 let style = self.text_style().get_or_insert_with(Default::default);
513 let underline = style.underline.get_or_insert_with(Default::default);
514 underline.color = Some(color.into());
515 self
516 }
517
518 /// Sets the text decoration style to a solid line.
519 /// [Docs](https://tailwindcss.com/docs/text-decoration-style)
520 fn text_decoration_solid(mut self) -> Self {
521 let style = self.text_style().get_or_insert_with(Default::default);
522 let underline = style.underline.get_or_insert_with(Default::default);
523 underline.wavy = false;
524 self
525 }
526
527 /// Sets the text decoration style to a wavy line.
528 /// [Docs](https://tailwindcss.com/docs/text-decoration-style)
529 fn text_decoration_wavy(mut self) -> Self {
530 let style = self.text_style().get_or_insert_with(Default::default);
531 let underline = style.underline.get_or_insert_with(Default::default);
532 underline.wavy = true;
533 self
534 }
535
536 /// Sets the text decoration to be 0px thick.
537 /// [Docs](https://tailwindcss.com/docs/text-decoration-thickness)
538 fn text_decoration_0(mut self) -> Self {
539 let style = self.text_style().get_or_insert_with(Default::default);
540 let underline = style.underline.get_or_insert_with(Default::default);
541 underline.thickness = px(0.);
542 self
543 }
544
545 /// Sets the text decoration to be 1px thick.
546 /// [Docs](https://tailwindcss.com/docs/text-decoration-thickness)
547 fn text_decoration_1(mut self) -> Self {
548 let style = self.text_style().get_or_insert_with(Default::default);
549 let underline = style.underline.get_or_insert_with(Default::default);
550 underline.thickness = px(1.);
551 self
552 }
553
554 /// Sets the text decoration to be 2px thick.
555 /// [Docs](https://tailwindcss.com/docs/text-decoration-thickness)
556 fn text_decoration_2(mut self) -> Self {
557 let style = self.text_style().get_or_insert_with(Default::default);
558 let underline = style.underline.get_or_insert_with(Default::default);
559 underline.thickness = px(2.);
560 self
561 }
562
563 /// Sets the text decoration to be 4px thick.
564 /// [Docs](https://tailwindcss.com/docs/text-decoration-thickness)
565 fn text_decoration_4(mut self) -> Self {
566 let style = self.text_style().get_or_insert_with(Default::default);
567 let underline = style.underline.get_or_insert_with(Default::default);
568 underline.thickness = px(4.);
569 self
570 }
571
572 /// Sets the text decoration to be 8px thick.
573 /// [Docs](https://tailwindcss.com/docs/text-decoration-thickness)
574 fn text_decoration_8(mut self) -> Self {
575 let style = self.text_style().get_or_insert_with(Default::default);
576 let underline = style.underline.get_or_insert_with(Default::default);
577 underline.thickness = px(8.);
578 self
579 }
580
581 /// Sets the font family of this element and its children.
582 fn font_family(mut self, family_name: impl Into<SharedString>) -> Self {
583 self.text_style()
584 .get_or_insert_with(Default::default)
585 .font_family = Some(family_name.into());
586 self
587 }
588
589 /// Sets the font of this element and its children.
590 fn font(mut self, font: Font) -> Self {
591 let Font {
592 family,
593 features,
594 fallbacks,
595 weight,
596 style,
597 } = font;
598
599 let text_style = self.text_style().get_or_insert_with(Default::default);
600 text_style.font_family = Some(family);
601 text_style.font_features = Some(features);
602 text_style.font_weight = Some(weight);
603 text_style.font_style = Some(style);
604 text_style.font_fallbacks = fallbacks;
605
606 self
607 }
608
609 /// Sets the line height of this element and its children.
610 fn line_height(mut self, line_height: impl Into<DefiniteLength>) -> Self {
611 self.text_style()
612 .get_or_insert_with(Default::default)
613 .line_height = Some(line_height.into());
614 self
615 }
616
617 /// Sets the opacity of this element and its children.
618 fn opacity(mut self, opacity: f32) -> Self {
619 self.style().opacity = Some(opacity);
620 self
621 }
622
623 /// Draws a debug border around this element.
624 #[cfg(debug_assertions)]
625 fn debug(mut self) -> Self {
626 self.style().debug = Some(true);
627 self
628 }
629
630 /// Draws a debug border on all conforming elements below this element.
631 #[cfg(debug_assertions)]
632 fn debug_below(mut self) -> Self {
633 self.style().debug_below = Some(true);
634 self
635 }
636}