use std::cell::RefCell;
use std::collections::{BTreeMap, BTreeSet};
use std::ops::Deref;
use std::rc::Rc;
use wasm_bindgen::JsCast;
use crate::*;
type CSSResource = (&'static str, &'static str);
static DOM_STYLES: &[CSSResource] = &[
css!("dom/checkbox"),
css!("dom/scrollbar"),
css!("dom/select"),
];
thread_local! {
static STYLE_SHEET_CACHE: RefCell<BTreeMap<&'static str, web_sys::CssStyleSheet>> = RefCell::new(
DOM_STYLES
.iter()
.map(|x| (x.0, StyleCache::into_style(x.1)))
.collect(),
);
}
#[derive(Clone)]
pub struct StyleCache(Rc<StyleCacheData>);
impl Deref for StyleCache {
type Target = StyleCacheData;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl PartialEq for StyleCache {
fn eq(&self, _other: &Self) -> bool {
true
}
}
impl StyleCache {
pub fn new(is_shadow: bool, elem: &web_sys::HtmlElement) -> StyleCache {
StyleCache(Rc::new(StyleCacheData::new(is_shadow, elem)))
}
pub fn add_style(&self, name: &'static str, css: &'static str) {
let mut map = self.0.styles.borrow_mut();
STYLE_SHEET_CACHE.with_borrow_mut(|cache| {
if !map.contains(name) {
map.insert(name);
if !cache.contains_key(name) {
let style = Self::into_style(css);
cache.insert(name, style);
}
self.adopted_style_sheets.splice(
map.iter().position(|x| x == &name).unwrap() as u32,
0,
cache.get(name).unwrap(),
);
}
});
}
fn into_style(css: &str) -> web_sys::CssStyleSheet {
let sheet = web_sys::CssStyleSheet::new().unwrap();
sheet.replace_sync(css).unwrap();
sheet
}
}
pub struct StyleCacheData {
styles: RefCell<BTreeSet<&'static str>>,
adopted_style_sheets: js_sys::Array,
}
impl StyleCacheData {
fn new(is_shadow: bool, elem: &web_sys::HtmlElement) -> Self {
let styles: RefCell<BTreeSet<&'static str>> =
RefCell::new(DOM_STYLES.iter().map(|x| x.0).collect());
let root: &JsValue = if is_shadow {
&elem.shadow_root().unwrap()
} else {
&web_sys::window().unwrap().document().unwrap()
};
let adopted_style_sheets = js_sys::Reflect::get(root, &"adoptedStyleSheets".into())
.unwrap()
.unchecked_into::<js_sys::Array>();
for name in styles.borrow().iter() {
STYLE_SHEET_CACHE.with_borrow(|x| adopted_style_sheets.push(x.get(name).unwrap()));
}
Self {
styles,
adopted_style_sheets,
}
}
}