Browse Source

Feat: implement vcomp fully

Jonathan Kelley 4 năm trước cách đây
mục cha
commit
29751a4bab
4 tập tin đã thay đổi với 273 bổ sung364 xóa
  1. 0 20
      packages/core/src/diff.rs
  2. 1 2
      packages/core/src/lib.rs
  3. 269 338
      packages/core/src/nodes.rs
  4. 3 4
      packages/core/src/virtual_dom.rs

+ 0 - 20
packages/core/src/diff.rs

@@ -55,7 +55,6 @@ use std::{cell::RefCell, cmp::Ordering, collections::VecDeque, rc::Rc};
 /// subscriptions and props changes.
 pub struct DiffMachine<'a> {
     pub change_list: EditMachine<'a>,
-
     pub diffed: FxHashSet<ScopeIdx>,
     pub need_to_diff: FxHashSet<ScopeIdx>,
 }
@@ -125,25 +124,6 @@ impl<'a> DiffMachine<'a> {
             }
 
             (_, VNode::Component(new)) => {
-                // let VComponent {
-                //     props,
-                //     props_type,
-                //     comp,
-                //     caller,
-                //     assigned_scope,
-                //     ..
-                // } = *new;
-
-                // make the component
-                // let idx = unsafe {
-                //     // let vdom = &mut *self.vdom;
-                //     vdom.insert_with(|f| {
-                //         todo!()
-                //         //
-                //         // create_scoped(caller, props, myidx, parent)
-                //     })
-                // };
-
                 // we have no stable reference to work from
                 // push the lifecycle event onto the queue
                 // self.lifecycle_events

+ 1 - 2
packages/core/src/lib.rs

@@ -89,10 +89,10 @@ pub mod builder {
 // types used internally that are important
 pub(crate) mod innerlude {
     // pub(crate) use crate::component::Properties;
-
     pub(crate) use crate::component::Properties;
     pub(crate) use crate::context::Context;
     pub(crate) use crate::error::{Error, Result};
+    pub use crate::events::EventTrigger;
     use crate::nodes;
     pub(crate) use crate::scope::Scope;
     pub(crate) use crate::virtual_dom::VirtualDom;
@@ -100,7 +100,6 @@ pub(crate) mod innerlude {
 
     pub use crate::component::ScopeIdx;
     pub use crate::diff::DiffMachine;
-    pub use crate::events::EventTrigger;
     pub use crate::patch::{EditList, EditMachine};
     // pub use crate::patchdx;
     // pub use crate::patchtList;

+ 269 - 338
packages/core/src/nodes.rs

@@ -3,394 +3,325 @@
 //!
 //! These VNodes should be *very* cheap and *very* fast to construct - building a full tree should be insanely quick.
 
+use crate::{
+    events::VirtualEvent,
+    innerlude::{Context, Properties, ScopeIdx, FC},
+};
+
 use bumpalo::Bump;
-pub use vcomponent::VComponent;
-pub use velement::VElement;
-pub use velement::{Attribute, Listener, NodeKey};
-pub use vnode::VNode;
-pub use vtext::VText;
+use std::fmt::Debug;
+use std::{
+    any::{Any, TypeId},
+    cell::RefCell,
+    marker::PhantomData,
+    rc::Rc,
+};
 
 /// A domtree represents the result of "Viewing" the context
 /// It's a placeholder over vnodes, to make working with lifetimes easier
 pub struct DomTree;
 
+// ==============================
+//   VNODES
+// ==============================
+
 /// Tools for the base unit of the virtual dom - the VNode
 /// VNodes are intended to be quickly-allocated, lightweight enum values.
 ///
 /// Components will be generating a lot of these very quickly, so we want to
 /// limit the amount of heap allocations / overly large enum sizes.
-mod vnode {
-    use super::*;
-
-    #[derive(Debug)]
-    pub enum VNode<'src> {
-        /// An element node (node type `ELEMENT_NODE`).
-        Element(&'src VElement<'src>),
-
-        /// A text node (node type `TEXT_NODE`).
-        ///
-        /// Note: This wraps a `VText` instead of a plain `String` in
-        /// order to enable custom methods like `create_text_node()` on the
-        /// wrapped type.
-        Text(VText<'src>),
-
-        /// A "suspended component"
-        /// This is a masqeurade over an underlying future that needs to complete
-        /// When the future is completed, the VNode will then trigger a render
-        Suspended,
-
-        /// A User-defined componen node (node type COMPONENT_NODE)
-        Component(VComponent<'src>),
-    }
+#[derive(Debug)]
+pub enum VNode<'src> {
+    /// An element node (node type `ELEMENT_NODE`).
+    Element(&'src VElement<'src>),
 
-    impl<'a> VNode<'a> {
-        /// Low-level constructor for making a new `Node` of type element with given
-        /// parts.
-        ///
-        /// This is primarily intended for JSX and templating proc-macros to compile
-        /// down into. If you are building nodes by-hand, prefer using the
-        /// `dodrio::builder::*` APIs.
-        #[inline]
-        pub fn element(
-            bump: &'a Bump,
-            key: NodeKey,
-            tag_name: &'a str,
-            listeners: &'a [Listener<'a>],
-            attributes: &'a [Attribute<'a>],
-            children: &'a [VNode<'a>],
-            namespace: Option<&'a str>,
-        ) -> VNode<'a> {
-            let element = bump.alloc_with(|| VElement {
-                key,
-                tag_name,
-                listeners,
-                attributes,
-                children,
-                namespace,
-            });
-            VNode::Element(element)
-        }
+    /// A text node (node type `TEXT_NODE`).
+    ///
+    /// Note: This wraps a `VText` instead of a plain `String` in
+    /// order to enable custom methods like `create_text_node()` on the
+    /// wrapped type.
+    Text(VText<'src>),
+
+    /// A "suspended component"
+    /// This is a masqeurade over an underlying future that needs to complete
+    /// When the future is completed, the VNode will then trigger a render
+    Suspended,
+
+    /// A User-defined componen node (node type COMPONENT_NODE)
+    Component(VComponent<'src>),
+}
 
-        /// Construct a new text node with the given text.
-        #[inline]
-        pub fn text(text: &'a str) -> VNode<'a> {
-            VNode::Text(VText { text })
-        }
+impl<'a> VNode<'a> {
+    /// Low-level constructor for making a new `Node` of type element with given
+    /// parts.
+    ///
+    /// This is primarily intended for JSX and templating proc-macros to compile
+    /// down into. If you are building nodes by-hand, prefer using the
+    /// `dodrio::builder::*` APIs.
+    #[inline]
+    pub fn element(
+        bump: &'a Bump,
+        key: NodeKey,
+        tag_name: &'a str,
+        listeners: &'a [Listener<'a>],
+        attributes: &'a [Attribute<'a>],
+        children: &'a [VNode<'a>],
+        namespace: Option<&'a str>,
+    ) -> VNode<'a> {
+        let element = bump.alloc_with(|| VElement {
+            key,
+            tag_name,
+            listeners,
+            attributes,
+            children,
+            namespace,
+        });
+        VNode::Element(element)
+    }
+
+    /// Construct a new text node with the given text.
+    #[inline]
+    pub fn text(text: &'a str) -> VNode<'a> {
+        VNode::Text(VText { text })
+    }
 
-        #[inline]
-        pub(crate) fn key(&self) -> NodeKey {
-            match &self {
-                VNode::Text(_) => NodeKey::NONE,
-                VNode::Element(e) => e.key,
-                VNode::Suspended => {
-                    todo!()
-                }
-                VNode::Component(_) => {
-                    todo!()
-                }
+    #[inline]
+    pub(crate) fn key(&self) -> NodeKey {
+        match &self {
+            VNode::Text(_) => NodeKey::NONE,
+            VNode::Element(e) => e.key,
+            VNode::Suspended => {
+                todo!()
+            }
+            VNode::Component(_) => {
+                todo!()
             }
         }
     }
 }
 
-mod velement {
-
-    // use crate::{events::VirtualEvent, innerlude::CbIdx};
-
-    use crate::{events::VirtualEvent, innerlude::ScopeIdx};
-
-    use super::*;
-    use std::fmt::Debug;
-
-    #[derive(Debug)]
-    pub struct VElement<'a> {
-        /// Elements have a tag name, zero or more attributes, and zero or more
-        pub key: NodeKey,
-        pub tag_name: &'a str,
-        pub listeners: &'a [Listener<'a>],
-        pub attributes: &'a [Attribute<'a>],
-        pub children: &'a [VNode<'a>],
-        pub namespace: Option<&'a str>,
-        // The HTML tag, such as "div"
-        // pub tag: &'a str,
-
-        // pub tag_name: &'a str,
-        // pub attributes: &'a [Attribute<'a>],
-        // todo: hook up listeners
-        // pub listeners: &'a [Listener<'a>],
-        // / HTML attributes such as id, class, style, etc
-        // pub attrs: HashMap<String, String>,
-        // TODO: @JON Get this to not heap allocate, but rather borrow
-        // pub attrs: HashMap<&'static str, &'static str>,
-
-        // TODO @Jon, re-enable "events"
-        //
-        // /// Events that will get added to your real DOM element via `.addEventListener`
-        // pub events: Events,
-        // pub events: HashMap<String, ()>,
-
-        // /// The children of this `VNode`. So a <div> <em></em> </div> structure would
-        // /// have a parent div and one child, em.
-        // pub children: Vec<VNode>,
-    }
+// ========================================================
+//   VElement (div, h1, etc), attrs, keys, listener handle
+// ========================================================
+#[derive(Debug)]
+pub struct VElement<'a> {
+    /// Elements have a tag name, zero or more attributes, and zero or more
+    pub key: NodeKey,
+    pub tag_name: &'a str,
+    pub listeners: &'a [Listener<'a>],
+    pub attributes: &'a [Attribute<'a>],
+    pub children: &'a [VNode<'a>],
+    pub namespace: Option<&'a str>,
+    // The HTML tag, such as "div"
+    // pub tag: &'a str,
+
+    // pub tag_name: &'a str,
+    // pub attributes: &'a [Attribute<'a>],
+    // todo: hook up listeners
+    // pub listeners: &'a [Listener<'a>],
+    // / HTML attributes such as id, class, style, etc
+    // pub attrs: HashMap<String, String>,
+    // TODO: @JON Get this to not heap allocate, but rather borrow
+    // pub attrs: HashMap<&'static str, &'static str>,
+
+    // TODO @Jon, re-enable "events"
+    //
+    // /// Events that will get added to your real DOM element via `.addEventListener`
+    // pub events: Events,
+    // pub events: HashMap<String, ()>,
+
+    // /// The children of this `VNode`. So a <div> <em></em> </div> structure would
+    // /// have a parent div and one child, em.
+    // pub children: Vec<VNode>,
+}
 
-    impl<'a> VElement<'a> {
-        // The tag of a component MUST be known at compile time
-        pub fn new(_tag: &'a str) -> Self {
-            todo!()
-            // VElement {
-            //     tag,
-            //     attrs: HashMap::new(),
-            //     events: HashMap::new(),
-            //     // events: Events(HashMap::new()),
-            //     children: vec![],
-            // }
-        }
+impl<'a> VElement<'a> {
+    // The tag of a component MUST be known at compile time
+    pub fn new(_tag: &'a str) -> Self {
+        todo!()
+        // VElement {
+        //     tag,
+        //     attrs: HashMap::new(),
+        //     events: HashMap::new(),
+        //     // events: Events(HashMap::new()),
+        //     children: vec![],
+        // }
     }
+}
 
-    /// An attribute on a DOM node, such as `id="my-thing"` or
-    /// `href="https://example.com"`.
-    #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
-    pub struct Attribute<'a> {
-        pub name: &'static str,
-        pub value: &'a str,
-    }
+/// An attribute on a DOM node, such as `id="my-thing"` or
+/// `href="https://example.com"`.
+#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
+pub struct Attribute<'a> {
+    pub name: &'static str,
+    pub value: &'a str,
+}
 
-    impl<'a> Attribute<'a> {
-        /// Get this attribute's name, such as `"id"` in `<div id="my-thing" />`.
-        #[inline]
-        pub fn name(&self) -> &'a str {
-            self.name
-        }
+impl<'a> Attribute<'a> {
+    /// Get this attribute's name, such as `"id"` in `<div id="my-thing" />`.
+    #[inline]
+    pub fn name(&self) -> &'a str {
+        self.name
+    }
 
-        /// The attribute value, such as `"my-thing"` in `<div id="my-thing" />`.
-        #[inline]
-        pub fn value(&self) -> &'a str {
-            self.value
-        }
+    /// The attribute value, such as `"my-thing"` in `<div id="my-thing" />`.
+    #[inline]
+    pub fn value(&self) -> &'a str {
+        self.value
+    }
 
-        /// Certain attributes are considered "volatile" and can change via user
-        /// input that we can't see when diffing against the old virtual DOM. For
-        /// these attributes, we want to always re-set the attribute on the physical
-        /// DOM node, even if the old and new virtual DOM nodes have the same value.
-        #[inline]
-        pub(crate) fn is_volatile(&self) -> bool {
-            match self.name {
-                "value" | "checked" | "selected" => true,
-                _ => false,
-            }
+    /// Certain attributes are considered "volatile" and can change via user
+    /// input that we can't see when diffing against the old virtual DOM. For
+    /// these attributes, we want to always re-set the attribute on the physical
+    /// DOM node, even if the old and new virtual DOM nodes have the same value.
+    #[inline]
+    pub(crate) fn is_volatile(&self) -> bool {
+        match self.name {
+            "value" | "checked" | "selected" => true,
+            _ => false,
         }
     }
+}
 
-    pub struct ListenerHandle {
-        pub event: &'static str,
-        pub scope: ScopeIdx,
-        pub id: usize,
-    }
+pub struct ListenerHandle {
+    pub event: &'static str,
+    pub scope: ScopeIdx,
+    pub id: usize,
+}
 
-    /// An event listener.
-    pub struct Listener<'bump> {
-        /// The type of event to listen for.
-        pub(crate) event: &'static str,
+/// An event listener.
+pub struct Listener<'bump> {
+    /// The type of event to listen for.
+    pub(crate) event: &'static str,
 
-        pub scope: ScopeIdx,
-        pub id: usize,
+    pub scope: ScopeIdx,
+    pub id: usize,
 
-        // pub(crate) _i: &'bump str,
-        // #[serde(skip_serializing, skip_deserializing, default="")]
-        // /// The callback to invoke when the event happens.
-        pub(crate) callback: &'bump (dyn Fn(VirtualEvent)),
-    }
-    impl Debug for Listener<'_> {
-        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-            f.debug_struct("Listener")
-                .field("event", &self.event)
-                .finish()
-        }
-    }
-    pub(crate) type ListenerCallback<'a> = &'a (dyn Fn(VirtualEvent));
-    union CallbackFatPtr<'a> {
-        callback: ListenerCallback<'a>,
-        parts: (u32, u32),
-    }
-    impl Listener<'_> {
-        #[inline]
-        pub(crate) fn get_callback_parts(&self) -> (u32, u32) {
-            assert_eq!(
-                std::mem::size_of::<ListenerCallback>(),
-                std::mem::size_of::<CallbackFatPtr>()
-            );
-
-            unsafe {
-                let fat = CallbackFatPtr {
-                    callback: self.callback,
-                };
-                let (a, b) = fat.parts;
-                debug_assert!(a != 0);
-                (a, b)
-            }
-        }
+    // pub(crate) _i: &'bump str,
+    // #[serde(skip_serializing, skip_deserializing, default="")]
+    // /// The callback to invoke when the event happens.
+    pub(crate) callback: &'bump (dyn Fn(VirtualEvent)),
+}
+impl Debug for Listener<'_> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.debug_struct("Listener")
+            .field("event", &self.event)
+            .finish()
     }
+}
 
-    /// The key for keyed children.
-    ///
-    /// Keys must be unique among siblings.
-    ///
-    /// If any sibling is keyed, then they all must be keyed.
-    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-    pub struct NodeKey(pub(crate) u32);
+/// The key for keyed children.
+///
+/// Keys must be unique among siblings.
+///
+/// If any sibling is keyed, then they all must be keyed.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct NodeKey(pub(crate) u32);
 
-    impl Default for NodeKey {
-        fn default() -> NodeKey {
-            NodeKey::NONE
-        }
+impl Default for NodeKey {
+    fn default() -> NodeKey {
+        NodeKey::NONE
+    }
+}
+impl NodeKey {
+    /// The default, lack of a key.
+    pub const NONE: NodeKey = NodeKey(u32::MAX);
+
+    /// Is this key `NodeKey::NONE`?
+    #[inline]
+    pub fn is_none(&self) -> bool {
+        *self == Self::NONE
     }
-    impl NodeKey {
-        /// The default, lack of a key.
-        pub const NONE: NodeKey = NodeKey(u32::MAX);
-
-        /// Is this key `NodeKey::NONE`?
-        #[inline]
-        pub fn is_none(&self) -> bool {
-            *self == Self::NONE
-        }
-
-        /// Is this key not `NodeKey::NONE`?
-        #[inline]
-        pub fn is_some(&self) -> bool {
-            !self.is_none()
-        }
 
-        /// Create a new `NodeKey`.
-        ///
-        /// `key` must not be `u32::MAX`.
-        #[inline]
-        pub fn new(key: u32) -> Self {
-            debug_assert_ne!(key, u32::MAX);
-            NodeKey(key)
-        }
+    /// Is this key not `NodeKey::NONE`?
+    #[inline]
+    pub fn is_some(&self) -> bool {
+        !self.is_none()
     }
 
-    // todo
-    // use zst enum for element type. Something like ValidElements::div
+    /// Create a new `NodeKey`.
+    ///
+    /// `key` must not be `u32::MAX`.
+    #[inline]
+    pub fn new(key: u32) -> Self {
+        debug_assert_ne!(key, u32::MAX);
+        NodeKey(key)
+    }
 }
 
-mod vtext {
-    #[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
-    pub struct VText<'bump> {
-        pub text: &'bump str,
-    }
+#[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
+pub struct VText<'bump> {
+    pub text: &'bump str,
+}
 
-    impl<'a> VText<'a> {
-        // / Create an new `VText` instance with the specified text.
-        pub fn new(text: &'a str) -> Self
-// pub fn new<S>(text: S) -> Self
-        // where
-        //     S: Into<str>,
-        {
-            VText { text: text.into() }
-        }
+impl<'a> VText<'a> {
+    // / Create an new `VText` instance with the specified text.
+    pub fn new(text: &'a str) -> Self
+// pub fn new(text: Into<str>) -> Self
+    {
+        VText { text: text.into() }
     }
 }
 
+// ==============================
+//   Custom components
+// ==============================
+
 /// Virtual Components for custom user-defined components
 /// Only supports the functional syntax
-mod vcomponent {
-    use crate::innerlude::{Context, Properties, ScopeIdx, FC};
-    use std::{
-        any::{Any, TypeId},
-        cell::RefCell,
-        marker::PhantomData,
-        rc::Rc,
-    };
-
-    use super::DomTree;
-
-    pub type StableScopeAddres = Rc<RefCell<Option<ScopeIdx>>>;
-
-    #[derive(Debug)]
-    pub struct VComponent<'src> {
-        _p: PhantomData<&'src ()>,
-        // pub(crate) props: Box<dyn std::any::Any>,
-        // pub(crate) props_type: TypeId,
-        // pub(crate) comp: *const (),
-        // pub(crate) caller: Caller,
-        pub(crate) comparator: Comparator,
-        // once a component gets mounted, its parent gets a stable address.
-        // this way we can carry the scope index from between renders
-        // genius, really!
-        // pub assigned_scope: StableScopeAddres,
-    }
-    pub struct Comparator(Box<dyn Fn(&dyn Any) -> bool>);
-    // pub struct Comparator<'src>(&'src dyn Fn(&dyn Any) -> bool);
-
-    pub struct Caller(Box<dyn Fn(Context) -> DomTree>);
-    impl std::fmt::Debug for Caller {
-        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-            todo!()
-        }
+pub type StableScopeAddres = Rc<RefCell<Option<usize>>>;
+
+#[derive(Debug)]
+pub struct VComponent<'src> {
+    pub stable_addr: StableScopeAddres,
+    pub comparator: Comparator,
+    pub caller: Caller,
+    _p: PhantomData<&'src ()>,
+}
+pub struct Comparator(Box<dyn Fn(&dyn Any) -> bool>);
+impl std::fmt::Debug for Comparator {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        Ok(())
     }
+}
 
-    impl std::fmt::Debug for Comparator {
-        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-            todo!()
-        }
+pub struct Caller(Box<dyn Fn(Context) -> DomTree>);
+impl std::fmt::Debug for Caller {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        Ok(())
     }
+}
 
-    impl<'a> VComponent<'a> {
-        // use the type parameter on props creation and move it into a portable context
-        // this lets us keep scope generic *and* downcast its props when we need to:
-        // - perform comparisons when diffing (memoization)
-        // -
-        pub fn new<P: Properties + 'static>(caller: FC<P>, comp: P) -> Self {
-            todo!()
-            // let p = Rc::new(props);
-
-            // let props_comparator = move |new_props: &dyn Any| -> bool {
-            //     new_props
-            //         .downcast_ref::<P>()
-            //         .map(|new_p| p.as_ref() == new_p)
-            //         .unwrap_or_else(|| {
-            //             log::debug!("downcasting failed, this receovered but SHOULD NOT FAIL");
-            //             false
-            //         })
-            // };
-
-            // Self {
-            //     _p: PhantomData,
-            //     comparator: Comparator(Box::new(props_comparator)),
-            // }
-            // let caller = move |ctx: Context| {
-            //     let t = comp(ctx, &props);
-            //     t
-            // };
-            // let _caller = comp as *const ();
-            // let _props = Box::new(props);
-
-            // cast to static?
-            // how do we save the type of props ?
-            // do it in the caller function?
-            // something like
-
-            // the "true" entrpypoint
-            //
-            // |caller| caller.call(fn, Props {})
-            // fn call<P>(f, new_props) {
-            //     let old_props = old.downcast_ref::<P>();
-            //     if new_props == old_props {
-            //         return;
-            //     } else {
-            //         // set the new props
-            //         // call the fn
-            //     }
-            // }
-
-            // todo!()
-            // Self {
-            //     _p: PhantomData {},
-            //     props,
-            //     caller,
-            // }
+impl<'a> VComponent<'a> {
+    // use the type parameter on props creation and move it into a portable context
+    // this lets us keep scope generic *and* downcast its props when we need to:
+    // - perform comparisons when diffing (memoization)
+    // TODO: lift the requirement that props need to be static
+    // we want them to borrow references... maybe force implementing a "to_static_unsafe" trait
+    pub fn new<P: Properties + 'static>(caller: FC<P>, props: P) -> Self {
+        let props = Rc::new(props);
+
+        // used for memoization
+        let p1 = props.clone();
+        let props_comparator = move |new_props: &dyn Any| -> bool {
+            new_props
+                .downcast_ref::<P>()
+                .map(|new_p| p1.as_ref() == new_p)
+                .unwrap_or_else(|| {
+                    log::debug!("downcasting failed, this receovered but SHOULD NOT FAIL");
+                    false
+                })
+        };
+
+        // used for actually rendering the custom component
+        let p2 = props.clone();
+        let caller = move |ctx: Context| -> DomTree { caller(ctx, p2.as_ref()) };
+
+        Self {
+            _p: PhantomData,
+            comparator: Comparator(Box::new(props_comparator)),
+            caller: Caller(Box::new(caller)),
+            stable_addr: Rc::new(RefCell::new(None)),
         }
     }
 }

+ 3 - 4
packages/core/src/virtual_dom.rs

@@ -185,8 +185,7 @@ impl VirtualDom {
 }
 
 enum LifeCycleEvent {
-    // Mount {
-//     props: &dyn Properties,
-// // f: FC<dyn Properties>,
-// },
+    Mount {},
 }
+
+// todo: add some "handle" to the vdom. Or a way of giving out closures that can mutate the vdoms internal data.