#[allow(unused)]
use crate::real_dom::RealDom;
use std::sync::{Arc, RwLock};
use rustc_hash::FxHashMap;
use shipyard::Component;
use crate::{
node::{FromAnyValue, NodeType},
node_ref::AttributeMask,
prelude::{NodeImmutable, NodeMut},
tree::TreeMut,
NodeId,
};
pub(crate) struct CustomElementRegistry<V: FromAnyValue + Send + Sync> {
builders: FxHashMap<(&'static str, Option<&'static str>), CustomElementBuilder<V>>,
}
impl<V: FromAnyValue + Send + Sync> Default for CustomElementRegistry<V> {
fn default() -> Self {
Self {
builders: FxHashMap::default(),
}
}
}
impl<V: FromAnyValue + Send + Sync> CustomElementRegistry<V> {
pub fn register<F, U>(&mut self)
where
F: CustomElementFactory<U, V>,
U: CustomElementUpdater<V>,
{
self.builders.insert(
(F::NAME, F::NAMESPACE),
CustomElementBuilder {
create: |node| Box::new(F::create(node)),
},
);
}
pub fn add_shadow_dom(&self, mut node: NodeMut<V>) {
let element_tag = if let NodeType::Element(el) = &*node.node_type() {
Some((el.tag.clone(), el.namespace.clone()))
} else {
None
};
if let Some((tag, ns)) = element_tag {
if let Some(builder) = self.builders.get(&(tag.as_str(), ns.as_deref())) {
let boxed_custom_element = { (builder.create)(node.reborrow()) };
let shadow_roots = boxed_custom_element.roots();
let light_id = node.id();
node.real_dom_mut().tree_mut().create_subtree(
light_id,
shadow_roots,
boxed_custom_element.slot(),
);
let boxed_custom_element = CustomElementManager {
inner: Arc::new(RwLock::new(boxed_custom_element)),
};
node.insert(boxed_custom_element);
}
}
}
}
struct CustomElementBuilder<V: FromAnyValue + Send + Sync> {
create: fn(NodeMut<V>) -> Box<dyn CustomElementUpdater<V>>,
}
pub trait CustomElement<V: FromAnyValue + Send + Sync = ()>: Send + Sync + 'static {
const NAME: &'static str;
const NAMESPACE: Option<&'static str> = None;
fn create(light_root: NodeMut<V>) -> Self;
fn roots(&self) -> Vec<NodeId>;
fn slot(&self) -> Option<NodeId> {
None
}
fn attributes_changed(&mut self, light_node: NodeMut<V>, attributes: &AttributeMask);
}
pub trait CustomElementFactory<W: CustomElementUpdater<V>, V: FromAnyValue + Send + Sync = ()>:
Send + Sync + 'static
{
const NAME: &'static str;
const NAMESPACE: Option<&'static str> = None;
fn create(dom: NodeMut<V>) -> W;
}
impl<W: CustomElement<V>, V: FromAnyValue + Send + Sync> CustomElementFactory<W, V> for W {
const NAME: &'static str = W::NAME;
const NAMESPACE: Option<&'static str> = W::NAMESPACE;
fn create(node: NodeMut<V>) -> Self {
Self::create(node)
}
}
pub trait CustomElementUpdater<V: FromAnyValue + Send + Sync = ()>: Send + Sync + 'static {
fn attributes_changed(&mut self, light_root: NodeMut<V>, attributes: &AttributeMask);
fn roots(&self) -> Vec<NodeId>;
fn slot(&self) -> Option<NodeId> {
None
}
}
impl<W: CustomElement<V>, V: FromAnyValue + Send + Sync> CustomElementUpdater<V> for W {
fn attributes_changed(&mut self, light_root: NodeMut<V>, attributes: &AttributeMask) {
self.attributes_changed(light_root, attributes);
}
fn roots(&self) -> Vec<NodeId> {
self.roots()
}
fn slot(&self) -> Option<NodeId> {
self.slot()
}
}
#[derive(Component, Clone)]
pub(crate) struct CustomElementManager<V: FromAnyValue = ()> {
inner: Arc<RwLock<Box<dyn CustomElementUpdater<V>>>>,
}
impl<V: FromAnyValue + Send + Sync> CustomElementManager<V> {
pub fn on_attributes_changed(&self, light_root: NodeMut<V>, attributes: &AttributeMask) {
self.inner
.write()
.unwrap()
.attributes_changed(light_root, attributes);
}
}