Skip to main content

whisker_css/keyword/
typography.rs

1//! Typography-related keyword enums (font + cursor).
2//!
3//! References:
4//! - <https://lynxjs.org/api/css/properties/font-style>
5//! - <https://lynxjs.org/api/css/properties/font-weight>
6//! - <https://lynxjs.org/api/css/properties/font-variant>
7//! - <https://lynxjs.org/api/css/properties/cursor>
8
9use core::fmt;
10
11use crate::to_css::ToCss;
12
13/// The `font-style` keyword.
14#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
15pub enum FontStyle {
16    /// `normal` — upright. Default.
17    Normal,
18    /// `italic` — italicized.
19    Italic,
20    /// `oblique` — slanted (typically synthesized from the upright
21    /// face when an explicit oblique face is unavailable).
22    Oblique,
23}
24
25impl ToCss for FontStyle {
26    fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
27        dest.write_str(match self {
28            FontStyle::Normal => "normal",
29            FontStyle::Italic => "italic",
30            FontStyle::Oblique => "oblique",
31        })
32    }
33}
34
35/// The `font-weight` keyword or numeric value. **Lynx does not
36/// support `bolder` or `lighter`**.
37///
38/// Numeric weights are accepted in the standard CSS range `1..=1000`
39/// (commonly `100`, `200`, …, `900`).
40#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
41pub enum FontWeight {
42    /// `normal` — equivalent to `400`. Default.
43    Normal,
44    /// `bold` — equivalent to `700`.
45    Bold,
46    /// Numeric weight, typically a multiple of 100.
47    Numeric(u16),
48}
49
50impl ToCss for FontWeight {
51    fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
52        match self {
53            FontWeight::Normal => dest.write_str("normal"),
54            FontWeight::Bold => dest.write_str("bold"),
55            FontWeight::Numeric(n) => write!(dest, "{n}"),
56        }
57    }
58}
59
60/// The `font-variant` keyword (Lynx accepts a small subset of the CSS
61/// font-variant shorthand).
62#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
63pub enum FontVariant {
64    /// `normal` — no variant features. Default.
65    Normal,
66    /// `small-caps` — render lowercase as small capitals.
67    SmallCaps,
68}
69
70impl ToCss for FontVariant {
71    fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
72        dest.write_str(match self {
73            FontVariant::Normal => "normal",
74            FontVariant::SmallCaps => "small-caps",
75        })
76    }
77}
78
79/// The `cursor` keyword. The Lynx set tracks the common subset of
80/// CSS cursors that map to mobile pointer affordances.
81#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
82pub enum Cursor {
83    /// `auto` — let the platform decide. Default.
84    Auto,
85    /// `default` — the platform's default pointer.
86    Default,
87    /// `pointer` — typically a hand, for interactive elements.
88    Pointer,
89    /// `text` — typically an I-beam, for selectable text.
90    Text,
91    /// `none` — hide the cursor.
92    None,
93}
94
95impl ToCss for Cursor {
96    fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
97        dest.write_str(match self {
98            Cursor::Auto => "auto",
99            Cursor::Default => "default",
100            Cursor::Pointer => "pointer",
101            Cursor::Text => "text",
102            Cursor::None => "none",
103        })
104    }
105}
106
107#[cfg(test)]
108mod tests {
109    use super::*;
110
111    #[test]
112    fn font_style_all() {
113        assert_eq!(FontStyle::Normal.to_css_string(), "normal");
114        assert_eq!(FontStyle::Italic.to_css_string(), "italic");
115        assert_eq!(FontStyle::Oblique.to_css_string(), "oblique");
116    }
117
118    #[test]
119    fn font_weight_keywords() {
120        assert_eq!(FontWeight::Normal.to_css_string(), "normal");
121        assert_eq!(FontWeight::Bold.to_css_string(), "bold");
122    }
123
124    #[test]
125    fn font_weight_numeric() {
126        assert_eq!(FontWeight::Numeric(100).to_css_string(), "100");
127        assert_eq!(FontWeight::Numeric(700).to_css_string(), "700");
128        assert_eq!(FontWeight::Numeric(950).to_css_string(), "950");
129    }
130
131    #[test]
132    fn font_variant_all() {
133        assert_eq!(FontVariant::Normal.to_css_string(), "normal");
134        assert_eq!(FontVariant::SmallCaps.to_css_string(), "small-caps");
135    }
136
137    #[test]
138    fn cursor_all() {
139        let cases = [
140            (Cursor::Auto, "auto"),
141            (Cursor::Default, "default"),
142            (Cursor::Pointer, "pointer"),
143            (Cursor::Text, "text"),
144            (Cursor::None, "none"),
145        ];
146        for (k, expected) in cases {
147            assert_eq!(k.to_css_string(), expected);
148        }
149    }
150}