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