Skip to main content

whisker_css/shorthand/
flex.rs

1//! `flex` shorthand.
2
3use crate::css::Css;
4use crate::to_css::number_to_string;
5use crate::value::FlexBasis;
6
7/// `flex` shorthand value. CSS allows `flex: <grow> <shrink>?
8/// <basis>?` plus the keywords `none`, `auto`, `initial`. This enum
9/// covers all five forms.
10#[derive(Clone, Debug, PartialEq)]
11pub enum Flex {
12    /// `none` — equivalent to `0 0 auto`.
13    None,
14    /// `auto` — equivalent to `1 1 auto`.
15    Auto,
16    /// `initial` — equivalent to `0 1 auto`.
17    Initial,
18    /// `<number>` — equivalent to `<number> 1 0%`.
19    Number(f32),
20    /// Explicit triple `grow shrink basis`.
21    Full {
22        /// `flex-grow`.
23        grow: f32,
24        /// `flex-shrink`.
25        shrink: f32,
26        /// `flex-basis`.
27        basis: FlexBasis,
28    },
29}
30
31impl Flex {
32    /// Expand to `(grow, shrink, basis)`.
33    pub fn expand(self) -> (f32, f32, FlexBasis) {
34        match self {
35            Flex::None => (0.0, 0.0, FlexBasis::Auto),
36            Flex::Auto => (1.0, 1.0, FlexBasis::Auto),
37            Flex::Initial => (0.0, 1.0, FlexBasis::Auto),
38            Flex::Number(n) => (
39                n,
40                1.0,
41                FlexBasis::LengthPercentage(crate::data_type::Percentage(0.0).into()),
42            ),
43            Flex::Full {
44                grow,
45                shrink,
46                basis,
47            } => (grow, shrink, basis),
48        }
49    }
50}
51
52impl Css {
53    /// Sets `flex` shorthand — expands to `flex-grow`, `flex-shrink`,
54    /// `flex-basis`.
55    /// <https://lynxjs.org/api/css/properties/flex>
56    pub fn flex(self, v: Flex) -> Self {
57        let (grow, shrink, basis) = v.expand();
58        self.push_raw("flex-grow", number_to_string(grow))
59            .push_raw("flex-shrink", number_to_string(shrink))
60            .push("flex-basis", basis)
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use crate::ext::*;
67    use crate::value::FlexBasis;
68    use crate::Css;
69
70    use super::*;
71
72    #[test]
73    fn flex_none() {
74        let s = Css::new().flex(Flex::None);
75        assert_eq!(
76            s.to_string(),
77            "flex-grow: 0; flex-shrink: 0; flex-basis: auto;"
78        );
79    }
80
81    #[test]
82    fn flex_auto() {
83        let s = Css::new().flex(Flex::Auto);
84        assert_eq!(
85            s.to_string(),
86            "flex-grow: 1; flex-shrink: 1; flex-basis: auto;"
87        );
88    }
89
90    #[test]
91    fn flex_initial() {
92        let s = Css::new().flex(Flex::Initial);
93        assert_eq!(
94            s.to_string(),
95            "flex-grow: 0; flex-shrink: 1; flex-basis: auto;"
96        );
97    }
98
99    #[test]
100    fn flex_number() {
101        let s = Css::new().flex(Flex::Number(2.0));
102        assert_eq!(
103            s.to_string(),
104            "flex-grow: 2; flex-shrink: 1; flex-basis: 0%;"
105        );
106    }
107
108    #[test]
109    fn flex_full_triple() {
110        let s = Css::new().flex(Flex::Full {
111            grow: 1.5,
112            shrink: 0.5,
113            basis: FlexBasis::LengthPercentage(px(100).into()),
114        });
115        assert_eq!(
116            s.to_string(),
117            "flex-grow: 1.5; flex-shrink: 0.5; flex-basis: 100px;"
118        );
119    }
120
121    #[test]
122    fn flex_then_grow_override() {
123        let s = Css::new().flex(Flex::Auto).flex_grow(3.0);
124        assert_eq!(
125            s.to_string(),
126            "flex-shrink: 1; flex-basis: auto; flex-grow: 3;"
127        );
128    }
129}