1use std::{cell::RefCell, rc::Rc};
2use web_sys::{window, Document, Element};
3
4use crate::{css::Css, id_generator::IdGenerator, parser::process_css};
5
6thread_local! {
7 static ID_GENERATOR: Rc<RefCell<IdGenerator>> = Rc::new(RefCell::new(IdGenerator::new()));
8}
9
10pub struct CssManager {
27 document: Document,
28}
29
30#[allow(dead_code)]
31impl CssManager {
32 pub fn new() -> Self {
40 CssManager {
41 document: window().unwrap().document().unwrap(),
42 }
43 }
44
45 pub fn attach_css(&mut self, css: &str) -> Css {
58 let id = ID_GENERATOR.with(|gen| gen.as_ref().borrow_mut().get_new_id());
60 let prefix = generate_prefix(id);
61
62 let (new_css, mapping) = process_css(css, &prefix);
64
65 let style: Element = add_new_style_element(&self.document);
67 style.set_text_content(Some(&new_css));
68
69 Css::new(id, style, mapping)
71 }
72}
73
74impl Default for CssManager {
75 fn default() -> Self {
76 Self::new()
77 }
78}
79
80fn add_new_style_element(document: &Document) -> Element {
81 let style = document.create_element("style").unwrap();
82 style.append_child(&document.create_text_node("")).unwrap();
83 document.head().unwrap().append_child(&style).unwrap();
84 style
85}
86
87fn generate_prefix(id: u8) -> String {
88 format!("_{}-", id)
89}
90
91#[cfg(test)]
92mod tests {
93
94 use gloo::utils::document;
95 use wasm_bindgen_test::*;
96 use web_sys::Node;
97
98 use super::*;
99 wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
100
101 #[wasm_bindgen_test]
102 fn manager_creates_properly() {
103 CssManager::new();
104 }
105
106 #[wasm_bindgen_test]
107 fn add_new_style_element_adds_element_properly() {
108 let _new_element = add_new_style_element(&document());
109
110 let style_element = document().head().unwrap().last_element_child().unwrap();
111
112 assert_eq!(style_element.local_name(), "style");
113 assert_eq!(
114 style_element.first_child().unwrap().node_type(),
115 Node::TEXT_NODE
116 );
117 }
118
119 #[wasm_bindgen_test]
120 fn manager_attaches_css_properly() {
121 let mut manager = CssManager::new();
122
123 let _css = manager.attach_css(".class1 { color: red; }");
124
125 let style_element = manager
126 .document
127 .head()
128 .unwrap()
129 .last_element_child()
130 .unwrap();
131
132 let css_txt = style_element.first_child().unwrap().text_content().unwrap();
133
134 assert_eq!(css_txt, "._0-class1 { color: red; }");
135 }
136}