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 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}