styled.rs

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