浏览代码

wip: clean up some things

Jonathan Kelley 2 年之前
父节点
当前提交
3b166c9edd
共有 64 个文件被更改,包括 543 次插入602 次删除
  1. 7 5
      Cargo.toml
  2. 1 1
      packages/autofmt/src/buffer.rs
  3. 1 1
      packages/autofmt/src/element.rs
  4. 23 23
      packages/core/src/create.rs
  5. 85 36
      packages/core/src/events.rs
  6. 10 106
      packages/core/src/factory.rs
  7. 17 91
      packages/core/src/lazynodes.rs
  8. 8 61
      packages/core/src/lib.rs
  9. 63 24
      packages/core/src/mutations.rs
  10. 7 8
      packages/core/src/nodes.rs
  11. 5 21
      packages/core/src/scheduler/suspense.rs
  12. 1 1
      packages/core/src/scope_arena.rs
  13. 102 8
      packages/core/src/scopes.rs
  14. 12 8
      packages/core/src/virtual_dom.rs
  15. 2 7
      packages/core/tests/README.md
  16. 5 5
      packages/core/tests/attr_cleanup.rs
  17. 1 1
      packages/core/tests/boolattrs.rs
  18. 1 1
      packages/core/tests/borrowedstate.rs
  19. 3 3
      packages/core/tests/context_api.rs
  20. 8 8
      packages/core/tests/create_dom.rs
  21. 1 1
      packages/core/tests/create_element.rs
  22. 5 5
      packages/core/tests/create_fragments.rs
  23. 2 2
      packages/core/tests/create_lists.rs
  24. 4 4
      packages/core/tests/create_passthru.rs
  25. 4 4
      packages/core/tests/cycle.rs
  26. 4 4
      packages/core/tests/diff_component.rs
  27. 7 7
      packages/core/tests/diff_element.rs
  28. 13 13
      packages/core/tests/diff_keyed_list.rs
  29. 26 26
      packages/core/tests/diff_unkeyed_list.rs
  30. 2 2
      packages/core/tests/kitchen_sink.rs
  31. 2 2
      packages/core/tests/lifecycle.rs
  32. 2 2
      packages/core/tests/suspense.rs
  33. 4 4
      packages/desktop/src/controller.rs
  34. 1 1
      packages/dioxus/benches/jsframework.rs
  35. 22 2
      packages/hooks/src/lib.rs
  36. 1 1
      packages/hooks/src/usestate.rs
  37. 1 1
      packages/html/src/events.rs
  38. 2 2
      packages/html/src/events/animation.rs
  39. 2 2
      packages/html/src/events/clipboard.rs
  40. 2 2
      packages/html/src/events/composition.rs
  41. 2 2
      packages/html/src/events/drag.rs
  42. 2 2
      packages/html/src/events/focus.rs
  43. 2 2
      packages/html/src/events/form.rs
  44. 2 2
      packages/html/src/events/image.rs
  45. 2 2
      packages/html/src/events/keyboard.rs
  46. 2 2
      packages/html/src/events/media.rs
  47. 2 2
      packages/html/src/events/mouse.rs
  48. 2 2
      packages/html/src/events/pointer.rs
  49. 2 2
      packages/html/src/events/scroll.rs
  50. 2 2
      packages/html/src/events/selection.rs
  51. 2 2
      packages/html/src/events/toggle.rs
  52. 2 2
      packages/html/src/events/touch.rs
  53. 2 2
      packages/html/src/events/transition.rs
  54. 2 2
      packages/html/src/events/wheel.rs
  55. 22 23
      packages/liveview/src/events.rs
  56. 1 1
      packages/native-core/src/real_dom.rs
  57. 2 2
      packages/native-core/src/utils.rs
  58. 1 1
      packages/rsx/src/component.rs
  59. 2 2
      packages/rsx/src/lib.rs
  60. 5 5
      packages/rsx/src/node.rs
  61. 1 1
      packages/tui/src/focus.rs
  62. 7 28
      packages/web/src/dom.rs
  63. 4 4
      packages/web/src/lib.rs
  64. 1 1
      packages/web/tests/hydrate.rs

+ 7 - 5
Cargo.toml

@@ -1,4 +1,3 @@
-
 [workspace]
 members = [
     "packages/dioxus",
@@ -12,17 +11,20 @@ members = [
     "packages/desktop",
     "packages/mobile",
     "packages/interpreter",
-    # "packages/tui",
     "packages/fermi",
     "packages/liveview",
     "packages/autofmt",
     "packages/rsx",
+    "docs/guide",
+    # "packages/tui",
     # "packages/native-core",
     # "packages/native-core-macro",
-    # "packages/edit-stream",
-    "docs/guide",
 ]
-
+exclude = [
+    "packages/tui",
+    "packages/native-core",
+    "packages/native-core-macro",
+]
 
 # This is a "virtual package"
 # It is not meant to be published, but is used so "cargo run --example XYZ" works properly

+ 1 - 1
packages/autofmt/src/buffer.rs

@@ -67,7 +67,7 @@ impl Buffer {
         match node {
             BodyNode::Element(el) => self.write_element(el),
             BodyNode::Component(component) => self.write_component(component),
-            BodyNode::DynamicText(text) => self.write_text(text),
+            BodyNode::Text(text) => self.write_text(text),
             BodyNode::RawExpr(exp) => self.write_raw_expr(exp),
             _ => Ok(()),
         }

+ 1 - 1
packages/autofmt/src/element.rs

@@ -280,7 +280,7 @@ impl Buffer {
         }
 
         match children {
-            [BodyNode::DynamicText(ref text)] => Some(text.source.as_ref().unwrap().value().len()),
+            [BodyNode::Text(ref text)] => Some(text.source.as_ref().unwrap().value().len()),
             [BodyNode::Component(ref comp)] => {
                 let attr_len = self.field_len(&comp.fields, &comp.manual_props);
 

+ 23 - 23
packages/core/src/create.rs

@@ -228,27 +228,29 @@ impl<'b> VirtualDom {
             self.create_static_node(node);
         }
 
-        self.mutations.template_mutations.push(SaveTemplate {
+        self.mutations.template_edits.push(SaveTemplate {
             name: template.template.id,
             m: template.template.roots.len(),
         });
     }
 
+    // todo: we shouldn't have any of instructions for building templates - renderers should be able to work with the
+    // template type directly, right?
     pub(crate) fn create_static_node(&mut self, node: &'b TemplateNode<'static>) {
         match *node {
             // Todo: create the children's template
             TemplateNode::Dynamic(_) => self
                 .mutations
-                .template_mutations
+                .template_edits
                 .push(CreateStaticPlaceholder {}),
             TemplateNode::Text(value) => self
                 .mutations
-                .template_mutations
+                .template_edits
                 .push(CreateStaticText { value }),
-            TemplateNode::DynamicText { .. } => self
-                .mutations
-                .template_mutations
-                .push(CreateTextPlaceholder),
+
+            TemplateNode::DynamicText { .. } => {
+                self.mutations.template_edits.push(CreateTextPlaceholder)
+            }
 
             TemplateNode::Element {
                 attrs,
@@ -257,21 +259,19 @@ impl<'b> VirtualDom {
                 tag,
                 ..
             } => {
-                if let Some(namespace) = namespace {
-                    self.mutations
-                        .template_mutations
-                        .push(CreateElementNamespace {
-                            name: tag,
-                            namespace,
-                        });
-                } else {
-                    self.mutations
-                        .template_mutations
-                        .push(CreateElement { name: tag });
+                match namespace {
+                    Some(namespace) => self.mutations.template_edits.push(CreateElementNamespace {
+                        name: tag,
+                        namespace,
+                    }),
+                    None => self
+                        .mutations
+                        .template_edits
+                        .push(CreateElement { name: tag }),
                 }
 
                 self.mutations
-                    .template_mutations
+                    .template_edits
                     .extend(attrs.iter().filter_map(|attr| match attr {
                         TemplateAttribute::Static {
                             name,
@@ -295,7 +295,7 @@ impl<'b> VirtualDom {
                     .for_each(|child| self.create_static_node(child));
 
                 self.mutations
-                    .template_mutations
+                    .template_edits
                     .push(AppendChildren { m: children.len() })
             }
         }
@@ -404,7 +404,7 @@ impl<'b> VirtualDom {
     ) -> usize {
         // Keep track of how many mutations are in the buffer in case we need to split them out if a suspense boundary
         // is encountered
-        let mutations_to_this_point = self.mutations.len();
+        let mutations_to_this_point = self.mutations.dom_edits.len();
 
         // Create the component's root element
         let created = self.create_scope(scope, new);
@@ -430,10 +430,10 @@ impl<'b> VirtualDom {
         // Note that we break off dynamic mutations only - since static mutations aren't rendered immediately
         let split_off = unsafe {
             std::mem::transmute::<Vec<Mutation>, Vec<Mutation>>(
-                self.mutations.split_off(mutations_to_this_point),
+                self.mutations.dom_edits.split_off(mutations_to_this_point),
             )
         };
-        boundary.mutations.borrow_mut().edits.extend(split_off);
+        boundary.mutations.borrow_mut().dom_edits.extend(split_off);
         boundary.created_on_stack.set(created);
         boundary
             .waiting_on

+ 85 - 36
packages/core/src/events.rs

@@ -1,57 +1,110 @@
-use bumpalo::boxed::Box as BumpBox;
 use std::{
-    any::Any,
     cell::{Cell, RefCell},
-    fmt::Debug,
     rc::Rc,
 };
 
-pub struct UiEvent<T: 'static + ?Sized> {
-    pub(crate) bubbles: Rc<Cell<bool>>,
+/// A wrapper around some generic data that handles the event's state
+///
+///
+/// Prevent this event from continuing to bubble up the tree to parent elements.
+///
+/// # Example
+///
+/// ```rust, ignore
+/// rsx! {
+///     button {
+///         onclick: move |evt: Event<MouseData>| {
+///             evt.cancel_bubble();
+///
+///         }
+///     }
+/// }
+/// ```
+pub struct Event<T: 'static + ?Sized> {
     pub(crate) data: Rc<T>,
+    pub(crate) propogates: Rc<Cell<bool>>,
 }
 
-impl UiEvent<dyn Any> {
-    pub fn downcast<T: 'static + Sized>(self) -> Option<UiEvent<T>> {
-        Some(UiEvent {
-            bubbles: self.bubbles,
-            data: self.data.downcast().ok()?,
-        })
+impl<T> Event<T> {
+    /// Prevent this event from continuing to bubble up the tree to parent elements.
+    ///
+    /// # Example
+    ///
+    /// ```rust, ignore
+    /// rsx! {
+    ///     button {
+    ///         onclick: move |evt: Event<MouseData>| {
+    ///             evt.cancel_bubble();
+    ///         }
+    ///     }
+    /// }
+    /// ```
+    #[deprecated = "use stop_propogation instead"]
+    pub fn cancel_bubble(&self) {
+        self.propogates.set(false);
+    }
+
+    /// Prevent this event from continuing to bubble up the tree to parent elements.
+    ///
+    /// # Example
+    ///
+    /// ```rust, ignore
+    /// rsx! {
+    ///     button {
+    ///         onclick: move |evt: Event<MouseData>| {
+    ///             evt.cancel_bubble();
+    ///         }
+    ///     }
+    /// }
+    /// ```
+    pub fn stop_propogation(&self) {
+        self.propogates.set(false);
+    }
+
+    /// Get a reference to the inner data from this event
+    ///
+    /// ```rust, ignore
+    /// rsx! {
+    ///     button {
+    ///         onclick: move |evt: Event<MouseData>| {
+    ///             let data = evt.inner.clone();
+    ///             cx.spawn(async move {
+    ///                 println!("{:?}", data);
+    ///             });
+    ///         }
+    ///     }
+    /// }
+    /// ```
+    pub fn inner(&self) -> &Rc<T> {
+        &self.data
     }
 }
-impl<T: ?Sized> Clone for UiEvent<T> {
+
+impl<T: ?Sized> Clone for Event<T> {
     fn clone(&self) -> Self {
         Self {
-            bubbles: self.bubbles.clone(),
+            propogates: self.propogates.clone(),
             data: self.data.clone(),
         }
     }
 }
-impl<T> UiEvent<T> {
-    pub fn cancel_bubble(&self) {
-        self.bubbles.set(false);
-    }
-}
 
-impl<T> std::ops::Deref for UiEvent<T> {
+impl<T> std::ops::Deref for Event<T> {
     type Target = Rc<T>;
-
     fn deref(&self) -> &Self::Target {
         &self.data
     }
 }
 
-impl<T: Debug> std::fmt::Debug for UiEvent<T> {
+impl<T: std::fmt::Debug> std::fmt::Debug for Event<T> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         f.debug_struct("UiEvent")
-            .field("bubble_state", &self.bubbles)
+            .field("bubble_state", &self.propogates)
             .field("data", &self.data)
             .finish()
     }
 }
 
-type ExternalListenerCallback<'bump, T> = BumpBox<'bump, dyn FnMut(T) + 'bump>;
-
 /// The callback type generated by the `rsx!` macro when an `on` field is specified for components.
 ///
 /// This makes it possible to pass `move |evt| {}` style closures into components as property fields.
@@ -60,9 +113,8 @@ type ExternalListenerCallback<'bump, T> = BumpBox<'bump, dyn FnMut(T) + 'bump>;
 /// # Example
 ///
 /// ```rust, ignore
-///
 /// rsx!{
-///     MyComponent { onclick: move |evt| log::info!("clicked"), }
+///     MyComponent { onclick: move |evt| log::info!("clicked") }
 /// }
 ///
 /// #[derive(Props)]
@@ -79,22 +131,17 @@ type ExternalListenerCallback<'bump, T> = BumpBox<'bump, dyn FnMut(T) + 'bump>;
 /// }
 ///
 /// ```
+#[derive(Default)]
 pub struct EventHandler<'bump, T = ()> {
-    /// The (optional) callback that the user specified
-    /// Uses a `RefCell` to allow for interior mutability, and FnMut closures.
-    pub callback: RefCell<Option<ExternalListenerCallback<'bump, T>>>,
+    pub(super) callback: RefCell<Option<ExternalListenerCallback<'bump, T>>>,
 }
 
-impl<'a, T> Default for EventHandler<'a, T> {
-    fn default() -> Self {
-        Self {
-            callback: RefCell::new(None),
-        }
-    }
-}
+type ExternalListenerCallback<'bump, T> = bumpalo::boxed::Box<'bump, dyn FnMut(T) + 'bump>;
 
 impl<T> EventHandler<'_, T> {
     /// Call this event handler with the appropriate event type
+    ///
+    /// This borrows the event using a RefCell. Recursively calling a listener will cause a panic.
     pub fn call(&self, event: T) {
         if let Some(callback) = self.callback.borrow_mut().as_mut() {
             callback(event);
@@ -102,6 +149,8 @@ impl<T> EventHandler<'_, T> {
     }
 
     /// Forcibly drop the internal handler callback, releasing memory
+    ///
+    /// This will force any future calls to "call" to not doing anything
     pub fn release(&self) {
         self.callback.replace(None);
     }

+ 10 - 106
packages/core/src/factory.rs

@@ -1,119 +1,21 @@
-use std::{
-    cell::{Cell, RefCell},
-    fmt::Arguments,
-};
-
+use crate::{innerlude::DynamicNode, AttributeValue, Element, LazyNodes, ScopeState, VNode};
 use bumpalo::boxed::Box as BumpBox;
 use bumpalo::Bump;
+use std::fmt::Arguments;
 use std::future::Future;
 
-use crate::{
-    any_props::{AnyProps, VProps},
-    arena::ElementId,
-    innerlude::{DynamicNode, EventHandler, VComponent, VText},
-    Attribute, AttributeValue, Element, LazyNodes, Properties, Scope, ScopeState, VNode,
-};
-
-impl ScopeState {
-    /// Create some text that's allocated along with the other vnodes
-    pub fn text<'a>(&'a self, args: Arguments) -> DynamicNode<'a> {
-        let (text, _) = self.raw_text(args);
-        DynamicNode::Text(VText {
-            id: Cell::new(ElementId(0)),
-            value: text,
-        })
-    }
-
-    pub fn raw_text_inline<'a>(&'a self, args: Arguments) -> &'a str {
-        self.raw_text(args).0
-    }
-
-    pub fn raw_text<'a>(&'a self, args: Arguments) -> (&'a str, bool) {
-        match args.as_str() {
-            Some(static_str) => (static_str, true),
-            None => {
-                use bumpalo::core_alloc::fmt::Write;
-                let mut str_buf = bumpalo::collections::String::new_in(self.bump());
-                str_buf.write_fmt(args).unwrap();
-                (str_buf.into_bump_str(), false)
-            }
-        }
-    }
-
-    pub fn fragment_from_iter<'a, 'c, I>(
-        &'a self,
-        node_iter: impl IntoDynNode<'a, I> + 'c,
-    ) -> DynamicNode {
-        node_iter.into_vnode(self)
-    }
-
-    /// Create a new [`Attribute`]
-    pub fn attr<'a>(
-        &'a self,
-        name: &'static str,
-        value: impl IntoAttributeValue<'a>,
-        namespace: Option<&'static str>,
-        volatile: bool,
-    ) -> Attribute<'a> {
-        Attribute {
-            name,
-            namespace,
-            volatile,
-            value: value.into_value(self.bump()),
-            mounted_element: Cell::new(ElementId(0)),
-        }
-    }
-
-    /// Create a new [`VNode::Component`]
-    pub fn component<'a, P, A, F: ComponentReturn<'a, A>>(
-        &'a self,
-        component: fn(Scope<'a, P>) -> F,
-        props: P,
-        fn_name: &'static str,
-    ) -> DynamicNode<'a>
-    where
-        P: Properties + 'a,
-    {
-        let as_component = component;
-        let vcomp = VProps::new(as_component, P::memoize, props);
-        let as_dyn: Box<dyn AnyProps<'a>> = Box::new(vcomp);
-        let extended: Box<dyn AnyProps> = unsafe { std::mem::transmute(as_dyn) };
-
-        // let as_dyn: &dyn AnyProps = self.bump().alloc(vcomp);
-        // todo: clean up borrowed props
-        // if !P::IS_STATIC {
-        // let vcomp = ex;
-        // let vcomp = unsafe { std::mem::transmute(vcomp) };
-        // self.items.borrow_mut().borrowed_props.push(vcomp);
-        // }
-
-        DynamicNode::Component(VComponent {
-            name: fn_name,
-            render_fn: component as *const (),
-            static_props: P::IS_STATIC,
-            props: Cell::new(Some(extended)),
-            scope: Cell::new(None),
-        })
-    }
-
-    /// Create a new [`EventHandler`] from an [`FnMut`]
-    pub fn event_handler<'a, T>(&'a self, f: impl FnMut(T) + 'a) -> EventHandler<'a, T> {
-        let handler: &mut dyn FnMut(T) = self.bump().alloc(f);
-        let caller = unsafe { BumpBox::from_raw(handler as *mut dyn FnMut(T)) };
-        let callback = RefCell::new(Some(caller));
-        EventHandler { callback }
-    }
-}
-
+#[doc(hidden)]
 pub trait ComponentReturn<'a, A = ()> {
     fn into_return(self, cx: &'a ScopeState) -> RenderReturn<'a>;
 }
+
 impl<'a> ComponentReturn<'a> for Element<'a> {
     fn into_return(self, _cx: &ScopeState) -> RenderReturn<'a> {
         RenderReturn::Sync(self)
     }
 }
 
+#[doc(hidden)]
 pub struct AsyncMarker;
 impl<'a, F> ComponentReturn<'a, AsyncMarker> for F
 where
@@ -142,6 +44,7 @@ impl<'a> RenderReturn<'a> {
     }
 }
 
+#[doc(hidden)]
 pub trait IntoDynNode<'a, A = ()> {
     fn into_vnode(self, cx: &'a ScopeState) -> DynamicNode<'a>;
 }
@@ -191,19 +94,19 @@ impl<'a, 'b> IntoDynNode<'a> for LazyNodes<'a, 'b> {
 
 impl<'a> IntoDynNode<'_> for &'a str {
     fn into_vnode(self, cx: &ScopeState) -> DynamicNode {
-        cx.text(format_args!("{}", self))
+        cx.text_node(format_args!("{}", self))
     }
 }
 
 impl IntoDynNode<'_> for String {
     fn into_vnode(self, cx: &ScopeState) -> DynamicNode {
-        cx.text(format_args!("{}", self))
+        cx.text_node(format_args!("{}", self))
     }
 }
 
 impl<'b> IntoDynNode<'b> for Arguments<'_> {
     fn into_vnode(self, cx: &'b ScopeState) -> DynamicNode<'b> {
-        cx.text(self)
+        cx.text_node(self)
     }
 }
 
@@ -235,6 +138,7 @@ impl<'a, 'b> IntoTemplate<'a> for LazyNodes<'a, 'b> {
 }
 
 // Note that we're using the E as a generic but this is never crafted anyways.
+#[doc(hidden)]
 pub struct FromNodeIterator;
 impl<'a, T, I> IntoDynNode<'a, FromNodeIterator> for T
 where

+ 17 - 91
packages/core/src/lazynodes.rs

@@ -3,7 +3,7 @@
 //! This module provides support for a type called `LazyNodes` which is a micro-heap located on the stack to make calls
 //! to `rsx!` more efficient.
 //!
-//! To support returning rsx! from branches in match statements, we need to use dynamic dispatch on [`NodeFactory`] closures.
+//! To support returning rsx! from branches in match statements, we need to use dynamic dispatch on [`ScopeState`] closures.
 //!
 //! This can be done either through boxing directly, or by using dynamic-sized-types and a custom allocator. In our case,
 //! we build a tiny alloactor in the stack and allocate the closure into that.
@@ -27,13 +27,11 @@ pub struct LazyNodes<'a, 'b> {
     inner: StackNodeStorage<'a, 'b>,
 }
 
-pub type NodeFactory<'a> = &'a ScopeState;
-
 type StackHeapSize = [usize; 16];
 
 enum StackNodeStorage<'a, 'b> {
     Stack(LazyStack),
-    Heap(Box<dyn FnMut(Option<NodeFactory<'a>>) -> Option<VNode<'a>> + 'b>),
+    Heap(Box<dyn FnMut(Option<&'a ScopeState>) -> Option<VNode<'a>> + 'b>),
 }
 
 impl<'a, 'b> LazyNodes<'a, 'b> {
@@ -42,11 +40,11 @@ impl<'a, 'b> LazyNodes<'a, 'b> {
     /// If the closure cannot fit into the stack allocation (16 bytes), then it
     /// is placed on the heap. Most closures will fit into the stack, and is
     /// the most optimal way to use the creation function.
-    pub fn new(val: impl FnOnce(NodeFactory<'a>) -> VNode<'a> + 'b) -> Self {
+    pub fn new(val: impl FnOnce(&'a ScopeState) -> VNode<'a> + 'b) -> Self {
         // there's no way to call FnOnce without a box, so we need to store it in a slot and use static dispatch
         let mut slot = Some(val);
 
-        let val = move |fac: Option<NodeFactory<'a>>| {
+        let val = move |fac: Option<&'a ScopeState>| {
             fac.map(
                 slot.take()
                     .expect("LazyNodes closure to be called only once"),
@@ -67,13 +65,13 @@ impl<'a, 'b> LazyNodes<'a, 'b> {
     /// Create a new [`LazyNodes`] closure, but force it onto the heap.
     pub fn new_boxed<F>(inner: F) -> Self
     where
-        F: FnOnce(NodeFactory<'a>) -> VNode<'a> + 'b,
+        F: FnOnce(&'a ScopeState) -> VNode<'a> + 'b,
     {
         // there's no way to call FnOnce without a box, so we need to store it in a slot and use static dispatch
         let mut slot = Some(inner);
 
         Self {
-            inner: StackNodeStorage::Heap(Box::new(move |fac: Option<NodeFactory<'a>>| {
+            inner: StackNodeStorage::Heap(Box::new(move |fac: Option<&'a ScopeState>| {
                 fac.map(
                     slot.take()
                         .expect("LazyNodes closure to be called only once"),
@@ -84,9 +82,9 @@ impl<'a, 'b> LazyNodes<'a, 'b> {
 
     unsafe fn new_inner<F>(val: F) -> Self
     where
-        F: FnMut(Option<NodeFactory<'a>>) -> Option<VNode<'a>> + 'b,
+        F: FnMut(Option<&'a ScopeState>) -> Option<VNode<'a>> + 'b,
     {
-        let mut ptr: *const _ = &val as &dyn FnMut(Option<NodeFactory<'a>>) -> Option<VNode<'a>>;
+        let mut ptr: *const _ = &val as &dyn FnMut(Option<&'a ScopeState>) -> Option<VNode<'a>>;
 
         assert_eq!(
             ptr as *const u8, &val as *const _ as *const u8,
@@ -162,12 +160,10 @@ impl<'a, 'b> LazyNodes<'a, 'b> {
     /// ```rust, ignore
     /// let f = LazyNodes::new(move |f| f.element("div", [], [], [] None));
     ///
-    /// let fac = NodeFactory::new(&cx);
-    ///
     /// let node = f.call(cac);
     /// ```
     #[must_use]
-    pub fn call(self, f: NodeFactory<'a>) -> VNode<'a> {
+    pub fn call(self, f: &'a ScopeState) -> VNode<'a> {
         match self.inner {
             StackNodeStorage::Heap(mut lazy) => {
                 lazy(Some(f)).expect("Closure should not be called twice")
@@ -184,18 +180,18 @@ struct LazyStack {
 }
 
 impl LazyStack {
-    fn call<'a>(&mut self, f: NodeFactory<'a>) -> VNode<'a> {
+    fn call<'a>(&mut self, f: &'a ScopeState) -> VNode<'a> {
         let LazyStack { buf, .. } = self;
         let data = buf.as_ref();
 
         let info_size =
-            mem::size_of::<*mut dyn FnMut(Option<NodeFactory<'a>>) -> Option<VNode<'a>>>()
+            mem::size_of::<*mut dyn FnMut(Option<&'a ScopeState>) -> Option<VNode<'a>>>()
                 / mem::size_of::<usize>()
                 - 1;
 
         let info_ofs = data.len() - info_size;
 
-        let g: *mut dyn FnMut(Option<NodeFactory<'a>>) -> Option<VNode<'a>> =
+        let g: *mut dyn FnMut(Option<&'a ScopeState>) -> Option<VNode<'a>> =
             unsafe { make_fat_ptr(data[..].as_ptr() as usize, &data[info_ofs..]) };
 
         self.dropped = true;
@@ -210,14 +206,14 @@ impl Drop for LazyStack {
             let LazyStack { buf, .. } = self;
             let data = buf.as_ref();
 
-            let info_size = mem::size_of::<
-                *mut dyn FnMut(Option<NodeFactory<'_>>) -> Option<VNode<'_>>,
-            >() / mem::size_of::<usize>()
-                - 1;
+            let info_size =
+                mem::size_of::<*mut dyn FnMut(Option<&ScopeState>) -> Option<VNode<'_>>>()
+                    / mem::size_of::<usize>()
+                    - 1;
 
             let info_ofs = data.len() - info_size;
 
-            let g: *mut dyn FnMut(Option<NodeFactory<'_>>) -> Option<VNode<'_>> =
+            let g: *mut dyn FnMut(Option<&ScopeState>) -> Option<VNode<'_>> =
                 unsafe { make_fat_ptr(data[..].as_ptr() as usize, &data[info_ofs..]) };
 
             self.dropped = true;
@@ -252,73 +248,3 @@ unsafe fn make_fat_ptr<T: ?Sized>(data_ptr: usize, meta_vals: &[usize]) -> *mut
 fn round_to_words(len: usize) -> usize {
     (len + mem::size_of::<usize>() - 1) / mem::size_of::<usize>()
 }
-
-// #[cfg(test)]
-// mod tests {
-//     use super::*;
-//     use crate::innerlude::{Element, Scope, VirtualDom};
-
-//     #[test]
-//     fn it_works() {
-//         fn app(cx: Scope<()>) -> Element {
-//             cx.render(LazyNodes::new(|f| f.text(format_args!("hello world!"))))
-//         }
-
-//         let mut dom = VirtualDom::new(app);
-//         dom.rebuild();
-
-//         let g = dom.base_scope().root_node();
-//         dbg!(g);
-//     }
-
-//     #[test]
-//     fn it_drops() {
-//         use std::rc::Rc;
-
-//         struct AppProps {
-//             inner: Rc<i32>,
-//         }
-
-//         fn app(cx: Scope<AppProps>) -> Element {
-//             struct DropInner {
-//                 id: i32,
-//             }
-//             impl Drop for DropInner {
-//                 fn drop(&mut self) {
-//                     eprintln!("dropping inner");
-//                 }
-//             }
-
-//             let caller = {
-//                 let it = (0..10).map(|i| {
-//                     let val = cx.props.inner.clone();
-//                     LazyNodes::new(move |f| {
-//                         eprintln!("hell closure");
-//                         let inner = DropInner { id: i };
-//                         f.text(format_args!("hello world {:?}, {:?}", inner.id, val))
-//                     })
-//                 });
-
-//                 LazyNodes::new(|f| {
-//                     eprintln!("main closure");
-//                     f.fragment_from_iter(it)
-//                 })
-//             };
-
-//             cx.render(caller)
-//         }
-
-//         let inner = Rc::new(0);
-//         let mut dom = VirtualDom::new_with_props(
-//             app,
-//             AppProps {
-//                 inner: inner.clone(),
-//             },
-//         );
-//         dom.rebuild();
-
-//         drop(dom);
-
-//         assert_eq!(Rc::strong_count(&inner), 1);
-//     }
-// }

+ 8 - 61
packages/core/src/lib.rs

@@ -1,4 +1,5 @@
 #![doc = include_str!("../README.md")]
+#![warn(missing_docs)]
 
 mod any_props;
 mod arena;
@@ -67,43 +68,13 @@ pub(crate) mod innerlude {
     /// )
     /// ```
     pub type Component<P = ()> = fn(Scope<P>) -> Element;
-
-    /// A list of attributes
-    pub type Attributes<'a> = Option<&'a [Attribute<'a>]>;
 }
 
 pub use crate::innerlude::{
-    // AnyAttributeValue, AnyEvent,
-    fc_to_builder,
-    Attribute,
-    AttributeValue,
-    Attributes,
-    Component,
-    DynamicNode,
-    Element,
-    ElementId,
-    Fragment,
-    LazyNodes,
-    Mutation,
-    Mutations,
-    NodeFactory,
-    Properties,
-    RenderReturn,
-    Scope,
-    ScopeId,
-    ScopeState,
-    Scoped,
-    SuspenseBoundary,
-    SuspenseContext,
-    TaskId,
-    Template,
-    TemplateAttribute,
-    TemplateNode,
-    UiEvent,
-    VComponent,
-    VNode,
-    VText,
-    VirtualDom,
+    fc_to_builder, Attribute, AttributeValue, Component, DynamicNode, Element, ElementId, Event,
+    Fragment, LazyNodes, Mutation, Mutations, Properties, RenderReturn, Scope, ScopeId, ScopeState,
+    Scoped, SuspenseBoundary, SuspenseContext, TaskId, Template, TemplateAttribute, TemplateNode,
+    VComponent, VNode, VText, VirtualDom,
 };
 
 /// The purpose of this module is to alleviate imports of many common types
@@ -111,9 +82,9 @@ pub use crate::innerlude::{
 /// This includes types like [`Scope`], [`Element`], and [`Component`].
 pub mod prelude {
     pub use crate::innerlude::{
-        fc_to_builder, Element, EventHandler, Fragment, LazyNodes, NodeFactory, Properties, Scope,
-        ScopeId, ScopeState, Scoped, TaskId, Template, TemplateAttribute, TemplateNode, UiEvent,
-        VNode, VirtualDom,
+        fc_to_builder, Element, Event, EventHandler, Fragment, LazyNodes, Properties, Scope,
+        ScopeId, ScopeState, Scoped, TaskId, Template, TemplateAttribute, TemplateNode, VNode,
+        VirtualDom,
     };
 }
 
@@ -121,28 +92,4 @@ pub mod exports {
     //! Important dependencies that are used by the rest of the library
     //! Feel free to just add the dependencies in your own Crates.toml
     pub use bumpalo;
-    pub use futures_channel;
-}
-
-#[macro_export]
-/// A helper macro for using hooks in async environements.
-///
-/// # Usage
-///
-///
-/// ```ignore
-/// let (data) = use_ref(&cx, || {});
-///
-/// let handle_thing = move |_| {
-///     to_owned![data]
-///     cx.spawn(async move {
-///         // do stuff
-///     });
-/// }
-/// ```
-macro_rules! to_owned {
-    ($($es:ident),+) => {$(
-        #[allow(unused_mut)]
-        let mut $es = $es.to_owned();
-    )*}
 }

+ 63 - 24
packages/core/src/mutations.rs

@@ -1,45 +1,50 @@
+use fxhash::FxHashSet;
+
 use crate::{arena::ElementId, ScopeId};
 
+/// A container for all the relevant steps to modify the Real DOM
+///
+/// This method returns "mutations" - IE the necessary changes to get the RealDOM to match the VirtualDOM. It also
+/// includes a list of NodeRefs that need to be applied and effects that need to be triggered after the RealDOM has
+/// applied the edits.
+///
+/// Mutations are the only link between the RealDOM and the VirtualDOM.
 #[derive(Debug, Default)]
 #[must_use = "not handling edits can lead to visual inconsistencies in UI"]
 pub struct Mutations<'a> {
+    /// The ID of the subtree that these edits are targetting
     pub subtree: usize,
-    pub template_mutations: Vec<Mutation<'a>>,
-    pub edits: Vec<Mutation<'a>>,
+
+    /// The list of Scopes that were diffed, created, and removed during the Diff process.
+    pub dirty_scopes: FxHashSet<ScopeId>,
+
+    /// Any mutations required to build the templates using [`Mutations`]
+    pub template_edits: Vec<Mutation<'a>>,
+
+    /// Any mutations required to patch the renderer to match the layout of the VirtualDom
+    pub dom_edits: Vec<Mutation<'a>>,
 }
 
 impl<'a> Mutations<'a> {
-    /// A useful tool for testing mutations
-    ///
     /// Rewrites IDs to just be "template", so you can compare the mutations
+    ///
+    /// Used really only for testing
     pub fn santize(mut self) -> Self {
-        for edit in self
-            .template_mutations
+        self.template_edits
             .iter_mut()
-            .chain(self.edits.iter_mut())
-        {
-            match edit {
+            .chain(self.dom_edits.iter_mut())
+            .for_each(|edit| match edit {
                 Mutation::LoadTemplate { name, .. } => *name = "template",
                 Mutation::SaveTemplate { name, .. } => *name = "template",
                 _ => {}
-            }
-        }
+            });
 
         self
     }
-}
-
-impl<'a> std::ops::Deref for Mutations<'a> {
-    type Target = Vec<Mutation<'a>>;
-
-    fn deref(&self) -> &Self::Target {
-        &self.edits
-    }
-}
 
-impl std::ops::DerefMut for Mutations<'_> {
-    fn deref_mut(&mut self) -> &mut Self::Target {
-        &mut self.edits
+    /// Push a new mutation into the dom_edits list
+    pub(crate) fn push(&mut self, mutation: Mutation<'static>) {
+        self.dom_edits.push(mutation)
     }
 }
 
@@ -54,7 +59,11 @@ each subtree has its own numbering scheme
 )]
 #[derive(Debug, PartialEq, Eq)]
 pub enum Mutation<'a> {
+    /// Pop the topmost node from our stack and append them to the node
+    /// at the top of the stack.
     AppendChildren {
+        /// How many nodes should be popped from the stack.
+        /// The node remaining on the stack will be the target for the append.
         m: usize,
     },
 
@@ -122,36 +131,61 @@ pub enum Mutation<'a> {
         m: usize,
     },
 
+    /// Save the top m nodes as a placeholder
     SaveTemplate {
+        /// The name of the template that we're saving
         name: &'static str,
+
+        /// How many nodes are being saved into this template
         m: usize,
     },
 
+    /// Set the value of a node's attribute.
     SetAttribute {
+        /// The name of the attribute to set.
         name: &'a str,
+        /// The value of the attribute.
         value: &'a str,
+
+        /// The ID of the node to set the attribute of.
         id: ElementId,
 
-        // value: &'bump str,
         /// The (optional) namespace of the attribute.
         /// For instance, "style" is in the "style" namespace.
         ns: Option<&'a str>,
     },
 
+    /// Set the value of a node's attribute.
     SetStaticAttribute {
+        /// The name of the attribute to set.
         name: &'a str,
+
+        /// The value of the attribute.
         value: &'a str,
+
+        /// The (optional) namespace of the attribute.
+        /// For instance, "style" is in the "style" namespace.
         ns: Option<&'a str>,
     },
 
+    /// Set the value of a node's attribute.
     SetBoolAttribute {
+        /// The name of the attribute to set.
         name: &'a str,
+
+        /// The value of the attribute.
         value: bool,
+
+        /// The ID of the node to set the attribute of.
         id: ElementId,
     },
 
+    /// Set the textcontent of a node.
     SetText {
+        /// The textcontent of the node
         value: &'a str,
+
+        /// The ID of the node to set the textcontent of.
         id: ElementId,
     },
 
@@ -175,11 +209,16 @@ pub enum Mutation<'a> {
         /// The ID of the node to remove.
         id: ElementId,
     },
+
+    /// Remove a particular node from the DOM
     Remove {
+        /// The ID of the node to remove.
         id: ElementId,
     },
 
+    /// Push the given root node onto our stack.
     PushRoot {
+        /// The ID of the root node to push.
         id: ElementId,
     },
 }

+ 7 - 8
packages/core/src/nodes.rs

@@ -1,4 +1,4 @@
-use crate::{any_props::AnyProps, arena::ElementId, Element, ScopeId, ScopeState, UiEvent};
+use crate::{any_props::AnyProps, arena::ElementId, Element, Event, ScopeId, ScopeState};
 use bumpalo::boxed::Box as BumpBox;
 use std::{
     any::{Any, TypeId},
@@ -70,7 +70,6 @@ pub struct Template<'a> {
     pub attr_paths: &'a [&'a [u8]],
 }
 
-/// A weird-ish variant of VNodes with way more limited types
 #[derive(Debug, Clone, Copy)]
 pub enum TemplateNode<'a> {
     Element {
@@ -98,7 +97,7 @@ impl<'a> DynamicNode<'a> {
         matches!(self, DynamicNode::Component(_))
     }
     pub fn placeholder() -> Self {
-        Self::Placeholder(Cell::new(ElementId(0)))
+        Self::Placeholder(Default::default())
     }
 }
 
@@ -156,18 +155,18 @@ pub enum AttributeValue<'a> {
     None,
 }
 
-type ListenerCb<'a> = BumpBox<'a, dyn FnMut(UiEvent<dyn Any>) + 'a>;
+type ListenerCb<'a> = BumpBox<'a, dyn FnMut(Event<dyn Any>) + 'a>;
 
 impl<'a> AttributeValue<'a> {
     pub fn new_listener<T: 'static>(
         cx: &'a ScopeState,
-        mut callback: impl FnMut(UiEvent<T>) + 'a,
+        mut callback: impl FnMut(Event<T>) + 'a,
     ) -> AttributeValue<'a> {
         let boxed: BumpBox<'a, dyn FnMut(_) + 'a> = unsafe {
-            BumpBox::from_raw(cx.bump().alloc(move |event: UiEvent<dyn Any>| {
+            BumpBox::from_raw(cx.bump().alloc(move |event: Event<dyn Any>| {
                 if let Ok(data) = event.data.downcast::<T>() {
-                    callback(UiEvent {
-                        bubbles: event.bubbles,
+                    callback(Event {
+                        propogates: event.propogates,
                         data,
                     })
                 }

+ 5 - 21
packages/core/src/scheduler/suspense.rs

@@ -15,25 +15,11 @@ pub type SuspenseContext = Rc<SuspenseBoundary>;
 
 /// Essentially a fiber in React
 pub struct SuspenseBoundary {
-    pub id: ScopeId,
-    pub waiting_on: RefCell<HashSet<SuspenseId>>,
-    pub mutations: RefCell<Mutations<'static>>,
-    pub placeholder: Cell<Option<ElementId>>,
-
-    pub created_on_stack: Cell<usize>,
-
-    // whenever the suspense resolves, we call this onresolve function
-    // this lets us do things like putting up a loading spinner
-    //
-    // todo: we need a way of controlling whether or not a component hides itself but still processes changes
-    // If we run into suspense, we perform a diff, so its important that the old elements are still around.
-    //
-    // When the timer expires, I imagine a container could hide the elements and show the spinner. This, however,
-    // can not be
-    pub onresolve: Option<Box<dyn FnOnce()>>,
-
-    /// Called when
-    pub onstart: Option<Box<dyn FnOnce()>>,
+    pub(crate) id: ScopeId,
+    pub(crate) waiting_on: RefCell<HashSet<SuspenseId>>,
+    pub(crate) mutations: RefCell<Mutations<'static>>,
+    pub(crate) placeholder: Cell<Option<ElementId>>,
+    pub(crate) created_on_stack: Cell<usize>,
 }
 
 impl SuspenseBoundary {
@@ -44,8 +30,6 @@ impl SuspenseBoundary {
             mutations: RefCell::new(Mutations::default()),
             placeholder: Cell::new(None),
             created_on_stack: Cell::new(0),
-            onresolve: None,
-            onstart: None,
         }
     }
 }

+ 1 - 1
packages/core/src/scope_arena.rs

@@ -49,7 +49,7 @@ impl VirtualDom {
             .and_then(|id| self.scopes.get_mut(id.0).map(|f| f.as_mut() as *mut _))
     }
 
-    pub fn ensure_drop_safety(&self, scope: ScopeId) {
+    fn ensure_drop_safety(&self, scope: ScopeId) {
         let scope = &self.scopes[scope.0];
         let node = unsafe { scope.previous_frame().try_load_node() };
 

+ 102 - 8
packages/core/src/scopes.rs

@@ -1,18 +1,21 @@
 use crate::{
     any_props::AnyProps,
+    any_props::VProps,
     arena::ElementId,
     bump_frame::BumpFrame,
-    factory::RenderReturn,
+    factory::{ComponentReturn, IntoAttributeValue, IntoDynNode, RenderReturn},
+    innerlude::{DynamicNode, EventHandler, VComponent, VText},
     innerlude::{Scheduler, SchedulerMsg},
     lazynodes::LazyNodes,
-    Element, TaskId,
+    Attribute, Element, Properties, TaskId,
 };
-use bumpalo::Bump;
-use std::future::Future;
+use bumpalo::{boxed::Box as BumpBox, Bump};
 use std::{
     any::{Any, TypeId},
     cell::{Cell, RefCell},
     collections::{HashMap, HashSet},
+    fmt::Arguments,
+    future::Future,
     rc::Rc,
     sync::Arc,
 };
@@ -59,9 +62,9 @@ impl<'a, T> std::ops::Deref for Scoped<'a, T> {
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
 pub struct ScopeId(pub usize);
 
-/// A component's state.
+/// A component's state separate from its props.
 ///
-/// This struct stores all the important information about a component's state without the props.
+/// This struct exists to provide a common interface for all scopes without relying on generics.
 pub struct ScopeState {
     pub(crate) render_cnt: Cell<usize>,
 
@@ -86,7 +89,7 @@ pub struct ScopeState {
     pub(crate) placeholder: Cell<Option<ElementId>>,
 }
 
-impl ScopeState {
+impl<'src> ScopeState {
     pub(crate) fn current_frame(&self) -> &BumpFrame {
         match self.render_cnt.get() % 2 {
             0 => &self.node_arena_1,
@@ -359,10 +362,101 @@ impl ScopeState {
     ///     cx.render(lazy_tree)
     /// }
     ///```
-    pub fn render<'src>(&'src self, rsx: LazyNodes<'src, '_>) -> Element<'src> {
+    pub fn render(&'src self, rsx: LazyNodes<'src, '_>) -> Element<'src> {
         Ok(rsx.call(self))
     }
 
+    /// Create a dynamic text node using [`Arguments`] and the [`ScopeState`]'s internal [`Bump`] allocator
+    pub fn text_node(&'src self, args: Arguments) -> DynamicNode<'src> {
+        DynamicNode::Text(VText {
+            value: self.raw_text(args),
+            id: Default::default(),
+        })
+    }
+
+    /// Allocate some text inside the [`ScopeState`] from [`Arguments`]
+    ///
+    /// Uses the currently active [`Bump`] allocator
+    pub fn raw_text(&'src self, args: Arguments) -> &'src str {
+        args.as_str().unwrap_or_else(|| {
+            use bumpalo::core_alloc::fmt::Write;
+            let mut str_buf = bumpalo::collections::String::new_in(self.bump());
+            str_buf.write_fmt(args).unwrap();
+            str_buf.into_bump_str()
+        })
+    }
+
+    /// Convert any item that implements [`IntoDynNode`] into a [`DynamicNode`] using the internal [`Bump`] allocator
+    pub fn make_node<'c, I>(&'src self, into: impl IntoDynNode<'src, I> + 'c) -> DynamicNode {
+        into.into_vnode(self)
+    }
+
+    /// Create a new [`Attribute`] from a name, value, namespace, and volatile bool
+    ///
+    /// "Volatile" referes to whether or not Dioxus should always override the value. This helps prevent the UI in
+    /// some renderers stay in sync with the VirtualDom's understanding of the world
+    pub fn attr(
+        &'src self,
+        name: &'static str,
+        value: impl IntoAttributeValue<'src>,
+        namespace: Option<&'static str>,
+        volatile: bool,
+    ) -> Attribute<'src> {
+        Attribute {
+            name,
+            namespace,
+            volatile,
+            mounted_element: Default::default(),
+            value: value.into_value(self.bump()),
+        }
+    }
+
+    /// Create a new [`DynamicNode::Component`] variant
+    ///
+    ///
+    /// The given component can be any of four signatures. Remember that an [`Element`] is really a [`Result<VNode>`].
+    ///
+    /// ```rust, ignore
+    /// // Without explicit props
+    /// fn(Scope) -> Element;
+    /// async fn(Scope<'_>) -> Element;
+    ///
+    /// // With explicit props
+    /// fn(Scope<Props>) -> Element;
+    /// async fn(Scope<Props<'_>>) -> Element;
+    /// ```
+    pub fn component<P, A, F: ComponentReturn<'src, A>>(
+        &'src self,
+        component: fn(Scope<'src, P>) -> F,
+        props: P,
+        fn_name: &'static str,
+    ) -> DynamicNode<'src>
+    where
+        P: Properties + 'src,
+    {
+        let vcomp = VProps::new(component, P::memoize, props);
+
+        // cast off the lifetime of the render return
+        let as_dyn: Box<dyn AnyProps<'src> + '_> = Box::new(vcomp);
+        let extended: Box<dyn AnyProps<'src> + 'src> = unsafe { std::mem::transmute(as_dyn) };
+
+        DynamicNode::Component(VComponent {
+            name: fn_name,
+            render_fn: component as *const (),
+            static_props: P::IS_STATIC,
+            props: Cell::new(Some(extended)),
+            scope: Cell::new(None),
+        })
+    }
+
+    /// Create a new [`EventHandler`] from an [`FnMut`]
+    pub fn event_handler<T>(&'src self, f: impl FnMut(T) + 'src) -> EventHandler<'src, T> {
+        let handler: &mut dyn FnMut(T) = self.bump().alloc(f);
+        let caller = unsafe { BumpBox::from_raw(handler as *mut dyn FnMut(T)) };
+        let callback = RefCell::new(Some(caller));
+        EventHandler { callback }
+    }
+
     /// Store a value between renders. The foundational hook for all other hooks.
     ///
     /// Accepts an `initializer` closure, which is run on the first use of the hook (typically the initial render). The return value of this closure is stored for the lifetime of the component, and a mutable reference to it is provided on every render as the return value of `use_hook`.

+ 12 - 8
packages/core/src/virtual_dom.rs

@@ -11,7 +11,7 @@ use crate::{
     nodes::{Template, TemplateId},
     scheduler::{SuspenseBoundary, SuspenseId},
     scopes::{ScopeId, ScopeState},
-    AttributeValue, Element, Scope, SuspenseContext, UiEvent,
+    AttributeValue, Element, Event, Scope, SuspenseContext,
 };
 use futures_util::{pin_mut, StreamExt};
 use slab::Slab;
@@ -350,8 +350,8 @@ impl VirtualDom {
         let mut listeners = vec![];
 
         // We will clone this later. The data itself is wrapped in RC to be used in callbacks if required
-        let uievent = UiEvent {
-            bubbles: Rc::new(Cell::new(bubbles)),
+        let uievent = Event {
+            propogates: Rc::new(Cell::new(bubbles)),
             data,
         };
 
@@ -395,7 +395,7 @@ impl VirtualDom {
                         cb(uievent.clone());
                     }
 
-                    if !uievent.bubbles.get() {
+                    if !uievent.propogates.get() {
                         return;
                     }
                 }
@@ -534,9 +534,12 @@ impl VirtualDom {
                 let context = scope.has_context::<SuspenseContext>().unwrap();
 
                 self.mutations
-                    .extend(context.mutations.borrow_mut().template_mutations.drain(..));
+                    .template_edits
+                    .extend(context.mutations.borrow_mut().template_edits.drain(..));
+
                 self.mutations
-                    .extend(context.mutations.borrow_mut().drain(..));
+                    .dom_edits
+                    .extend(context.mutations.borrow_mut().dom_edits.drain(..));
 
                 // TODO: count how many nodes are on the stack?
                 self.mutations.push(Mutation::ReplaceWith {
@@ -556,7 +559,7 @@ impl VirtualDom {
                 }
 
                 // Save the current mutations length so we can split them into boundary
-                let mutations_to_this_point = self.mutations.len();
+                let mutations_to_this_point = self.mutations.dom_edits.len();
 
                 // Run the scope and get the mutations
                 self.run_scope(dirty.id);
@@ -575,7 +578,8 @@ impl VirtualDom {
                     boundary_mut
                         .mutations
                         .borrow_mut()
-                        .extend(self.mutations.split_off(mutations_to_this_point));
+                        .dom_edits
+                        .extend(self.mutations.dom_edits.split_off(mutations_to_this_point));
 
                     // Attach suspended leaves
                     boundary

+ 2 - 7
packages/core/tests/README.md

@@ -1,9 +1,6 @@
 # Testing of Dioxus core
 
 
-NodeFactory
-- [] rsx, html, NodeFactory generate the same structures
-
 Diffing
 - [x] create elements
 - [x] create text
@@ -19,15 +16,13 @@ Diffing
 - [x] keyed diffing
 - [x] keyed diffing out of order
 - [x] keyed diffing with prefix/suffix
-- [x] suspended nodes work 
+- [x] suspended nodes work
 
 Lifecycle
 - [] Components mount properly
 - [] Components create new child components
 - [] Replaced components unmount old components and mount new
 - [] Post-render effects are called
-- [] 
-
 
 Shared Context
 - [] Shared context propagates downwards
@@ -37,7 +32,7 @@ Suspense
 - [] use_suspense generates suspended nodes
 
 
-Hooks 
+Hooks
 - [] Drop order is maintained
 - [] Shared hook state is okay
 - [] use_hook works

+ 5 - 5
packages/core/tests/attr_cleanup.rs

@@ -23,7 +23,7 @@ fn attrs_cycle() {
     });
 
     assert_eq!(
-        dom.rebuild().santize().edits,
+        dom.rebuild().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
             AppendChildren { m: 1 },
@@ -32,7 +32,7 @@ fn attrs_cycle() {
 
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
             AssignId { path: &[0,], id: ElementId(3,) },
@@ -44,7 +44,7 @@ fn attrs_cycle() {
 
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(3) },
             ReplaceWith { id: ElementId(2), m: 1 }
@@ -53,7 +53,7 @@ fn attrs_cycle() {
 
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(2) },
             AssignId { path: &[0], id: ElementId(1) },
@@ -66,7 +66,7 @@ fn attrs_cycle() {
     // we take the node taken by attributes since we reused it
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(1) },
             ReplaceWith { id: ElementId(2), m: 1 }

+ 1 - 1
packages/core/tests/boolattrs.rs

@@ -5,7 +5,7 @@ use dioxus::prelude::*;
 fn bool_test() {
     let mut app = VirtualDom::new(|cx| cx.render(rsx!(div { hidden: false })));
     assert_eq!(
-        app.rebuild().santize().edits,
+        app.rebuild().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(1) },
             SetBoolAttribute { name: "hidden", value: false, id: ElementId(1,) },

+ 1 - 1
packages/core/tests/borrowedstate.rs

@@ -8,7 +8,7 @@ fn test_borrowed_state() {
     let mut dom = VirtualDom::new(Parent);
 
     assert_eq!(
-        dom.rebuild().santize().edits,
+        dom.rebuild().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
             LoadTemplate { name: "template", index: 0, id: ElementId(2,) },

+ 3 - 3
packages/core/tests/context_api.rs

@@ -20,7 +20,7 @@ fn state_shares() {
 
     let mut dom = VirtualDom::new(app);
     assert_eq!(
-        dom.rebuild().santize().edits,
+        dom.rebuild().santize().dom_edits,
         [
             CreateTextNode { value: "Value is 0", id: ElementId(1,) },
             AppendChildren { m: 1 },
@@ -37,7 +37,7 @@ fn state_shares() {
 
     dom.mark_dirty(ScopeId(2));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [SetText { value: "Value is 2", id: ElementId(1,) },]
     );
 
@@ -45,7 +45,7 @@ fn state_shares() {
     dom.mark_dirty(ScopeId(2));
     let edits = dom.render_immediate();
     assert_eq!(
-        edits.santize().edits,
+        edits.santize().dom_edits,
         [SetText { value: "Value is 3", id: ElementId(1,) },]
     );
 }

+ 8 - 8
packages/core/tests/create_dom.rs

@@ -23,7 +23,7 @@ fn test_original_diff() {
 
     let edits = dom.rebuild().santize();
     assert_eq!(
-        edits.template_mutations,
+        edits.template_edits,
         [
             // create template
             CreateElement { name: "div" },
@@ -36,7 +36,7 @@ fn test_original_diff() {
     );
 
     assert_eq!(
-        edits.edits,
+        edits.dom_edits,
         [
             // add to root
             LoadTemplate { name: "template", index: 0, id: ElementId(1) },
@@ -67,7 +67,7 @@ fn create() {
 
     let edits = dom.rebuild().santize();
     assert_eq!(
-        edits.template_mutations,
+        edits.template_edits,
         [
             // create template
             CreateElement { name: "div" },
@@ -99,7 +99,7 @@ fn create_list() {
 
     let edits = dom.rebuild().santize();
     assert_eq!(
-        edits.template_mutations,
+        edits.template_edits,
         [
             // create template
             CreateElement { name: "div" },
@@ -123,7 +123,7 @@ fn create_simple() {
 
     let edits = dom.rebuild().santize();
     assert_eq!(
-        edits.template_mutations,
+        edits.template_edits,
         [
             // create template
             CreateElement { name: "div" },
@@ -160,7 +160,7 @@ fn create_components() {
 
     let edits = dom.rebuild().santize();
     assert_eq!(
-        edits.template_mutations,
+        edits.template_edits,
         [
             // The "child" template
             CreateElement { name: "h1" },
@@ -196,7 +196,7 @@ fn anchors() {
     // note that the template under "false" doesn't show up since it's not loaded
     let edits = dom.rebuild().santize();
     assert_eq!(
-        edits.template_mutations,
+        edits.template_edits,
         [
             // create each template
             CreateElement { name: "div" },
@@ -207,7 +207,7 @@ fn anchors() {
     );
 
     assert_eq!(
-        edits.edits,
+        edits.dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(1) },
             CreatePlaceholder { id: ElementId(2) },

+ 1 - 1
packages/core/tests/create_element.rs

@@ -12,7 +12,7 @@ fn multiroot() {
     });
 
     assert_eq!(
-        dom.rebuild().santize().template_mutations,
+        dom.rebuild().santize().template_edits,
         [
             CreateElement { name: "div" },
             CreateStaticText { value: "Hello a" },

+ 5 - 5
packages/core/tests/create_fragments.rs

@@ -14,7 +14,7 @@ fn empty_fragment_creates_nothing() {
     let edits = vdom.rebuild();
 
     assert_eq!(
-        edits.edits,
+        edits.dom_edits,
         [
             CreatePlaceholder { id: ElementId(1) },
             AppendChildren { m: 1 }
@@ -32,7 +32,7 @@ fn root_fragments_work() {
     });
 
     assert_eq!(
-        vdom.rebuild().edits.last().unwrap(),
+        vdom.rebuild().dom_edits.last().unwrap(),
         &AppendChildren { m: 2 }
     );
 }
@@ -59,7 +59,7 @@ fn fragments_nested() {
     });
 
     assert_eq!(
-        vdom.rebuild().edits.last().unwrap(),
+        vdom.rebuild().dom_edits.last().unwrap(),
         &AppendChildren { m: 8 }
     );
 }
@@ -84,7 +84,7 @@ fn fragments_across_components() {
     }
 
     assert_eq!(
-        VirtualDom::new(app).rebuild().edits.last().unwrap(),
+        VirtualDom::new(app).rebuild().dom_edits.last().unwrap(),
         &AppendChildren { m: 8 }
     );
 }
@@ -98,7 +98,7 @@ fn list_fragments() {
         ))
     }
     assert_eq!(
-        VirtualDom::new(app).rebuild().edits.last().unwrap(),
+        VirtualDom::new(app).rebuild().dom_edits.last().unwrap(),
         &AppendChildren { m: 7 }
     );
 }

+ 2 - 2
packages/core/tests/create_lists.rs

@@ -28,7 +28,7 @@ fn list_renders() {
     let edits = dom.rebuild().santize();
 
     assert_eq!(
-        edits.template_mutations,
+        edits.template_edits,
         [
             // Create the outer div
             CreateElement { name: "div" },
@@ -51,7 +51,7 @@ fn list_renders() {
     );
 
     assert_eq!(
-        edits.edits,
+        edits.dom_edits,
         [
             // Load the outer div
             LoadTemplate { name: "template", index: 0, id: ElementId(1) },

+ 4 - 4
packages/core/tests/create_passthru.rs

@@ -26,7 +26,7 @@ fn nested_passthru_creates() {
     let edits = dom.rebuild().santize();
 
     assert_eq!(
-        edits.edits,
+        edits.dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(1) },
             AppendChildren { m: 1 },
@@ -64,7 +64,7 @@ fn nested_passthru_creates_add() {
     let mut dom = VirtualDom::new(app);
 
     assert_eq!(
-        dom.rebuild().santize().edits,
+        dom.rebuild().santize().dom_edits,
         [
             // load 1
             LoadTemplate { name: "template", index: 0, id: ElementId(1) },
@@ -92,11 +92,11 @@ fn dynamic_node_as_root() {
     let edits = dom.rebuild().santize();
 
     // Since the roots were all dynamic, they should not cause any template muations
-    assert_eq!(edits.template_mutations, []);
+    assert_eq!(edits.template_edits, []);
 
     // The root node is text, so we just create it on the spot
     assert_eq!(
-        edits.edits,
+        edits.dom_edits,
         [
             CreateTextNode { value: "123", id: ElementId(1) },
             CreateTextNode { value: "456", id: ElementId(2) },

+ 4 - 4
packages/core/tests/cycle.rs

@@ -14,7 +14,7 @@ fn cycling_elements() {
 
     let edits = dom.rebuild().santize();
     assert_eq!(
-        edits.edits,
+        edits.dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
             AppendChildren { m: 1 },
@@ -23,7 +23,7 @@ fn cycling_elements() {
 
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
             ReplaceWith { id: ElementId(1,), m: 1 },
@@ -33,7 +33,7 @@ fn cycling_elements() {
     // notice that the IDs cycle back to ElementId(1), preserving a minimal memory footprint
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
             ReplaceWith { id: ElementId(2,), m: 1 },
@@ -42,7 +42,7 @@ fn cycling_elements() {
 
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
             ReplaceWith { id: ElementId(1,), m: 1 },

+ 4 - 4
packages/core/tests/diff_component.rs

@@ -61,7 +61,7 @@ fn component_swap() {
     let mut dom = VirtualDom::new(app);
     let edits = dom.rebuild().santize();
     assert_eq!(
-        edits.edits,
+        edits.dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(1) },
             LoadTemplate { name: "template", index: 0, id: ElementId(2) },
@@ -75,7 +75,7 @@ fn component_swap() {
 
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(6) },
             ReplaceWith { id: ElementId(5), m: 1 }
@@ -84,7 +84,7 @@ fn component_swap() {
 
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(5) },
             ReplaceWith { id: ElementId(6), m: 1 }
@@ -93,7 +93,7 @@ fn component_swap() {
 
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(6) },
             ReplaceWith { id: ElementId(5), m: 1 }

+ 7 - 7
packages/core/tests/diff_element.rs

@@ -14,19 +14,19 @@ fn text_diff() {
 
     vdom.mark_dirty(ScopeId(0));
     assert_eq!(
-        vdom.render_immediate().edits,
+        vdom.render_immediate().dom_edits,
         [SetText { value: "hello 1", id: ElementId(2) }]
     );
 
     vdom.mark_dirty(ScopeId(0));
     assert_eq!(
-        vdom.render_immediate().edits,
+        vdom.render_immediate().dom_edits,
         [SetText { value: "hello 2", id: ElementId(2) }]
     );
 
     vdom.mark_dirty(ScopeId(0));
     assert_eq!(
-        vdom.render_immediate().edits,
+        vdom.render_immediate().dom_edits,
         [SetText { value: "hello 3", id: ElementId(2) }]
     );
 }
@@ -48,7 +48,7 @@ fn element_swap() {
 
     vdom.mark_dirty(ScopeId(0));
     assert_eq!(
-        vdom.render_immediate().santize().edits,
+        vdom.render_immediate().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
             ReplaceWith { id: ElementId(1,), m: 1 },
@@ -57,7 +57,7 @@ fn element_swap() {
 
     vdom.mark_dirty(ScopeId(0));
     assert_eq!(
-        vdom.render_immediate().santize().edits,
+        vdom.render_immediate().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
             ReplaceWith { id: ElementId(2,), m: 1 },
@@ -66,7 +66,7 @@ fn element_swap() {
 
     vdom.mark_dirty(ScopeId(0));
     assert_eq!(
-        vdom.render_immediate().santize().edits,
+        vdom.render_immediate().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
             ReplaceWith { id: ElementId(1,), m: 1 },
@@ -75,7 +75,7 @@ fn element_swap() {
 
     vdom.mark_dirty(ScopeId(0));
     assert_eq!(
-        vdom.render_immediate().santize().edits,
+        vdom.render_immediate().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
             ReplaceWith { id: ElementId(2,), m: 1 },

+ 13 - 13
packages/core/tests/diff_keyed_list.rs

@@ -21,7 +21,7 @@ fn keyed_diffing_out_of_order() {
     });
 
     assert_eq!(
-        dom.rebuild().santize().edits,
+        dom.rebuild().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
             LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
@@ -39,7 +39,7 @@ fn keyed_diffing_out_of_order() {
 
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().edits,
+        dom.render_immediate().dom_edits,
         [
             PushRoot { id: ElementId(7,) },
             InsertBefore { id: ElementId(5,), m: 1 },
@@ -64,7 +64,7 @@ fn keyed_diffing_out_of_order_adds() {
 
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().edits,
+        dom.render_immediate().dom_edits,
         [
             PushRoot { id: ElementId(5,) },
             PushRoot { id: ElementId(4,) },
@@ -90,7 +90,7 @@ fn keyed_diffing_out_of_order_adds_3() {
 
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().edits,
+        dom.render_immediate().dom_edits,
         [
             PushRoot { id: ElementId(5,) },
             PushRoot { id: ElementId(4,) },
@@ -116,7 +116,7 @@ fn keyed_diffing_out_of_order_adds_4() {
 
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().edits,
+        dom.render_immediate().dom_edits,
         [
             PushRoot { id: ElementId(5,) },
             PushRoot { id: ElementId(4,) },
@@ -142,7 +142,7 @@ fn keyed_diffing_out_of_order_adds_5() {
 
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().edits,
+        dom.render_immediate().dom_edits,
         [
             PushRoot { id: ElementId(5,) },
             InsertBefore { id: ElementId(4,), m: 1 },
@@ -167,7 +167,7 @@ fn keyed_diffing_additions() {
 
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(6) },
             LoadTemplate { name: "template", index: 0, id: ElementId(7) },
@@ -192,7 +192,7 @@ fn keyed_diffing_additions_and_moves_on_ends() {
 
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [
             // create 11, 12
             LoadTemplate { name: "template", index: 0, id: ElementId(5) },
@@ -222,7 +222,7 @@ fn keyed_diffing_additions_and_moves_in_middle() {
     // LIS: 4, 5, 6
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [
             // create 5, 6
             LoadTemplate { name: "template", index: 0, id: ElementId(5) },
@@ -256,7 +256,7 @@ fn controlled_keyed_diffing_out_of_order() {
     // LIS: 5, 6
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [
             // remove 7
             Remove { id: ElementId(4,) },
@@ -289,7 +289,7 @@ fn controlled_keyed_diffing_out_of_order_max_test() {
 
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [
             Remove { id: ElementId(5,) },
             LoadTemplate { name: "template", index: 0, id: ElementId(5) },
@@ -318,7 +318,7 @@ fn remove_list() {
 
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [
             Remove { id: ElementId(3) },
             Remove { id: ElementId(4) },
@@ -343,7 +343,7 @@ fn no_common_keys() {
 
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [
             Remove { id: ElementId(2) },
             Remove { id: ElementId(3) },

+ 26 - 26
packages/core/tests/diff_unkeyed_list.rs

@@ -17,7 +17,7 @@ fn list_creates_one_by_one() {
 
     // load the div and then assign the empty fragment as a placeholder
     assert_eq!(
-        dom.rebuild().santize().edits,
+        dom.rebuild().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
             AssignId { path: &[0], id: ElementId(2,) },
@@ -28,7 +28,7 @@ fn list_creates_one_by_one() {
     // Rendering the first item should replace the placeholder with an element
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(3,) },
             HydrateText { path: &[0], value: "0", id: ElementId(4,) },
@@ -39,7 +39,7 @@ fn list_creates_one_by_one() {
     // Rendering the next item should insert after the previous
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
             HydrateText { path: &[0], value: "1", id: ElementId(5,) },
@@ -50,7 +50,7 @@ fn list_creates_one_by_one() {
     // ... and again!
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(6,) },
             HydrateText { path: &[0], value: "2", id: ElementId(7,) },
@@ -61,7 +61,7 @@ fn list_creates_one_by_one() {
     // once more
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(8,) },
             HydrateText { path: &[0], value: "3", id: ElementId(9,) },
@@ -86,7 +86,7 @@ fn removes_one_by_one() {
 
     // load the div and then assign the empty fragment as a placeholder
     assert_eq!(
-        dom.rebuild().santize().edits,
+        dom.rebuild().santize().dom_edits,
         [
             // The container
             LoadTemplate { name: "template", index: 0, id: ElementId(1) },
@@ -108,14 +108,14 @@ fn removes_one_by_one() {
     // Rendering the first item should replace the placeholder with an element
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [Remove { id: ElementId(6) }]
     );
 
     // Remove div(2)
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [Remove { id: ElementId(4) }]
     );
 
@@ -123,7 +123,7 @@ fn removes_one_by_one() {
     // todo: this should just be a remove with no placeholder
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [
             CreatePlaceholder { id: ElementId(3) },
             ReplaceWith { id: ElementId(2), m: 1 }
@@ -134,7 +134,7 @@ fn removes_one_by_one() {
     // todo: this should actually be append to, but replace placeholder is fine for now
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(2) },
             HydrateText { path: &[0], value: "0", id: ElementId(4) },
@@ -161,7 +161,7 @@ fn list_shrink_multiroot() {
     });
 
     assert_eq!(
-        dom.rebuild().santize().edits,
+        dom.rebuild().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
             AssignId { path: &[0,], id: ElementId(2,) },
@@ -171,7 +171,7 @@ fn list_shrink_multiroot() {
 
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(3) },
             HydrateText { path: &[0], value: "0", id: ElementId(4) },
@@ -183,7 +183,7 @@ fn list_shrink_multiroot() {
 
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(2) },
             HydrateText { path: &[0], value: "1", id: ElementId(7) },
@@ -195,7 +195,7 @@ fn list_shrink_multiroot() {
 
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(10) },
             HydrateText { path: &[0], value: "2", id: ElementId(11) },
@@ -223,7 +223,7 @@ fn removes_one_by_one_multiroot() {
 
     // load the div and then assign the empty fragment as a placeholder
     assert_eq!(
-        dom.rebuild().santize().edits,
+        dom.rebuild().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(1) },
             //
@@ -250,19 +250,19 @@ fn removes_one_by_one_multiroot() {
 
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [Remove { id: ElementId(10) }, Remove { id: ElementId(12) }]
     );
 
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [Remove { id: ElementId(6) }, Remove { id: ElementId(8) }]
     );
 
     dom.mark_dirty(ScopeId(0));
     assert_eq!(
-        dom.render_immediate().santize().edits,
+        dom.render_immediate().santize().dom_edits,
         [
             Remove { id: ElementId(4) },
             CreatePlaceholder { id: ElementId(5) },
@@ -282,7 +282,7 @@ fn two_equal_fragments_are_equal_static() {
     });
 
     _ = dom.rebuild();
-    assert!(dom.render_immediate().edits.is_empty());
+    assert!(dom.render_immediate().dom_edits.is_empty());
 }
 
 #[test]
@@ -296,7 +296,7 @@ fn two_equal_fragments_are_equal() {
     });
 
     _ = dom.rebuild();
-    assert!(dom.render_immediate().edits.is_empty());
+    assert!(dom.render_immediate().dom_edits.is_empty());
 }
 
 #[test]
@@ -315,9 +315,9 @@ fn remove_many() {
     });
 
     let edits = dom.rebuild().santize();
-    assert!(edits.template_mutations.is_empty());
+    assert!(edits.template_edits.is_empty());
     assert_eq!(
-        edits.edits,
+        edits.dom_edits,
         [
             CreatePlaceholder { id: ElementId(1,) },
             AppendChildren { m: 1 },
@@ -327,7 +327,7 @@ fn remove_many() {
     dom.mark_dirty(ScopeId(0));
     let edits = dom.render_immediate().santize();
     assert_eq!(
-        edits.edits,
+        edits.dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
             HydrateText { path: &[0,], value: "hello 0", id: ElementId(3,) },
@@ -338,7 +338,7 @@ fn remove_many() {
     dom.mark_dirty(ScopeId(0));
     let edits = dom.render_immediate().santize();
     assert_eq!(
-        edits.edits,
+        edits.dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
             HydrateText { path: &[0,], value: "hello 1", id: ElementId(4,) },
@@ -355,7 +355,7 @@ fn remove_many() {
     dom.mark_dirty(ScopeId(0));
     let edits = dom.render_immediate().santize();
     assert_eq!(
-        edits.edits,
+        edits.dom_edits,
         [
             Remove { id: ElementId(1,) },
             Remove { id: ElementId(5,) },
@@ -369,7 +369,7 @@ fn remove_many() {
     dom.mark_dirty(ScopeId(0));
     let edits = dom.render_immediate().santize();
     assert_eq!(
-        edits.edits,
+        edits.dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(2,) },
             HydrateText { path: &[0,], value: "hello 0", id: ElementId(10,) },

+ 2 - 2
packages/core/tests/kitchen_sink.rs

@@ -30,7 +30,7 @@ fn dual_stream() {
 
     use Mutation::*;
     assert_eq!(
-        edits.template_mutations,
+        edits.template_edits,
         [
             CreateElement { name: "div" },
             SetStaticAttribute { name: "class", value: "asd", ns: None },
@@ -66,7 +66,7 @@ fn dual_stream() {
     );
 
     assert_eq!(
-        edits.edits,
+        edits.dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(1) },
             SetAttribute { name: "class", value: "123", id: ElementId(1), ns: None },

+ 2 - 2
packages/core/tests/lifecycle.rs

@@ -28,7 +28,7 @@ fn manual_diffing() {
     *value.lock().unwrap() = "goodbye";
 
     assert_eq!(
-        dom.rebuild().santize().edits,
+        dom.rebuild().santize().dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(3) },
             HydrateText { path: &[0], value: "goodbye", id: ElementId(4) },
@@ -62,7 +62,7 @@ fn events_generate() {
     let edits = dom.render_immediate();
 
     assert_eq!(
-        edits.edits,
+        edits.dom_edits,
         [
             CreatePlaceholder { id: ElementId(2) },
             ReplaceWith { id: ElementId(1), m: 1 }

+ 2 - 2
packages/core/tests/suspense.rs

@@ -13,7 +13,7 @@ async fn it_works() {
 
     // We should at least get the top-level template in before pausing for the children
     assert_eq!(
-        mutations.template_mutations,
+        mutations.template_edits,
         [
             CreateElement { name: "div" },
             CreateStaticText { value: "Waiting for child..." },
@@ -25,7 +25,7 @@ async fn it_works() {
 
     // And we should load it in and assign the placeholder properly
     assert_eq!(
-        mutations.edits,
+        mutations.dom_edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(1) },
             // hmmmmmmmmm.... with suspense how do we guarantee that IDs increase linearly?

+ 4 - 4
packages/desktop/src/controller.rs

@@ -54,8 +54,8 @@ impl DesktopController {
                 {
                     let edits = dom.rebuild();
                     let mut queue = edit_queue.lock().unwrap();
-                    queue.push(serde_json::to_string(&edits.template_mutations).unwrap());
-                    queue.push(serde_json::to_string(&edits.edits).unwrap());
+                    queue.push(serde_json::to_string(&edits.template_edits).unwrap());
+                    queue.push(serde_json::to_string(&edits.dom_edits).unwrap());
                     proxy.send_event(UserWindowEvent::EditsReady).unwrap();
                 }
 
@@ -79,8 +79,8 @@ impl DesktopController {
 
                     {
                         let mut queue = edit_queue.lock().unwrap();
-                        queue.push(serde_json::to_string(&muts.template_mutations).unwrap());
-                        queue.push(serde_json::to_string(&muts.edits).unwrap());
+                        queue.push(serde_json::to_string(&muts.template_edits).unwrap());
+                        queue.push(serde_json::to_string(&muts.dom_edits).unwrap());
                         let _ = proxy.send_event(UserWindowEvent::EditsReady);
                     }
                 }

+ 1 - 1
packages/dioxus/benches/jsframework.rs

@@ -46,7 +46,7 @@ fn create_rows(c: &mut Criterion) {
 
         b.iter(|| {
             let g = dom.rebuild();
-            assert!(g.edits.len() > 1);
+            assert!(g.dom_edits.len() > 1);
         })
     });
 }

+ 22 - 2
packages/hooks/src/lib.rs

@@ -1,5 +1,25 @@
-// #![deny(missing_docs)]
-//! Useful foundational hooks for Dioxus
+#[macro_export]
+/// A helper macro for using hooks in async environements.
+///
+/// # Usage
+///
+///
+/// ```ignore
+/// let (data) = use_ref(&cx, || {});
+///
+/// let handle_thing = move |_| {
+///     to_owned![data]
+///     cx.spawn(async move {
+///         // do stuff
+///     });
+/// }
+/// ```
+macro_rules! to_owned {
+    ($($es:ident),+) => {$(
+        #[allow(unused_mut)]
+        let mut $es = $es.to_owned();
+    )*}
+}
 
 mod usestate;
 pub use usestate::{use_state, UseState};

+ 1 - 1
packages/hooks/src/usestate.rs

@@ -39,7 +39,7 @@ pub fn use_state<T: 'static>(
         let update_callback = cx.schedule_update();
         let slot = Rc::new(RefCell::new(current_val.clone()));
         let setter = Rc::new({
-            dioxus_core::to_owned![update_callback, slot];
+            to_owned![update_callback, slot];
             move |new| {
                 {
                     let mut slot = slot.borrow_mut();

+ 1 - 1
packages/html/src/events.rs

@@ -11,7 +11,7 @@ macro_rules! impl_event {
     ) => {
         $(
             $( #[$attr] )*
-            pub fn $name<'a>(_cx: &'a ::dioxus_core::ScopeState, _f: impl FnMut(::dioxus_core::UiEvent<$data>) + 'a) -> ::dioxus_core::Attribute<'a> {
+            pub fn $name<'a>(_cx: &'a ::dioxus_core::ScopeState, _f: impl FnMut(::dioxus_core::Event<$data>) + 'a) -> ::dioxus_core::Attribute<'a> {
                 ::dioxus_core::Attribute {
                     name: stringify!($name),
                     value: ::dioxus_core::AttributeValue::new_listener(_cx, _f),

+ 2 - 2
packages/html/src/events/animation.rs

@@ -1,6 +1,6 @@
-use dioxus_core::UiEvent;
+use dioxus_core::Event;
 
-pub type AnimationEvent = UiEvent<AnimationData>;
+pub type AnimationEvent = Event<AnimationData>;
 
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
 #[derive(Debug, Clone)]

+ 2 - 2
packages/html/src/events/clipboard.rs

@@ -1,6 +1,6 @@
-use dioxus_core::UiEvent;
+use dioxus_core::Event;
 
-pub type ClipboardEvent = UiEvent<ClipboardData>;
+pub type ClipboardEvent = Event<ClipboardData>;
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
 #[derive(Debug, Clone)]
 pub struct ClipboardData {

+ 2 - 2
packages/html/src/events/composition.rs

@@ -1,6 +1,6 @@
-use dioxus_core::UiEvent;
+use dioxus_core::Event;
 
-pub type CompositionEvent = UiEvent<CompositionData>;
+pub type CompositionEvent = Event<CompositionData>;
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
 #[derive(Debug, Clone)]
 pub struct CompositionData {

+ 2 - 2
packages/html/src/events/drag.rs

@@ -1,10 +1,10 @@
 use std::any::Any;
 
-use dioxus_core::UiEvent;
+use dioxus_core::Event;
 
 use crate::MouseData;
 
-pub type DragEvent = UiEvent<DragData>;
+pub type DragEvent = Event<DragData>;
 
 /// The DragEvent interface is a DOM event that represents a drag and drop interaction. The user initiates a drag by
 /// placing a pointer device (such as a mouse) on the touch surface and then dragging the pointer to a new location

+ 2 - 2
packages/html/src/events/focus.rs

@@ -1,6 +1,6 @@
-use dioxus_core::UiEvent;
+use dioxus_core::Event;
 
-pub type FocusEvent = UiEvent<FocusData>;
+pub type FocusEvent = Event<FocusData>;
 
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
 #[derive(Debug, Clone)]

+ 2 - 2
packages/html/src/events/form.rs

@@ -1,8 +1,8 @@
 use std::{collections::HashMap, fmt::Debug, sync::Arc};
 
-use dioxus_core::UiEvent;
+use dioxus_core::Event;
 
-pub type FormEvent = UiEvent<FormData>;
+pub type FormEvent = Event<FormData>;
 
 /* DOMEvent:  Send + SyncTarget relatedTarget */
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]

+ 2 - 2
packages/html/src/events/image.rs

@@ -1,6 +1,6 @@
-use dioxus_core::UiEvent;
+use dioxus_core::Event;
 
-pub type ImageEvent = UiEvent<ImageData>;
+pub type ImageEvent = Event<ImageData>;
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
 #[derive(Debug, Clone)]
 pub struct ImageData {

+ 2 - 2
packages/html/src/events/keyboard.rs

@@ -1,11 +1,11 @@
 use crate::input_data::{decode_key_location, encode_key_location};
-use dioxus_core::UiEvent;
+use dioxus_core::Event;
 use keyboard_types::{Code, Key, Location, Modifiers};
 use std::convert::TryInto;
 use std::fmt::{Debug, Formatter};
 use std::str::FromStr;
 
-pub type KeyboardEvent = UiEvent<KeyboardData>;
+pub type KeyboardEvent = Event<KeyboardData>;
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
 #[derive(Clone)]
 pub struct KeyboardData {

+ 2 - 2
packages/html/src/events/media.rs

@@ -1,6 +1,6 @@
-use dioxus_core::UiEvent;
+use dioxus_core::Event;
 
-pub type MediaEvent = UiEvent<MediaData>;
+pub type MediaEvent = Event<MediaData>;
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
 #[derive(Debug, Clone)]
 pub struct MediaData {}

+ 2 - 2
packages/html/src/events/mouse.rs

@@ -2,11 +2,11 @@ use crate::geometry::{ClientPoint, Coordinates, ElementPoint, PagePoint, ScreenP
 use crate::input_data::{
     decode_mouse_button_set, encode_mouse_button_set, MouseButton, MouseButtonSet,
 };
-use dioxus_core::UiEvent;
+use dioxus_core::Event;
 use keyboard_types::Modifiers;
 use std::fmt::{Debug, Formatter};
 
-pub type MouseEvent = UiEvent<MouseData>;
+pub type MouseEvent = Event<MouseData>;
 
 /// A synthetic event that wraps a web-style [`MouseEvent`](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent)
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]

+ 2 - 2
packages/html/src/events/pointer.rs

@@ -1,6 +1,6 @@
-use dioxus_core::UiEvent;
+use dioxus_core::Event;
 
-pub type PointerEvent = UiEvent<PointerData>;
+pub type PointerEvent = Event<PointerData>;
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
 #[derive(Debug, Clone)]
 pub struct PointerData {

+ 2 - 2
packages/html/src/events/scroll.rs

@@ -1,6 +1,6 @@
-use dioxus_core::UiEvent;
+use dioxus_core::Event;
 
-pub type ScrollEvent = UiEvent<ScrollData>;
+pub type ScrollEvent = Event<ScrollData>;
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
 #[derive(Debug, Clone)]
 pub struct ScrollData {}

+ 2 - 2
packages/html/src/events/selection.rs

@@ -1,6 +1,6 @@
-use dioxus_core::UiEvent;
+use dioxus_core::Event;
 
-pub type SelectionEvent = UiEvent<SelectionData>;
+pub type SelectionEvent = Event<SelectionData>;
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
 #[derive(Debug, Clone)]
 pub struct SelectionData {}

+ 2 - 2
packages/html/src/events/toggle.rs

@@ -1,6 +1,6 @@
-use dioxus_core::UiEvent;
+use dioxus_core::Event;
 
-pub type ToggleEvent = UiEvent<ToggleData>;
+pub type ToggleEvent = Event<ToggleData>;
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
 #[derive(Debug, Clone)]
 pub struct ToggleData {}

+ 2 - 2
packages/html/src/events/touch.rs

@@ -1,6 +1,6 @@
-use dioxus_core::UiEvent;
+use dioxus_core::Event;
 
-pub type TouchEvent = UiEvent<TouchData>;
+pub type TouchEvent = Event<TouchData>;
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
 #[derive(Debug, Clone)]
 pub struct TouchData {

+ 2 - 2
packages/html/src/events/transition.rs

@@ -1,6 +1,6 @@
-use dioxus_core::UiEvent;
+use dioxus_core::Event;
 
-pub type TransitionEvent = UiEvent<TransitionData>;
+pub type TransitionEvent = Event<TransitionData>;
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
 #[derive(Debug, Clone)]
 pub struct TransitionData {

+ 2 - 2
packages/html/src/events/wheel.rs

@@ -1,10 +1,10 @@
-use dioxus_core::UiEvent;
+use dioxus_core::Event;
 use euclid::UnknownUnit;
 use std::fmt::{Debug, Formatter};
 
 use crate::geometry::{LinesVector, PagesVector, PixelsVector, WheelDelta};
 
-pub type WheelEvent = UiEvent<WheelData>;
+pub type WheelEvent = Event<WheelData>;
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
 #[derive(Clone)]
 pub struct WheelData {

+ 22 - 23
packages/liveview/src/events.rs

@@ -6,9 +6,8 @@ use std::any::Any;
 use std::sync::Arc;
 
 use dioxus_core::ElementId;
-use dioxus_core::{EventPriority, UserEvent};
 use dioxus_html::event_bubbles;
-use dioxus_html::on::*;
+use dioxus_html::events::*;
 
 #[derive(serde::Serialize, serde::Deserialize)]
 pub(crate) struct IpcMessage {
@@ -30,29 +29,29 @@ struct ImEvent {
     contents: serde_json::Value,
 }
 
-pub fn trigger_from_serialized(val: serde_json::Value) -> UserEvent {
-    let ImEvent {
-        event,
-        mounted_dom_id,
-        contents,
-    } = serde_json::from_value(val).unwrap();
-
-    let mounted_dom_id = Some(mounted_dom_id);
-
-    let name = event_name_from_type(&event);
-    let event = make_synthetic_event(&event, contents);
-
-    UserEvent {
-        name,
-        priority: EventPriority::Low,
-        scope_id: None,
-        element: mounted_dom_id,
-        data: event,
-        bubbles: event_bubbles(name),
-    }
+pub fn trigger_from_serialized(val: serde_json::Value) -> () {
+    todo!()
+    // let ImEvent {
+    //     event,
+    //     mounted_dom_id,
+    //     contents,
+    // } = serde_json::from_value(val).unwrap();
+
+    // let mounted_dom_id = Some(mounted_dom_id);
+
+    // let name = event_name_from_type(&event);
+    // let event = make_synthetic_event(&event, contents);
+
+    // UserEvent {
+    //     name,
+    //     scope_id: None,
+    //     element: mounted_dom_id,
+    //     data: event,
+    //     bubbles: event_bubbles(name),
+    // }
 }
 
-fn make_synthetic_event(name: &str, val: serde_json::Value) -> Arc<dyn Any + Send + Sync> {
+fn make_synthetic_event(name: &str, val: serde_json::Value) -> Arc<dyn Any> {
     match name {
         "copy" | "cut" | "paste" => {
             //

+ 1 - 1
packages/native-core/src/real_dom.rs

@@ -67,7 +67,7 @@ impl<S: State> RealDom<S> {
         let mut nodes_updated = Vec::new();
         nodes_updated.push((RealNodeId::ElementId(ElementId(0)), NodeMask::ALL));
         for mutations in mutations_vec {
-            for e in mutations.edits {
+            for e in mutations.dom_edits {
                 use dioxus_core::DomEdit::*;
                 match e {
                     AppendChildren { root, children } => {

+ 2 - 2
packages/native-core/src/utils.rs

@@ -72,7 +72,7 @@ impl PersistantElementIter {
     pub fn prune<S: State>(&mut self, mutations: &Mutations, rdom: &RealDom<S>) -> bool {
         let mut changed = false;
         let ids_removed: Vec<_> = mutations
-            .edits
+            .dom_edits
             .iter()
             .filter_map(|e| {
                 // nodes within templates will never be removed
@@ -97,7 +97,7 @@ impl PersistantElementIter {
         for (el_id, child_idx) in self.stack.iter_mut() {
             if let NodePosition::InChild(child_idx) = child_idx {
                 if let NodeType::Element { children, .. } = &rdom[*el_id].node_data.node_type {
-                    for m in &mutations.edits {
+                    for m in &mutations.dom_edits {
                         match m {
                             DomEdit::Remove { root } => {
                                 let id = rdom.resolve_maybe_id(*root);

+ 1 - 1
packages/rsx/src/component.rs

@@ -219,7 +219,7 @@ impl ToTokens for ContentField {
         match self {
             ContentField::ManExpr(e) => e.to_tokens(tokens),
             ContentField::Formatted(s) => tokens.append_all(quote! {
-                __cx.raw_text(#s).0
+                __cx.raw_text(#s)
             }),
             ContentField::OnHandlerRaw(e) => tokens.append_all(quote! {
                 __cx.event_handler(#e)

+ 2 - 2
packages/rsx/src/lib.rs

@@ -77,7 +77,7 @@ impl ToTokens for CallBody {
             })
         } else {
             out_tokens.append_all(quote! {
-                ::dioxus::core::LazyNodes::new( move | __cx: ::dioxus::core::NodeFactory| -> ::dioxus::core::VNode {
+                ::dioxus::core::LazyNodes::new( move | __cx: &::dioxus::core::ScopeState| -> ::dioxus::core::VNode {
                     #body
                 })
             })
@@ -106,7 +106,7 @@ impl<'a> ToTokens for TemplateRenderer<'a> {
         };
 
         let key_tokens = match key {
-            Some(tok) => quote! { Some( __cx.raw_text_inline(#tok) ) },
+            Some(tok) => quote! { Some( __cx.raw_text(#tok) ) },
             None => quote! { None },
         };
 

+ 5 - 5
packages/rsx/src/node.rs

@@ -131,10 +131,10 @@ impl ToTokens for BodyNode {
             BodyNode::Element(el) => el.to_tokens(tokens),
             BodyNode::Component(comp) => comp.to_tokens(tokens),
             BodyNode::Text(txt) => tokens.append_all(quote! {
-                __cx.text(#txt)
+                __cx.text_node(#txt)
             }),
             BodyNode::RawExpr(exp) => tokens.append_all(quote! {
-                 __cx.fragment_from_iter(#exp)
+                 __cx.make_node(#exp)
             }),
             BodyNode::ForLoop(exp) => {
                 let ForLoop {
@@ -144,7 +144,7 @@ impl ToTokens for BodyNode {
                 let renderer = TemplateRenderer { roots: &body };
 
                 tokens.append_all(quote! {
-                     __cx.fragment_from_iter(
+                     __cx.make_node(
                         (#expr).into_iter().map(|#pat| { #renderer })
                      )
                 })
@@ -152,7 +152,7 @@ impl ToTokens for BodyNode {
             BodyNode::IfChain(chain) => {
                 if is_if_chain_terminated(chain) {
                     tokens.append_all(quote! {
-                         __cx.fragment_from_iter(#chain)
+                         __cx.make_node(#chain)
                     });
                 } else {
                     let ExprIf {
@@ -206,7 +206,7 @@ impl ToTokens for BodyNode {
                     });
 
                     tokens.append_all(quote! {
-                        __cx.fragment_from_iter(#body)
+                        __cx.make_node(#body)
                     });
                 }
             }

+ 1 - 1
packages/tui/src/focus.rs

@@ -256,7 +256,7 @@ impl FocusState {
         if self.focus_iter.prune(mutations, rdom) {
             self.dirty = true;
         }
-        for m in &mutations.edits {
+        for m in &mutations.dom_edits {
             match m {
                 dioxus_core::DomEdit::ReplaceWith { root, .. } => remove_children(
                     &mut [&mut self.last_focused_id],

+ 7 - 28
packages/web/src/dom.rs

@@ -19,36 +19,14 @@ use web_sys::{Document, Element, Event, HtmlElement};
 use crate::Config;
 
 pub struct WebsysDom {
-    pub interpreter: Interpreter,
-
-    pub(crate) root: Element,
-
-    pub handler: Closure<dyn FnMut(&Event)>,
+    interpreter: Interpreter,
+    handler: Closure<dyn FnMut(&Event)>,
+    root: Element,
 }
 
 impl WebsysDom {
     pub fn new(cfg: Config, event_channel: mpsc::UnboundedSender<Event>) -> Self {
         // eventually, we just want to let the interpreter do all the work of decoding events into our event type
-        let callback: Box<dyn FnMut(&Event)> = Box::new(move |event: &web_sys::Event| {
-            _ = event_channel.unbounded_send(event.clone());
-
-            // if let Ok(synthetic_event) = decoded {
-            //     // Try to prevent default if the attribute is set
-            //     if let Some(node) = target.dyn_ref::<HtmlElement>() {
-            //         if let Some(name) = node.get_attribute("dioxus-prevent-default") {
-            //             if name == synthetic_event.name
-            //                 || name.trim_start_matches("on") == synthetic_event.name
-            //             {
-            //                 log::trace!("Preventing default");
-            //                 event.prevent_default();
-            //             }
-            //         }
-            //     }
-
-            //     sender_callback.as_ref()(SchedulerMsg::Event(synthetic_event))
-            // }
-        });
-
         // a match here in order to avoid some error during runtime browser test
         let document = load_document();
         let root = match document.get_element_by_id(&cfg.rootname) {
@@ -58,8 +36,10 @@ impl WebsysDom {
 
         Self {
             interpreter: Interpreter::new(root.clone()),
-            handler: Closure::wrap(callback),
             root,
+            handler: Closure::wrap(Box::new(move |event: &web_sys::Event| {
+                let _ = event_channel.unbounded_send(event.clone());
+            })),
         }
     }
 
@@ -99,11 +79,10 @@ impl WebsysDom {
                 }
                 SetText { value, id } => i.SetText(id.0 as u32, value.into()),
                 NewEventListener { name, scope, id } => {
-                    let handler: &Function = self.handler.as_ref().unchecked_ref();
                     self.interpreter.NewEventListener(
                         name,
                         id.0 as u32,
-                        handler,
+                        self.handler.as_ref().unchecked_ref(),
                         event_bubbles(&name[2..]),
                     );
                 }

+ 4 - 4
packages/web/src/lib.rs

@@ -192,8 +192,8 @@ pub async fn run_with_props<T: 'static>(root: fn(Scope<T>) -> Element, root_prop
     if should_hydrate {
     } else {
         let edits = dom.rebuild();
-        websys_dom.apply_edits(edits.template_mutations);
-        websys_dom.apply_edits(edits.edits);
+        websys_dom.apply_edits(edits.template_edits);
+        websys_dom.apply_edits(edits.dom_edits);
     }
 
     let mut work_loop = ric_raf::RafLoop::new();
@@ -247,8 +247,8 @@ pub async fn run_with_props<T: 'static>(root: fn(Scope<T>) -> Element, root_prop
 
         log::debug!("edits {:#?}", edits);
 
-        websys_dom.apply_edits(edits.template_mutations);
-        websys_dom.apply_edits(edits.edits);
+        websys_dom.apply_edits(edits.template_edits);
+        websys_dom.apply_edits(edits.dom_edits);
     }
 }
 

+ 1 - 1
packages/web/tests/hydrate.rs

@@ -23,7 +23,7 @@ fn makes_tree() {
     let mut dom = VirtualDom::new(app);
     let muts = dom.rebuild();
 
-    dbg!(muts.edits);
+    dbg!(muts.dom_edits);
 }
 
 #[wasm_bindgen_test]