1use crate::{
2 self as gpui, AbsoluteLength, AlignContent, AlignItems, AlignSelf, BlendMode, BorderStyle,
3 CursorStyle, DefiniteLength, Display, Fill, FlexDirection, FlexWrap, Font, FontStyle,
4 FontWeight, GridPlacement, GridTemplate, Hsla, JustifyContent, Length, Pixels, SharedString,
5 StrikethroughStyle, StyleRefinement, TemplateColumnMinSize, TextAlign, TextOverflow,
6 TextShadow, TextStyleRefinement, UnderlineStyle, WhiteSpace, point, px, relative, rems,
7};
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};
13
14const ELLIPSIS: SharedString = SharedString::new_static("…");
15
16#[cfg_attr(
19 any(feature = "inspector", debug_assertions),
20 gpui_macros::derive_inspector_reflection
21)]
22pub trait Styled: Sized {
23 fn style(&mut self) -> &mut StyleRefinement;
25
26 gpui_macros::style_helpers!();
27 gpui_macros::visibility_style_methods!();
28 gpui_macros::margin_style_methods!();
29 gpui_macros::padding_style_methods!();
30 gpui_macros::position_style_methods!();
31 gpui_macros::overflow_style_methods!();
32 gpui_macros::cursor_style_methods!();
33 gpui_macros::border_style_methods!();
34 gpui_macros::box_shadow_style_methods!();
35
36 fn block(mut self) -> Self {
39 self.style().display = Some(Display::Block);
40 self
41 }
42
43 fn flex(mut self) -> Self {
46 self.style().display = Some(Display::Flex);
47 self
48 }
49
50 fn grid(mut self) -> Self {
53 self.style().display = Some(Display::Grid);
54 self
55 }
56
57 fn whitespace_normal(mut self) -> Self {
60 self.text_style()
61 .get_or_insert_with(Default::default)
62 .white_space = Some(WhiteSpace::Normal);
63 self
64 }
65
66 fn whitespace_nowrap(mut self) -> Self {
69 self.text_style()
70 .get_or_insert_with(Default::default)
71 .white_space = Some(WhiteSpace::Nowrap);
72 self
73 }
74
75 fn text_ellipsis(mut self) -> Self {
78 self.text_style()
79 .get_or_insert_with(Default::default)
80 .text_overflow = Some(TextOverflow::Truncate(ELLIPSIS));
81 self
82 }
83
84 fn text_overflow(mut self, overflow: TextOverflow) -> Self {
86 self.text_style()
87 .get_or_insert_with(Default::default)
88 .text_overflow = Some(overflow);
89 self
90 }
91
92 fn text_align(mut self, align: TextAlign) -> Self {
94 self.text_style()
95 .get_or_insert_with(Default::default)
96 .text_align = Some(align);
97 self
98 }
99
100 fn text_left(mut self) -> Self {
102 self.text_align(TextAlign::Left)
103 }
104
105 fn text_center(mut self) -> Self {
107 self.text_align(TextAlign::Center)
108 }
109
110 fn text_right(mut self) -> Self {
112 self.text_align(TextAlign::Right)
113 }
114
115 fn truncate(mut self) -> Self {
118 self.overflow_hidden().whitespace_nowrap().text_ellipsis()
119 }
120
121 fn line_clamp(mut self, lines: usize) -> Self {
124 let mut text_style = self.text_style().get_or_insert_with(Default::default);
125 text_style.line_clamp = Some(lines);
126 self.overflow_hidden()
127 }
128
129 fn letter_spacing(mut self, spacing: impl Into<Pixels>) -> Self {
132 self.text_style()
133 .get_or_insert_with(Default::default)
134 .letter_spacing = Some(spacing.into());
135 self
136 }
137
138 fn tracking_tighter(self) -> Self {
140 self.letter_spacing(px(-0.5))
141 }
142
143 fn tracking_tight(self) -> Self {
145 self.letter_spacing(px(-0.25))
146 }
147
148 fn tracking_normal(self) -> Self {
150 self.letter_spacing(px(0.0))
151 }
152
153 fn tracking_wide(self) -> Self {
155 self.letter_spacing(px(0.5))
156 }
157
158 fn tracking_wider(self) -> Self {
160 self.letter_spacing(px(1.0))
161 }
162
163 fn tracking_widest(self) -> Self {
165 self.letter_spacing(px(2.0))
166 }
167
168 fn continuous_corners(mut self) -> Self {
171 self.style().continuous_corners = Some(true);
172 self
173 }
174
175 fn blend_mode(mut self, mode: BlendMode) -> Self {
177 self.style().blend_mode = Some(mode);
178 self
179 }
180
181 fn text_shadow(mut self, shadow: TextShadow) -> Self {
183 self.text_style()
184 .get_or_insert_with(Default::default)
185 .text_shadow = Some(shadow);
186 self
187 }
188
189 fn text_shadow_sm(mut self) -> Self {
191 self.text_style()
192 .get_or_insert_with(Default::default)
193 .text_shadow = Some(TextShadow {
194 color: Hsla {
195 h: 0.0,
196 s: 0.0,
197 l: 0.0,
198 a: 0.2,
199 },
200 offset: point(px(0.0), px(1.0)),
201 blur_radius: px(2.0),
202 });
203 self
204 }
205
206 fn text_shadow_md(mut self) -> Self {
208 self.text_style()
209 .get_or_insert_with(Default::default)
210 .text_shadow = Some(TextShadow {
211 color: Hsla {
212 h: 0.0,
213 s: 0.0,
214 l: 0.0,
215 a: 0.25,
216 },
217 offset: point(px(0.0), px(2.0)),
218 blur_radius: px(4.0),
219 });
220 self
221 }
222
223 fn text_shadow_lg(mut self) -> Self {
225 self.text_style()
226 .get_or_insert_with(Default::default)
227 .text_shadow = Some(TextShadow {
228 color: Hsla {
229 h: 0.0,
230 s: 0.0,
231 l: 0.0,
232 a: 0.3,
233 },
234 offset: point(px(0.0), px(3.0)),
235 blur_radius: px(6.0),
236 });
237 self
238 }
239
240 fn flex_col(mut self) -> Self {
243 self.style().flex_direction = Some(FlexDirection::Column);
244 self
245 }
246
247 fn flex_col_reverse(mut self) -> Self {
250 self.style().flex_direction = Some(FlexDirection::ColumnReverse);
251 self
252 }
253
254 fn flex_row(mut self) -> Self {
257 self.style().flex_direction = Some(FlexDirection::Row);
258 self
259 }
260
261 fn flex_row_reverse(mut self) -> Self {
264 self.style().flex_direction = Some(FlexDirection::RowReverse);
265 self
266 }
267
268 fn flex_1(mut self) -> Self {
271 self.style().flex_grow = Some(1.);
272 self.style().flex_shrink = Some(1.);
273 self.style().flex_basis = Some(relative(0.).into());
274 self
275 }
276
277 fn flex_auto(mut self) -> Self {
280 self.style().flex_grow = Some(1.);
281 self.style().flex_shrink = Some(1.);
282 self.style().flex_basis = Some(Length::Auto);
283 self
284 }
285
286 fn flex_initial(mut self) -> Self {
289 self.style().flex_grow = Some(0.);
290 self.style().flex_shrink = Some(1.);
291 self.style().flex_basis = Some(Length::Auto);
292 self
293 }
294
295 fn flex_none(mut self) -> Self {
298 self.style().flex_grow = Some(0.);
299 self.style().flex_shrink = Some(0.);
300 self
301 }
302
303 fn flex_basis(mut self, basis: impl Into<Length>) -> Self {
306 self.style().flex_basis = Some(basis.into());
307 self
308 }
309
310 fn flex_grow(mut self) -> Self {
313 self.style().flex_grow = Some(1.);
314 self
315 }
316
317 fn flex_shrink(mut self) -> Self {
320 self.style().flex_shrink = Some(1.);
321 self
322 }
323
324 fn flex_shrink_0(mut self) -> Self {
327 self.style().flex_shrink = Some(0.);
328 self
329 }
330
331 fn flex_wrap(mut self) -> Self {
334 self.style().flex_wrap = Some(FlexWrap::Wrap);
335 self
336 }
337
338 fn flex_wrap_reverse(mut self) -> Self {
341 self.style().flex_wrap = Some(FlexWrap::WrapReverse);
342 self
343 }
344
345 fn flex_nowrap(mut self) -> Self {
348 self.style().flex_wrap = Some(FlexWrap::NoWrap);
349 self
350 }
351
352 fn items_start(mut self) -> Self {
355 self.style().align_items = Some(AlignItems::FlexStart);
356 self
357 }
358
359 fn items_end(mut self) -> Self {
362 self.style().align_items = Some(AlignItems::FlexEnd);
363 self
364 }
365
366 fn items_center(mut self) -> Self {
369 self.style().align_items = Some(AlignItems::Center);
370 self
371 }
372
373 fn items_baseline(mut self) -> Self {
376 self.style().align_items = Some(AlignItems::Baseline);
377 self
378 }
379
380 fn self_start(mut self) -> Self {
382 self.style().align_self = Some(AlignSelf::Start);
383 self
384 }
385
386 fn self_end(mut self) -> Self {
388 self.style().align_self = Some(AlignSelf::End);
389 self
390 }
391
392 fn self_flex_start(mut self) -> Self {
394 self.style().align_self = Some(AlignSelf::FlexStart);
395 self
396 }
397
398 fn self_flex_end(mut self) -> Self {
400 self.style().align_self = Some(AlignSelf::FlexEnd);
401 self
402 }
403
404 fn self_center(mut self) -> Self {
406 self.style().align_self = Some(AlignSelf::Center);
407 self
408 }
409
410 fn self_baseline(mut self) -> Self {
412 self.style().align_self = Some(AlignSelf::Baseline);
413 self
414 }
415
416 fn self_stretch(mut self) -> Self {
418 self.style().align_self = Some(AlignSelf::Stretch);
419 self
420 }
421
422 fn justify_start(mut self) -> Self {
425 self.style().justify_content = Some(JustifyContent::Start);
426 self
427 }
428
429 fn justify_end(mut self) -> Self {
432 self.style().justify_content = Some(JustifyContent::End);
433 self
434 }
435
436 fn justify_center(mut self) -> Self {
439 self.style().justify_content = Some(JustifyContent::Center);
440 self
441 }
442
443 fn justify_between(mut self) -> Self {
447 self.style().justify_content = Some(JustifyContent::SpaceBetween);
448 self
449 }
450
451 fn justify_around(mut self) -> Self {
455 self.style().justify_content = Some(JustifyContent::SpaceAround);
456 self
457 }
458
459 fn content_normal(mut self) -> Self {
462 self.style().align_content = None;
463 self
464 }
465
466 fn content_center(mut self) -> Self {
469 self.style().align_content = Some(AlignContent::Center);
470 self
471 }
472
473 fn content_start(mut self) -> Self {
476 self.style().align_content = Some(AlignContent::FlexStart);
477 self
478 }
479
480 fn content_end(mut self) -> Self {
483 self.style().align_content = Some(AlignContent::FlexEnd);
484 self
485 }
486
487 fn content_between(mut self) -> Self {
491 self.style().align_content = Some(AlignContent::SpaceBetween);
492 self
493 }
494
495 fn content_around(mut self) -> Self {
499 self.style().align_content = Some(AlignContent::SpaceAround);
500 self
501 }
502
503 fn content_evenly(mut self) -> Self {
507 self.style().align_content = Some(AlignContent::SpaceEvenly);
508 self
509 }
510
511 fn content_stretch(mut self) -> Self {
514 self.style().align_content = Some(AlignContent::Stretch);
515 self
516 }
517
518 fn bg<F>(mut self, fill: F) -> Self
520 where
521 F: Into<Fill>,
522 Self: Sized,
523 {
524 self.style().background = Some(fill.into());
525 self
526 }
527
528 fn border_dashed(mut self) -> Self {
530 self.style().border_style = Some(BorderStyle::Dashed);
531 self
532 }
533
534 fn text_style(&mut self) -> &mut Option<TextStyleRefinement> {
536 let style: &mut StyleRefinement = self.style();
537 &mut style.text
538 }
539
540 fn text_color(mut self, color: impl Into<Hsla>) -> Self {
544 self.text_style().get_or_insert_with(Default::default).color = Some(color.into());
545 self
546 }
547
548 fn font_weight(mut self, weight: FontWeight) -> Self {
552 self.text_style()
553 .get_or_insert_with(Default::default)
554 .font_weight = Some(weight);
555 self
556 }
557
558 fn text_bg(mut self, bg: impl Into<Hsla>) -> Self {
562 self.text_style()
563 .get_or_insert_with(Default::default)
564 .background_color = Some(bg.into());
565 self
566 }
567
568 fn text_size(mut self, size: impl Into<AbsoluteLength>) -> Self {
572 self.text_style()
573 .get_or_insert_with(Default::default)
574 .font_size = Some(size.into());
575 self
576 }
577
578 fn text_xs(mut self) -> Self {
581 self.text_style()
582 .get_or_insert_with(Default::default)
583 .font_size = Some(rems(0.75).into());
584 self
585 }
586
587 fn text_sm(mut self) -> Self {
590 self.text_style()
591 .get_or_insert_with(Default::default)
592 .font_size = Some(rems(0.875).into());
593 self
594 }
595
596 fn text_base(mut self) -> Self {
599 self.text_style()
600 .get_or_insert_with(Default::default)
601 .font_size = Some(rems(1.0).into());
602 self
603 }
604
605 fn text_lg(mut self) -> Self {
608 self.text_style()
609 .get_or_insert_with(Default::default)
610 .font_size = Some(rems(1.125).into());
611 self
612 }
613
614 fn text_xl(mut self) -> Self {
617 self.text_style()
618 .get_or_insert_with(Default::default)
619 .font_size = Some(rems(1.25).into());
620 self
621 }
622
623 fn text_2xl(mut self) -> Self {
626 self.text_style()
627 .get_or_insert_with(Default::default)
628 .font_size = Some(rems(1.5).into());
629 self
630 }
631
632 fn text_3xl(mut self) -> Self {
635 self.text_style()
636 .get_or_insert_with(Default::default)
637 .font_size = Some(rems(1.875).into());
638 self
639 }
640
641 fn italic(mut self) -> Self {
644 self.text_style()
645 .get_or_insert_with(Default::default)
646 .font_style = Some(FontStyle::Italic);
647 self
648 }
649
650 fn not_italic(mut self) -> Self {
653 self.text_style()
654 .get_or_insert_with(Default::default)
655 .font_style = Some(FontStyle::Normal);
656 self
657 }
658
659 fn underline(mut self) -> Self {
662 let style = self.text_style().get_or_insert_with(Default::default);
663 style.underline = Some(UnderlineStyle {
664 thickness: px(1.),
665 ..Default::default()
666 });
667 self
668 }
669
670 fn line_through(mut self) -> Self {
673 let style = self.text_style().get_or_insert_with(Default::default);
674 style.strikethrough = Some(StrikethroughStyle {
675 thickness: px(1.),
676 ..Default::default()
677 });
678 self
679 }
680
681 fn text_decoration_none(mut self) -> Self {
685 self.text_style()
686 .get_or_insert_with(Default::default)
687 .underline = None;
688 self
689 }
690
691 fn text_decoration_color(mut self, color: impl Into<Hsla>) -> Self {
693 let style = self.text_style().get_or_insert_with(Default::default);
694 let underline = style.underline.get_or_insert_with(Default::default);
695 underline.color = Some(color.into());
696 self
697 }
698
699 fn text_decoration_solid(mut self) -> Self {
702 let style = self.text_style().get_or_insert_with(Default::default);
703 let underline = style.underline.get_or_insert_with(Default::default);
704 underline.wavy = false;
705 self
706 }
707
708 fn text_decoration_wavy(mut self) -> Self {
711 let style = self.text_style().get_or_insert_with(Default::default);
712 let underline = style.underline.get_or_insert_with(Default::default);
713 underline.wavy = true;
714 self
715 }
716
717 fn text_decoration_0(mut self) -> Self {
720 let style = self.text_style().get_or_insert_with(Default::default);
721 let underline = style.underline.get_or_insert_with(Default::default);
722 underline.thickness = px(0.);
723 self
724 }
725
726 fn text_decoration_1(mut self) -> Self {
729 let style = self.text_style().get_or_insert_with(Default::default);
730 let underline = style.underline.get_or_insert_with(Default::default);
731 underline.thickness = px(1.);
732 self
733 }
734
735 fn text_decoration_2(mut self) -> Self {
738 let style = self.text_style().get_or_insert_with(Default::default);
739 let underline = style.underline.get_or_insert_with(Default::default);
740 underline.thickness = px(2.);
741 self
742 }
743
744 fn text_decoration_4(mut self) -> Self {
747 let style = self.text_style().get_or_insert_with(Default::default);
748 let underline = style.underline.get_or_insert_with(Default::default);
749 underline.thickness = px(4.);
750 self
751 }
752
753 fn text_decoration_8(mut self) -> Self {
756 let style = self.text_style().get_or_insert_with(Default::default);
757 let underline = style.underline.get_or_insert_with(Default::default);
758 underline.thickness = px(8.);
759 self
760 }
761
762 fn font_family(mut self, family_name: impl Into<SharedString>) -> Self {
764 self.text_style()
765 .get_or_insert_with(Default::default)
766 .font_family = Some(family_name.into());
767 self
768 }
769
770 fn font(mut self, font: Font) -> Self {
772 let Font {
773 family,
774 features,
775 fallbacks,
776 weight,
777 style,
778 } = font;
779
780 let text_style = self.text_style().get_or_insert_with(Default::default);
781 text_style.font_family = Some(family);
782 text_style.font_features = Some(features);
783 text_style.font_weight = Some(weight);
784 text_style.font_style = Some(style);
785 text_style.font_fallbacks = fallbacks;
786
787 self
788 }
789
790 fn line_height(mut self, line_height: impl Into<DefiniteLength>) -> Self {
792 self.text_style()
793 .get_or_insert_with(Default::default)
794 .line_height = Some(line_height.into());
795 self
796 }
797
798 fn opacity(mut self, opacity: f32) -> Self {
800 self.style().opacity = Some(opacity);
801 self
802 }
803
804 fn rotate(mut self, angle_degrees: f32) -> Self {
806 self.style().rotate = Some(angle_degrees.to_radians());
807 self
808 }
809
810 fn scale(mut self, factor: f32) -> Self {
812 self.style().scale = Some(point(factor, factor));
813 self
814 }
815
816 fn scale_xy(mut self, x: f32, y: f32) -> Self {
818 self.style().scale = Some(point(x, y));
819 self
820 }
821
822 fn transform_origin(mut self, x: f32, y: f32) -> Self {
825 self.style().transform_origin = Some(point(x, y));
826 self
827 }
828
829 fn grid_cols(mut self, cols: u16) -> Self {
831 self.style().grid_cols = Some(GridTemplate {
832 repeat: cols,
833 min_size: TemplateColumnMinSize::Zero,
834 });
835 self
836 }
837
838 fn grid_cols_min_content(mut self, cols: u16) -> Self {
841 self.style().grid_cols = Some(GridTemplate {
842 repeat: cols,
843 min_size: TemplateColumnMinSize::MinContent,
844 });
845 self
846 }
847
848 fn grid_cols_max_content(mut self, cols: u16) -> Self {
850 self.style().grid_cols = Some(GridTemplate {
851 repeat: cols,
852 min_size: TemplateColumnMinSize::MaxContent,
853 });
854 self
855 }
856
857 fn grid_rows(mut self, rows: u16) -> Self {
859 self.style().grid_rows = Some(GridTemplate {
860 repeat: rows,
861 min_size: TemplateColumnMinSize::Zero,
862 });
863 self
864 }
865
866 fn grid_rows_min_content(mut self, rows: u16) -> Self {
869 self.style().grid_rows = Some(GridTemplate {
870 repeat: rows,
871 min_size: TemplateColumnMinSize::MinContent,
872 });
873 self
874 }
875
876 fn grid_rows_max_content(mut self, rows: u16) -> Self {
878 self.style().grid_rows = Some(GridTemplate {
879 repeat: rows,
880 min_size: TemplateColumnMinSize::MaxContent,
881 });
882 self
883 }
884
885 fn col_start(mut self, start: i16) -> Self {
887 let grid_location = self.style().grid_location_mut();
888 grid_location.column.start = GridPlacement::Line(start);
889 self
890 }
891
892 fn col_start_auto(mut self) -> Self {
894 let grid_location = self.style().grid_location_mut();
895 grid_location.column.start = GridPlacement::Auto;
896 self
897 }
898
899 fn col_end(mut self, end: i16) -> Self {
901 let grid_location = self.style().grid_location_mut();
902 grid_location.column.end = GridPlacement::Line(end);
903 self
904 }
905
906 fn col_end_auto(mut self) -> Self {
908 let grid_location = self.style().grid_location_mut();
909 grid_location.column.end = GridPlacement::Auto;
910 self
911 }
912
913 fn col_span(mut self, span: u16) -> Self {
915 let grid_location = self.style().grid_location_mut();
916 grid_location.column = GridPlacement::Span(span)..GridPlacement::Span(span);
917 self
918 }
919
920 fn col_span_full(mut self) -> Self {
922 let grid_location = self.style().grid_location_mut();
923 grid_location.column = GridPlacement::Line(1)..GridPlacement::Line(-1);
924 self
925 }
926
927 fn row_start(mut self, start: i16) -> Self {
929 let grid_location = self.style().grid_location_mut();
930 grid_location.row.start = GridPlacement::Line(start);
931 self
932 }
933
934 fn row_start_auto(mut self) -> Self {
936 let grid_location = self.style().grid_location_mut();
937 grid_location.row.start = GridPlacement::Auto;
938 self
939 }
940
941 fn row_end(mut self, end: i16) -> Self {
943 let grid_location = self.style().grid_location_mut();
944 grid_location.row.end = GridPlacement::Line(end);
945 self
946 }
947
948 fn row_end_auto(mut self) -> Self {
950 let grid_location = self.style().grid_location_mut();
951 grid_location.row.end = GridPlacement::Auto;
952 self
953 }
954
955 fn row_span(mut self, span: u16) -> Self {
957 let grid_location = self.style().grid_location_mut();
958 grid_location.row = GridPlacement::Span(span)..GridPlacement::Span(span);
959 self
960 }
961
962 fn row_span_full(mut self) -> Self {
964 let grid_location = self.style().grid_location_mut();
965 grid_location.row = GridPlacement::Line(1)..GridPlacement::Line(-1);
966 self
967 }
968
969 #[cfg(debug_assertions)]
971 fn debug(mut self) -> Self {
972 self.style().debug = Some(true);
973 self
974 }
975
976 #[cfg(debug_assertions)]
978 fn debug_below(mut self) -> Self {
979 self.style().debug_below = Some(true);
980 self
981 }
982}
983
984#[cfg(test)]
985mod tests {
986 use super::*;
987
988 #[test]
989 fn cursor_none_requires_no_argument_and_sets_explicit_none() {
990 let mut element = crate::div().cursor_pointer().cursor_none();
991 assert_eq!(element.style().mouse_cursor, Some(CursorStyle::None));
992 }
993
994 #[test]
995 fn grid_content_sizing_builders_select_expected_modes() {
996 let mut min_columns = crate::div().grid_cols_min_content(2);
997 assert_eq!(
998 min_columns.style().grid_cols,
999 Some(GridTemplate {
1000 repeat: 2,
1001 min_size: TemplateColumnMinSize::MinContent,
1002 })
1003 );
1004
1005 let mut min_rows = crate::div().grid_rows_min_content(3);
1006 assert_eq!(
1007 min_rows.style().grid_rows,
1008 Some(GridTemplate {
1009 repeat: 3,
1010 min_size: TemplateColumnMinSize::MinContent,
1011 })
1012 );
1013
1014 let mut max_rows = crate::div().grid_rows_max_content(4);
1015 assert_eq!(
1016 max_rows.style().grid_rows,
1017 Some(GridTemplate {
1018 repeat: 4,
1019 min_size: TemplateColumnMinSize::MaxContent,
1020 })
1021 );
1022 }
1023}