styled.rs

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