use silex_core::prelude::*;
use std::fmt::Display;
pub trait ThemeType {}
pub type Theme = ();
pub trait ThemeToCss: Display {
fn to_css_variables(&self) -> String;
fn get_variable_values(&self) -> Vec<String>;
fn get_variable_names() -> &'static [&'static str];
}
pub fn theme_variables<T>(theme: ReadSignal<T>) -> ThemeVariables<T>
where
T: ThemeType + ThemeToCss + Clone + 'static,
{
::silex_core::prelude::provide_context(theme);
ThemeVariables(theme)
}
pub struct ThemeVariables<T>(pub ReadSignal<T>);
impl<T> ::silex_dom::attribute::ApplyToDom for ThemeVariables<T>
where
T: ThemeType + ThemeToCss + Clone + 'static,
{
fn apply(&self, el: &::web_sys::Element, _target: ::silex_dom::attribute::ApplyTarget) {
let theme = self.0;
let el = el.clone();
::silex_core::prelude::Effect::new(move |prev_values: Option<Vec<String>>| {
use ::wasm_bindgen::JsCast;
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 theme_val = theme.get();
let names = T::get_variable_names();
let values = theme_val.get_variable_values();
if let Some(old_vals) = &prev_values {
for (i, (name, value)) in names.iter().zip(values.iter()).enumerate() {
if Some(value) != old_vals.get(i) {
let _ = style.set_property(name, value);
}
}
} else {
for (name, value) in names.iter().zip(values.iter()) {
let _ = style.set_property(name, value);
}
}
return values;
}
Vec::new()
});
}
}
impl<T> silex_dom::attribute::IntoStorable for ThemeVariables<T>
where
T: ThemeType + ThemeToCss + Clone + 'static,
{
type Stored = Self;
fn into_storable(self) -> Self::Stored {
self
}
}
pub fn use_theme<T: 'static>() -> ReadSignal<T> {
::silex_core::prelude::use_context::<ReadSignal<T>>()
.expect("No ThemeProvider found in hierarchy")
}
pub fn set_global_theme<T>(theme: ReadSignal<T>)
where
T: ThemeType + ThemeToCss + Clone + 'static,
{
::silex_core::prelude::provide_context(theme);
::silex_core::prelude::Effect::new(move |prev_values: Option<Vec<String>>| {
use ::wasm_bindgen::JsCast;
let doc = ::silex_dom::document();
if let Some(root) = doc.document_element()
&& let Some(style) = root.dyn_ref::<::web_sys::HtmlElement>().map(|e| e.style())
{
let theme_val = theme.get();
let names = T::get_variable_names();
let values = theme_val.get_variable_values();
if let Some(old_vals) = &prev_values {
for (i, (name, value)) in names.iter().zip(values.iter()).enumerate() {
if Some(value) != old_vals.get(i) {
let _ = style.set_property(name, value);
}
}
} else {
for (name, value) in names.iter().zip(values.iter()) {
let _ = style.set_property(name, value);
}
}
return values;
}
Vec::new()
});
}