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, 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 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 /// Get 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 /// Set the text color of this element, this value cascades to its child elements.
333 fn text_color(mut self, color: impl Into<Hsla>) -> Self {
334 self.text_style().get_or_insert_with(Default::default).color = Some(color.into());
335 self
336 }
337
338 /// Set the font weight of this element, this value cascades to its child elements.
339 fn font_weight(mut self, weight: FontWeight) -> Self {
340 self.text_style()
341 .get_or_insert_with(Default::default)
342 .font_weight = Some(weight);
343 self
344 }
345
346 /// Set the background color of this element, this value cascades to its child elements.
347 fn text_bg(mut self, bg: impl Into<Hsla>) -> Self {
348 self.text_style()
349 .get_or_insert_with(Default::default)
350 .background_color = Some(bg.into());
351 self
352 }
353
354 /// Set the text size of this element, this value cascades to its child elements.
355 fn text_size(mut self, size: impl Into<AbsoluteLength>) -> Self {
356 self.text_style()
357 .get_or_insert_with(Default::default)
358 .font_size = Some(size.into());
359 self
360 }
361
362 /// Set the text size to 'extra small',
363 /// see the [Tailwind Docs](https://tailwindcss.com/docs/font-size#setting-the-font-size)
364 fn text_xs(mut self) -> Self {
365 self.text_style()
366 .get_or_insert_with(Default::default)
367 .font_size = Some(rems(0.75).into());
368 self
369 }
370
371 /// Set the text size to 'small',
372 /// see the [Tailwind Docs](https://tailwindcss.com/docs/font-size#setting-the-font-size)
373 fn text_sm(mut self) -> Self {
374 self.text_style()
375 .get_or_insert_with(Default::default)
376 .font_size = Some(rems(0.875).into());
377 self
378 }
379
380 /// Reset the text styling for this element and its children.
381 fn text_base(mut self) -> Self {
382 self.text_style()
383 .get_or_insert_with(Default::default)
384 .font_size = Some(rems(1.0).into());
385 self
386 }
387
388 /// Set the text size to 'large',
389 /// see the [Tailwind Docs](https://tailwindcss.com/docs/font-size#setting-the-font-size)
390 fn text_lg(mut self) -> Self {
391 self.text_style()
392 .get_or_insert_with(Default::default)
393 .font_size = Some(rems(1.125).into());
394 self
395 }
396
397 /// Set the text size to 'extra large',
398 /// see the [Tailwind Docs](https://tailwindcss.com/docs/font-size#setting-the-font-size)
399 fn text_xl(mut self) -> Self {
400 self.text_style()
401 .get_or_insert_with(Default::default)
402 .font_size = Some(rems(1.25).into());
403 self
404 }
405
406 /// Set the text size to 'extra-extra large',
407 /// see the [Tailwind Docs](https://tailwindcss.com/docs/font-size#setting-the-font-size)
408 fn text_2xl(mut self) -> Self {
409 self.text_style()
410 .get_or_insert_with(Default::default)
411 .font_size = Some(rems(1.5).into());
412 self
413 }
414
415 /// Set the text size to 'extra-extra-extra large',
416 /// see the [Tailwind Docs](https://tailwindcss.com/docs/font-size#setting-the-font-size)
417 fn text_3xl(mut self) -> Self {
418 self.text_style()
419 .get_or_insert_with(Default::default)
420 .font_size = Some(rems(1.875).into());
421 self
422 }
423
424 /// Set the font style to 'non-italic',
425 /// see the [Tailwind Docs](https://tailwindcss.com/docs/font-style#italicizing-text)
426 fn non_italic(mut self) -> Self {
427 self.text_style()
428 .get_or_insert_with(Default::default)
429 .font_style = Some(FontStyle::Normal);
430 self
431 }
432
433 /// Set the font style to 'italic',
434 /// see the [Tailwind 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 /// Remove the text decoration on this element, this value cascades to its child elements.
443 fn text_decoration_none(mut self) -> Self {
444 self.text_style()
445 .get_or_insert_with(Default::default)
446 .underline = None;
447 self
448 }
449
450 /// Set the color for the underline on this element
451 fn text_decoration_color(mut self, color: impl Into<Hsla>) -> Self {
452 let style = self.text_style().get_or_insert_with(Default::default);
453 let underline = style.underline.get_or_insert_with(Default::default);
454 underline.color = Some(color.into());
455 self
456 }
457
458 /// Set the underline to a solid line
459 fn text_decoration_solid(mut self) -> Self {
460 let style = self.text_style().get_or_insert_with(Default::default);
461 let underline = style.underline.get_or_insert_with(Default::default);
462 underline.wavy = false;
463 self
464 }
465
466 /// Set the underline to a wavy line
467 fn text_decoration_wavy(mut self) -> Self {
468 let style = self.text_style().get_or_insert_with(Default::default);
469 let underline = style.underline.get_or_insert_with(Default::default);
470 underline.wavy = true;
471 self
472 }
473
474 /// Set the underline to be 0 thickness, see the [Tailwind Docs](https://tailwindcss.com/docs/text-decoration-thickness)
475 fn text_decoration_0(mut self) -> Self {
476 let style = self.text_style().get_or_insert_with(Default::default);
477 let underline = style.underline.get_or_insert_with(Default::default);
478 underline.thickness = px(0.);
479 self
480 }
481
482 /// Set the underline to be 1px thick, see the [Tailwind Docs](https://tailwindcss.com/docs/text-decoration-thickness)
483 fn text_decoration_1(mut self) -> Self {
484 let style = self.text_style().get_or_insert_with(Default::default);
485 let underline = style.underline.get_or_insert_with(Default::default);
486 underline.thickness = px(1.);
487 self
488 }
489
490 /// Set the underline to be 2px thick, see the [Tailwind Docs](https://tailwindcss.com/docs/text-decoration-thickness)
491 fn text_decoration_2(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.thickness = px(2.);
495 self
496 }
497
498 /// Set the underline to be 4px thick, see the [Tailwind Docs](https://tailwindcss.com/docs/text-decoration-thickness)
499 fn text_decoration_4(mut self) -> Self {
500 let style = self.text_style().get_or_insert_with(Default::default);
501 let underline = style.underline.get_or_insert_with(Default::default);
502 underline.thickness = px(4.);
503 self
504 }
505
506 /// Set the underline to be 8px thick, see the [Tailwind Docs](https://tailwindcss.com/docs/text-decoration-thickness)
507 fn text_decoration_8(mut self) -> Self {
508 let style = self.text_style().get_or_insert_with(Default::default);
509 let underline = style.underline.get_or_insert_with(Default::default);
510 underline.thickness = px(8.);
511 self
512 }
513
514 /// Change the font family on this element and its children.
515 fn font_family(mut self, family_name: impl Into<SharedString>) -> Self {
516 self.text_style()
517 .get_or_insert_with(Default::default)
518 .font_family = Some(family_name.into());
519 self
520 }
521
522 /// Change the font of this element and its children.
523 fn font(mut self, font: Font) -> Self {
524 let Font {
525 family,
526 features,
527 fallbacks,
528 weight,
529 style,
530 } = font;
531
532 let text_style = self.text_style().get_or_insert_with(Default::default);
533 text_style.font_family = Some(family);
534 text_style.font_features = Some(features);
535 text_style.font_weight = Some(weight);
536 text_style.font_style = Some(style);
537 text_style.font_fallbacks = fallbacks;
538
539 self
540 }
541
542 /// Set the line height on this element and its children.
543 fn line_height(mut self, line_height: impl Into<DefiniteLength>) -> Self {
544 self.text_style()
545 .get_or_insert_with(Default::default)
546 .line_height = Some(line_height.into());
547 self
548 }
549
550 /// Set opacity on this element and its children.
551 fn opacity(mut self, opacity: f32) -> Self {
552 self.style().opacity = Some(opacity);
553 self
554 }
555
556 /// Draw a debug border around this element.
557 #[cfg(debug_assertions)]
558 fn debug(mut self) -> Self {
559 self.style().debug = Some(true);
560 self
561 }
562
563 /// Draw a debug border on all conforming elements below this element.
564 #[cfg(debug_assertions)]
565 fn debug_below(mut self) -> Self {
566 self.style().debug_below = Some(true);
567 self
568 }
569}