Skip to main content

whisker_css/prop/
border.rs

1//! Border longhand properties + `border-radius` corners.
2
3use crate::css::Css;
4use crate::data_type::{Color, LengthPercentage};
5use crate::keyword::BorderStyle;
6
7impl Css {
8    // ---------- border-width longhands ----------
9
10    /// Sets `border-top-width`.
11    /// <https://lynxjs.org/api/css/properties/border-top-width>
12    pub fn border_top_width(self, v: impl Into<LengthPercentage>) -> Self {
13        self.push("border-top-width", v.into())
14    }
15
16    /// Sets `border-right-width`.
17    /// <https://lynxjs.org/api/css/properties/border-right-width>
18    pub fn border_right_width(self, v: impl Into<LengthPercentage>) -> Self {
19        self.push("border-right-width", v.into())
20    }
21
22    /// Sets `border-bottom-width`.
23    /// <https://lynxjs.org/api/css/properties/border-bottom-width>
24    pub fn border_bottom_width(self, v: impl Into<LengthPercentage>) -> Self {
25        self.push("border-bottom-width", v.into())
26    }
27
28    /// Sets `border-left-width`.
29    /// <https://lynxjs.org/api/css/properties/border-left-width>
30    pub fn border_left_width(self, v: impl Into<LengthPercentage>) -> Self {
31        self.push("border-left-width", v.into())
32    }
33
34    // ---------- border-style longhands ----------
35
36    /// Sets `border-top-style`.
37    /// <https://lynxjs.org/api/css/properties/border-top-style>
38    pub fn border_top_style(self, v: BorderStyle) -> Self {
39        self.push("border-top-style", v)
40    }
41
42    /// Sets `border-right-style`.
43    /// <https://lynxjs.org/api/css/properties/border-right-style>
44    pub fn border_right_style(self, v: BorderStyle) -> Self {
45        self.push("border-right-style", v)
46    }
47
48    /// Sets `border-bottom-style`.
49    /// <https://lynxjs.org/api/css/properties/border-bottom-style>
50    pub fn border_bottom_style(self, v: BorderStyle) -> Self {
51        self.push("border-bottom-style", v)
52    }
53
54    /// Sets `border-left-style`.
55    /// <https://lynxjs.org/api/css/properties/border-left-style>
56    pub fn border_left_style(self, v: BorderStyle) -> Self {
57        self.push("border-left-style", v)
58    }
59
60    // ---------- border-color longhands ----------
61
62    /// Sets `border-top-color`.
63    /// <https://lynxjs.org/api/css/properties/border-top-color>
64    pub fn border_top_color(self, v: Color) -> Self {
65        self.push("border-top-color", v)
66    }
67
68    /// Sets `border-right-color`.
69    /// <https://lynxjs.org/api/css/properties/border-right-color>
70    pub fn border_right_color(self, v: Color) -> Self {
71        self.push("border-right-color", v)
72    }
73
74    /// Sets `border-bottom-color`.
75    /// <https://lynxjs.org/api/css/properties/border-bottom-color>
76    pub fn border_bottom_color(self, v: Color) -> Self {
77        self.push("border-bottom-color", v)
78    }
79
80    /// Sets `border-left-color`.
81    /// <https://lynxjs.org/api/css/properties/border-left-color>
82    pub fn border_left_color(self, v: Color) -> Self {
83        self.push("border-left-color", v)
84    }
85
86    // ---------- border-radius corners ----------
87
88    /// Sets `border-top-left-radius`.
89    /// <https://lynxjs.org/api/css/properties/border-top-left-radius>
90    pub fn border_top_left_radius(self, v: impl Into<LengthPercentage>) -> Self {
91        self.push("border-top-left-radius", v.into())
92    }
93
94    /// Sets `border-top-right-radius`.
95    /// <https://lynxjs.org/api/css/properties/border-top-right-radius>
96    pub fn border_top_right_radius(self, v: impl Into<LengthPercentage>) -> Self {
97        self.push("border-top-right-radius", v.into())
98    }
99
100    /// Sets `border-bottom-right-radius`.
101    /// <https://lynxjs.org/api/css/properties/border-bottom-right-radius>
102    pub fn border_bottom_right_radius(self, v: impl Into<LengthPercentage>) -> Self {
103        self.push("border-bottom-right-radius", v.into())
104    }
105
106    /// Sets `border-bottom-left-radius`.
107    /// <https://lynxjs.org/api/css/properties/border-bottom-left-radius>
108    pub fn border_bottom_left_radius(self, v: impl Into<LengthPercentage>) -> Self {
109        self.push("border-bottom-left-radius", v.into())
110    }
111
112    /// Sets `border-radius` shorthand. Expands to the four corner
113    /// longhand properties so subsequent per-corner overrides win.
114    /// <https://lynxjs.org/api/css/properties/border-radius>
115    pub fn border_radius(self, v: impl Into<LengthPercentage>) -> Self {
116        let v = v.into();
117        self.border_top_left_radius(v.clone())
118            .border_top_right_radius(v.clone())
119            .border_bottom_right_radius(v.clone())
120            .border_bottom_left_radius(v)
121    }
122
123    /// Sets `border-radius` to a [`BorderRadius`](crate::BorderRadius)
124    /// with per-corner control and optional elliptical second axis.
125    /// Pushed as the shorthand because Lynx serializes elliptical
126    /// corners via the `/` separator that has no longhand form.
127    /// <https://lynxjs.org/api/css/properties/border-radius>
128    pub fn border_radius_full(self, v: crate::BorderRadius) -> Self {
129        self.push("border-radius", v)
130    }
131}
132
133#[cfg(test)]
134mod tests {
135    use crate::data_type::Color;
136    use crate::ext::*;
137    use crate::keyword::BorderStyle;
138    use crate::Css;
139
140    #[test]
141    fn border_width_per_side() {
142        let s = Css::new()
143            .border_top_width(px(1))
144            .border_right_width(px(2))
145            .border_bottom_width(px(3))
146            .border_left_width(px(4));
147        assert_eq!(
148            s.to_string(),
149            "border-top-width: 1px; border-right-width: 2px; border-bottom-width: 3px; border-left-width: 4px;"
150        );
151    }
152
153    #[test]
154    fn border_style_per_side() {
155        let s = Css::new()
156            .border_top_style(BorderStyle::Solid)
157            .border_right_style(BorderStyle::Dashed)
158            .border_bottom_style(BorderStyle::Dotted)
159            .border_left_style(BorderStyle::Double);
160        assert_eq!(
161            s.to_string(),
162            "border-top-style: solid; border-right-style: dashed; border-bottom-style: dotted; border-left-style: double;"
163        );
164    }
165
166    #[test]
167    fn border_color_per_side() {
168        let red = Color::hex(0xFF0000);
169        let blue = Color::hex(0x0000FF);
170        let s = Css::new()
171            .border_top_color(red)
172            .border_right_color(blue)
173            .border_bottom_color(red)
174            .border_left_color(blue);
175        assert_eq!(
176            s.to_string(),
177            "border-top-color: rgb(255, 0, 0); border-right-color: rgb(0, 0, 255); border-bottom-color: rgb(255, 0, 0); border-left-color: rgb(0, 0, 255);"
178        );
179    }
180
181    #[test]
182    fn border_radius_uniform_expands() {
183        let s = Css::new().border_radius(px(8));
184        assert_eq!(
185            s.to_string(),
186            "border-top-left-radius: 8px; border-top-right-radius: 8px; border-bottom-right-radius: 8px; border-bottom-left-radius: 8px;"
187        );
188    }
189
190    #[test]
191    fn border_radius_corners_individual_override() {
192        let s = Css::new()
193            .border_radius(px(8))
194            .border_top_left_radius(px(0));
195        assert_eq!(
196            s.to_string(),
197            "border-top-right-radius: 8px; border-bottom-right-radius: 8px; border-bottom-left-radius: 8px; border-top-left-radius: 0px;"
198        );
199    }
200}