whisker_css/shorthand/
border.rs1use crate::css::Css;
4use crate::data_type::{Color, LengthPercentage};
5use crate::keyword::BorderStyle;
6
7#[derive(Clone, Debug, Default, PartialEq)]
13pub struct Border {
14 pub width: Option<LengthPercentage>,
16 pub style: Option<BorderStyle>,
18 pub color: Option<Color>,
20}
21
22impl Border {
23 pub fn new() -> Self {
25 Self::default()
26 }
27
28 pub fn width(mut self, v: impl Into<LengthPercentage>) -> Self {
30 self.width = Some(v.into());
31 self
32 }
33
34 pub fn style(mut self, v: BorderStyle) -> Self {
36 self.style = Some(v);
37 self
38 }
39
40 pub fn solid(self) -> Self {
42 self.style(BorderStyle::Solid)
43 }
44
45 pub fn dashed(self) -> Self {
47 self.style(BorderStyle::Dashed)
48 }
49
50 pub fn dotted(self) -> Self {
52 self.style(BorderStyle::Dotted)
53 }
54
55 pub fn color(mut self, v: Color) -> Self {
57 self.color = Some(v);
58 self
59 }
60}
61
62impl Css {
63 pub fn border(self, b: Border) -> Self {
68 self.border_top(b.clone())
69 .border_right(b.clone())
70 .border_bottom(b.clone())
71 .border_left(b)
72 }
73
74 pub fn border_top(mut self, b: Border) -> Self {
77 if let Some(w) = b.width {
78 self = self.border_top_width(w);
79 }
80 if let Some(s) = b.style {
81 self = self.border_top_style(s);
82 }
83 if let Some(c) = b.color {
84 self = self.border_top_color(c);
85 }
86 self
87 }
88
89 pub fn border_right(mut self, b: Border) -> Self {
92 if let Some(w) = b.width {
93 self = self.border_right_width(w);
94 }
95 if let Some(s) = b.style {
96 self = self.border_right_style(s);
97 }
98 if let Some(c) = b.color {
99 self = self.border_right_color(c);
100 }
101 self
102 }
103
104 pub fn border_bottom(mut self, b: Border) -> Self {
107 if let Some(w) = b.width {
108 self = self.border_bottom_width(w);
109 }
110 if let Some(s) = b.style {
111 self = self.border_bottom_style(s);
112 }
113 if let Some(c) = b.color {
114 self = self.border_bottom_color(c);
115 }
116 self
117 }
118
119 pub fn border_left(mut self, b: Border) -> Self {
122 if let Some(w) = b.width {
123 self = self.border_left_width(w);
124 }
125 if let Some(s) = b.style {
126 self = self.border_left_style(s);
127 }
128 if let Some(c) = b.color {
129 self = self.border_left_color(c);
130 }
131 self
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use crate::data_type::Color;
138 use crate::ext::*;
139 use crate::keyword::BorderStyle;
140 use crate::Css;
141
142 use super::*;
143
144 #[test]
145 fn border_full() {
146 let s = Css::new().border(
147 Border::new()
148 .width(px(1))
149 .solid()
150 .color(Color::hex(0xCCCCCC)),
151 );
152 assert_eq!(
153 s.to_string(),
154 "border-top-width: 1px; border-top-style: solid; border-top-color: rgb(204, 204, 204); border-right-width: 1px; border-right-style: solid; border-right-color: rgb(204, 204, 204); border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(204, 204, 204); border-left-width: 1px; border-left-style: solid; border-left-color: rgb(204, 204, 204);"
155 );
156 }
157
158 #[test]
159 fn border_partial_only_style() {
160 let s = Css::new().border(Border::new().solid());
161 assert_eq!(
162 s.to_string(),
163 "border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid;"
164 );
165 }
166
167 #[test]
168 fn border_bottom_overrides_border() {
169 let s = Css::new()
170 .border(
171 Border::new()
172 .width(px(1))
173 .solid()
174 .color(Color::hex(0x000000)),
175 )
176 .border_bottom(Border::new().width(px(3)).color(Color::hex(0xFF0000)));
177 let css = s.to_string();
180 assert!(css.contains("border-bottom-width: 3px"));
181 assert!(css.contains("border-bottom-color: rgb(255, 0, 0)"));
182 assert!(css.contains("border-bottom-style: solid"));
183 assert!(css.contains("border-top-width: 1px"));
184 }
185
186 #[test]
187 fn border_style_constructors() {
188 let solid = Border::new().solid();
189 let dashed = Border::new().dashed();
190 let dotted = Border::new().dotted();
191 assert_eq!(solid.style, Some(BorderStyle::Solid));
192 assert_eq!(dashed.style, Some(BorderStyle::Dashed));
193 assert_eq!(dotted.style, Some(BorderStyle::Dotted));
194 }
195
196 #[test]
197 fn border_per_side_individual() {
198 let s = Css::new()
199 .border_top(Border::new().width(px(1)).solid())
200 .border_right(Border::new().width(px(2)).dashed())
201 .border_bottom(Border::new().width(px(3)).dotted())
202 .border_left(Border::new().width(px(4)).style(BorderStyle::Double));
203 assert_eq!(
204 s.to_string(),
205 "border-top-width: 1px; border-top-style: solid; border-right-width: 2px; border-right-style: dashed; border-bottom-width: 3px; border-bottom-style: dotted; border-left-width: 4px; border-left-style: double;"
206 );
207 }
208}