فهرست منبع

feat: events work again!

Jonathan Kelley 4 سال پیش
والد
کامیت
9d7ee79

+ 1 - 1
Cargo.toml

@@ -53,7 +53,7 @@ members = [
     "packages/core",
     "packages/html-namespace",
     "packages/web",
-    "packages/cli",
+    # "packages/cli",
     # "packages/atoms",
     # "packages/ssr",
     # "packages/docsite",

+ 3 - 1
notes/TODO.md

@@ -2,7 +2,7 @@
 - [] Transition away from names and towards compile-time safe tags
 - [] Fix diffing of fragments
 - [] Properly integrate memoization to prevent safety issues with children
-- [x] Understand the issue with callbacks (outdated generations)
+- [] Understand and fix the issue with callbacks (outdated generations)
 - [] Fix examples for core, web, ssr, and general
 - [] Finish up documentation
 - [] Polish the Recoil (Dirac?) API
@@ -16,3 +16,5 @@
 - [] ...some how deserialize (hydrate) the dom state?
 - [] Implement controlled inputs for select and textarea
 - [] ...somehow... noderefs....
+
+use_state(&cx, )

+ 1 - 1
packages/core/.vscode/settings.json

@@ -1,3 +1,3 @@
 {
-    "rust-analyzer.inlayHints.enable": false
+    "rust-analyzer.inlayHints.enable": true
 }

+ 6 - 1
packages/core/Cargo.toml

@@ -16,7 +16,7 @@ dioxus-core-macro = { path="../core-macro", version="0.1.1" }
 # Backs scopes and graphs between parent and children
 generational-arena = { version="0.2.8" }
 
-# Bumpalo backs the VNode creation
+# Bumpalo is used as a micro heap backing each component
 bumpalo = { version="3.6.0", features=["collections", "boxed"] }
 
 # custom error type
@@ -25,6 +25,9 @@ thiserror = "1"
 # faster hashmaps
 fxhash = "0.2.1"
 
+# even *faster* hashmaps for index-based types
+nohash-hasher = "0.2.0"
+
 # Used in diffing
 longest-increasing-subsequence = "0.1.0"
 
@@ -33,8 +36,10 @@ log = "0.4"
 
 # Serialize the Edits for use in Webview/Liveview instances
 serde = { version="1", features=["derive"], optional=true }
+
 smallvec = "1.6.1"
 
+
 [features]
 default = []
 serialize = ["serde", "generational-arena/serde"]

+ 2 - 5
packages/core/src/debug_renderer.rs

@@ -16,7 +16,7 @@ impl DebugRenderer {
     ///
     /// This means that the root component must either consumes its own context, or statics are used to generate the page.
     /// The root component can access things like routing in its context.
-    pub fn new(root: impl for<'a> Fn(Context<'a, ()>) -> VNode + 'static) -> Self {
+    pub fn new(root: FC<()>) -> Self {
         Self::new_with_props(root, ())
     }
 
@@ -24,10 +24,7 @@ impl DebugRenderer {
     /// Automatically progresses the creation of the VNode tree to completion.
     ///
     /// A VDom is automatically created. If you want more granular control of the VDom, use `from_vdom`
-    pub fn new_with_props<T: Properties + 'static>(
-        root: impl for<'a> Fn(Context<'a, T>) -> VNode + 'static,
-        root_props: T,
-    ) -> Self {
+    pub fn new_with_props<T: Properties + 'static>(root: FC<T>, root_props: T) -> Self {
         Self::from_vdom(VirtualDom::new_with_props(root, root_props))
     }
 

+ 69 - 43
packages/core/src/diff.rs

@@ -60,7 +60,13 @@ pub trait RealDom {
     fn create_element_ns(&mut self, tag: &str, namespace: &str) -> RealDomNode;
 
     // events
-    fn new_event_listener(&mut self, event: &str, scope: ScopeIdx, id: usize);
+    fn new_event_listener(
+        &mut self,
+        event: &str,
+        scope: ScopeIdx,
+        element_id: usize,
+        realnode: RealDomNode,
+    );
     // fn new_event_listener(&mut self, event: &str);
     fn remove_event_listener(&mut self, event: &str);
 
@@ -138,6 +144,7 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
                         self.dom.replace_with();
                         return;
                     }
+                    new.dom_id.set(old.dom_id.get());
 
                     self.diff_listeners(old.listeners, new.listeners);
                     self.diff_attr(old.attributes, new.attributes, new.namespace.is_some());
@@ -145,6 +152,7 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
                 }
                 // New node is a text element, need to replace the element with a simple text node
                 VNode::Text(_) => {
+                    log::debug!("Replacing el with text");
                     self.create(new_node);
                     self.dom.replace_with();
                 }
@@ -169,8 +177,10 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
             VNode::Text(old) => match new_node {
                 VNode::Text(new) => {
                     if old.text != new.text {
+                        log::debug!("Text has changed {}, {}", old.text, new.text);
                         self.dom.set_text(new.text);
                     }
+                    new.dom_id.set(old.dom_id.get());
                 }
                 VNode::Element(_) | VNode::Component(_) => {
                     self.create(new_node);
@@ -316,10 +326,10 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
                 };
                 el.dom_id.set(real_id);
 
-                listeners.iter().enumerate().for_each(|(_id, listener)| {
-                    todo!()
-                    // dom
-                    //     .new_event_listener(listener.event, listener.scope, listener.id)
+                listeners.iter().enumerate().for_each(|(idx, listener)| {
+                    self.dom
+                        .new_event_listener(listener.event, listener.scope, idx, real_id);
+                    listener.mounted_node.set(real_id);
                 });
 
                 for attr in *attributes {
@@ -333,12 +343,12 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
                 // to emit three instructions to (1) create a text node, (2) set its
                 // text content, and finally (3) append the text node to this
                 // parent.
-                if children.len() == 1 {
-                    if let VNode::Text(text) = &children[0] {
-                        self.dom.set_text(text.text);
-                        return;
-                    }
-                }
+                // if children.len() == 1 {
+                //     if let VNode::Text(text) = &children[0] {
+                //         self.dom.set_text(text.text);
+                //         return;
+                //     }
+                // }
 
                 for child in *children {
                     self.create(child);
@@ -405,8 +415,8 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
                 new_component.run_scope().unwrap();
 
                 // And then run the diff algorithm
-                todo!();
-                // self.diff_node(new_component.old_frame(), new_component.next_frame());
+                // todo!();
+                self.diff_node(new_component.old_frame(), new_component.next_frame());
 
                 // Finally, insert this node as a seen node.
                 self.seen_nodes.insert(idx);
@@ -473,6 +483,8 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
         if !old.is_empty() || !new.is_empty() {
             // self.dom.commit_traversal();
         }
+        // TODO
+        // what does "diffing listeners" even mean?
 
         'outer1: for (_l_idx, new_l) in new.iter().enumerate() {
             // go through each new listener
@@ -480,34 +492,34 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
             // if any characteristics changed, remove and then re-add
 
             // if nothing changed, then just move on
-
             let event_type = new_l.event;
 
             for old_l in old {
                 if new_l.event == old_l.event {
-                    if new_l.id != old_l.id {
-                        self.dom.remove_event_listener(event_type);
-                        // TODO! we need to mess with events and assign them by RealDomNode
-                        // self.dom
-                        //     .update_event_listener(event_type, new_l.scope, new_l.id)
-                    }
+                    new_l.mounted_node.set(old_l.mounted_node.get());
+                    // if new_l.id != old_l.id {
+                    //     self.dom.remove_event_listener(event_type);
+                    //     // TODO! we need to mess with events and assign them by RealDomNode
+                    //     // self.dom
+                    //     //     .update_event_listener(event_type, new_l.scope, new_l.id)
+                    // }
 
                     continue 'outer1;
                 }
             }
 
-            self.dom
-                .new_event_listener(event_type, new_l.scope, new_l.id);
+            // self.dom
+            //     .new_event_listener(event_type, new_l.scope, new_l.id);
         }
 
-        'outer2: for old_l in old {
-            for new_l in new {
-                if new_l.event == old_l.event {
-                    continue 'outer2;
-                }
-            }
-            self.dom.remove_event_listener(old_l.event);
-        }
+        // 'outer2: for old_l in old {
+        //     for new_l in new {
+        //         if new_l.event == old_l.event {
+        //             continue 'outer2;
+        //         }
+        //     }
+        //     self.dom.remove_event_listener(old_l.event);
+        // }
     }
 
     // Diff a node's attributes.
@@ -590,11 +602,12 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
                     // Don't take this fast path...
                 }
 
-                (_, VNode::Text(text)) => {
-                    // self.dom.commit_traversal();
-                    self.dom.set_text(text.text);
-                    return;
-                }
+                // (_, VNode::Text(text)) => {
+                //     // self.dom.commit_traversal();
+                //     log::debug!("using optimized text set");
+                //     self.dom.set_text(text.text);
+                //     return;
+                // }
 
                 // todo: any more optimizations
                 (_, _) => {}
@@ -1047,7 +1060,7 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
     //     [... parent]
     //
     // the change list stack is in the same state when this function returns.
-    fn diff_non_keyed_children(&self, old: &'a [VNode<'a>], new: &'a [VNode<'a>]) {
+    fn diff_non_keyed_children(&mut self, old: &'a [VNode<'a>], new: &'a [VNode<'a>]) {
         // Handled these cases in `diff_children` before calling this function.
         debug_assert!(!new.is_empty());
         debug_assert!(!old.is_empty());
@@ -1057,13 +1070,26 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
         // self.dom.push_root()
         //     [... parent child]
 
-        todo!()
-        // for (i, (new_child, old_child)) in new.iter().zip(old.iter()).enumerate() {
-        //     // [... parent prev_child]
-        //     self.dom.go_to_sibling(i);
-        //     // [... parent this_child]
-        //     self.diff_node(old_child, new_child);
-        // }
+        // todo!()
+        for (i, (new_child, old_child)) in new.iter().zip(old.iter()).enumerate() {
+            // [... parent prev_child]
+            // self.dom.go_to_sibling(i);
+            // [... parent this_child]
+            self.dom.push_root(old_child.get_mounted_id().unwrap());
+            self.diff_node(old_child, new_child);
+
+            let old_id = old_child.get_mounted_id().unwrap();
+            let new_id = new_child.get_mounted_id().unwrap();
+
+            log::debug!(
+                "pushed root. {:?}, {:?}",
+                old_child.get_mounted_id().unwrap(),
+                new_child.get_mounted_id().unwrap()
+            );
+            if old_id != new_id {
+                log::debug!("Mismatch: {:?}", new_child);
+            }
+        }
 
         // match old.len().cmp(&new.len()) {
         //     // old.len > new.len -> removing some nodes

+ 18 - 20
packages/core/src/events.rs

@@ -6,20 +6,20 @@
 
 use std::rc::Rc;
 
-use crate::innerlude::ScopeIdx;
+use crate::{innerlude::ScopeIdx, virtual_dom::RealDomNode};
 
 #[derive(Debug)]
 pub struct EventTrigger {
     pub component_id: ScopeIdx,
-    pub listener_id: usize,
+    pub real_node_id: RealDomNode,
     pub event: VirtualEvent,
 }
 
 impl EventTrigger {
-    pub fn new(event: VirtualEvent, scope: ScopeIdx, id: usize) -> Self {
+    pub fn new(event: VirtualEvent, scope: ScopeIdx, mounted_dom_id: RealDomNode) -> Self {
         Self {
             component_id: scope,
-            listener_id: id,
+            real_node_id: mounted_dom_id,
             event,
         }
     }
@@ -55,17 +55,15 @@ pub mod on {
     use crate::{
         builder::ElementBuilder,
         builder::NodeCtx,
-        innerlude::{Attribute, Listener, VNode},
+        innerlude::{Attribute, Listener, RealDomNode, VNode},
     };
+    use std::cell::Cell;
 
     use super::VirtualEvent;
 
     macro_rules! event_directory {
         ( $( $eventdata:ident: [ $( $name:ident )* ]; )* ) => {
             $(
-
-
-
                 $(
                     pub fn $name<'a>(
                         c: &'_ NodeCtx<'a>,
@@ -74,7 +72,7 @@ pub mod on {
                         let bump = &c.bump();
                         Listener {
                             event: stringify!($name),
-                            id: *c.listener_id.borrow(),
+                            mounted_node: bump.alloc(Cell::new(RealDomNode::empty())),
                             scope: c.scope_ref.arena_idx,
                             callback: bump.alloc(move |evt: VirtualEvent| match evt {
                                 VirtualEvent::$eventdata(event) => callback(event),
@@ -121,31 +119,31 @@ pub mod on {
         /// Returns whether or not a specific event is a bubbling event
         fn bubbles(&self) -> bool;
         /// Sets or returns whether the event should propagate up the hierarchy or not
-        fn cancelBubble(&self) -> ();
+        fn cancel_bubble(&self);
         /// Returns whether or not an event can have its default action prevented
         fn cancelable(&self) -> bool;
         /// Returns whether the event is composed or not
         fn composed(&self) -> bool;
         /// Returns the event's path
-        fn composedPath(&self) -> ();
+        fn composed_path(&self) -> String;
         /// Returns the element whose event listeners triggered the event
-        fn currentTarget(&self) -> ();
+        fn current_target(&self);
         /// Returns whether or not the preventDefault method was called for the event
-        fn defaultPrevented(&self) -> ();
+        fn default_prevented(&self) -> bool;
         /// Returns which phase of the event flow is currently being evaluated
-        fn eventPhase(&self) -> ();
+        fn event_phase(&self) -> usize;
         /// Returns whether or not an event is trusted
-        fn isTrusted(&self) -> ();
+        fn is_trusted(&self) -> bool;
         /// Cancels the event if it is cancelable, meaning that the default action that belongs to the event will
-        fn preventDefault(&self) -> ();
+        fn prevent_default(&self);
         /// Prevents other listeners of the same event from being called
-        fn stopImmediatePropagation(&self) -> ();
+        fn stop_immediate_propagation(&self);
         /// Prevents further propagation of an event during event flow
-        fn stopPropagation(&self) -> ();
+        fn stop_propagation(&self);
         /// Returns the element that triggered the event
-        fn target(&self) -> ();
+        fn target(&self);
         /// Returns the time (in milliseconds relative to the epoch) at which the event was created
-        fn timeStamp(&self) -> usize;
+        fn time_stamp(&self) -> usize;
     }
 
     pub trait ClipboardEvent: Debug {

+ 32 - 29
packages/core/src/nodebuilder.rs

@@ -1,7 +1,12 @@
 //! Helpers for building virtual DOM VNodes.
 
 use std::{
-    any::Any, borrow::BorrowMut, cell::RefCell, fmt::Arguments, intrinsics::transmute, u128,
+    any::Any,
+    borrow::BorrowMut,
+    cell::{Cell, RefCell},
+    fmt::Arguments,
+    intrinsics::transmute,
+    u128,
 };
 
 use crate::{
@@ -9,7 +14,7 @@ use crate::{
     innerlude::{Properties, VComponent, FC},
     nodes::{Attribute, Listener, NodeKey, VNode},
     prelude::{VElement, VFragment},
-    virtual_dom::Scope,
+    virtual_dom::{RealDomNode, Scope},
 };
 
 /// A virtual DOM element builder.
@@ -353,12 +358,11 @@ where
     /// ```
     pub fn on(self, event: &'static str, callback: impl Fn(VirtualEvent) + 'a) -> Self {
         let bump = &self.ctx.bump();
-
         let listener = Listener {
             event,
             callback: bump.alloc(callback),
-            id: *self.ctx.listener_id.borrow(),
             scope: self.ctx.scope_ref.arena_idx,
+            mounted_node: bump.alloc(Cell::new(RealDomNode::empty())),
         };
         self.add_listener(listener)
     }
@@ -367,7 +371,8 @@ where
         self.listeners.push(listener);
 
         // bump the context id forward
-        *self.ctx.listener_id.borrow_mut() += 1;
+        let id = self.ctx.listener_id.get();
+        self.ctx.listener_id.set(id + 1);
 
         // Add this listener to the context list
         // This casts the listener to a self-referential pointer
@@ -378,7 +383,7 @@ where
                 .scope_ref
                 .listeners
                 .borrow_mut()
-                .push(r.callback as *const _);
+                .push((r.mounted_node as *const _, r.callback as *const _));
         });
 
         self
@@ -499,15 +504,19 @@ where
             let child = item.into_vnode(&self.ctx);
             self.children.push(child);
         }
-        let len_after = self.children.len();
-        if len_after > len_before {
-            let last_child = self.children.last().unwrap();
-            if last_child.key().is_none() {
-                // TODO: Somehow get the name of the component when NodeCtx is being made
-                const ERR_MSG: &str = r#"Warning: Each child in an array or iterator should have a unique "key" prop. 
-                Check the render method of XXXX. 
-                See fb.me/react-warning-keys for more information. "#;
-                log::error!("{}", ERR_MSG);
+        if self.children.len() > len_before + 1 {
+            if self.children.last().unwrap().key().is_none() {
+                if cfg!(debug_assertions) {
+                    log::error!(
+                        r#"
+Warning: Each child in an array or iterator should have a unique "key" prop. 
+Not providing a key will lead to poor performance with lists.
+See docs.rs/dioxus for more information. 
+---
+To help you identify where this error is coming from, we've generated a backtrace.
+                        "#,
+                    );
+                }
             }
         }
         self
@@ -549,17 +558,6 @@ impl<'a, F> VNodeBuilder<'a, LazyNodes<'a, F>> for LazyNodes<'a, F> where
 {
 }
 
-// Cover the cases where nodes are pre-rendered.
-// Likely used by enums.
-// ----
-//  let nodes = ctx.render(rsx!{ ... };
-//  rsx! { {nodes } }
-// impl<'a> IntoVNode<'a> for VNode {
-//     fn into_vnode(self, _ctx: &NodeCtx<'a>) -> VNode<'a> {
-//         self.root
-//     }
-// }
-
 // Wrap the the node-builder closure in a concrete type.
 // ---
 // This is a bit of a hack to implement the IntoVNode trait for closure types.
@@ -611,12 +609,14 @@ where
 
 impl<'a> IntoVNode<'a> for () {
     fn into_vnode(self, ctx: &NodeCtx<'a>) -> VNode<'a> {
+        todo!();
         VNode::Suspended
     }
 }
 
 impl<'a> IntoVNode<'a> for Option<()> {
     fn into_vnode(self, ctx: &NodeCtx<'a>) -> VNode<'a> {
+        todo!();
         VNode::Suspended
     }
 }
@@ -735,7 +735,8 @@ impl<'a, 'b> ChildrenList<'a, 'b> {
 #[derive(Clone)]
 pub struct NodeCtx<'a> {
     pub scope_ref: &'a Scope,
-    pub listener_id: RefCell<usize>,
+    pub listener_id: Cell<usize>,
+    // pub listener_id: RefCell<usize>,
 }
 
 impl<'a> NodeCtx<'a> {
@@ -744,11 +745,13 @@ impl<'a> NodeCtx<'a> {
         &self.scope_ref.cur_frame().bump
     }
 
-    fn text(&self, args: Arguments) -> VNode<'a> {
+    /// Create some text that's allocated along with the other vnodes
+    pub fn text(&self, args: Arguments) -> VNode<'a> {
         text3(self.bump(), args)
     }
 
-    fn element<'b, Listeners, Attributes, Children>(
+    /// Create an element builder
+    pub fn element<'b, Listeners, Attributes, Children>(
         &'b self,
         tag_name: &'static str,
     ) -> ElementBuilder<

+ 21 - 5
packages/core/src/nodes.rs

@@ -13,7 +13,7 @@ use bumpalo::Bump;
 use std::{
     any::Any,
     cell::{Cell, RefCell},
-    fmt::{Arguments, Debug},
+    fmt::{Arguments, Debug, Formatter},
     marker::PhantomData,
     rc::Rc,
 };
@@ -127,8 +127,8 @@ impl<'a> VNode<'a> {
 
     pub fn get_mounted_id(&self) -> Option<RealDomNode> {
         match self {
-            VNode::Element(_) => todo!(),
-            VNode::Text(_) => todo!(),
+            VNode::Element(el) => Some(el.dom_id.get()),
+            VNode::Text(te) => Some(te.dom_id.get()),
             VNode::Fragment(_) => todo!(),
             VNode::Suspended => todo!(),
             VNode::Component(_) => todo!(),
@@ -136,6 +136,18 @@ impl<'a> VNode<'a> {
     }
 }
 
+impl Debug for VNode<'_> {
+    fn fmt(&self, s: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
+        match self {
+            VNode::Element(el) => write!(s, "element, {}", el.tag_name),
+            VNode::Text(t) => write!(s, "text, {}", t.text),
+            VNode::Fragment(_) => write!(s, "fragment"),
+            VNode::Suspended => write!(s, "suspended"),
+            VNode::Component(_) => write!(s, "component"),
+        }
+    }
+}
+
 #[derive(Clone)]
 pub struct VText<'src> {
     pub text: &'src str,
@@ -201,11 +213,14 @@ pub struct Listener<'bump> {
     /// The type of event to listen for.
     pub(crate) event: &'static str,
 
+    /// Which scope?
+    /// This might not actually be relevant
     pub scope: ScopeIdx,
-    pub id: usize,
+
+    pub mounted_node: &'bump Cell<RealDomNode>,
 
     /// The callback to invoke when the event happens.
-    pub(crate) callback: &'bump (dyn Fn(VirtualEvent)),
+    pub(crate) callback: &'bump dyn Fn(VirtualEvent),
 }
 
 /// The key for keyed children.
@@ -259,6 +274,7 @@ pub struct VComponent<'src> {
     pub key: NodeKey<'src>,
 
     pub mounted_root: Cell<RealDomNode>,
+
     pub ass_scope: RefCell<VCompAssociatedScope>,
 
     // pub comparator: Rc<dyn Fn(&VComponent) -> bool + 'src>,

+ 43 - 32
packages/core/src/virtual_dom.rs

@@ -24,7 +24,7 @@ use bumpalo::Bump;
 use generational_arena::Arena;
 use std::{
     any::{Any, TypeId},
-    cell::RefCell,
+    cell::{Cell, RefCell},
     collections::{HashMap, HashSet, VecDeque},
     fmt::Debug,
     future::Future,
@@ -63,7 +63,7 @@ pub struct VirtualDom {
     _root_prop_type: std::any::TypeId,
 }
 
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug, PartialEq)]
 pub struct RealDomNode(pub u32);
 impl RealDomNode {
     pub fn new(id: u32) -> Self {
@@ -109,7 +109,7 @@ impl VirtualDom {
     ///
     /// let dom = VirtualDom::new(Example);
     /// ```
-    pub fn new(root: impl Fn(Context<()>) -> VNode + 'static) -> Self {
+    pub fn new(root: FC<()>) -> Self {
         Self::new_with_props(root, ())
     }
 
@@ -141,10 +141,7 @@ impl VirtualDom {
     ///
     /// let dom = VirtualDom::new(Example);
     /// ```
-    pub fn new_with_props<P: Properties + 'static>(
-        root: impl Fn(Context<P>) -> VNode + 'static,
-        root_props: P,
-    ) -> Self {
+    pub fn new_with_props<P: Properties + 'static>(root: FC<P>, root_props: P) -> Self {
         let components = ScopeArena::new(Arena::new());
 
         // Normally, a component would be passed as a child in the RSX macro which automatically produces OpaqueComponents
@@ -260,11 +257,11 @@ impl VirtualDom {
     pub fn progress_with_event<Dom: RealDom>(
         &mut self,
         realdom: &mut Dom,
-        event: EventTrigger,
+        trigger: EventTrigger,
     ) -> Result<()> {
-        let id = event.component_id.clone();
+        let id = trigger.component_id.clone();
 
-        self.components.try_get_mut(id)?.call_listener(event)?;
+        self.components.try_get_mut(id)?.call_listener(trigger)?;
 
         let mut diff_machine = DiffMachine::new(
             realdom,
@@ -397,7 +394,12 @@ pub struct Scope {
     // - is self-refenrential and therefore needs to point into the bump
     // Stores references into the listeners attached to the vnodes
     // NEEDS TO BE PRIVATE
-    pub(crate) listeners: RefCell<Vec<*const dyn Fn(VirtualEvent)>>,
+    pub(crate) listeners: RefCell<Vec<(*const Cell<RealDomNode>, *const dyn Fn(VirtualEvent))>>,
+    // pub(crate) listeners: RefCell<nohash_hasher::IntMap<u32, *const dyn Fn(VirtualEvent)>>,
+    // pub(crate) listeners: RefCell<Vec<*const dyn Fn(VirtualEvent)>>,
+    // pub(crate) listeners: RefCell<Vec<*const dyn Fn(VirtualEvent)>>,
+    // NoHashMap<RealDomNode, <*const dyn Fn(VirtualEvent)>
+    // pub(crate) listeners: RefCell<Vec<*const dyn Fn(VirtualEvent)>>,
 }
 
 // We need to pin the hook so it doesn't move as we initialize the list of hooks
@@ -450,7 +452,7 @@ impl Scope {
         let child_nodes = unsafe { std::mem::transmute(child_nodes) };
 
         Self {
-            child_nodes: child_nodes,
+            child_nodes,
             caller,
             parent,
             arena_idx,
@@ -490,12 +492,12 @@ impl Scope {
         self.frames.next().bump.reset();
 
         // Remove all the outdated listeners
-        //
-        self.listeners
-            .try_borrow_mut()
-            .ok()
-            .ok_or(Error::FatalInternal("Borrowing listener failed"))?
-            .drain(..);
+        self.listeners.borrow_mut().clear();
+        // self.listeners
+        //     .try_borrow_mut()
+        //     .ok()
+        //     .ok_or(Error::FatalInternal("Borrowing listener failed"))?
+        //     .drain(..);
 
         *self.hookidx.borrow_mut() = 0;
 
@@ -529,26 +531,35 @@ impl Scope {
     // The listener list will be completely drained because the next frame will write over previous listeners
     pub fn call_listener(&mut self, trigger: EventTrigger) -> Result<()> {
         let EventTrigger {
-            listener_id, event, ..
+            real_node_id,
+            event,
+            ..
         } = trigger;
 
         // todo: implement scanning for outdated events
+
+        // Convert the raw ptr into an actual object
+        // This operation is assumed to be safe
+
+        log::debug!("Calling listeners! {:?}", self.listeners.borrow().len());
+        let listners = self.listeners.borrow();
+        let (_, listener) = listners
+            .iter()
+            .find(|(domptr, _)| {
+                let p = unsafe { &**domptr };
+                p.get() == real_node_id
+            })
+            .expect(&format!(
+                "Failed to find real node with ID {:?}",
+                real_node_id
+            ));
+
+        // TODO: Don'tdo a linear scan! Do a hashmap lookup! It'll be faster!
         unsafe {
-            // Convert the raw ptr into an actual object
-            // This operation is assumed to be safe
-            let listener_fn = self
-                .listeners
-                .try_borrow()
-                .ok()
-                .ok_or(Error::FatalInternal("Borrowing listener failed"))?
-                .get(listener_id as usize)
-                .ok_or(Error::FatalInternal("Event should exist if triggered"))?
-                .as_ref()
-                .ok_or(Error::FatalInternal("Raw event ptr is invalid"))?;
-
-            // Run the callback with the user event
+            let listener_fn = &**listener;
             listener_fn(event);
         }
+
         Ok(())
     }
 

+ 2 - 1
packages/web/Cargo.toml

@@ -27,8 +27,9 @@ atoms = { path="../atoms" }
 # futures = "0.3.12"
 # html-validation = { path = "../html-validation", version = "0.1.1" }
 
-# async-channel = "1.6.1"
+async-channel = "1.6.1"
 nohash-hasher = "0.2.0"
+anyhow = "1.0.41"
 # futures-lite = "1.11.3"
 
 [dependencies.web-sys]

+ 2 - 2
packages/web/examples/demoday.rs

@@ -11,7 +11,7 @@ fn App(ctx: Context<()>) -> VNode {
     ctx.render(rsx! {
         main { class: "dark:bg-gray-800 bg-white relative h-screen"
             NavBar {}
-            {(0..10).map(|f| rsx!{ Landing {} })}
+            {(0..10).map(|f| rsx!(Landing { key: "{f}" }))}
         }
     })
 }
@@ -62,7 +62,7 @@ fn Landing(ctx: Context<()>) -> VNode {
             div { class: "container mx-auto px-6 flex flex-col justify-between items-center relative py-8"
                 div { class: "flex flex-col"
                     h1 { class: "font-light w-full uppercase text-center text-4xl sm:text-5xl dark:text-white text-gray-800"
-                        "The React Framework for Production"
+                        "The Dioxus Framework for Production"
                     }
                     h2{ class: "font-light max-w-2xl mx-auto w-full text-xl dark:text-white text-gray-500 text-center py-8"
                         "Next.js gives you the best developer experience with all the features you need for production: \n

+ 1 - 5
packages/web/examples/hello.rs

@@ -11,11 +11,7 @@ fn main() {
 }
 
 static Example: FC<()> = |ctx| {
-    let nodes = (0..5).map(|f| {
-        rsx! {
-            li {"{f}"}
-        }
-    });
+    let nodes = (0..15).map(|f| rsx! (li { key: "{f}", "{f}"}));
     ctx.render(rsx! {
         div {
             span {

+ 1 - 2
packages/web/examples/jackjill.rs

@@ -33,12 +33,11 @@ static Example: FC<()> = |ctx| {
                             <button
                                 class="inline-block py-4 px-8 mr-6 leading-none text-white bg-indigo-600 hover:bg-indigo-900 font-semibold rounded shadow"
                                 onclick={move |_| set_name("jack")}>
-                                "Jack!"
+                                    "Jack!"
                                 </button>
 
                                 <button
                                     class="inline-block py-4 px-8 mr-6 leading-none text-white bg-indigo-600 hover:bg-indigo-900 font-semibold rounded shadow"
-                                    onclick={move |_| set_name("jill")}
                                     onclick={move |_| set_name("jill")}>
                                     "Jill!"
                                 </button>

+ 28 - 0
packages/web/examples/listy.rs

@@ -0,0 +1,28 @@
+use dioxus_core as dioxus;
+use dioxus_core::prelude::*;
+use dioxus_web::WebsysRenderer;
+
+fn main() {
+    wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
+    console_error_panic_hook::set_once();
+
+    log::info!("hello world");
+    wasm_bindgen_futures::spawn_local(WebsysRenderer::start(JonsFavoriteCustomApp));
+}
+
+fn JonsFavoriteCustomApp(cx: Context<()>) -> VNode {
+    let items = (0..20).map(|f| {
+        rsx! {
+            li {"{f}"}
+        }
+    });
+
+    cx.render(rsx! {
+        div {
+            "list"
+            ul {
+                {items}
+            }
+        }
+    })
+}

+ 13 - 21
packages/web/src/lib.rs

@@ -12,7 +12,7 @@ pub use dioxus_core as dioxus;
 use dioxus_core::{events::EventTrigger, prelude::FC};
 
 pub use dioxus_core::prelude;
-pub mod interpreter;
+// pub mod interpreter;
 pub mod new;
 
 /// The `WebsysRenderer` provides a way of rendering a Dioxus Virtual DOM to the browser's DOM.
@@ -34,7 +34,7 @@ impl WebsysRenderer {
     ///
     /// Run the app to completion, panicing if any error occurs while rendering.
     /// Pairs well with the wasm_bindgen async handler
-    pub async fn start(root: impl for<'a> Fn(Context<'a, ()>) -> VNode + 'static) {
+    pub async fn start(root: FC<()>) {
         Self::new(root).run().await.expect("Virtual DOM failed :(");
     }
 
@@ -42,7 +42,7 @@ impl WebsysRenderer {
     ///
     /// This means that the root component must either consumes its own context, or statics are used to generate the page.
     /// The root component can access things like routing in its context.
-    pub fn new(root: impl for<'a> Fn(Context<'a, ()>) -> VNode + 'static) -> Self {
+    pub fn new(root: FC<()>) -> Self {
         Self::new_with_props(root, ())
     }
 
@@ -50,10 +50,7 @@ impl WebsysRenderer {
     /// Automatically progresses the creation of the VNode tree to completion.
     ///
     /// A VDom is automatically created. If you want more granular control of the VDom, use `from_vdom`
-    pub fn new_with_props<T: Properties + 'static>(
-        root: impl for<'a> Fn(Context<'a, T>) -> VNode + 'static,
-        root_props: T,
-    ) -> Self {
+    pub fn new_with_props<T: Properties + 'static>(root: FC<T>, root_props: T) -> Self {
         Self::from_vdom(VirtualDom::new_with_props(root, root_props))
     }
 
@@ -63,28 +60,23 @@ impl WebsysRenderer {
     }
 
     pub async fn run(&mut self) -> dioxus_core::error::Result<()> {
-        // let (sender, mut receiver) = async_channel::unbounded::<EventTrigger>();
-
         let body_element = prepare_websys_dom();
 
-        // let mut patch_machine = interpreter::PatchMachine::new(body_element.clone(), move |ev| {
-        //     log::debug!("Event trigger! {:#?}", ev);
-        //     let mut c = sender.clone();
-        //     wasm_bindgen_futures::spawn_local(async move {
-        //         c.send(ev).await.unwrap();
-        //     });
-        // });
-
         let root_node = body_element.first_child().unwrap();
 
-        let mut websys_dom = crate::new::WebsysDom::new(body_element);
+        let mut websys_dom = crate::new::WebsysDom::new(body_element.clone());
 
         websys_dom.stack.push(root_node);
-        // patch_machine.stack.push(root_node.clone());
-
-        // todo: initialize the event registry properly on the root
 
         self.internal_dom.rebuild(&mut websys_dom)?;
+
+        while let Some(trigger) = websys_dom.wait_for_event().await {
+            let root_node = body_element.first_child().unwrap();
+            websys_dom.stack.push(root_node.clone());
+            self.internal_dom
+                .progress_with_event(&mut websys_dom, trigger)?;
+        }
+
         // let edits = self.internal_dom.rebuild()?;
         // log::debug!("Received edits: {:#?}", edits);
         // edits.iter().for_each(|edit| {

+ 387 - 61
packages/web/src/new.rs

@@ -1,19 +1,35 @@
-use std::collections::HashMap;
+use std::{collections::HashMap, rc::Rc, sync::Arc};
 
-use dioxus_core::virtual_dom::RealDomNode;
+use dioxus_core::{
+    events::{EventTrigger, VirtualEvent},
+    prelude::ScopeIdx,
+    virtual_dom::RealDomNode,
+};
+use fxhash::FxHashMap;
 use nohash_hasher::IntMap;
 use wasm_bindgen::{closure::Closure, JsCast};
 use web_sys::{
     window, Document, Element, Event, HtmlElement, HtmlInputElement, HtmlOptionElement, Node,
 };
 
-use crate::interpreter::Stack;
 pub struct WebsysDom {
     pub stack: Stack,
     nodes: IntMap<u32, Node>,
     document: Document,
     root: Element,
 
+    event_receiver: async_channel::Receiver<EventTrigger>,
+    trigger: Arc<dyn Fn(EventTrigger)>,
+
+    // every callback gets a monotomically increasing callback ID
+    callback_id: usize,
+
+    // map of listener types to number of those listeners
+    listeners: FxHashMap<String, (usize, Closure<dyn FnMut(&Event)>)>,
+
+    // Map of callback_id to component index and listener id
+    callback_map: FxHashMap<usize, (usize, usize)>,
+
     // We need to make sure to add comments between text nodes
     // We ensure that the text siblings are patched by preventing the browser from merging
     // neighboring text nodes. Originally inspired by some of React's work from 2016.
@@ -33,18 +49,39 @@ impl WebsysDom {
             .document()
             .expect("must have access to the Document");
 
+        let (sender, mut receiver) = async_channel::unbounded::<EventTrigger>();
+
+        let sender_callback = Arc::new(move |ev| {
+            let mut c = sender.clone();
+            wasm_bindgen_futures::spawn_local(async move {
+                c.send(ev).await.unwrap();
+            });
+        });
+
+        let mut nodes =
+            HashMap::with_capacity_and_hasher(1000, nohash_hasher::BuildNoHashHasher::default());
+
+        nodes.insert(0_u32, root.clone().dyn_into::<Node>().unwrap());
         Self {
             stack: Stack::with_capacity(10),
-            nodes: HashMap::with_capacity_and_hasher(
-                1000,
-                nohash_hasher::BuildNoHashHasher::default(),
-            ),
+            nodes,
+
+            callback_id: 0,
+            listeners: FxHashMap::default(),
+            callback_map: FxHashMap::default(),
             document,
+            event_receiver: receiver,
+            trigger: sender_callback,
             root,
             last_node_was_text: false,
             node_counter: Counter(0),
         }
     }
+
+    pub async fn wait_for_event(&mut self) -> Option<EventTrigger> {
+        let v = self.event_receiver.recv().await.unwrap();
+        Some(v)
+    }
 }
 
 struct Counter(u32);
@@ -56,11 +93,13 @@ impl Counter {
 }
 impl dioxus_core::diff::RealDom for WebsysDom {
     fn push_root(&mut self, root: dioxus_core::virtual_dom::RealDomNode) {
+        log::debug!("Called `[`push_root] {:?}", root);
         let domnode = self.nodes.get(&root.0).expect("Failed to pop know root");
         self.stack.push(domnode.clone());
     }
 
     fn append_child(&mut self) {
+        log::debug!("Called [`append_child`]");
         let child = self.stack.pop();
 
         if child.dyn_ref::<web_sys::Text>().is_some() {
@@ -81,6 +120,7 @@ impl dioxus_core::diff::RealDom for WebsysDom {
     }
 
     fn replace_with(&mut self) {
+        log::debug!("Called [`replace_with`]");
         let new_node = self.stack.pop();
         let old_node = self.stack.pop();
 
@@ -117,10 +157,12 @@ impl dioxus_core::diff::RealDom for WebsysDom {
     }
 
     fn remove(&mut self) {
+        log::debug!("Called [`remove`]");
         todo!()
     }
 
     fn remove_all_children(&mut self) {
+        log::debug!("Called [`remove_all_children`]");
         todo!()
     }
 
@@ -134,6 +176,8 @@ impl dioxus_core::diff::RealDom for WebsysDom {
         self.stack.push(textnode.clone());
         self.nodes.insert(nid, textnode);
 
+        log::debug!("Called [`create_text_node`]: {}, {}", text, nid);
+
         RealDomNode::new(nid)
     }
 
@@ -148,6 +192,7 @@ impl dioxus_core::diff::RealDom for WebsysDom {
         self.stack.push(el.clone());
         let nid = self.node_counter.next();
         self.nodes.insert(nid, el);
+        log::debug!("Called [`create_element`]: {}, {:?}", tag, nid);
         RealDomNode::new(nid)
     }
 
@@ -166,6 +211,7 @@ impl dioxus_core::diff::RealDom for WebsysDom {
         self.stack.push(el.clone());
         let nid = self.node_counter.next();
         self.nodes.insert(nid, el);
+        log::debug!("Called [`create_element_ns`]: {:}", nid);
         RealDomNode::new(nid)
     }
 
@@ -173,81 +219,133 @@ impl dioxus_core::diff::RealDom for WebsysDom {
         &mut self,
         event: &str,
         scope: dioxus_core::prelude::ScopeIdx,
-        id: usize,
+        el_id: usize,
+        real_id: RealDomNode,
     ) {
-        // if let Some(entry) = self.listeners.get_mut(event) {
-        //     entry.0 += 1;
-        // } else {
-        //     let trigger = self.trigger.clone();
-        //     let handler = Closure::wrap(Box::new(move |event: &web_sys::Event| {
-        //         log::debug!("Handling event!");
-
-        //         let target = event
-        //             .target()
-        //             .expect("missing target")
-        //             .dyn_into::<Element>()
-        //             .expect("not a valid element");
-
-        //         let typ = event.type_();
-
-        //         let gi_id: Option<usize> = target
-        //             .get_attribute(&format!("dioxus-giid-{}", typ))
-        //             .and_then(|v| v.parse().ok());
-
-        //         let gi_gen: Option<u64> = target
-        //             .get_attribute(&format!("dioxus-gigen-{}", typ))
-        //             .and_then(|v| v.parse().ok());
-
-        //         let li_idx: Option<usize> = target
-        //             .get_attribute(&format!("dioxus-lidx-{}", typ))
-        //             .and_then(|v| v.parse().ok());
-
-        //         if let (Some(gi_id), Some(gi_gen), Some(li_idx)) = (gi_id, gi_gen, li_idx) {
-        //             // Call the trigger
-        //             log::debug!(
-        //                 "decoded gi_id: {},  gi_gen: {},  li_idx: {}",
-        //                 gi_id,
-        //                 gi_gen,
-        //                 li_idx
-        //             );
-
-        //             let triggered_scope = ScopeIdx::from_raw_parts(gi_id, gi_gen);
-        //             trigger.0.as_ref()(EventTrigger::new(
-        //                 virtual_event_from_websys_event(event),
-        //                 triggered_scope,
-        //                 // scope,
-        //                 li_idx,
-        //             ));
-        //         }
-        //     }) as Box<dyn FnMut(&Event)>);
-
-        //     self.root
-        //         .add_event_listener_with_callback(event, (&handler).as_ref().unchecked_ref())
-        //         .unwrap();
-
-        //     // Increment the listeners
-        //     self.listeners.insert(event.into(), (1, handler));
-        // }
+        log::debug!(
+            "Called [`new_event_listener`]: {}, {:?}, {}, {:?}",
+            event,
+            scope,
+            el_id,
+            real_id
+        );
+        // attach the correct attributes to the element
+        // these will be used by accessing the event's target
+        // This ensures we only ever have one handler attached to the root, but decide
+        // dynamically when we want to call a listener.
+
+        let el = self.stack.top();
+
+        let el = el
+            .dyn_ref::<Element>()
+            .expect(&format!("not an element: {:?}", el));
+
+        let (gi_id, gi_gen) = (&scope).into_raw_parts();
+        el.set_attribute(
+            &format!("dioxus-event-{}", event),
+            &format!("{}.{}.{}.{}", gi_id, gi_gen, el_id, real_id.0),
+        )
+        .unwrap();
+
+        // Register the callback to decode
+
+        if let Some(entry) = self.listeners.get_mut(event) {
+            entry.0 += 1;
+        } else {
+            let trigger = self.trigger.clone();
+            let handler = Closure::wrap(Box::new(move |event: &web_sys::Event| {
+                // "Result" cannot be received from JS
+                // Instead, we just build and immediately execute a closure that returns result
+                let res = || -> anyhow::Result<EventTrigger> {
+                    log::debug!("Handling event!");
+
+                    let target = event
+                        .target()
+                        .expect("missing target")
+                        .dyn_into::<Element>()
+                        .expect("not a valid element");
+
+                    let typ = event.type_();
+                    use anyhow::Context;
+                    let val: String = target
+                        .get_attribute(&format!("dioxus-event-{}", typ))
+                        .context("")?;
+
+                    let mut fields = val.splitn(4, ".");
+
+                    let gi_id = fields
+                        .next()
+                        .and_then(|f| f.parse::<usize>().ok())
+                        .context("")?;
+                    let gi_gen = fields
+                        .next()
+                        .and_then(|f| f.parse::<u64>().ok())
+                        .context("")?;
+                    let el_id = fields
+                        .next()
+                        .and_then(|f| f.parse::<usize>().ok())
+                        .context("")?;
+                    let real_id = fields
+                        .next()
+                        .and_then(|f| f.parse::<u32>().ok().map(RealDomNode::new))
+                        .context("")?;
+
+                    // Call the trigger
+                    log::debug!(
+                        "decoded gi_id: {},  gi_gen: {},  li_idx: {}",
+                        gi_id,
+                        gi_gen,
+                        el_id
+                    );
+
+                    let triggered_scope = ScopeIdx::from_raw_parts(gi_id, gi_gen);
+                    Ok(EventTrigger::new(
+                        virtual_event_from_websys_event(event),
+                        triggered_scope,
+                        real_id,
+                    ))
+                };
+
+                match res() {
+                    Ok(synthetic_event) => trigger.as_ref()(synthetic_event),
+                    Err(_) => log::error!("Error decoding Dioxus event attribute."),
+                };
+            }) as Box<dyn FnMut(&Event)>);
+
+            self.root
+                .add_event_listener_with_callback(event, (&handler).as_ref().unchecked_ref())
+                .unwrap();
+
+            // Increment the listeners
+            self.listeners.insert(event.into(), (1, handler));
+        }
     }
 
     fn remove_event_listener(&mut self, event: &str) {
+        log::debug!("Called [`remove_event_listener`]: {}", event);
         todo!()
     }
 
     fn set_text(&mut self, text: &str) {
+        log::debug!("Called [`set_text`]: {}", text);
         self.stack.top().set_text_content(Some(text))
     }
 
     fn set_attribute(&mut self, name: &str, value: &str, is_namespaced: bool) {
+        log::debug!("Called [`set_attribute`]: {}, {}", name, value);
         if name == "class" {
             if let Some(el) = self.stack.top().dyn_ref::<Element>() {
                 el.set_class_name(value);
             }
         } else {
+            if let Some(el) = self.stack.top().dyn_ref::<Element>() {
+                el.set_attribute(name, value).unwrap();
+            }
         }
     }
 
     fn remove_attribute(&mut self, name: &str) {
+        log::debug!("Called [`remove_attribute`]: {}", name);
         let node = self.stack.top();
         if let Some(node) = node.dyn_ref::<web_sys::Element>() {
             node.remove_attribute(name).unwrap();
@@ -270,6 +368,234 @@ impl dioxus_core::diff::RealDom for WebsysDom {
     }
 
     fn raw_node_as_any_mut(&self) -> &mut dyn std::any::Any {
+        log::debug!("Called [`raw_node_as_any_mut`]");
         todo!()
     }
 }
+
+#[derive(Debug, Default)]
+pub struct Stack {
+    list: Vec<Node>,
+}
+
+impl Stack {
+    pub fn with_capacity(cap: usize) -> Self {
+        Stack {
+            list: Vec::with_capacity(cap),
+        }
+    }
+
+    pub fn push(&mut self, node: Node) {
+        // debug!("stack-push: {:?}", node);
+        self.list.push(node);
+    }
+
+    pub fn pop(&mut self) -> Node {
+        let res = self.list.pop().unwrap();
+        res
+    }
+
+    pub fn clear(&mut self) {
+        self.list.clear();
+    }
+
+    pub fn top(&self) -> &Node {
+        match self.list.last() {
+            Some(a) => a,
+            None => panic!("Called 'top' of an empty stack, make sure to push the root first"),
+        }
+    }
+}
+
+fn virtual_event_from_websys_event(event: &web_sys::Event) -> VirtualEvent {
+    use dioxus_core::events::on::*;
+    match event.type_().as_str() {
+        "copy" | "cut" | "paste" => {
+            // let evt: web_sys::ClipboardEvent = event.clone().dyn_into().unwrap();
+
+            todo!()
+        }
+
+        "compositionend" | "compositionstart" | "compositionupdate" => {
+            let evt: web_sys::CompositionEvent = event.clone().dyn_into().unwrap();
+            todo!()
+        }
+
+        "keydown" | "keypress" | "keyup" => {
+            let evt: web_sys::KeyboardEvent = event.clone().dyn_into().unwrap();
+            todo!()
+        }
+
+        "focus" | "blur" => {
+            let evt: web_sys::FocusEvent = event.clone().dyn_into().unwrap();
+            todo!()
+        }
+
+        "change" => {
+            let evt: web_sys::Event = event.clone().dyn_into().expect("wrong error typ");
+            todo!()
+            // VirtualEvent::FormEvent(FormEvent {value:})
+        }
+
+        "input" | "invalid" | "reset" | "submit" => {
+            // is a special react events
+            let evt: web_sys::InputEvent = event.clone().dyn_into().expect("wrong event type");
+            let this: web_sys::EventTarget = evt.target().unwrap();
+
+            let value = (&this)
+                .dyn_ref()
+                .map(|input: &web_sys::HtmlInputElement| input.value())
+                .or_else(|| {
+                    (&this)
+                        .dyn_ref()
+                        .map(|input: &web_sys::HtmlTextAreaElement| input.value())
+                })
+                .or_else(|| {
+                    (&this)
+                        .dyn_ref::<web_sys::HtmlElement>()
+                        .unwrap()
+                        .text_content()
+                })
+                .expect("only an InputElement or TextAreaElement or an element with contenteditable=true can have an oninput event listener");
+
+            // let p2 = evt.data_transfer();
+
+            // let value: Option<String> = (&evt).data();
+            // let value = val;
+            // let value = value.unwrap_or_default();
+            // let value = (&evt).data().expect("No data to unwrap");
+
+            // todo - this needs to be a "controlled" event
+            // these events won't carry the right data with them
+            todo!()
+            // VirtualEvent::FormEvent(FormEvent { value })
+        }
+
+        "click" | "contextmenu" | "doubleclick" | "drag" | "dragend" | "dragenter" | "dragexit"
+        | "dragleave" | "dragover" | "dragstart" | "drop" | "mousedown" | "mouseenter"
+        | "mouseleave" | "mousemove" | "mouseout" | "mouseover" | "mouseup" => {
+            let evt: web_sys::MouseEvent = event.clone().dyn_into().unwrap();
+
+            #[derive(Debug)]
+            pub struct CustomMouseEvent(web_sys::MouseEvent);
+            impl dioxus_core::events::on::MouseEvent for CustomMouseEvent {
+                fn alt_key(&self) -> bool {
+                    todo!()
+                }
+                fn button(&self) -> i32 {
+                    todo!()
+                }
+                fn buttons(&self) -> i32 {
+                    todo!()
+                }
+                fn client_x(&self) -> i32 {
+                    todo!()
+                }
+                fn client_y(&self) -> i32 {
+                    todo!()
+                }
+                fn ctrl_key(&self) -> bool {
+                    todo!()
+                }
+                fn meta_key(&self) -> bool {
+                    todo!()
+                }
+                fn page_x(&self) -> i32 {
+                    todo!()
+                }
+                fn page_y(&self) -> i32 {
+                    todo!()
+                }
+                fn screen_x(&self) -> i32 {
+                    todo!()
+                }
+                fn screen_y(&self) -> i32 {
+                    todo!()
+                }
+                fn shift_key(&self) -> bool {
+                    todo!()
+                }
+                fn get_modifier_state(&self, key_code: usize) -> bool {
+                    todo!()
+                }
+            }
+            VirtualEvent::MouseEvent(Rc::new(CustomMouseEvent(evt)))
+            // MouseEvent(Box::new(RawMouseEvent {
+            //                 alt_key: evt.alt_key(),
+            //                 button: evt.button() as i32,
+            //                 buttons: evt.buttons() as i32,
+            //                 client_x: evt.client_x(),
+            //                 client_y: evt.client_y(),
+            //                 ctrl_key: evt.ctrl_key(),
+            //                 meta_key: evt.meta_key(),
+            //                 page_x: evt.page_x(),
+            //                 page_y: evt.page_y(),
+            //                 screen_x: evt.screen_x(),
+            //                 screen_y: evt.screen_y(),
+            //                 shift_key: evt.shift_key(),
+            //                 get_modifier_state: GetModifierKey(Box::new(|f| {
+            //                     // evt.get_modifier_state(f)
+            //                     todo!("This is not yet implemented properly, sorry :(");
+            //                 })),
+            //             }))
+            // todo!()
+            // VirtualEvent::MouseEvent()
+        }
+
+        "pointerdown" | "pointermove" | "pointerup" | "pointercancel" | "gotpointercapture"
+        | "lostpointercapture" | "pointerenter" | "pointerleave" | "pointerover" | "pointerout" => {
+            let evt: web_sys::PointerEvent = event.clone().dyn_into().unwrap();
+            todo!()
+        }
+
+        "select" => {
+            // let evt: web_sys::SelectionEvent = event.clone().dyn_into().unwrap();
+            // not required to construct anything special beyond standard event stuff
+            todo!()
+        }
+
+        "touchcancel" | "touchend" | "touchmove" | "touchstart" => {
+            let evt: web_sys::TouchEvent = event.clone().dyn_into().unwrap();
+            todo!()
+        }
+
+        "scroll" => {
+            // let evt: web_sys::UIEvent = event.clone().dyn_into().unwrap();
+            todo!()
+        }
+
+        "wheel" => {
+            let evt: web_sys::WheelEvent = event.clone().dyn_into().unwrap();
+            todo!()
+        }
+
+        "abort" | "canplay" | "canplaythrough" | "durationchange" | "emptied" | "encrypted"
+        | "ended" | "error" | "loadeddata" | "loadedmetadata" | "loadstart" | "pause" | "play"
+        | "playing" | "progress" | "ratechange" | "seeked" | "seeking" | "stalled" | "suspend"
+        | "timeupdate" | "volumechange" | "waiting" => {
+            // not required to construct anything special beyond standard event stuff
+
+            // let evt: web_sys::MediaEvent = event.clone().dyn_into().unwrap();
+            // let evt: web_sys::MediaEvent = event.clone().dyn_into().unwrap();
+            todo!()
+        }
+
+        "animationstart" | "animationend" | "animationiteration" => {
+            let evt: web_sys::AnimationEvent = event.clone().dyn_into().unwrap();
+            todo!()
+        }
+
+        "transitionend" => {
+            let evt: web_sys::TransitionEvent = event.clone().dyn_into().unwrap();
+            todo!()
+        }
+
+        "toggle" => {
+            // not required to construct anything special beyond standard event stuff (target)
+
+            // let evt: web_sys::ToggleEvent = event.clone().dyn_into().unwrap();
+            todo!()
+        }
+        _ => VirtualEvent::OtherEvent,
+    }
+}

+ 0 - 1
packages/web/src/interpreter.rs → packages/web/src/old/interpreter.rs

@@ -2,7 +2,6 @@ use std::{borrow::Borrow, convert::TryInto, default, fmt::Debug, sync::Arc};
 
 use dioxus_core::{
     events::{EventTrigger, VirtualEvent},
-    patch::Edit,
     prelude::ScopeIdx,
 };
 use fxhash::FxHashMap;