Skip to main content

whisker_css/keyword/
layout.rs

1//! Layout-related keyword enums.
2//!
3//! References:
4//! - <https://lynxjs.org/api/css/properties/display>
5//! - <https://lynxjs.org/api/css/properties/position>
6//! - <https://lynxjs.org/api/css/properties/overflow>
7//! - <https://lynxjs.org/api/css/properties/visibility>
8//! - <https://lynxjs.org/api/css/properties/box-sizing>
9//! - <https://lynxjs.org/api/css/properties/pointer-events>
10
11use core::fmt;
12
13use crate::to_css::ToCss;
14
15/// The `display` keyword. Lynx's default for `<view>` is
16/// [`Display::Linear`] (Lynx's vertical/horizontal stacking layout);
17/// `flex` is required to opt into CSS flexbox semantics.
18#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
19pub enum Display {
20    /// `none` — element is removed from the layout tree.
21    None,
22    /// `flex` — CSS flexbox layout.
23    Flex,
24    /// `grid` — CSS grid layout.
25    Grid,
26    /// `linear` — Lynx's linear layout (default for `<view>`).
27    Linear,
28    /// `relative` — Lynx's relative-positioning container.
29    Relative,
30}
31
32impl ToCss for Display {
33    fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
34        dest.write_str(match self {
35            Display::None => "none",
36            Display::Flex => "flex",
37            Display::Grid => "grid",
38            Display::Linear => "linear",
39            Display::Relative => "relative",
40        })
41    }
42}
43
44/// The `position` keyword. **Lynx does not support `static`** — the
45/// default in Lynx is `relative`, so a `static` value is meaningless
46/// and is omitted from this enum.
47#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
48pub enum PositionKind {
49    /// `relative` — positioned with normal flow as origin (default).
50    Relative,
51    /// `absolute` — positioned with the containing block as origin.
52    Absolute,
53    /// `fixed` — positioned with the viewport as origin.
54    Fixed,
55    /// `sticky` — switches between `relative` and `fixed` based on
56    /// scroll position.
57    Sticky,
58}
59
60impl ToCss for PositionKind {
61    fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
62        dest.write_str(match self {
63            PositionKind::Relative => "relative",
64            PositionKind::Absolute => "absolute",
65            PositionKind::Fixed => "fixed",
66            PositionKind::Sticky => "sticky",
67        })
68    }
69}
70
71/// The `overflow` keyword. **Lynx supports only two values** —
72/// `visible` (default) and `hidden`. CSS's `scroll` and `auto` are
73/// **not** supported; use a `<scroll-view>` element for scrolling.
74#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
75pub enum Overflow {
76    /// `visible` — content overflows the box. Default.
77    Visible,
78    /// `hidden` — content is clipped to the box.
79    Hidden,
80}
81
82impl ToCss for Overflow {
83    fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
84        dest.write_str(match self {
85            Overflow::Visible => "visible",
86            Overflow::Hidden => "hidden",
87        })
88    }
89}
90
91/// The `visibility` keyword. **Lynx does not support `collapse`**.
92#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
93pub enum Visibility {
94    /// `visible` — element is rendered. Default.
95    Visible,
96    /// `hidden` — element is invisible but still occupies space.
97    Hidden,
98}
99
100impl ToCss for Visibility {
101    fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
102        dest.write_str(match self {
103            Visibility::Visible => "visible",
104            Visibility::Hidden => "hidden",
105        })
106    }
107}
108
109/// The `box-sizing` keyword.
110#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
111pub enum BoxSizing {
112    /// `content-box` — `width`/`height` apply to the content box only.
113    ContentBox,
114    /// `border-box` — `width`/`height` include padding and border.
115    BorderBox,
116}
117
118impl ToCss for BoxSizing {
119    fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
120        dest.write_str(match self {
121            BoxSizing::ContentBox => "content-box",
122            BoxSizing::BorderBox => "border-box",
123        })
124    }
125}
126
127/// The `pointer-events` keyword.
128#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
129pub enum PointerEvents {
130    /// `auto` — element receives pointer events.
131    Auto,
132    /// `none` — element is invisible to pointer events; events pass
133    /// through.
134    None,
135}
136
137impl ToCss for PointerEvents {
138    fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
139        dest.write_str(match self {
140            PointerEvents::Auto => "auto",
141            PointerEvents::None => "none",
142        })
143    }
144}
145
146#[cfg(test)]
147mod tests {
148    use super::*;
149
150    #[test]
151    fn display_keywords() {
152        let cases = [
153            (Display::None, "none"),
154            (Display::Flex, "flex"),
155            (Display::Grid, "grid"),
156            (Display::Linear, "linear"),
157            (Display::Relative, "relative"),
158        ];
159        for (k, expected) in cases {
160            assert_eq!(k.to_css_string(), expected);
161        }
162    }
163
164    #[test]
165    fn position_keywords() {
166        let cases = [
167            (PositionKind::Relative, "relative"),
168            (PositionKind::Absolute, "absolute"),
169            (PositionKind::Fixed, "fixed"),
170            (PositionKind::Sticky, "sticky"),
171        ];
172        for (k, expected) in cases {
173            assert_eq!(k.to_css_string(), expected);
174        }
175    }
176
177    #[test]
178    fn overflow_keywords() {
179        assert_eq!(Overflow::Visible.to_css_string(), "visible");
180        assert_eq!(Overflow::Hidden.to_css_string(), "hidden");
181    }
182
183    #[test]
184    fn visibility_keywords() {
185        assert_eq!(Visibility::Visible.to_css_string(), "visible");
186        assert_eq!(Visibility::Hidden.to_css_string(), "hidden");
187    }
188
189    #[test]
190    fn box_sizing_keywords() {
191        assert_eq!(BoxSizing::ContentBox.to_css_string(), "content-box");
192        assert_eq!(BoxSizing::BorderBox.to_css_string(), "border-box");
193    }
194
195    #[test]
196    fn pointer_events_keywords() {
197        assert_eq!(PointerEvents::Auto.to_css_string(), "auto");
198        assert_eq!(PointerEvents::None.to_css_string(), "none");
199    }
200}