Skip to main content

whisker_css/keyword/
text.rs

1//! Text-related keyword enums.
2//!
3//! References:
4//! - <https://lynxjs.org/api/css/properties/text-align>
5//! - <https://lynxjs.org/api/css/properties/text-decoration>
6//! - <https://lynxjs.org/api/css/properties/text-overflow>
7//! - <https://lynxjs.org/api/css/properties/text-transform>
8//! - <https://lynxjs.org/api/css/properties/vertical-align>
9//! - <https://lynxjs.org/api/css/properties/direction>
10//! - <https://lynxjs.org/api/css/properties/white-space>
11//! - <https://lynxjs.org/api/css/properties/word-break>
12//! - <https://lynxjs.org/api/css/properties/word-wrap>
13
14use core::fmt;
15
16use crate::to_css::ToCss;
17
18/// The `text-align` keyword. **Lynx does not support `justify`**.
19#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
20pub enum TextAlign {
21    /// `left` — align to the left edge.
22    Left,
23    /// `right` — align to the right edge.
24    Right,
25    /// `center` — center the text.
26    Center,
27    /// `start` — align to the logical start (writing-mode aware).
28    Start,
29    /// `end` — align to the logical end.
30    End,
31}
32
33impl ToCss for TextAlign {
34    fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
35        dest.write_str(match self {
36            TextAlign::Left => "left",
37            TextAlign::Right => "right",
38            TextAlign::Center => "center",
39            TextAlign::Start => "start",
40            TextAlign::End => "end",
41        })
42    }
43}
44
45/// The `text-decoration-line` keyword (one or more values).
46#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
47pub enum TextDecorationLine {
48    /// `none` — no decoration.
49    None,
50    /// `underline` — line below the text.
51    Underline,
52    /// `overline` — line above the text.
53    Overline,
54    /// `line-through` — line through the middle of the text.
55    LineThrough,
56}
57
58impl ToCss for TextDecorationLine {
59    fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
60        dest.write_str(match self {
61            TextDecorationLine::None => "none",
62            TextDecorationLine::Underline => "underline",
63            TextDecorationLine::Overline => "overline",
64            TextDecorationLine::LineThrough => "line-through",
65        })
66    }
67}
68
69/// The `text-decoration-style` keyword.
70#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
71pub enum TextDecorationStyle {
72    /// `solid` — single straight line. Default.
73    Solid,
74    /// `double` — two parallel lines.
75    Double,
76    /// `dotted` — line made of dots.
77    Dotted,
78    /// `dashed` — line made of dashes.
79    Dashed,
80    /// `wavy` — wavy line.
81    Wavy,
82}
83
84impl ToCss for TextDecorationStyle {
85    fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
86        dest.write_str(match self {
87            TextDecorationStyle::Solid => "solid",
88            TextDecorationStyle::Double => "double",
89            TextDecorationStyle::Dotted => "dotted",
90            TextDecorationStyle::Dashed => "dashed",
91            TextDecorationStyle::Wavy => "wavy",
92        })
93    }
94}
95
96/// The `text-overflow` keyword.
97#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
98pub enum TextOverflow {
99    /// `clip` — clip overflowing text at the box edge. Default.
100    Clip,
101    /// `ellipsis` — replace overflowing text with `…`.
102    Ellipsis,
103}
104
105impl ToCss for TextOverflow {
106    fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
107        dest.write_str(match self {
108            TextOverflow::Clip => "clip",
109            TextOverflow::Ellipsis => "ellipsis",
110        })
111    }
112}
113
114/// The `text-transform` keyword.
115#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
116pub enum TextTransform {
117    /// `none` — no transformation. Default.
118    None,
119    /// `uppercase` — convert to uppercase.
120    Uppercase,
121    /// `lowercase` — convert to lowercase.
122    Lowercase,
123    /// `capitalize` — capitalize the first letter of each word.
124    Capitalize,
125}
126
127impl ToCss for TextTransform {
128    fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
129        dest.write_str(match self {
130            TextTransform::None => "none",
131            TextTransform::Uppercase => "uppercase",
132            TextTransform::Lowercase => "lowercase",
133            TextTransform::Capitalize => "capitalize",
134        })
135    }
136}
137
138/// The `vertical-align` keyword.
139#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
140pub enum VerticalAlign {
141    /// `baseline` — align to the parent baseline.
142    Baseline,
143    /// `top` — align to the top of the line box.
144    Top,
145    /// `middle` — center on the parent's center.
146    Middle,
147    /// `bottom` — align to the bottom of the line box.
148    Bottom,
149    /// `super` — raise to superscript.
150    Super,
151    /// `sub` — lower to subscript.
152    Sub,
153}
154
155impl ToCss for VerticalAlign {
156    fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
157        dest.write_str(match self {
158            VerticalAlign::Baseline => "baseline",
159            VerticalAlign::Top => "top",
160            VerticalAlign::Middle => "middle",
161            VerticalAlign::Bottom => "bottom",
162            VerticalAlign::Super => "super",
163            VerticalAlign::Sub => "sub",
164        })
165    }
166}
167
168/// The `direction` keyword.
169#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
170pub enum Direction {
171    /// `ltr` — left-to-right. Default.
172    Ltr,
173    /// `rtl` — right-to-left.
174    Rtl,
175}
176
177impl ToCss for Direction {
178    fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
179        dest.write_str(match self {
180            Direction::Ltr => "ltr",
181            Direction::Rtl => "rtl",
182        })
183    }
184}
185
186/// The `white-space` keyword.
187#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
188pub enum WhiteSpace {
189    /// `normal` — collapse whitespace, allow wrapping. Default.
190    Normal,
191    /// `nowrap` — collapse whitespace, no wrapping.
192    Nowrap,
193    /// `pre` — preserve whitespace, no wrapping.
194    Pre,
195    /// `pre-wrap` — preserve whitespace, allow wrapping.
196    PreWrap,
197    /// `pre-line` — collapse whitespace, preserve line breaks.
198    PreLine,
199}
200
201impl ToCss for WhiteSpace {
202    fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
203        dest.write_str(match self {
204            WhiteSpace::Normal => "normal",
205            WhiteSpace::Nowrap => "nowrap",
206            WhiteSpace::Pre => "pre",
207            WhiteSpace::PreWrap => "pre-wrap",
208            WhiteSpace::PreLine => "pre-line",
209        })
210    }
211}
212
213/// The `word-break` keyword.
214#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
215pub enum WordBreak {
216    /// `normal` — break at standard locations. Default.
217    Normal,
218    /// `break-all` — break at any character.
219    BreakAll,
220    /// `keep-all` — never break at CJK punctuation.
221    KeepAll,
222}
223
224impl ToCss for WordBreak {
225    fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
226        dest.write_str(match self {
227            WordBreak::Normal => "normal",
228            WordBreak::BreakAll => "break-all",
229            WordBreak::KeepAll => "keep-all",
230        })
231    }
232}
233
234/// The `word-wrap` (aka `overflow-wrap`) keyword.
235#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
236pub enum WordWrap {
237    /// `normal` — break at allowed break points only. Default.
238    Normal,
239    /// `break-word` — break long words to prevent overflow.
240    BreakWord,
241}
242
243impl ToCss for WordWrap {
244    fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
245        dest.write_str(match self {
246            WordWrap::Normal => "normal",
247            WordWrap::BreakWord => "break-word",
248        })
249    }
250}
251
252#[cfg(test)]
253mod tests {
254    use super::*;
255
256    macro_rules! assert_keyword_set {
257        ($cases:expr) => {
258            for (k, expected) in $cases {
259                assert_eq!(k.to_css_string(), expected);
260            }
261        };
262    }
263
264    #[test]
265    fn text_align_all() {
266        assert_keyword_set!([
267            (TextAlign::Left, "left"),
268            (TextAlign::Right, "right"),
269            (TextAlign::Center, "center"),
270            (TextAlign::Start, "start"),
271            (TextAlign::End, "end"),
272        ]);
273    }
274
275    #[test]
276    fn text_decoration_line_all() {
277        assert_keyword_set!([
278            (TextDecorationLine::None, "none"),
279            (TextDecorationLine::Underline, "underline"),
280            (TextDecorationLine::Overline, "overline"),
281            (TextDecorationLine::LineThrough, "line-through"),
282        ]);
283    }
284
285    #[test]
286    fn text_decoration_style_all() {
287        assert_keyword_set!([
288            (TextDecorationStyle::Solid, "solid"),
289            (TextDecorationStyle::Double, "double"),
290            (TextDecorationStyle::Dotted, "dotted"),
291            (TextDecorationStyle::Dashed, "dashed"),
292            (TextDecorationStyle::Wavy, "wavy"),
293        ]);
294    }
295
296    #[test]
297    fn text_overflow_all() {
298        assert_keyword_set!([
299            (TextOverflow::Clip, "clip"),
300            (TextOverflow::Ellipsis, "ellipsis"),
301        ]);
302    }
303
304    #[test]
305    fn text_transform_all() {
306        assert_keyword_set!([
307            (TextTransform::None, "none"),
308            (TextTransform::Uppercase, "uppercase"),
309            (TextTransform::Lowercase, "lowercase"),
310            (TextTransform::Capitalize, "capitalize"),
311        ]);
312    }
313
314    #[test]
315    fn vertical_align_all() {
316        assert_keyword_set!([
317            (VerticalAlign::Baseline, "baseline"),
318            (VerticalAlign::Top, "top"),
319            (VerticalAlign::Middle, "middle"),
320            (VerticalAlign::Bottom, "bottom"),
321            (VerticalAlign::Super, "super"),
322            (VerticalAlign::Sub, "sub"),
323        ]);
324    }
325
326    #[test]
327    fn direction_all() {
328        assert_keyword_set!([(Direction::Ltr, "ltr"), (Direction::Rtl, "rtl")]);
329    }
330
331    #[test]
332    fn white_space_all() {
333        assert_keyword_set!([
334            (WhiteSpace::Normal, "normal"),
335            (WhiteSpace::Nowrap, "nowrap"),
336            (WhiteSpace::Pre, "pre"),
337            (WhiteSpace::PreWrap, "pre-wrap"),
338            (WhiteSpace::PreLine, "pre-line"),
339        ]);
340    }
341
342    #[test]
343    fn word_break_all() {
344        assert_keyword_set!([
345            (WordBreak::Normal, "normal"),
346            (WordBreak::BreakAll, "break-all"),
347            (WordBreak::KeepAll, "keep-all"),
348        ]);
349    }
350
351    #[test]
352    fn word_wrap_all() {
353        assert_keyword_set!([
354            (WordWrap::Normal, "normal"),
355            (WordWrap::BreakWord, "break-word"),
356        ]);
357    }
358}