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.
 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}