styled.rs

  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}