diff --git a/dynatos/src/lib.rs b/dynatos/src/lib.rs index b968d90..b26be92 100644 --- a/dynatos/src/lib.rs +++ b/dynatos/src/lib.rs @@ -15,7 +15,7 @@ mod object_dyn_prop; pub use self::{ dyn_element::dyn_element, element_dyn_attr::ElementDynAttr, - node_dyn_child::{AsDynNode, AsOptNode, NodeDynChild}, + node_dyn_child::{NodeDynChild, ToDynNode}, node_dyn_text::{NodeDynText, WithDynText}, object_attach_effect::ObjectAttachEffect, object_dyn_prop::ObjectDynProp, diff --git a/dynatos/src/node_dyn_child.rs b/dynatos/src/node_dyn_child.rs index ec4729e..ce26497 100644 --- a/dynatos/src/node_dyn_child.rs +++ b/dynatos/src/node_dyn_child.rs @@ -7,6 +7,7 @@ use { dynatos_reactive::Effect, dynatos_util::{TryOrReturnExt, WeakRef}, std::cell::RefCell, + wasm_bindgen::JsCast, }; /// Extension trait to add a reactive child to an node @@ -18,7 +19,7 @@ where /// Adds a dynamic child to this node fn dyn_child(&self, child: C) where - C: AsDynNode + 'static, + C: ToDynNode + 'static, { // Create the value to attach // Note: It's important that we only keep a `WeakRef` to the node. @@ -36,9 +37,7 @@ where let node = node.get().or_return()?; // Get the new child - // Note: If the new child already exists, - let new_child = child.as_node(); - let new_child = new_child.get(); + let new_child = child.to_node(); // Check if someone's messed with our previous child // TODO: At this point should we give up, since we lost the position? @@ -54,37 +53,37 @@ where // Then check if we need to substitute in the empty child let new_child = match new_child { // If the new child is the same as the old one, we can return - Some(child) if prev_child.as_ref() == Some(child) => return, + Some(child) if prev_child.as_ref() == Some(&child) => return, // Otherwise, if this is a duplicate node, warn and use an empty child // Note: The typical browser behavior would be to remove the previous // child, then add ours. Unfortunately, removing other nodes might // cause another dyn child to panic due to it's previous node being // missing. - Some(child) if node.contains(Some(child)) => { + Some(child) if node.contains(Some(&child)) => { tracing::warn!("Attempted to add a reactive node multiple times"); - &empty_child + empty_child.clone() }, // Otherwise, use the new child Some(child) => child, // Finally, if no child was given, use the empty child - None => &empty_child, + None => empty_child.clone(), }; // Then update the node match &mut *prev_child { // If we already have a node, replace it Some(prev_child) => node - .replace_child(new_child, prev_child) + .replace_child(&new_child, prev_child) .expect("Unable to replace reactive child"), // Otherwise, we're running for the first time, so append the child - None => node.append_child(new_child).expect("Unable to append reactive child"), + None => node.append_child(&new_child).expect("Unable to append reactive child"), }; - *prev_child = Some(new_child.clone()); + *prev_child = Some(new_child); }) .or_return()?; @@ -97,52 +96,13 @@ where /// Returns the node, for chaining fn with_dyn_child(self, child: C) -> Self where - C: AsDynNode + 'static, + C: ToDynNode + 'static, { self.dyn_child(child); self } } -/// Type used for the output of [`AsDynNode`]. -/// -/// This allows [`AsDynNode`] to work with both owned -/// values, as well as `Option`s of those owned values. -pub trait AsOptNode { - fn get(&self) -> Option<&web_sys::Node>; -} - -impl AsOptNode for &N -where - N: AsOptNode, -{ - fn get(&self) -> Option<&web_sys::Node> { - N::get(self) - } -} - -impl AsOptNode for Option -where - N: AsOptNode, -{ - fn get(&self) -> Option<&web_sys::Node> { - self.as_ref().and_then(N::get) - } -} - -// TODO: Impl for `impl AsRef` if we can get rid of -// the conflict with the function impl -#[duplicate::duplicate_item( - Ty; - [web_sys::Node]; - [web_sys::Element]; -)] -impl AsOptNode for Ty { - fn get(&self) -> Option<&web_sys::Node> { - Some(self) - } -} - /// Trait for values accepted by [`NodeDynChild`]. /// /// This allows it to work with the following types: @@ -151,25 +111,18 @@ impl AsOptNode for Ty { /// - `N` /// - `Option` /// Where `N` is a node type. -pub trait AsDynNode { - /// The inner node type. - type Node<'a>: AsOptNode - where - Self: 'a; - +pub trait ToDynNode { /// Retrieves / Computes the inner node - fn as_node(&self) -> Self::Node<'_>; + fn to_node(&self) -> Option; } -impl AsDynNode for F +impl ToDynNode for F where F: Fn() -> N, - N: AsOptNode, + N: ToDynNode, { - type Node<'a> = N where Self: 'a; - - fn as_node(&self) -> Self::Node<'_> { - self() + fn to_node(&self) -> Option { + self().to_node() } } @@ -180,23 +133,18 @@ where [web_sys::Node]; [web_sys::Element]; )] -impl AsDynNode for Ty { - type Node<'a> = &'a Ty; - - fn as_node(&self) -> Self::Node<'_> { - self +impl ToDynNode for Ty { + fn to_node(&self) -> Option { + let node = self.dyn_ref::().expect("Unable to cast to element"); + Some(node.clone()) } } -#[duplicate::duplicate_item( - Ty; - [web_sys::Node]; - [web_sys::Element]; -)] -impl AsDynNode for Option { - type Node<'a> = Option<&'a Ty>; - - fn as_node(&self) -> Self::Node<'_> { - self.as_ref() +impl ToDynNode for Option +where + N: ToDynNode, +{ + fn to_node(&self) -> Option { + self.as_ref().and_then(N::to_node) } }