use silex_core::traits::{Get, IntoSignal, With};
use silex_dom::attribute::{ApplyTarget, ApplyToDom, IntoStorable};
use silex_dom::document;
use std::fmt::Display;
use std::rc::Rc;
use wasm_bindgen::JsCast;
pub fn inject_style(id: &str, content: &str) {
let doc = document();
if doc.get_element_by_id(id).is_some() {
return;
}
let head = doc.head().expect("No <head> element found in document");
let style_el = doc
.create_element("style")
.expect("Failed to create style element");
style_el.set_id(id);
style_el.set_inner_html(content);
let style_node: web_sys::Node = style_el.unchecked_into();
head.append_child(&style_node)
.expect("Failed to append style to head");
}
#[derive(Clone)]
pub struct DynamicCss {
pub class_name: &'static str,
pub vars: Vec<(&'static str, Rc<dyn Fn() -> String>)>,
}
impl ApplyToDom for DynamicCss {
fn apply(self, el: &web_sys::Element, target: ApplyTarget) {
self.class_name.apply(el, target);
for (name, getter) in self.vars {
let el = el.clone();
let name = name.to_string();
silex_core::reactivity::Effect::new(move |_| {
let value = getter();
if let Some(style) = el
.dyn_ref::<web_sys::HtmlElement>()
.map(|e| e.style())
.or_else(|| el.dyn_ref::<web_sys::SvgElement>().map(|e| e.style()))
{
let _ = style.set_property(&name, &value);
}
});
}
}
}
impl IntoStorable for DynamicCss {
type Stored = Self;
fn into_storable(self) -> Self::Stored {
self
}
}
pub fn make_dynamic_val<S>(source: S) -> Rc<dyn Fn() -> String>
where
S: IntoSignal,
S::Value: Clone + Sized, S::Signal: Get + 'static,
<S::Signal as With>::Value: Display,
{
let signal = source.into_signal();
Rc::new(move || format!("{}", signal.get()))
}