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