Skip to main content

whisker_css/prop/
position.rs

1//! Position properties: `position`, edges (`top`/`right`/`bottom`/
2//! `left`), `z-index`, `inset*`.
3
4use crate::css::Css;
5use crate::data_type::LengthPercentage;
6use crate::data_type_ext::Integer;
7use crate::keyword::PositionKind;
8
9impl Css {
10    /// Sets `position`. Lynx default: `relative`.
11    /// `static` is **not** supported by Lynx.
12    /// <https://lynxjs.org/api/css/properties/position>
13    pub fn position(self, v: PositionKind) -> Self {
14        self.push("position", v)
15    }
16
17    /// Sets `top` offset (positioned elements).
18    /// <https://lynxjs.org/api/css/properties/top>
19    pub fn top(self, v: impl Into<LengthPercentage>) -> Self {
20        self.push("top", v.into())
21    }
22
23    /// Sets `right` offset (positioned elements).
24    /// <https://lynxjs.org/api/css/properties/right>
25    pub fn right(self, v: impl Into<LengthPercentage>) -> Self {
26        self.push("right", v.into())
27    }
28
29    /// Sets `bottom` offset (positioned elements).
30    /// <https://lynxjs.org/api/css/properties/bottom>
31    pub fn bottom(self, v: impl Into<LengthPercentage>) -> Self {
32        self.push("bottom", v.into())
33    }
34
35    /// Sets `left` offset (positioned elements).
36    /// <https://lynxjs.org/api/css/properties/left>
37    pub fn left(self, v: impl Into<LengthPercentage>) -> Self {
38        self.push("left", v.into())
39    }
40
41    /// Sets `inset-inline-start` — logical start edge.
42    /// <https://lynxjs.org/api/css/properties/inset-inline-start>
43    pub fn inset_inline_start(self, v: impl Into<LengthPercentage>) -> Self {
44        self.push("inset-inline-start", v.into())
45    }
46
47    /// Sets `inset-inline-end` — logical end edge.
48    /// <https://lynxjs.org/api/css/properties/inset-inline-end>
49    pub fn inset_inline_end(self, v: impl Into<LengthPercentage>) -> Self {
50        self.push("inset-inline-end", v.into())
51    }
52
53    /// Sets `z-index`. Lynx default: `auto` (no stacking context promotion).
54    /// <https://lynxjs.org/api/css/properties/z-index>
55    pub fn z_index(self, v: i32) -> Self {
56        self.push("z-index", Integer(v))
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use crate::ext::*;
63    use crate::keyword::PositionKind;
64    use crate::Css;
65
66    #[test]
67    fn position_absolute_with_offsets() {
68        let s = Css::new()
69            .position(PositionKind::Absolute)
70            .top(px(10))
71            .right(0.percent())
72            .bottom(px(10))
73            .left(0.percent());
74        assert_eq!(
75            s.to_string(),
76            "position: absolute; top: 10px; right: 0%; bottom: 10px; left: 0%;"
77        );
78    }
79
80    #[test]
81    fn z_index_negative_allowed() {
82        let s = Css::new().z_index(-1);
83        assert_eq!(s.to_string(), "z-index: -1;");
84    }
85
86    #[test]
87    fn inset_inline_logical_edges() {
88        let s = Css::new().inset_inline_start(px(4)).inset_inline_end(px(8));
89        assert_eq!(
90            s.to_string(),
91            "inset-inline-start: 4px; inset-inline-end: 8px;"
92        );
93    }
94
95    #[test]
96    fn all_position_keywords() {
97        let cases = [
98            (PositionKind::Relative, "relative"),
99            (PositionKind::Absolute, "absolute"),
100            (PositionKind::Fixed, "fixed"),
101            (PositionKind::Sticky, "sticky"),
102        ];
103        for (k, expected) in cases {
104            let s = Css::new().position(k);
105            assert_eq!(s.to_string(), format!("position: {expected};"));
106        }
107    }
108}