styled.rs

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