use crate::view::{Mountable, ToTemplate};
use std::{borrow::Cow, fmt::Debug, marker::PhantomData};
use wasm_bindgen::JsValue;
pub mod dom;
pub type Rndr = dom::Dom;
pub mod types {
pub use super::dom::{
ClassList, CssStyleDeclaration, Element, Event, Node, Placeholder,
TemplateElement, Text,
};
}
pub trait Renderer: Send + Sized + Debug + 'static {
type Node: Mountable + Clone + 'static;
type Element: AsRef<Self::Node>
+ CastFrom<Self::Node>
+ Mountable
+ Clone
+ 'static;
type Text: AsRef<Self::Node>
+ CastFrom<Self::Node>
+ Mountable
+ Clone
+ 'static;
type Placeholder: AsRef<Self::Node>
+ CastFrom<Self::Node>
+ Mountable
+ Clone
+ 'static;
fn intern(text: &str) -> &str;
fn create_text_node(text: &str) -> Self::Text;
fn create_placeholder() -> Self::Placeholder;
fn set_text(node: &Self::Text, text: &str);
fn set_attribute(node: &Self::Element, name: &str, value: &str);
fn remove_attribute(node: &Self::Element, name: &str);
fn insert_node(
parent: &Self::Element,
new_child: &Self::Node,
marker: Option<&Self::Node>,
);
fn remove_node(
parent: &Self::Element,
child: &Self::Node,
) -> Option<Self::Node>;
fn clear_children(parent: &Self::Element);
fn remove(node: &Self::Node);
fn get_parent(node: &Self::Node) -> Option<Self::Node>;
fn first_child(node: &Self::Node) -> Option<Self::Node>;
fn next_sibling(node: &Self::Node) -> Option<Self::Node>;
fn log_node(node: &Self::Node);
}
#[must_use = "This will invalidate the event handler when it is dropped. You \
should store it in some other data structure to clean it up \
later to avoid dropping it immediately, or leak it with \
std::mem::forget() to never drop it."]
#[allow(clippy::type_complexity)]
pub struct RemoveEventHandler<T>(
Option<Box<dyn FnOnce() + Send + Sync>>,
PhantomData<fn() -> T>,
);
impl<T> RemoveEventHandler<T> {
pub(crate) fn new(remove: impl FnOnce() + Send + Sync + 'static) -> Self {
Self(Some(Box::new(remove)), PhantomData)
}
#[allow(clippy::type_complexity)]
pub(crate) fn into_inner(
mut self,
) -> Option<Box<dyn FnOnce() + Send + Sync>> {
self.0.take()
}
}
impl<T> Drop for RemoveEventHandler<T> {
fn drop(&mut self) {
if let Some(cb) = self.0.take() {
cb()
}
}
}
pub trait DomRenderer: Renderer {
type Event;
type ClassList: Clone + 'static;
type CssStyleDeclaration: Clone + 'static;
type TemplateElement;
fn set_property(el: &Self::Element, key: &str, value: &JsValue);
fn add_event_listener(
el: &Self::Element,
name: &str,
cb: Box<dyn FnMut(Self::Event)>,
) -> RemoveEventHandler<Self::Element>;
fn add_event_listener_delegated(
el: &Self::Element,
name: Cow<'static, str>,
delegation_key: Cow<'static, str>,
cb: Box<dyn FnMut(Self::Event)>,
) -> RemoveEventHandler<Self::Element>;
fn event_target<T>(ev: &Self::Event) -> T
where
T: CastFrom<Self::Element>;
fn class_list(el: &Self::Element) -> Self::ClassList;
fn add_class(class_list: &Self::ClassList, name: &str);
fn remove_class(class_list: &Self::ClassList, name: &str);
fn style(el: &Self::Element) -> Self::CssStyleDeclaration;
fn set_css_property(
style: &Self::CssStyleDeclaration,
name: &str,
value: &str,
);
fn set_inner_html(el: &Self::Element, html: &str);
fn get_template<V>() -> Self::TemplateElement
where
V: ToTemplate + 'static;
fn clone_template(tpl: &Self::TemplateElement) -> Self::Element;
fn create_element_from_html(html: &str) -> Self::Element;
}
pub trait CastFrom<T>
where
Self: Sized,
{
fn cast_from(source: T) -> Option<Self>;
}