floem_css/
style.rs

1use std::rc::Rc;
2
3use floem::reactive::{use_context, SignalWith};
4use floem::style::Style;
5use floem::views::Decorators;
6use floem::IntoView;
7use floem_css_parser::css_to_rules;
8use smallvec::SmallVec;
9
10use crate::parser::parse_rules;
11use crate::StyleProvider;
12
13pub trait StyleCss: IntoView {
14    #[must_use]
15    fn css(self, keys: &'static str) -> <Self as IntoView>::V;
16}
17
18impl<V> StyleCss for V
19where
20    V: IntoView + 'static,
21{
22    /// # Panics
23    /// Panics at compile time if `RwSignal<Theme>` context is not provided
24    fn css(self, keys: &'static str) -> <Self as IntoView>::V {
25        let theme = use_context::<Rc<StyleProvider>>().unwrap();
26        self.style(move |s| theme.map.with(|t| t.apply_classes(s, keys)))
27            .debug_name(keys)
28    }
29}
30
31pub struct StyleMap {
32    keys: SmallVec<[String; 32]>,
33    styles: SmallVec<[Style; 32]>,
34}
35
36impl StyleMap {
37    pub fn from_css(input: &str) -> Self {
38        parse_rules(&css_to_rules(input))
39    }
40}
41
42impl StyleMap {
43    pub const fn new_const() -> Self {
44        Self {
45            keys: SmallVec::new_const(),
46            styles: SmallVec::new_const(),
47        }
48    }
49
50    pub fn get(&self, key: &str) -> Option<Style> {
51        self.keys
52            .iter()
53            .position(|k| k == key)
54            .and_then(|idx| self.styles.get(idx).cloned())
55    }
56
57    pub fn is_empty(&self) -> bool {
58        self.keys.is_empty()
59    }
60
61    pub fn clear(&mut self) {
62        self.keys.clear();
63        self.styles.clear();
64    }
65
66    pub fn insert(&mut self, key: &str, style: Style) {
67        self.keys.push(key.to_string());
68        self.styles.push(style);
69    }
70
71    pub fn remove(&mut self, key: &str) -> Option<Style> {
72        self.keys.iter().position(|k| k == key).map(|idx| {
73            self.keys.remove(idx);
74            self.styles.remove(idx)
75        })
76    }
77}
78
79impl StyleMap {
80    #[must_use]
81    pub fn apply_classes(&self, s: Style, class_str: &str) -> Style {
82        class_str
83            .split_whitespace()
84            .fold(s, |s, key| s.apply_opt(self.get(key), Style::apply))
85    }
86}