diff --git a/Cargo.toml b/Cargo.toml index cf4e99b42..9d609e50f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,7 +55,7 @@ members = [ "packages/core-macro", "packages/core", "packages/html-namespace", - # "packages/web", + "packages/web", # "packages/cli", # "packages/atoms", # "packages/ssr", diff --git a/packages/core/src/diff.rs b/packages/core/src/diff.rs index d5e87a2c4..399720991 100644 --- a/packages/core/src/diff.rs +++ b/packages/core/src/diff.rs @@ -4,15 +4,15 @@ //! Notice: //! ------ //! -//! The inspiration and code for this module was originally taken from Dodrio (@fitzgen) and modified to support Components, -//! Fragments, Suspense, and additional batching operations. +//! The inspiration and code for this module was originally taken from Dodrio (@fitzgen) and then modified to support +//! Components, Fragments, Suspense, and additional batching operations. //! //! Implementation Details: //! ----------------------- //! //! All nodes are addressed by their IDs. The RealDom provides an imperative interface for making changes to these nodes. -//! We don't necessarily intend for changes to happen exactly during the diffing process, so the implementor may choose -//! to batch nodes if it is more performant for their application. The u32 should be a no-op to hash, +//! We don't necessarily require that DOM changes happen instnatly during the diffing process, so the implementor may choose +//! to batch nodes if it is more performant for their application. We care about an ID size of u32 //! //! //! Further Reading and Thoughts @@ -58,6 +58,8 @@ pub trait RealDom { fn create_text_node(&mut self, text: &str) -> RealDomNode; fn create_element(&mut self, tag: &str) -> RealDomNode; fn create_element_ns(&mut self, tag: &str, namespace: &str) -> RealDomNode; + // placeholders are nodes that don't get rendered but still exist as an "anchor" in the real dom + fn create_placeholder(&mut self) -> RealDomNode; // events fn new_event_listener( @@ -152,7 +154,6 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { } // New node is a text element, need to replace the element with a simple text node VNode::Text(_) => { - log::debug!("Replacing el with text"); self.create(new_node); self.dom.replace_with(); } @@ -167,10 +168,22 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { // New node is actually a sequence of nodes. // We need to replace this one node with a sequence of nodes // Not yet implement because it's kinda hairy - VNode::Fragment(_) => todo!(), + VNode::Fragment(new) => { + match new.children.len() { + 0 => { + // remove + } + 1 => { + // replace + } + _ => { + // remove and mount many + } + } + } // New Node is actually suspended. Todo - VNode::Suspended => todo!(), + VNode::Suspended { real } => todo!(), }, // Old element was text @@ -200,7 +213,7 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { } } } - VNode::Suspended => todo!(), + VNode::Suspended { real } => todo!(), }, // Old element was a component @@ -214,75 +227,74 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { // It's also a component VNode::Component(new) => { - match old.user_fc == new.user_fc { + if old.user_fc == new.user_fc { // Make sure we're dealing with the same component (by function pointer) - true => { - // Make sure the new component vnode is referencing the right scope id - let scope_id = old.ass_scope.borrow().clone(); - *new.ass_scope.borrow_mut() = scope_id; - // make sure the component's caller function is up to date + // Make sure the new component vnode is referencing the right scope id + let scope_id = old.ass_scope.borrow().clone(); + *new.ass_scope.borrow_mut() = scope_id; + + // make sure the component's caller function is up to date + self.components + .with_scope(scope_id.unwrap(), |scope| { + scope.caller = Rc::downgrade(&new.caller) + }) + .unwrap(); + + // React doesn't automatically memoize, but we do. + // The cost is low enough to make it worth checking + let should_render = match old.comparator { + Some(comparator) => comparator(new), + None => true, + }; + + if should_render { + // // self.dom.commit_traversal(); self.components - .with_scope(scope_id.unwrap(), |scope| { - scope.caller = Rc::downgrade(&new.caller) + .with_scope(scope_id.unwrap(), |f| { + f.run_scope().unwrap(); }) .unwrap(); - - // React doesn't automatically memoize, but we do. - // The cost is low enough to make it worth checking - let should_render = match old.comparator { - Some(comparator) => comparator(new), - None => true, - }; - - if should_render { - // // self.dom.commit_traversal(); - self.components - .with_scope(scope_id.unwrap(), |f| { - f.run_scope().unwrap(); - }) - .unwrap(); - // diff_machine.change_list.load_known_root(root_id); - // run the scope - // - } else { - // Component has memoized itself and doesn't need to be re-rendered. - // We still need to make sure the child's props are up-to-date. - // Don't commit traversal - } + // diff_machine.change_list.load_known_root(root_id); + // run the scope + // + } else { + // Component has memoized itself and doesn't need to be re-rendered. + // We still need to make sure the child's props are up-to-date. + // Don't commit traversal } + } else { // It's an entirely different component - false => { - // A new component has shown up! We need to destroy the old node - // Wipe the old one and plant the new one - // self.dom.commit_traversal(); - // self.dom.replace_node_with(old.dom_id, new.dom_id); - // self.create(new_node); - // self.dom.replace_with(); - self.create(new_node); - // self.create_and_repalce(new_node, old.mounted_root.get()); + // A new component has shown up! We need to destroy the old node - // Now we need to remove the old scope and all of its descendents - let old_scope = old.ass_scope.borrow().as_ref().unwrap().clone(); - self.destroy_scopes(old_scope); - } + // Wipe the old one and plant the new one + // self.dom.commit_traversal(); + // self.dom.replace_node_with(old.dom_id, new.dom_id); + // self.create(new_node); + // self.dom.replace_with(); + self.create(new_node); + // self.create_and_repalce(new_node, old.mounted_root.get()); + + // Now we need to remove the old scope and all of its descendents + let old_scope = old.ass_scope.borrow().as_ref().unwrap().clone(); + self.destroy_scopes(old_scope); } } VNode::Fragment(_) => todo!(), - VNode::Suspended => todo!(), + VNode::Suspended { real } => todo!(), } } VNode::Fragment(old) => { // match new_node { - VNode::Fragment(_) => todo!(), + VNode::Fragment(new) => todo!(), // going from fragment to element means we're going from many (or potentially none) to one VNode::Element(new) => {} VNode::Text(_) => todo!(), - VNode::Suspended => todo!(), + VNode::Suspended { real } => todo!(), VNode::Component(_) => todo!(), } } @@ -290,10 +302,12 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { // a suspended node will perform a mem-copy of the previous elements until it is ready // this means that event listeners will need to be disabled and removed // it also means that props will need to disabled - IE if the node "came out of hibernation" any props should be considered outdated - VNode::Suspended => { + VNode::Suspended { real: old_real } => { // match new_node { - VNode::Suspended => todo!(), + VNode::Suspended { real: new_real } => { + // + } VNode::Element(_) => todo!(), VNode::Text(_) => todo!(), VNode::Fragment(_) => todo!(), @@ -354,6 +368,10 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { // to emit three instructions to (1) create a text node, (2) set its // text content, and finally (3) append the text node to this // parent. + // + // Notice: this is a web-specific optimization and may be changed in the future + // + // TODO move over // if children.len() == 1 { // if let VNode::Text(text) = &children[0] { // self.dom.set_text(text.text); @@ -373,7 +391,7 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { } VNode::Component(component) => { - self.dom.create_text_node("placeholder for vcomponent"); + let real_id = self.dom.create_placeholder(); // let root_id = next_id(); // self.dom.save_known_root(root_id); @@ -426,7 +444,6 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { new_component.run_scope().unwrap(); // And then run the diff algorithm - // todo!(); self.diff_node(new_component.old_frame(), new_component.next_frame()); // Finally, insert this node as a seen node. @@ -437,21 +454,17 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { VNode::Fragment(frag) => { // create the children directly in the space for child in frag.children { - todo!() - // self.create(child); - // self.dom.append_child(); + self.create(child); + self.dom.append_child(); } } - VNode::Suspended => { - todo!("Creation of VNode::Suspended not yet supported") + VNode::Suspended { real } => { + let id = self.dom.create_placeholder(); + real.set(id); } } } - - fn iter_children(&self, node: &VNode<'a>) -> ChildIterator<'a> { - todo!() - } } impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { @@ -680,29 +693,29 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { // [... parent] // // Upon exiting, the change list stack is in the same state. - fn diff_keyed_children(&self, old: &[VNode<'a>], new: &[VNode<'a>]) { - todo!(); - // if cfg!(debug_assertions) { - // let mut keys = fxhash::FxHashSet::default(); - // let mut assert_unique_keys = |children: &[VNode]| { - // keys.clear(); - // for child in children { - // let key = child.key(); - // debug_assert!( - // key.is_some(), - // "if any sibling is keyed, all siblings must be keyed" - // ); - // keys.insert(key); - // } - // debug_assert_eq!( - // children.len(), - // keys.len(), - // "keyed siblings must each have a unique key" - // ); - // }; - // assert_unique_keys(old); - // assert_unique_keys(new); - // } + fn diff_keyed_children(&self, old: &'a [VNode<'a>], new: &'a [VNode<'a>]) { + // todo!(); + if cfg!(debug_assertions) { + let mut keys = fxhash::FxHashSet::default(); + let mut assert_unique_keys = |children: &'a [VNode<'a>]| { + keys.clear(); + for child in children { + let key = child.key(); + debug_assert!( + key.is_some(), + "if any sibling is keyed, all siblings must be keyed" + ); + keys.insert(key); + } + debug_assert_eq!( + children.len(), + keys.len(), + "keyed siblings must each have a unique key" + ); + }; + assert_unique_keys(old); + assert_unique_keys(new); + } // First up, we diff all the nodes with the same key at the beginning of the // children. @@ -1090,7 +1103,12 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { // [... parent prev_child] // self.dom.go_to_sibling(i); // [... parent this_child] - self.dom.push_root(old_child.get_mounted_id().unwrap()); + + let did = old_child.get_mounted_id().unwrap(); + if did.0 == 0 { + log::debug!("Root is bad {:#?}", old_child); + } + self.dom.push_root(did); self.diff_node(old_child, new_child); let old_id = old_child.get_mounted_id().unwrap(); @@ -1270,7 +1288,7 @@ impl<'a> Iterator for ChildIterator<'a> { // Immediately abort suspended nodes - can't do anything with them yet // VNode::Suspended => should_pop = true, - VNode::Suspended => todo!(), + VNode::Suspended { real } => todo!(), // For components, we load their root and push them onto the stack VNode::Component(sc) => { @@ -1370,7 +1388,7 @@ mod tests { // These would represent failing cases. VNode::Fragment(_) => panic!("Found: Fragment"), - VNode::Suspended => panic!("Found: Suspended"), + VNode::Suspended { real } => panic!("Found: Suspended"), VNode::Component(_) => panic!("Found: Component"), } } diff --git a/packages/core/src/nodebuilder.rs b/packages/core/src/nodebuilder.rs index dccf929fa..e09076b6a 100644 --- a/packages/core/src/nodebuilder.rs +++ b/packages/core/src/nodebuilder.rs @@ -611,14 +611,18 @@ where impl<'a> IntoVNode<'a> for () { fn into_vnode(self, cx: &NodeCtx<'a>) -> VNode<'a> { todo!(); - VNode::Suspended + VNode::Suspended { + real: Cell::new(RealDomNode::empty()), + } } } impl<'a> IntoVNode<'a> for Option<()> { fn into_vnode(self, cx: &NodeCtx<'a>) -> VNode<'a> { todo!(); - VNode::Suspended + VNode::Suspended { + real: Cell::new(RealDomNode::empty()), + } } } diff --git a/packages/core/src/nodes.rs b/packages/core/src/nodes.rs index f619eb8b2..9e5d971c5 100644 --- a/packages/core/src/nodes.rs +++ b/packages/core/src/nodes.rs @@ -35,7 +35,7 @@ pub enum VNode<'src> { /// A "suspended component" /// This is a masqeurade over an underlying future that needs to complete /// When the future is completed, the VNode will then trigger a render - Suspended, + Suspended { real: Cell }, /// A User-defined componen node (node type COMPONENT_NODE) Component(&'src VComponent<'src>), @@ -49,7 +49,7 @@ impl<'a> Clone for VNode<'a> { VNode::Text(old) => VNode::Text(old.clone()), VNode::Fragment(fragment) => VNode::Fragment(fragment), VNode::Component(component) => VNode::Component(component), - VNode::Suspended => VNode::Suspended, + VNode::Suspended { real } => VNode::Suspended { real: real.clone() }, } } } @@ -85,7 +85,7 @@ impl<'old, 'new> VNode<'old> { } VNode::Text(_) => todo!(), VNode::Fragment(_) => todo!(), - VNode::Suspended => todo!(), + VNode::Suspended { real } => todo!(), VNode::Component(_) => todo!(), } } @@ -142,7 +142,7 @@ impl<'a> VNode<'a> { VNode::Component(c) => c.key, // todo suspend should be allowed to have keys - VNode::Suspended => NodeKey::NONE, + VNode::Suspended { .. } => NodeKey::NONE, } } @@ -155,7 +155,7 @@ impl<'a> VNode<'a> { VNode::Element(_) => true, VNode::Text(_) => true, VNode::Fragment(_) => false, - VNode::Suspended => false, + VNode::Suspended { .. } => false, VNode::Component(_) => false, } } @@ -165,7 +165,7 @@ impl<'a> VNode<'a> { VNode::Element(el) => Some(el.dom_id.get()), VNode::Text(te) => Some(te.dom_id.get()), VNode::Fragment(_) => todo!(), - VNode::Suspended => todo!(), + VNode::Suspended { .. } => todo!(), VNode::Component(_) => todo!(), } } @@ -177,7 +177,7 @@ impl Debug for VNode<'_> { VNode::Element(el) => write!(s, "element, {}", el.tag_name), VNode::Text(t) => write!(s, "text, {}", t.text), VNode::Fragment(_) => write!(s, "fragment"), - VNode::Suspended => write!(s, "suspended"), + VNode::Suspended { .. } => write!(s, "suspended"), VNode::Component(_) => write!(s, "component"), } } @@ -436,163 +436,3 @@ impl<'a> VFragment<'a> { Self { key, children } } } - -// /// This method converts a list of nested real/virtual nodes into a stream of nodes that are definitely associated -// /// with the real dom. The only types of nodes that may be returned are text, elemets, and components. -// /// -// /// Components *are* considered virtual, but this iterator can't necessarily handle them without the scope arena. -// /// -// /// Why? -// /// --- -// /// Fragments are seen as virtual nodes but are actually a list of possibly-real nodes. -// /// JS implementations normalize their node lists when fragments are present. Here, we just create a new iterator -// /// that iterates through the recursive nesting of fragments. -// /// -// /// Fragments are stupid and I wish we didn't need to support them. -// /// -// /// This iterator only supports 3 levels of nested fragments -// /// -// pub fn iterate_real_nodes<'a>(nodes: &'a [VNode<'a>]) -> RealNodeIterator<'a> { -// RealNodeIterator::new(nodes) -// } - -// pub struct RealNodeIterator<'a> { -// nodes: &'a [VNode<'a>], - -// // this node is always a "real" node -// // the index is "what sibling # is it" -// // IE in a list of children on a fragment, the node will be a text node that's the 5th sibling -// node_stack: Vec<(&'a VNode<'a>, u32)>, -// } - -// impl<'a> RealNodeIterator<'a> { -// // We immediately descend to the first real node we can find -// fn new(nodes: &'a [VNode<'a>]) -> Self { -// let mut node_stack = Vec::new(); -// if nodes.len() > 0 { -// let mut cur_node = nodes.get(0).unwrap(); -// loop { -// node_stack.push((cur_node, 0_u32)); -// if !cur_node.is_real() { -// cur_node = cur_node.get_child(0).unwrap(); -// } else { -// break; -// } -// } -// } - -// Self { nodes, node_stack } -// } - -// // // advances the cursor to the next element, panicing if we're on the 3rd level and still finding fragments -// // fn advance_cursor(&mut self) { -// // let (mut cur_node, mut cur_id) = self.node_stack.last().unwrap(); - -// // while !cur_node.is_real() { -// // match cur_node { -// // VNode::Element(_) | VNode::Text(_) => todo!(), -// // VNode::Suspended => todo!(), -// // VNode::Component(_) => todo!(), -// // VNode::Fragment(frag) => { -// // let p = frag.children; -// // } -// // } -// // } -// // } - -// fn next_node(&mut self) -> bool { -// let (mut cur_node, cur_id) = self.node_stack.last_mut().unwrap(); - -// match cur_node { -// VNode::Fragment(frag) => { -// // -// if *cur_id + 1 > frag.children.len() as u32 { -// self.node_stack.pop(); -// let next = self.node_stack.last_mut(); -// return false; -// } -// *cur_id += 1; -// true -// } - -// VNode::Element(_) => todo!(), -// VNode::Text(_) => todo!(), -// VNode::Suspended => todo!(), -// VNode::Component(_) => todo!(), -// } -// } - -// fn get_current_node(&self) -> Option<&VNode<'a>> { -// self.node_stack.last().map(|(node, id)| match node { -// VNode::Element(_) => todo!(), -// VNode::Text(_) => todo!(), -// VNode::Fragment(_) => todo!(), -// VNode::Suspended => todo!(), -// VNode::Component(_) => todo!(), -// }) -// } -// } - -// impl<'a> Iterator for RealNodeIterator<'a> { -// type Item = &'a VNode<'a>; - -// fn next(&mut self) -> Option { -// todo!() -// // let top_idx = self.nesting_idxs.get_mut(0).unwrap(); -// // let node = &self.nodes.get_mut(*top_idx as usize); - -// // if node.is_none() { -// // return None; -// // } -// // let node = node.unwrap(); - -// // match node { -// // VNode::Element(_) | VNode::Text(_) => { -// // *top_idx += 1; -// // return Some(node); -// // } -// // VNode::Suspended => todo!(), -// // // we need access over the scope map -// // VNode::Component(_) => todo!(), - -// // VNode::Fragment(frag) => { -// // let nest_idx = self.nesting_idxs.get_mut(1).unwrap(); -// // let node = &frag.children.get_mut(*nest_idx as usize); -// // match node { -// // VNode::Element(_) | VNode::Text(_) => { -// // *nest_idx += 1; -// // return Some(node); -// // } -// // VNode::Fragment(_) => todo!(), -// // VNode::Suspended => todo!(), -// // VNode::Component(_) => todo!(), -// // } -// // } -// // } -// } -// } - -mod tests { - use crate::debug_renderer::DebugRenderer; - use crate::nodebuilder::LazyNodes; - - use crate as dioxus; - use dioxus::prelude::*; - #[test] - fn iterate_nodes() { - let rs = rsx! { - Fragment { - Fragment { - Fragment { - Fragment { - h1 {"abc1"} - } - h2 {"abc2"} - } - h3 {"abc3"} - } - h4 {"abc4"} - } - }; - } -} diff --git a/packages/core/src/util.rs b/packages/core/src/util.rs index dc798d20c..b5c4f86c5 100644 --- a/packages/core/src/util.rs +++ b/packages/core/src/util.rs @@ -1,7 +1,7 @@ use crate::innerlude::*; pub struct DebugDom { - counter: u32, + counter: u64, } impl DebugDom { pub fn new() -> Self { @@ -33,6 +33,10 @@ impl RealDom for DebugDom { self.counter += 1; RealDomNode::new(self.counter) } + fn create_placeholder(&mut self) -> RealDomNode { + self.counter += 1; + RealDomNode::new(self.counter) + } fn new_event_listener( &mut self, diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index 472c017d1..d55790fb2 100644 --- a/packages/core/src/virtual_dom.rs +++ b/packages/core/src/virtual_dom.rs @@ -64,14 +64,19 @@ pub struct VirtualDom { _root_prop_type: std::any::TypeId, } +/// The `RealDomNode` is an ID handle that corresponds to a foreign DOM node. +/// +/// "u64" was chosen for two reasons +/// - 0 cost hashing +/// - use with slotmap and other versioned slot arenas #[derive(Clone, Copy, Debug, PartialEq)] -pub struct RealDomNode(pub u32); +pub struct RealDomNode(pub u64); impl RealDomNode { - pub fn new(id: u32) -> Self { + pub fn new(id: u64) -> Self { Self(id) } pub fn empty() -> Self { - Self(u32::MIN) + Self(u64::MIN) } } @@ -795,7 +800,7 @@ Any function prefixed with "use" should not be called conditionally. } /// There are hooks going on here! - fn use_context(&self) -> &'src T { + fn use_context(&self) -> &'src Rc { self.try_use_context().unwrap() } @@ -871,7 +876,9 @@ Any function prefixed with "use" should not be called conditionally. } None => { // we need to register this task - VNode::Suspended + VNode::Suspended { + real: Cell::new(RealDomNode::empty()), + } } } } diff --git a/packages/web/Cargo.toml b/packages/web/Cargo.toml index 577706d00..78a2fb6ee 100644 --- a/packages/web/Cargo.toml +++ b/packages/web/Cargo.toml @@ -26,6 +26,7 @@ atoms = { path="../atoms" } async-channel = "1.6.1" nohash-hasher = "0.2.0" anyhow = "1.0.41" +slotmap = "1.0.3" [dependencies.web-sys] version = "0.3.50" diff --git a/packages/web/examples/jackjill.rs b/packages/web/examples/jackjill.rs index 4fcc7dacb..d01021a4e 100644 --- a/packages/web/examples/jackjill.rs +++ b/packages/web/examples/jackjill.rs @@ -36,11 +36,11 @@ static Example: FC<()> = |cx| { "Jack!" - + diff --git a/packages/web/src/new.rs b/packages/web/src/new.rs index b4c874002..3f4bfb69f 100644 --- a/packages/web/src/new.rs +++ b/packages/web/src/new.rs @@ -7,6 +7,7 @@ use dioxus_core::{ }; use fxhash::FxHashMap; use nohash_hasher::IntMap; +use slotmap::{DefaultKey, Key, KeyData}; use wasm_bindgen::{closure::Closure, JsCast}; use web_sys::{ window, Document, Element, Event, HtmlElement, HtmlInputElement, HtmlOptionElement, Node, @@ -14,7 +15,7 @@ use web_sys::{ pub struct WebsysDom { pub stack: Stack, - nodes: IntMap, + nodes: slotmap::SlotMap, document: Document, root: Element, @@ -39,8 +40,6 @@ pub struct WebsysDom { // `ptns` = Percy text node separator // TODO last_node_was_text: bool, - - node_counter: Counter, } impl WebsysDom { pub fn new(root: Element) -> Self { @@ -52,16 +51,18 @@ impl WebsysDom { let (sender, mut receiver) = async_channel::unbounded::(); let sender_callback = Arc::new(move |ev| { - let mut c = sender.clone(); + let c = sender.clone(); wasm_bindgen_futures::spawn_local(async move { c.send(ev).await.unwrap(); }); }); - let mut nodes = - HashMap::with_capacity_and_hasher(1000, nohash_hasher::BuildNoHashHasher::default()); + let mut nodes = slotmap::SlotMap::new(); + // HashMap::with_capacity_and_hasher(1000, nohash_hasher::BuildNoHashHasher::default()); + // let mut nodes = + // HashMap::with_capacity_and_hasher(1000, nohash_hasher::BuildNoHashHasher::default()); - nodes.insert(0_u32, root.clone().dyn_into::().unwrap()); + let root_id = nodes.insert(root.clone().dyn_into::().unwrap()); Self { stack: Stack::with_capacity(10), nodes, @@ -74,7 +75,6 @@ impl WebsysDom { trigger: sender_callback, root, last_node_was_text: false, - node_counter: Counter(0), } } @@ -84,17 +84,11 @@ impl WebsysDom { } } -struct Counter(u32); -impl Counter { - fn next(&mut self) -> u32 { - self.0 += 1; - self.0 - } -} impl dioxus_core::diff::RealDom for WebsysDom { fn push_root(&mut self, root: dioxus_core::virtual_dom::RealDomNode) { - log::debug!("Called `[`push_root] {:?}", root); - let domnode = self.nodes.get(&root.0).expect("Failed to pop know root"); + log::debug!("Called [push_root] {:?}", root); + let key: DefaultKey = KeyData::from_ffi(root.0).into(); + let domnode = self.nodes.get(key).expect("Failed to pop know root"); self.stack.push(domnode.clone()); } @@ -166,15 +160,19 @@ impl dioxus_core::diff::RealDom for WebsysDom { todo!() } + fn create_placeholder(&mut self) -> RealDomNode { + self.create_element("pre") + } fn create_text_node(&mut self, text: &str) -> dioxus_core::virtual_dom::RealDomNode { - let nid = self.node_counter.next(); + // let nid = self.node_counter.next(); let textnode = self .document .create_text_node(text) .dyn_into::() .unwrap(); self.stack.push(textnode.clone()); - self.nodes.insert(nid, textnode); + let nid = self.nodes.insert(textnode); + let nid = nid.data().as_ffi(); log::debug!("Called [`create_text_node`]: {}, {}", text, nid); @@ -190,8 +188,8 @@ impl dioxus_core::diff::RealDom for WebsysDom { .unwrap(); self.stack.push(el.clone()); - let nid = self.node_counter.next(); - self.nodes.insert(nid, el); + // let nid = self.node_counter.?next(); + let nid = self.nodes.insert(el).data().as_ffi(); log::debug!("Called [`create_element`]: {}, {:?}", tag, nid); RealDomNode::new(nid) } @@ -209,8 +207,9 @@ impl dioxus_core::diff::RealDom for WebsysDom { .unwrap(); self.stack.push(el.clone()); - let nid = self.node_counter.next(); - self.nodes.insert(nid, el); + let nid = self.nodes.insert(el).data().as_ffi(); + // let nid = self.node_counter.next(); + // self.nodes.insert(nid, el); log::debug!("Called [`create_element_ns`]: {:}", nid); RealDomNode::new(nid) } @@ -287,7 +286,7 @@ impl dioxus_core::diff::RealDom for WebsysDom { .context("")?; let real_id = fields .next() - .and_then(|f| f.parse::().ok().map(RealDomNode::new)) + .and_then(|f| f.parse::().ok().map(RealDomNode::new)) .context("")?; // Call the trigger