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