polished_css/style/
mod.rs

1//! Specififies the look and feel of a targetted UI element(s).
2
3use crate::{
4    property::Property,
5    selector::{pseudo::PseudoSelector, Selector, SelectorDisplay},
6};
7
8pub type Content = String;
9pub type Declarations = Vec<String>;
10
11#[derive(Clone, Debug, Default, PartialEq, typed_builder::TypedBuilder)]
12pub struct Style {
13    #[builder(default, setter(into))]
14    pub selector: Selector,
15    #[builder(default, setter(transform = |list: &[&impl Property]| properties_to_declarations(list)))]
16    pub declarations: Declarations,
17    #[builder(default, setter(strip_option))]
18    pub pseudo: Option<PseudoSelector>,
19    // TODO: Add media queries
20    // TODO: Add container queries
21}
22
23fn properties_to_declarations(properties: &[&impl Property]) -> Declarations {
24    properties
25        .iter()
26        .map(|property| property.declaration())
27        .collect()
28}
29
30impl Style {
31    #[must_use]
32    pub fn content(&self) -> Content {
33        let declarations = self.declarations.join(";");
34
35        if self.selector.is_inlined() {
36            declarations
37        } else {
38            let selector = self.selector.as_styles_content();
39            format!("{selector}{{{declarations}}}")
40        }
41    }
42}
43
44#[cfg(test)]
45mod test {
46    #[test]
47    fn builder() {
48        use crate::{
49            data_type::{AlphaStorage, PercentageStorage},
50            selector::{Class, Element, Id},
51        };
52        assert_eq!(
53            super::Style::builder()
54                .declarations(&[&crate::property::Opacity::invisible()])
55                .build()
56                .content(),
57            String::from("opacity:0")
58        );
59
60        assert_eq!(
61            super::Style::builder()
62                .selector(Id::from("test"))
63                .declarations(&[&crate::property::Opacity::visible()])
64                .build()
65                .content(),
66            String::from("#test{opacity:1}")
67        );
68
69        assert_eq!(
70            super::Style::builder()
71                .selector(Element::Main)
72                .declarations(&[&crate::property::Opacity::invisible()])
73                .build()
74                .content(),
75            String::from("main{opacity:0}")
76        );
77
78        assert_eq!(
79            super::Style::builder()
80                .selector(Class::from("my-example-class"))
81                .declarations(&[&crate::property::Opacity::percentage(100.0)])
82                .build()
83                .content(),
84            String::from(".my-example-class{opacity:100%}")
85        );
86    }
87}