1use crate::theme::tokens::{Color, RadiusScale, SpacingScale, ThemeTokens, TypographyScale};
7use std::fmt::Write;
8
9#[derive(Default, Clone)]
27pub struct Style {
28 pub display: Option<String>,
30 pub flex_direction: Option<String>,
31 pub flex_wrap: Option<String>,
32 pub align_items: Option<String>,
33 pub align_self: Option<String>,
34 pub justify_content: Option<String>,
35 pub justify_items: Option<String>,
36 pub gap: Option<String>,
37 pub row_gap: Option<String>,
38 pub column_gap: Option<String>,
39
40 pub padding: Option<String>,
42 pub padding_top: Option<String>,
43 pub padding_right: Option<String>,
44 pub padding_bottom: Option<String>,
45 pub padding_left: Option<String>,
46 pub margin: Option<String>,
47 pub margin_top: Option<String>,
48 pub margin_right: Option<String>,
49 pub margin_bottom: Option<String>,
50 pub margin_left: Option<String>,
51
52 pub background_color: Option<String>,
54 pub color: Option<String>,
55 pub border_color: Option<String>,
56
57 pub font_size: Option<String>,
59 pub font_weight: Option<String>,
60 pub font_family: Option<String>,
61 pub line_height: Option<String>,
62 pub text_align: Option<String>,
63 pub text_decoration: Option<String>,
64 pub letter_spacing: Option<String>,
65
66 pub border_radius: Option<String>,
68 pub border: Option<String>,
69 pub border_top: Option<String>,
70 pub border_right: Option<String>,
71 pub border_bottom: Option<String>,
72 pub border_left: Option<String>,
73 pub border_width: Option<String>,
74 pub box_shadow: Option<String>,
75
76 pub width: Option<String>,
78 pub height: Option<String>,
79 pub min_width: Option<String>,
80 pub min_height: Option<String>,
81 pub max_width: Option<String>,
82 pub max_height: Option<String>,
83
84 pub position: Option<String>,
86 pub top: Option<String>,
87 pub right: Option<String>,
88 pub bottom: Option<String>,
89 pub left: Option<String>,
90 pub z_index: Option<String>,
91
92 pub cursor: Option<String>,
94 pub opacity: Option<String>,
95 pub transition: Option<String>,
96 pub transform: Option<String>,
97 pub overflow: Option<String>,
98 pub visibility: Option<String>,
99 pub pointer_events: Option<String>,
100 pub user_select: Option<String>,
101 pub white_space: Option<String>,
102 pub word_break: Option<String>,
103 pub outline: Option<String>,
104 pub resize: Option<String>,
105}
106
107impl Style {
108 pub fn new() -> Self {
110 Self::default()
111 }
112
113 pub fn flex(mut self) -> Self {
119 self.display = Some("flex".into());
120 self
121 }
122
123 pub fn block(mut self) -> Self {
125 self.display = Some("block".into());
126 self
127 }
128
129 pub fn inline_block(mut self) -> Self {
131 self.display = Some("inline-block".into());
132 self
133 }
134
135 pub fn inline_flex(mut self) -> Self {
137 self.display = Some("inline-flex".into());
138 self
139 }
140
141 pub fn grid(mut self) -> Self {
143 self.display = Some("grid".into());
144 self
145 }
146
147 pub fn hidden(mut self) -> Self {
149 self.display = Some("none".into());
150 self
151 }
152
153 pub fn flex_col(mut self) -> Self {
155 self.flex_direction = Some("column".into());
156 self
157 }
158
159 pub fn flex_row(mut self) -> Self {
161 self.flex_direction = Some("row".into());
162 self
163 }
164
165 pub fn flex_wrap(mut self) -> Self {
167 self.flex_wrap = Some("wrap".into());
168 self
169 }
170
171 pub fn flex_nowrap(mut self) -> Self {
173 self.flex_wrap = Some("nowrap".into());
174 self
175 }
176
177 pub fn items_center(mut self) -> Self {
179 self.align_items = Some("center".into());
180 self
181 }
182
183 pub fn items_start(mut self) -> Self {
185 self.align_items = Some("flex-start".into());
186 self
187 }
188
189 pub fn items_end(mut self) -> Self {
191 self.align_items = Some("flex-end".into());
192 self
193 }
194
195 pub fn items_stretch(mut self) -> Self {
197 self.align_items = Some("stretch".into());
198 self
199 }
200
201 pub fn self_center(mut self) -> Self {
203 self.align_self = Some("center".into());
204 self
205 }
206
207 pub fn justify_center(mut self) -> Self {
209 self.justify_content = Some("center".into());
210 self
211 }
212
213 pub fn justify_start(mut self) -> Self {
215 self.justify_content = Some("flex-start".into());
216 self
217 }
218
219 pub fn justify_end(mut self) -> Self {
221 self.justify_content = Some("flex-end".into());
222 self
223 }
224
225 pub fn justify_between(mut self) -> Self {
227 self.justify_content = Some("space-between".into());
228 self
229 }
230
231 pub fn justify_around(mut self) -> Self {
233 self.justify_content = Some("space-around".into());
234 self
235 }
236
237 pub fn justify_evenly(mut self) -> Self {
239 self.justify_content = Some("space-evenly".into());
240 self
241 }
242
243 pub fn gap(mut self, spacing: &SpacingScale, size: &str) -> Self {
245 let val = spacing.get(size);
246 self.gap = Some(format!("{}px", val));
247 self
248 }
249
250 pub fn gap_px(mut self, px: u16) -> Self {
252 self.gap = Some(format!("{}px", px));
253 self
254 }
255
256 pub fn row_gap(mut self, spacing: &SpacingScale, size: &str) -> Self {
258 let val = spacing.get(size);
259 self.row_gap = Some(format!("{}px", val));
260 self
261 }
262
263 pub fn column_gap(mut self, spacing: &SpacingScale, size: &str) -> Self {
265 let val = spacing.get(size);
266 self.column_gap = Some(format!("{}px", val));
267 self
268 }
269
270 pub fn p(mut self, spacing: &SpacingScale, size: &str) -> Self {
276 let val = spacing.get(size);
277 self.padding = Some(format!("{}px", val));
278 self
279 }
280
281 pub fn p_px(mut self, px: u16) -> Self {
283 self.padding = Some(format!("{}px", px));
284 self
285 }
286
287 pub fn px(mut self, spacing: &SpacingScale, size: &str) -> Self {
289 let val = spacing.get(size);
290 self.padding_left = Some(format!("{}px", val));
291 self.padding_right = Some(format!("{}px", val));
292 self
293 }
294
295 pub fn px_px(mut self, px: u16) -> Self {
297 self.padding_left = Some(format!("{}px", px));
298 self.padding_right = Some(format!("{}px", px));
299 self
300 }
301
302 pub fn py(mut self, spacing: &SpacingScale, size: &str) -> Self {
304 let val = spacing.get(size);
305 self.padding_top = Some(format!("{}px", val));
306 self.padding_bottom = Some(format!("{}px", val));
307 self
308 }
309
310 pub fn py_px(mut self, px: u16) -> Self {
312 self.padding_top = Some(format!("{}px", px));
313 self.padding_bottom = Some(format!("{}px", px));
314 self
315 }
316
317 pub fn pt(mut self, spacing: &SpacingScale, size: &str) -> Self {
319 let val = spacing.get(size);
320 self.padding_top = Some(format!("{}px", val));
321 self
322 }
323
324 pub fn pr(mut self, spacing: &SpacingScale, size: &str) -> Self {
326 let val = spacing.get(size);
327 self.padding_right = Some(format!("{}px", val));
328 self
329 }
330
331 pub fn pb(mut self, spacing: &SpacingScale, size: &str) -> Self {
333 let val = spacing.get(size);
334 self.padding_bottom = Some(format!("{}px", val));
335 self
336 }
337
338 pub fn pl(mut self, spacing: &SpacingScale, size: &str) -> Self {
340 let val = spacing.get(size);
341 self.padding_left = Some(format!("{}px", val));
342 self
343 }
344
345 pub fn pt_px(mut self, px: u16) -> Self {
347 self.padding_top = Some(format!("{}px", px));
348 self
349 }
350
351 pub fn pr_px(mut self, px: u16) -> Self {
353 self.padding_right = Some(format!("{}px", px));
354 self
355 }
356
357 pub fn pb_px(mut self, px: u16) -> Self {
359 self.padding_bottom = Some(format!("{}px", px));
360 self
361 }
362
363 pub fn pl_px(mut self, px: u16) -> Self {
365 self.padding_left = Some(format!("{}px", px));
366 self
367 }
368
369 pub fn m(mut self, spacing: &SpacingScale, size: &str) -> Self {
371 let val = spacing.get(size);
372 self.margin = Some(format!("{}px", val));
373 self
374 }
375
376 pub fn m_px(mut self, px: u16) -> Self {
378 self.margin = Some(format!("{}px", px));
379 self
380 }
381
382 pub fn mx(mut self, spacing: &SpacingScale, size: &str) -> Self {
384 let val = spacing.get(size);
385 self.margin_left = Some(format!("{}px", val));
386 self.margin_right = Some(format!("{}px", val));
387 self
388 }
389
390 pub fn my(mut self, spacing: &SpacingScale, size: &str) -> Self {
392 let val = spacing.get(size);
393 self.margin_top = Some(format!("{}px", val));
394 self.margin_bottom = Some(format!("{}px", val));
395 self
396 }
397
398 pub fn mt(mut self, spacing: &SpacingScale, size: &str) -> Self {
400 let val = spacing.get(size);
401 self.margin_top = Some(format!("{}px", val));
402 self
403 }
404
405 pub fn mr(mut self, spacing: &SpacingScale, size: &str) -> Self {
407 let val = spacing.get(size);
408 self.margin_right = Some(format!("{}px", val));
409 self
410 }
411
412 pub fn mb(mut self, spacing: &SpacingScale, size: &str) -> Self {
414 let val = spacing.get(size);
415 self.margin_bottom = Some(format!("{}px", val));
416 self
417 }
418
419 pub fn mb_px(mut self, px: i16) -> Self {
421 self.margin_bottom = Some(format!("{}px", px));
422 self
423 }
424
425 pub fn ml(mut self, spacing: &SpacingScale, size: &str) -> Self {
427 let val = spacing.get(size);
428 self.margin_left = Some(format!("{}px", val));
429 self
430 }
431
432 pub fn bg(mut self, color: &Color) -> Self {
438 self.background_color = Some(color.to_rgba());
439 self
440 }
441
442 pub fn bg_hex(mut self, hex: &str) -> Self {
444 self.background_color = Some(hex.into());
445 self
446 }
447
448 pub fn text_color(mut self, color: &Color) -> Self {
450 self.color = Some(color.to_rgba());
451 self
452 }
453
454 pub fn text_hex(mut self, hex: &str) -> Self {
456 self.color = Some(hex.into());
457 self
458 }
459
460 pub fn border_color(mut self, color: &Color) -> Self {
462 self.border_color = Some(color.to_rgba());
463 self
464 }
465
466 pub fn text(mut self, typography: &TypographyScale, size: &str) -> Self {
472 let t = typography.get(size);
473 self.font_size = Some(format!("{}px", t.size));
474 self.font_weight = Some(t.weight.to_string());
475 self.font_family = Some(t.family.clone());
476 self.line_height = Some(t.line_height.to_string());
477 if let Some(ls) = t.letter_spacing {
478 self.letter_spacing = Some(format!("{}em", ls));
479 }
480 self
481 }
482
483 pub fn font_size(mut self, size: u16) -> Self {
485 self.font_size = Some(format!("{}px", size));
486 self
487 }
488
489 pub fn font_weight(mut self, weight: u16) -> Self {
491 self.font_weight = Some(weight.to_string());
492 self
493 }
494
495 pub fn font_family(mut self, family: &str) -> Self {
497 self.font_family = Some(family.into());
498 self
499 }
500
501 pub fn line_height(mut self, height: f32) -> Self {
503 self.line_height = Some(height.to_string());
504 self
505 }
506
507 pub fn text_align(mut self, align: &str) -> Self {
509 self.text_align = Some(align.into());
510 self
511 }
512
513 pub fn text_center(mut self) -> Self {
515 self.text_align = Some("center".into());
516 self
517 }
518
519 pub fn text_left(mut self) -> Self {
521 self.text_align = Some("left".into());
522 self
523 }
524
525 pub fn text_right(mut self) -> Self {
527 self.text_align = Some("right".into());
528 self
529 }
530
531 pub fn text_align_left(mut self) -> Self {
533 self.text_align = Some("left".into());
534 self
535 }
536
537 pub fn no_underline(mut self) -> Self {
539 self.text_decoration = Some("none".into());
540 self
541 }
542
543 pub fn underline(mut self) -> Self {
545 self.text_decoration = Some("underline".into());
546 self
547 }
548
549 pub fn rounded(mut self, radius: &RadiusScale, size: &str) -> Self {
555 let val = radius.get(size);
556 self.border_radius = Some(format!("{}px", val));
557 self
558 }
559
560 pub fn rounded_px(mut self, px: u16) -> Self {
562 self.border_radius = Some(format!("{}px", px));
563 self
564 }
565
566 pub fn rounded_full(mut self) -> Self {
568 self.border_radius = Some("9999px".into());
569 self
570 }
571
572 pub fn border(mut self, width: u8, color: &Color) -> Self {
574 self.border = Some(format!("{}px solid {}", width, color.to_rgba()));
575 self
576 }
577
578 pub fn border_width(mut self, width: u8) -> Self {
580 self.border_width = Some(format!("{}px", width));
581 self
582 }
583
584 pub fn border_top(mut self, width: u8, color: &Color) -> Self {
586 self.border_top = Some(format!("{}px solid {}", width, color.to_rgba()));
587 self
588 }
589
590 pub fn border_right(mut self, width: u8, color: &Color) -> Self {
592 self.border_right = Some(format!("{}px solid {}", width, color.to_rgba()));
593 self
594 }
595
596 pub fn border_bottom(mut self, width: u8, color: &Color) -> Self {
598 self.border_bottom = Some(format!("{}px solid {}", width, color.to_rgba()));
599 self
600 }
601
602 pub fn border_left(mut self, width: u8, color: &Color) -> Self {
604 self.border_left = Some(format!("{}px solid {}", width, color.to_rgba()));
605 self
606 }
607
608 pub fn border_style(mut self, style: &str) -> Self {
610 let existing = self.transform.clone().unwrap_or_default();
613 self.transform = Some(format!("{} border-style: {};", existing, style));
614 self
615 }
616
617 pub fn shadow(mut self, shadow: &str) -> Self {
619 self.box_shadow = Some(shadow.into());
620 self
621 }
622
623 pub fn shadow_themed(mut self, theme: &ThemeTokens, size: &str) -> Self {
625 self.box_shadow = Some(theme.shadows.get(size).clone());
626 self
627 }
628
629 pub fn shadow_none(mut self) -> Self {
631 self.box_shadow = Some("none".into());
632 self
633 }
634
635 pub fn w(mut self, width: &str) -> Self {
641 self.width = Some(width.into());
642 self
643 }
644
645 pub fn w_px(mut self, px: u16) -> Self {
647 self.width = Some(format!("{}px", px));
648 self
649 }
650
651 pub fn w_percent(mut self, pct: u8) -> Self {
653 self.width = Some(format!("{}%", pct));
654 self
655 }
656
657 pub fn w_full(mut self) -> Self {
659 self.width = Some("100%".into());
660 self
661 }
662
663 pub fn h(mut self, height: &str) -> Self {
665 self.height = Some(height.into());
666 self
667 }
668
669 pub fn h_px(mut self, px: u16) -> Self {
671 self.height = Some(format!("{}px", px));
672 self
673 }
674
675 pub fn h_percent(mut self, pct: u8) -> Self {
677 self.height = Some(format!("{}%", pct));
678 self
679 }
680
681 pub fn h_full(mut self) -> Self {
683 self.height = Some("100%".into());
684 self
685 }
686
687 pub fn min_w(mut self, width: &str) -> Self {
689 self.min_width = Some(width.into());
690 self
691 }
692
693 pub fn min_w_px(mut self, px: u16) -> Self {
695 self.min_width = Some(format!("{}px", px));
696 self
697 }
698
699 pub fn min_h(mut self, height: &str) -> Self {
701 self.min_height = Some(height.into());
702 self
703 }
704
705 pub fn min_h_px(mut self, px: u16) -> Self {
707 self.min_height = Some(format!("{}px", px));
708 self
709 }
710
711 pub fn max_w(mut self, width: &str) -> Self {
713 self.max_width = Some(width.into());
714 self
715 }
716
717 pub fn max_w_px(mut self, px: u16) -> Self {
719 self.max_width = Some(format!("{}px", px));
720 self
721 }
722
723 pub fn max_h(mut self, height: &str) -> Self {
725 self.max_height = Some(height.into());
726 self
727 }
728
729 pub fn max_h_px(mut self, px: u16) -> Self {
731 self.max_height = Some(format!("{}px", px));
732 self
733 }
734
735 pub fn position(mut self, value: &str) -> Self {
741 self.position = Some(value.into());
742 self
743 }
744
745 pub fn relative(mut self) -> Self {
747 self.position = Some("relative".into());
748 self
749 }
750
751 pub fn absolute(mut self) -> Self {
753 self.position = Some("absolute".into());
754 self
755 }
756
757 pub fn fixed(mut self) -> Self {
759 self.position = Some("fixed".into());
760 self
761 }
762
763 pub fn sticky(mut self) -> Self {
765 self.position = Some("sticky".into());
766 self
767 }
768
769 pub fn top(mut self, value: &str) -> Self {
771 self.top = Some(value.into());
772 self
773 }
774
775 pub fn right(mut self, value: &str) -> Self {
777 self.right = Some(value.into());
778 self
779 }
780
781 pub fn bottom(mut self, value: &str) -> Self {
783 self.bottom = Some(value.into());
784 self
785 }
786
787 pub fn left(mut self, value: &str) -> Self {
789 self.left = Some(value.into());
790 self
791 }
792
793 pub fn z_index(mut self, z: i16) -> Self {
795 self.z_index = Some(z.to_string());
796 self
797 }
798
799 pub fn cursor(mut self, cursor: &str) -> Self {
805 self.cursor = Some(cursor.into());
806 self
807 }
808
809 pub fn cursor_pointer(mut self) -> Self {
811 self.cursor = Some("pointer".into());
812 self
813 }
814
815 pub fn opacity(mut self, opacity: f32) -> Self {
817 self.opacity = Some(opacity.clamp(0.0, 1.0).to_string());
818 self
819 }
820
821 pub fn transition(mut self, transition: &str) -> Self {
823 self.transition = Some(transition.into());
824 self
825 }
826
827 pub fn transform(mut self, transform: &str) -> Self {
829 self.transform = Some(transform.into());
830 self
831 }
832
833 pub fn overflow_hidden(mut self) -> Self {
835 self.overflow = Some("hidden".into());
836 self
837 }
838
839 pub fn overflow_auto(mut self) -> Self {
841 self.overflow = Some("auto".into());
842 self
843 }
844
845 pub fn overflow_scroll(mut self) -> Self {
847 self.overflow = Some("scroll".into());
848 self
849 }
850
851 pub fn invisible(mut self) -> Self {
853 self.visibility = Some("hidden".into());
854 self
855 }
856
857 pub fn visible(mut self) -> Self {
859 self.visibility = Some("visible".into());
860 self
861 }
862
863 pub fn pointer_events_none(mut self) -> Self {
865 self.pointer_events = Some("none".into());
866 self
867 }
868
869 pub fn pointer_events_auto(mut self) -> Self {
871 self.pointer_events = Some("auto".into());
872 self
873 }
874
875 pub fn select_none(mut self) -> Self {
877 self.user_select = Some("none".into());
878 self
879 }
880
881 pub fn whitespace_nowrap(mut self) -> Self {
883 self.white_space = Some("nowrap".into());
884 self
885 }
886
887 pub fn break_all(mut self) -> Self {
889 self.word_break = Some("break-all".into());
890 self
891 }
892
893 pub fn outline(mut self, value: &str) -> Self {
895 self.outline = Some(value.into());
896 self
897 }
898
899 pub fn resize(mut self, value: &str) -> Self {
901 self.resize = Some(value.into());
902 self
903 }
904
905 pub fn flex_shrink(mut self, value: u8) -> Self {
907 self.transform = Some(format!("flex-shrink: {}", value));
910 self
911 }
912
913 pub fn bg_transparent(mut self) -> Self {
915 self.background_color = Some("transparent".into());
916 self
917 }
918
919 pub fn flex_grow(mut self, value: u8) -> Self {
921 let existing = self.transform.unwrap_or_default();
923 self.transform = Some(format!("{} flex-grow: {};", existing, value));
924 self
925 }
926
927 pub fn min_h_full(mut self) -> Self {
929 self.min_height = Some("100%".into());
930 self
931 }
932
933 pub fn inset(mut self, value: &str) -> Self {
935 self.top = Some(value.into());
936 self.right = Some(value.into());
937 self.bottom = Some(value.into());
938 self.left = Some(value.into());
939 self
940 }
941
942 pub fn flex_1(mut self) -> Self {
944 let existing = self.transform.unwrap_or_default();
945 self.transform = Some(format!("{} flex: 1 1 0%;", existing));
946 self
947 }
948
949 pub fn overflow_x_auto(mut self) -> Self {
951 let existing = self.transform.unwrap_or_default();
952 self.transform = Some(format!("{} overflow-x: auto;", existing));
953 self
954 }
955
956 pub fn overflow_y_auto(mut self) -> Self {
958 let existing = self.transform.unwrap_or_default();
959 self.transform = Some(format!("{} overflow-y: auto;", existing));
960 self
961 }
962
963 pub fn custom(mut self, css: &str) -> Self {
965 let existing = self.transform.unwrap_or_default();
966 self.transform = Some(format!("{} {}", existing, css));
967 self
968 }
969
970 pub fn build(self) -> String {
976 let mut style = String::new();
977
978 write_if_some(&mut style, "display", &self.display);
980 write_if_some(&mut style, "flex-direction", &self.flex_direction);
981 write_if_some(&mut style, "flex-wrap", &self.flex_wrap);
982 write_if_some(&mut style, "align-items", &self.align_items);
983 write_if_some(&mut style, "align-self", &self.align_self);
984 write_if_some(&mut style, "justify-content", &self.justify_content);
985 write_if_some(&mut style, "justify-items", &self.justify_items);
986 write_if_some(&mut style, "gap", &self.gap);
987 write_if_some(&mut style, "row-gap", &self.row_gap);
988 write_if_some(&mut style, "column-gap", &self.column_gap);
989
990 write_if_some(&mut style, "padding", &self.padding);
992 write_if_some(&mut style, "padding-top", &self.padding_top);
993 write_if_some(&mut style, "padding-right", &self.padding_right);
994 write_if_some(&mut style, "padding-bottom", &self.padding_bottom);
995 write_if_some(&mut style, "padding-left", &self.padding_left);
996 write_if_some(&mut style, "margin", &self.margin);
997 write_if_some(&mut style, "margin-top", &self.margin_top);
998 write_if_some(&mut style, "margin-right", &self.margin_right);
999 write_if_some(&mut style, "margin-bottom", &self.margin_bottom);
1000 write_if_some(&mut style, "margin-left", &self.margin_left);
1001
1002 write_if_some(&mut style, "background-color", &self.background_color);
1004 write_if_some(&mut style, "color", &self.color);
1005 write_if_some(&mut style, "border-color", &self.border_color);
1006
1007 write_if_some(&mut style, "font-size", &self.font_size);
1009 write_if_some(&mut style, "font-weight", &self.font_weight);
1010 write_if_some(&mut style, "font-family", &self.font_family);
1011 write_if_some(&mut style, "line-height", &self.line_height);
1012 write_if_some(&mut style, "text-align", &self.text_align);
1013 write_if_some(&mut style, "text-decoration", &self.text_decoration);
1014 write_if_some(&mut style, "letter-spacing", &self.letter_spacing);
1015
1016 write_if_some(&mut style, "border-radius", &self.border_radius);
1018 write_if_some(&mut style, "border", &self.border);
1019 write_if_some(&mut style, "border-top", &self.border_top);
1020 write_if_some(&mut style, "border-right", &self.border_right);
1021 write_if_some(&mut style, "border-bottom", &self.border_bottom);
1022 write_if_some(&mut style, "border-left", &self.border_left);
1023 write_if_some(&mut style, "border-width", &self.border_width);
1024 write_if_some(&mut style, "box-shadow", &self.box_shadow);
1025
1026 write_if_some(&mut style, "width", &self.width);
1028 write_if_some(&mut style, "height", &self.height);
1029 write_if_some(&mut style, "min-width", &self.min_width);
1030 write_if_some(&mut style, "min-height", &self.min_height);
1031 write_if_some(&mut style, "max-width", &self.max_width);
1032 write_if_some(&mut style, "max-height", &self.max_height);
1033
1034 write_if_some(&mut style, "position", &self.position);
1036 write_if_some(&mut style, "top", &self.top);
1037 write_if_some(&mut style, "right", &self.right);
1038 write_if_some(&mut style, "bottom", &self.bottom);
1039 write_if_some(&mut style, "left", &self.left);
1040 write_if_some(&mut style, "z-index", &self.z_index);
1041
1042 write_if_some(&mut style, "cursor", &self.cursor);
1044 write_if_some(&mut style, "opacity", &self.opacity);
1045 write_if_some(&mut style, "transition", &self.transition);
1046 write_if_some(&mut style, "transform", &self.transform);
1047 write_if_some(&mut style, "overflow", &self.overflow);
1048 write_if_some(&mut style, "visibility", &self.visibility);
1049 write_if_some(&mut style, "pointer-events", &self.pointer_events);
1050 write_if_some(&mut style, "user-select", &self.user_select);
1051 write_if_some(&mut style, "white-space", &self.white_space);
1052 write_if_some(&mut style, "word-break", &self.word_break);
1053 write_if_some(&mut style, "outline", &self.outline);
1054 write_if_some(&mut style, "resize", &self.resize);
1055
1056 style
1057 }
1058
1059 pub fn merge(mut self, other: Style) -> Self {
1061 if other.display.is_some() {
1063 self.display = other.display;
1064 }
1065 if other.flex_direction.is_some() {
1066 self.flex_direction = other.flex_direction;
1067 }
1068 if other.flex_wrap.is_some() {
1069 self.flex_wrap = other.flex_wrap;
1070 }
1071 if other.align_items.is_some() {
1072 self.align_items = other.align_items;
1073 }
1074 if other.align_self.is_some() {
1075 self.align_self = other.align_self;
1076 }
1077 if other.justify_content.is_some() {
1078 self.justify_content = other.justify_content;
1079 }
1080 if other.justify_items.is_some() {
1081 self.justify_items = other.justify_items;
1082 }
1083 if other.gap.is_some() {
1084 self.gap = other.gap;
1085 }
1086 if other.row_gap.is_some() {
1087 self.row_gap = other.row_gap;
1088 }
1089 if other.column_gap.is_some() {
1090 self.column_gap = other.column_gap;
1091 }
1092
1093 if other.padding.is_some() {
1095 self.padding = other.padding;
1096 }
1097 if other.padding_top.is_some() {
1098 self.padding_top = other.padding_top;
1099 }
1100 if other.padding_right.is_some() {
1101 self.padding_right = other.padding_right;
1102 }
1103 if other.padding_bottom.is_some() {
1104 self.padding_bottom = other.padding_bottom;
1105 }
1106 if other.padding_left.is_some() {
1107 self.padding_left = other.padding_left;
1108 }
1109 if other.margin.is_some() {
1110 self.margin = other.margin;
1111 }
1112 if other.margin_top.is_some() {
1113 self.margin_top = other.margin_top;
1114 }
1115 if other.margin_right.is_some() {
1116 self.margin_right = other.margin_right;
1117 }
1118 if other.margin_bottom.is_some() {
1119 self.margin_bottom = other.margin_bottom;
1120 }
1121 if other.margin_left.is_some() {
1122 self.margin_left = other.margin_left;
1123 }
1124
1125 if other.background_color.is_some() {
1127 self.background_color = other.background_color;
1128 }
1129 if other.color.is_some() {
1130 self.color = other.color;
1131 }
1132 if other.border_color.is_some() {
1133 self.border_color = other.border_color;
1134 }
1135
1136 if other.font_size.is_some() {
1138 self.font_size = other.font_size;
1139 }
1140 if other.font_weight.is_some() {
1141 self.font_weight = other.font_weight;
1142 }
1143 if other.font_family.is_some() {
1144 self.font_family = other.font_family;
1145 }
1146 if other.line_height.is_some() {
1147 self.line_height = other.line_height;
1148 }
1149 if other.text_align.is_some() {
1150 self.text_align = other.text_align;
1151 }
1152 if other.text_decoration.is_some() {
1153 self.text_decoration = other.text_decoration;
1154 }
1155 if other.letter_spacing.is_some() {
1156 self.letter_spacing = other.letter_spacing;
1157 }
1158
1159 if other.border_radius.is_some() {
1161 self.border_radius = other.border_radius;
1162 }
1163 if other.border.is_some() {
1164 self.border = other.border;
1165 }
1166 if other.border_top.is_some() {
1167 self.border_top = other.border_top;
1168 }
1169 if other.border_right.is_some() {
1170 self.border_right = other.border_right;
1171 }
1172 if other.border_bottom.is_some() {
1173 self.border_bottom = other.border_bottom;
1174 }
1175 if other.border_left.is_some() {
1176 self.border_left = other.border_left;
1177 }
1178 if other.border_width.is_some() {
1179 self.border_width = other.border_width;
1180 }
1181 if other.box_shadow.is_some() {
1182 self.box_shadow = other.box_shadow;
1183 }
1184
1185 if other.width.is_some() {
1187 self.width = other.width;
1188 }
1189 if other.height.is_some() {
1190 self.height = other.height;
1191 }
1192 if other.min_width.is_some() {
1193 self.min_width = other.min_width;
1194 }
1195 if other.min_height.is_some() {
1196 self.min_height = other.min_height;
1197 }
1198 if other.max_width.is_some() {
1199 self.max_width = other.max_width;
1200 }
1201 if other.max_height.is_some() {
1202 self.max_height = other.max_height;
1203 }
1204
1205 if other.position.is_some() {
1207 self.position = other.position;
1208 }
1209 if other.top.is_some() {
1210 self.top = other.top;
1211 }
1212 if other.right.is_some() {
1213 self.right = other.right;
1214 }
1215 if other.bottom.is_some() {
1216 self.bottom = other.bottom;
1217 }
1218 if other.left.is_some() {
1219 self.left = other.left;
1220 }
1221 if other.z_index.is_some() {
1222 self.z_index = other.z_index;
1223 }
1224
1225 if other.cursor.is_some() {
1227 self.cursor = other.cursor;
1228 }
1229 if other.opacity.is_some() {
1230 self.opacity = other.opacity;
1231 }
1232 if other.transition.is_some() {
1233 self.transition = other.transition;
1234 }
1235 if other.transform.is_some() {
1236 self.transform = other.transform;
1237 }
1238 if other.overflow.is_some() {
1239 self.overflow = other.overflow;
1240 }
1241 if other.visibility.is_some() {
1242 self.visibility = other.visibility;
1243 }
1244 if other.pointer_events.is_some() {
1245 self.pointer_events = other.pointer_events;
1246 }
1247 if other.user_select.is_some() {
1248 self.user_select = other.user_select;
1249 }
1250 if other.white_space.is_some() {
1251 self.white_space = other.white_space;
1252 }
1253 if other.word_break.is_some() {
1254 self.word_break = other.word_break;
1255 }
1256 if other.outline.is_some() {
1257 self.outline = other.outline;
1258 }
1259 if other.resize.is_some() {
1260 self.resize = other.resize;
1261 }
1262
1263 self
1264 }
1265}
1266
1267fn write_if_some(style: &mut String, property: &str, value: &Option<String>) {
1269 if let Some(v) = value {
1270 write!(style, "{}:{};", property, v).unwrap();
1271 }
1272}
1273
1274#[cfg(test)]
1275mod tests {
1276 use super::*;
1277 use crate::theme::tokens::ThemeTokens;
1278
1279 #[test]
1280 fn test_basic_style() {
1281 let style = Style::new().flex().items_center().build();
1282
1283 assert!(style.contains("display:flex"));
1284 assert!(style.contains("align-items:center"));
1285 }
1286
1287 #[test]
1288 fn test_style_with_theme() {
1289 let theme = ThemeTokens::light();
1290 let style = Style::new()
1291 .flex()
1292 .gap(&theme.spacing, "md")
1293 .bg(&theme.colors.primary)
1294 .rounded(&theme.radius, "md")
1295 .build();
1296
1297 assert!(style.contains("display:flex"));
1298 assert!(style.contains("gap:16px"));
1299 assert!(style.contains("background-color:"));
1300 assert!(style.contains("border-radius:8px"));
1301 }
1302
1303 #[test]
1304 fn test_style_merge() {
1305 let base = Style::new().flex().items_center();
1306 let override_style = Style::new().justify_center();
1307
1308 let merged = base.merge(override_style);
1309 let style_str = merged.build();
1310
1311 assert!(style_str.contains("display:flex"));
1312 assert!(style_str.contains("align-items:center"));
1313 assert!(style_str.contains("justify-content:center"));
1314 }
1315}