Parcourir la source

feat: wire up both desktop and web

Jonathan Kelley il y a 3 ans
Parent
commit
05331dd

+ 1 - 0
packages/desktop/src/index.html

@@ -15,5 +15,6 @@
 
 <script>var exports = {};</script>
 <script type="text/javascript" src="index.js" type="module"></script>
+<script>main()</script>
 
 </html>

+ 8 - 0
packages/jsinterpreter/README.md

@@ -0,0 +1,8 @@
+# JS Interpreter
+
+After diffing old and new trees, the Dioxus VirtualDom produces patches that are used to modify the existing Dom. We can send these patches anywhere - including targets without WASM support.
+
+In renderers with support for JavaScript, we use the interpreter from this repository - written in TypeScript - to patch the Dom. This lets us circumvent any overhead on the Rust <-> Dom boundary and keep consistency in our interpreter implementation in web/webview targets.
+
+
+For now - both Dioxus Web and Dioxus Desktop (webview) use the same interpreter code with tweaks.

+ 75 - 58
packages/jsinterpreter/interpreter.js

@@ -1,23 +1,22 @@
-"use strict";
-exports.__esModule = true;
-exports.Interpreter = void 0;
 function serialize_event(event) {
     var _a, _b;
     switch (event.type) {
         case "copy":
         case "cut":
-        case "past":
+        case "past": {
             return {};
+        }
         case "compositionend":
         case "compositionstart":
-        case "compositionupdate":
+        case "compositionupdate": {
             var data = event.data;
             return {
-                data: data
+                data: data,
             };
+        }
         case "keydown":
         case "keypress":
-        case "keyup":
+        case "keyup": {
             var _c = event, charCode = _c.charCode, key = _c.key, altKey = _c.altKey, ctrlKey = _c.ctrlKey, metaKey = _c.metaKey, keyCode = _c.keyCode, shiftKey = _c.shiftKey, location_1 = _c.location, repeat = _c.repeat, which = _c.which;
             return {
                 char_code: charCode,
@@ -30,12 +29,14 @@ function serialize_event(event) {
                 location: location_1,
                 repeat: repeat,
                 which: which,
-                locale: "locale"
+                locale: "locale",
             };
+        }
         case "focus":
-        case "blur":
+        case "blur": {
             return {};
-        case "change":
+        }
+        case "change": {
             var target = event.target;
             var value = void 0;
             if (target.type === "checkbox" || target.type === "radio") {
@@ -45,19 +46,20 @@ function serialize_event(event) {
                 value = (_a = target.value) !== null && _a !== void 0 ? _a : target.textContent;
             }
             return {
-                value: value
+                value: value,
             };
+        }
         case "input":
         case "invalid":
         case "reset":
         case "submit": {
-            var target_1 = event.target;
-            var value_1 = (_b = target_1.value) !== null && _b !== void 0 ? _b : target_1.textContent;
-            if (target_1.type == "checkbox") {
-                value_1 = target_1.checked ? "true" : "false";
+            var target = event.target;
+            var value = (_b = target.value) !== null && _b !== void 0 ? _b : target.textContent;
+            if (target.type == "checkbox") {
+                value = target.checked ? "true" : "false";
             }
             return {
-                value: value_1
+                value: value,
             };
         }
         case "click":
@@ -78,20 +80,20 @@ function serialize_event(event) {
         case "mouseout":
         case "mouseover":
         case "mouseup": {
-            var _d = event, altKey_1 = _d.altKey, button = _d.button, buttons = _d.buttons, clientX = _d.clientX, clientY = _d.clientY, ctrlKey_1 = _d.ctrlKey, metaKey_1 = _d.metaKey, pageX = _d.pageX, pageY = _d.pageY, screenX_1 = _d.screenX, screenY_1 = _d.screenY, shiftKey_1 = _d.shiftKey;
+            var _d = event, altKey = _d.altKey, button = _d.button, buttons = _d.buttons, clientX = _d.clientX, clientY = _d.clientY, ctrlKey = _d.ctrlKey, metaKey = _d.metaKey, pageX = _d.pageX, pageY = _d.pageY, screenX_1 = _d.screenX, screenY_1 = _d.screenY, shiftKey = _d.shiftKey;
             return {
-                alt_key: altKey_1,
+                alt_key: altKey,
                 button: button,
                 buttons: buttons,
                 client_x: clientX,
                 client_y: clientY,
-                ctrl_key: ctrlKey_1,
-                meta_key: metaKey_1,
+                ctrl_key: ctrlKey,
+                meta_key: metaKey,
                 page_x: pageX,
                 page_y: pageY,
                 screen_x: screenX_1,
                 screen_y: screenY_1,
-                shift_key: shiftKey_1
+                shift_key: shiftKey,
             };
         }
         case "pointerdown":
@@ -104,20 +106,20 @@ function serialize_event(event) {
         case "pointerleave":
         case "pointerover":
         case "pointerout": {
-            var _e = event, altKey_2 = _e.altKey, button = _e.button, buttons = _e.buttons, clientX = _e.clientX, clientY = _e.clientY, ctrlKey_2 = _e.ctrlKey, metaKey_2 = _e.metaKey, pageX = _e.pageX, pageY = _e.pageY, screenX_2 = _e.screenX, screenY_2 = _e.screenY, shiftKey_2 = _e.shiftKey, pointerId = _e.pointerId, width = _e.width, height = _e.height, pressure = _e.pressure, tangentialPressure = _e.tangentialPressure, tiltX = _e.tiltX, tiltY = _e.tiltY, twist = _e.twist, pointerType = _e.pointerType, isPrimary = _e.isPrimary;
+            var _e = event, altKey = _e.altKey, button = _e.button, buttons = _e.buttons, clientX = _e.clientX, clientY = _e.clientY, ctrlKey = _e.ctrlKey, metaKey = _e.metaKey, pageX = _e.pageX, pageY = _e.pageY, screenX_2 = _e.screenX, screenY_2 = _e.screenY, shiftKey = _e.shiftKey, pointerId = _e.pointerId, width = _e.width, height = _e.height, pressure = _e.pressure, tangentialPressure = _e.tangentialPressure, tiltX = _e.tiltX, tiltY = _e.tiltY, twist = _e.twist, pointerType = _e.pointerType, isPrimary = _e.isPrimary;
             return {
-                alt_key: altKey_2,
+                alt_key: altKey,
                 button: button,
                 buttons: buttons,
                 client_x: clientX,
                 client_y: clientY,
-                ctrl_key: ctrlKey_2,
-                meta_key: metaKey_2,
+                ctrl_key: ctrlKey,
+                meta_key: metaKey,
                 page_x: pageX,
                 page_y: pageY,
                 screen_x: screenX_2,
                 screen_y: screenY_2,
-                shift_key: shiftKey_2,
+                shift_key: shiftKey,
                 pointer_id: pointerId,
                 width: width,
                 height: height,
@@ -127,35 +129,37 @@ function serialize_event(event) {
                 tilt_y: tiltY,
                 twist: twist,
                 pointer_type: pointerType,
-                is_primary: isPrimary
+                is_primary: isPrimary,
             };
         }
-        case "select":
+        case "select": {
             return {};
+        }
         case "touchcancel":
         case "touchend":
         case "touchmove":
         case "touchstart": {
-            var _f = event, altKey_3 = _f.altKey, ctrlKey_3 = _f.ctrlKey, metaKey_3 = _f.metaKey, shiftKey_3 = _f.shiftKey;
+            var _f = event, altKey = _f.altKey, ctrlKey = _f.ctrlKey, metaKey = _f.metaKey, shiftKey = _f.shiftKey;
             return {
                 // changed_touches: event.changedTouches,
                 // target_touches: event.targetTouches,
                 // touches: event.touches,
-                alt_key: altKey_3,
-                ctrl_key: ctrlKey_3,
-                meta_key: metaKey_3,
-                shift_key: shiftKey_3
+                alt_key: altKey,
+                ctrl_key: ctrlKey,
+                meta_key: metaKey,
+                shift_key: shiftKey,
             };
         }
-        case "scroll":
+        case "scroll": {
             return {};
+        }
         case "wheel": {
             var _g = event, deltaX = _g.deltaX, deltaY = _g.deltaY, deltaZ = _g.deltaZ, deltaMode = _g.deltaMode;
             return {
                 delta_x: deltaX,
                 delta_y: deltaY,
                 delta_z: deltaZ,
-                delta_mode: deltaMode
+                delta_mode: deltaMode,
             };
         }
         case "animationstart":
@@ -165,7 +169,7 @@ function serialize_event(event) {
             return {
                 animation_name: animationName,
                 elapsed_time: elapsedTime,
-                pseudo_element: pseudoElement
+                pseudo_element: pseudoElement,
             };
         }
         case "transitionend": {
@@ -173,7 +177,7 @@ function serialize_event(event) {
             return {
                 property_name: propertyName,
                 elapsed_time: elapsedTime,
-                pseudo_element: pseudoElement
+                pseudo_element: pseudoElement,
             };
         }
         case "abort":
@@ -198,12 +202,15 @@ function serialize_event(event) {
         case "suspend":
         case "timeupdate":
         case "volumechange":
-        case "waiting":
+        case "waiting": {
             return {};
-        case "toggle":
+        }
+        case "toggle": {
             return {};
-        default:
+        }
+        default: {
             return {};
+        }
     }
 }
 var bool_attrs = {
@@ -214,7 +221,7 @@ var bool_attrs = {
     autoplay: true,
     checked: true,
     controls: true,
-    "default": true,
+    default: true,
     defer: true,
     disabled: true,
     formnovalidate: true,
@@ -232,13 +239,14 @@ var bool_attrs = {
     required: true,
     reversed: true,
     selected: true,
-    truespeed: true
+    truespeed: true,
 };
 var Interpreter = /** @class */ (function () {
     function Interpreter(root) {
         this.root = root;
         this.stack = [root];
         this.listeners = {};
+        this.handlers = {};
         this.lastNodeWasText = false;
         this.nodes = [root];
     }
@@ -303,17 +311,28 @@ var Interpreter = /** @class */ (function () {
         this.stack.push(el);
         this.nodes[root] = el;
     };
-    Interpreter.prototype.NewEventListener = function (event_name, scope, root) {
-        console.log('new event listener', event_name, root, scope);
+    Interpreter.prototype.NewEventListener = function (event_name, scope, root, handler) {
+        // console.log('new event listener', event_name, root, scope);
         var element = this.nodes[root];
         element.setAttribute("dioxus-event-".concat(event_name), "".concat(scope, ".").concat(root));
-        // if (!this.listeners[event_name]) {
-        //   this.listeners[event_name] = handler;
-        //   this.root.addEventListener(event_name, handler);
-        // }
+        if (this.listeners[event_name] === undefined) {
+            this.listeners[event_name] = 0;
+            this.handlers[event_name] = handler;
+            this.root.addEventListener(event_name, handler);
+        }
+        else {
+            this.listeners[event_name]++;
+        }
     };
-    Interpreter.prototype.RemoveEventListener = function (root, event_name, scope) {
-        //
+    Interpreter.prototype.RemoveEventListener = function (root, event_name) {
+        var element = this.nodes[root];
+        element.removeAttribute("dioxus-event-".concat(event_name));
+        this.listeners[event_name]--;
+        if (this.listeners[event_name] === 0) {
+            this.root.removeEventListener(event_name, this.handlers[event_name]);
+            delete this.listeners[event_name];
+            delete this.handlers[event_name];
+        }
     };
     Interpreter.prototype.SetText = function (root, text) {
         this.nodes[root].textContent = text;
@@ -369,7 +388,6 @@ var Interpreter = /** @class */ (function () {
         }
     };
     Interpreter.prototype.handleEdits = function (edits) {
-        console.log("handling edits ", edits);
         this.stack.push(this.root);
         for (var _i = 0, edits_1 = edits; _i < edits_1.length; _i++) {
             var edit = edits_1[_i];
@@ -409,13 +427,13 @@ var Interpreter = /** @class */ (function () {
                 this.CreatePlaceholder(edit.root);
                 break;
             case "RemoveEventListener":
-                this.RemoveEventListener(edit.root, edit.event_name, edit.scope);
+                this.RemoveEventListener(edit.root, edit.event_name);
                 break;
             case "NewEventListener":
                 // todo: only on desktop should we make our own handler
                 var handler = function (event) {
                     var target = event.target;
-                    console.log("event", event);
+                    // console.log("event", event);
                     if (target != null) {
                         var real_id = target.getAttribute("dioxus-id");
                         var should_prevent_default = target.getAttribute("dioxus-prevent-default");
@@ -429,12 +447,11 @@ var Interpreter = /** @class */ (function () {
                         window.rpc.call("user_event", {
                             event: edit.event_name,
                             mounted_dom_id: parseInt(real_id),
-                            contents: contents
+                            contents: contents,
                         });
                     }
                 };
-                this.NewEventListener(edit.event_name, edit.scope, edit.root);
-                // this.NewEventListener(edit, handler);
+                this.NewEventListener(edit.event_name, edit.scope, edit.root, handler);
                 break;
             case "SetText":
                 this.SetText(edit.root, edit.text);
@@ -449,7 +466,7 @@ var Interpreter = /** @class */ (function () {
     };
     return Interpreter;
 }());
-exports.Interpreter = Interpreter;
+export { Interpreter };
 function main() {
     var root = window.document.getElementById("main");
     if (root != null) {
@@ -457,4 +474,4 @@ function main() {
         window.rpc.call("initialize");
     }
 }
-main();
+//# sourceMappingURL=interpreter.js.map

+ 49 - 28
packages/jsinterpreter/interpreter.ts

@@ -1,23 +1,23 @@
-
-
 function serialize_event(event: Event) {
   switch (event.type) {
     case "copy":
     case "cut":
-    case "past":
+    case "past": {
       return {};
+    }
 
     case "compositionend":
     case "compositionstart":
-    case "compositionupdate":
+    case "compositionupdate": {
       let { data } = (event as CompositionEvent);
       return {
         data,
       };
+    }
 
     case "keydown":
     case "keypress":
-    case "keyup":
+    case "keyup": {
       let {
         charCode,
         key,
@@ -44,12 +44,14 @@ function serialize_event(event: Event) {
         which: which,
         locale: "locale",
       };
+    }
 
     case "focus":
-    case "blur":
+    case "blur": {
       return {};
+    }
 
-    case "change":
+    case "change": {
       let target = event.target as HTMLInputElement;
       let value;
       if (target.type === "checkbox" || target.type === "radio") {
@@ -61,6 +63,7 @@ function serialize_event(event: Event) {
       return {
         value: value,
       };
+    }
 
     case "input":
     case "invalid":
@@ -187,8 +190,9 @@ function serialize_event(event: Event) {
       };
     }
 
-    case "select":
+    case "select": {
       return {};
+    }
 
     case "touchcancel":
     case "touchend":
@@ -211,8 +215,10 @@ function serialize_event(event: Event) {
       };
     }
 
-    case "scroll":
+    case "scroll": {
       return {};
+    }
+
     case "wheel": {
       const {
         deltaX,
@@ -278,14 +284,17 @@ function serialize_event(event: Event) {
     case "suspend":
     case "timeupdate":
     case "volumechange":
-    case "waiting":
+    case "waiting": {
       return {};
+    }
 
-    case "toggle":
+    case "toggle": {
       return {};
+    }
 
-    default:
+    default: {
       return {};
+    }
   }
 }
 
@@ -321,7 +330,8 @@ const bool_attrs = {
 export class Interpreter {
   root: Element;
   stack: Element[];
-  listeners: { [key: string]: (event: Event) => void };
+  listeners: { [key: string]: number };
+  handlers: { [key: string]: (evt: Event) => void };
   lastNodeWasText: boolean;
   nodes: Element[];
 
@@ -329,8 +339,8 @@ export class Interpreter {
   constructor(root: Element) {
     this.root = root;
     this.stack = [root];
-    this.listeners = {
-    };
+    this.listeners = {};
+    this.handlers = {};
     this.lastNodeWasText = false;
     this.nodes = [root];
   }
@@ -412,23 +422,36 @@ export class Interpreter {
     this.nodes[root] = el;
   }
 
-  NewEventListener(event_name: string, scope: number, root: number) {
-    console.log('new event listener', event_name, root, scope);
+  NewEventListener(event_name: string, scope: number, root: number, handler: (evt: Event) => void) {
+    // console.log('new event listener', event_name, root, scope);
     const element = this.nodes[root];
     element.setAttribute(
       `dioxus-event-${event_name}`,
       `${scope}.${root}`
     );
 
-    // if (!this.listeners[event_name]) {
-    //   this.listeners[event_name] = handler;
-    //   this.root.addEventListener(event_name, handler);
-    // }
+    if (this.listeners[event_name] === undefined) {
+      this.listeners[event_name] = 0;
+      this.handlers[event_name] = handler;
+      this.root.addEventListener(event_name, handler);
+    } else {
+      this.listeners[event_name]++;
+    }
   }
 
+  RemoveEventListener(root: number, event_name: string) {
+    const element = this.nodes[root];
+    element.removeAttribute(
+      `dioxus-event-${event_name}`
+    );
 
-  RemoveEventListener(root: number, event_name: string, scope: number) {
-    //
+    this.listeners[event_name]--;
+
+    if (this.listeners[event_name] === 0) {
+      this.root.removeEventListener(event_name, this.handlers[event_name]);
+      delete this.listeners[event_name];
+      delete this.handlers[event_name];
+    }
   }
 
 
@@ -492,7 +515,6 @@ export class Interpreter {
   }
 
   handleEdits(edits: DomEdit[]) {
-    console.log("handling edits ", edits);
     this.stack.push(this.root);
 
     for (let edit of edits) {
@@ -533,13 +555,13 @@ export class Interpreter {
         this.CreatePlaceholder(edit.root);
         break;
       case "RemoveEventListener":
-        this.RemoveEventListener(edit.root, edit.event_name, edit.scope);
+        this.RemoveEventListener(edit.root, edit.event_name);
         break;
       case "NewEventListener":
         // todo: only on desktop should we make our own handler
         let handler = (event: Event) => {
           const target = event.target as Element | null;
-          console.log("event", event);
+          // console.log("event", event);
           if (target != null) {
 
             const real_id = target.getAttribute(`dioxus-id`);
@@ -565,8 +587,7 @@ export class Interpreter {
             });
           }
         };
-        this.NewEventListener(edit.event_name, edit.scope, edit.root);
-        // this.NewEventListener(edit, handler);
+        this.NewEventListener(edit.event_name, edit.scope, edit.root, handler);
         break;
       case "SetText":
         this.SetText(edit.root, edit.text);

+ 9 - 5
packages/jsinterpreter/tsconfig.json

@@ -1,9 +1,13 @@
 {
     "compilerOptions": {
-        "target": "es5",
-        "module": "commonjs",
-        "strict": true,
-        "outDir": "dist",
-        "sourceMap": true
+        "target": "ES5",
+        "module": "ESNext",
+        "lib": [
+            "es2015",
+            "es5",
+            "es6",
+            "dom"
+        ],
+        "strict": true
     }
 }

+ 11 - 5
packages/web/src/bindings.rs

@@ -1,8 +1,8 @@
-use dioxus_core::DomEdit;
-use wasm_bindgen::{convert::IntoWasmAbi, describe::WasmDescribe, prelude::*};
-use web_sys::{Element, HtmlElement, Node};
+use js_sys::Function;
+use wasm_bindgen::prelude::*;
+use web_sys::{Element, Node};
 
-#[wasm_bindgen(module = "/src/interpreter.js")]
+#[wasm_bindgen(module = "/../jsinterpreter/interpreter.js")]
 extern "C" {
     pub type Interpreter;
 
@@ -43,7 +43,13 @@ extern "C" {
     pub fn CreatePlaceholder(this: &Interpreter, root: u64);
 
     #[wasm_bindgen(method)]
-    pub fn NewEventListener(this: &Interpreter, name: &str, scope: usize, root: u64);
+    pub fn NewEventListener(
+        this: &Interpreter,
+        name: &str,
+        scope: usize,
+        root: u64,
+        handler: &Function,
+    );
 
     #[wasm_bindgen(method)]
     pub fn RemoveEventListener(this: &Interpreter, root: u64, name: &str);

+ 1 - 1
packages/web/src/cache.rs

@@ -1,4 +1,4 @@
-pub static BUILTIN_INTERNED_STRINGS: &[&'static str] = &[
+pub static BUILTIN_INTERNED_STRINGS: &[&str] = &[
     // Important tags to dioxus
     "dioxus-id",
     "dioxus",

+ 2 - 3
packages/web/src/cfg.rs

@@ -3,10 +3,9 @@
 /// This struct helps configure the specifics of hydration and render destination for WebSys.
 ///
 /// # Example
+///
 /// ```rust, ignore
-/// fn main() {
-///     dioxus::web::launch(App, |cfg| cfg.hydrate(true).root_name("myroot"))
-/// }
+/// dioxus::web::launch(App, |cfg| cfg.hydrate(true).root_name("myroot"))
 /// ```
 pub struct WebConfig {
     pub(crate) hydrate: bool,

+ 34 - 60
packages/web/src/dom.rs

@@ -8,51 +8,50 @@
 //! - Partial delegation?>
 
 use crate::bindings::Interpreter;
-use dioxus_core::{DomEdit, ElementId, SchedulerMsg, ScopeId, UserEvent};
-use fxhash::FxHashMap;
-use std::{any::Any, fmt::Debug, rc::Rc, sync::Arc};
-use wasm_bindgen::{closure::Closure, JsCast, JsValue};
-use web_sys::{
-    CssStyleDeclaration, Document, Element, Event, HtmlElement, HtmlInputElement,
-    HtmlOptionElement, HtmlTextAreaElement, Node,
-};
+use dioxus_core::{DomEdit, ElementId, SchedulerMsg, UserEvent};
+use js_sys::Function;
+use std::{any::Any, rc::Rc, sync::Arc};
+use wasm_bindgen::{closure::Closure, JsCast};
+use web_sys::{Document, Element, Event, HtmlElement};
 
-use crate::{nodeslab::NodeSlab, WebConfig};
+use crate::WebConfig;
 
 pub struct WebsysDom {
-    document: Document,
-
     pub interpreter: Interpreter,
 
     pub(crate) root: Element,
 
-    sender_callback: Rc<dyn Fn(SchedulerMsg)>,
-
-    // map of listener types to number of those listeners
-    // This is roughly a delegater
-    // TODO: check how infero delegates its events - some are more performant
-    listeners: FxHashMap<&'static str, ListenerEntry>,
+    handler: Closure<dyn FnMut(&Event)>,
 }
 
-type ListenerEntry = (usize, Closure<dyn FnMut(&Event)>);
-
 impl WebsysDom {
     pub fn new(cfg: WebConfig, sender_callback: Rc<dyn Fn(SchedulerMsg)>) -> Self {
-        let document = load_document();
-
-        let listeners = FxHashMap::default();
+        // 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| {
+            if let Ok(synthetic_event) = decode_trigger(event) {
+                // Try to prevent default if the attribute is set
+                if let Some(target) = event.target() {
+                    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();
+                            }
+                        }
+                    }
+                }
 
-        let mut stack = Stack::with_capacity(10);
+                sender_callback.as_ref()(SchedulerMsg::Event(synthetic_event))
+            }
+        });
 
         let root = load_document().get_element_by_id(&cfg.rootname).unwrap();
-        let root_node = root.clone().dyn_into::<Node>().unwrap();
-        stack.push(root_node);
 
         Self {
             interpreter: Interpreter::new(root.clone()),
-            listeners,
-            document,
-            sender_callback,
+            handler: Closure::wrap(callback),
             root,
         }
     }
@@ -78,7 +77,12 @@ impl WebsysDom {
                     event_name,
                     scope,
                     root,
-                } => self.interpreter.NewEventListener(event_name, scope.0, root),
+                } => {
+                    //
+                    let handler: &Function = self.handler.as_ref().unchecked_ref();
+                    self.interpreter
+                        .NewEventListener(event_name, scope.0, root, handler);
+                }
                 DomEdit::RemoveEventListener { root, event } => {
                     self.interpreter.RemoveEventListener(root, event)
                 }
@@ -97,37 +101,6 @@ impl WebsysDom {
     }
 }
 
-#[derive(Debug, Default)]
-struct Stack {
-    list: Vec<Node>,
-}
-
-impl Stack {
-    #[inline]
-    fn with_capacity(cap: usize) -> Self {
-        Stack {
-            list: Vec::with_capacity(cap),
-        }
-    }
-
-    #[inline]
-    fn push(&mut self, node: Node) {
-        self.list.push(node);
-    }
-
-    #[inline]
-    fn pop(&mut self) -> Node {
-        self.list.pop().unwrap()
-    }
-
-    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"),
-        }
-    }
-}
-
 pub struct DioxusWebsysEvent(web_sys::Event);
 
 // safety: currently the web is not multithreaded and our VirtualDom exists on the same thread
@@ -267,6 +240,7 @@ fn virtual_event_from_websys_event(event: web_sys::Event) -> Arc<dyn Any + Send
                 shift_key: evt.shift_key(),
             })
         }
+
         "scroll" => Arc::new(()),
         "wheel" => {
             let evt: &web_sys::WheelEvent = event.dyn_ref().unwrap();

+ 0 - 529
packages/web/src/interpreter.js

@@ -1,529 +0,0 @@
-"use strict";
-var exports = {};
-exports.__esModule = true;
-exports.Interpreter = void 0;
-function serialize_event(event) {
-  var _a, _b;
-  switch (event.type) {
-    case "copy":
-    case "cut":
-    case "past":
-      return {};
-    case "compositionend":
-    case "compositionstart":
-    case "compositionupdate":
-      var data = event.data;
-      return {
-        data: data,
-      };
-    case "keydown":
-    case "keypress":
-    case "keyup":
-      var _c = event,
-        charCode = _c.charCode,
-        key = _c.key,
-        altKey = _c.altKey,
-        ctrlKey = _c.ctrlKey,
-        metaKey = _c.metaKey,
-        keyCode = _c.keyCode,
-        shiftKey = _c.shiftKey,
-        location_1 = _c.location,
-        repeat = _c.repeat,
-        which = _c.which;
-      return {
-        char_code: charCode,
-        key: key,
-        alt_key: altKey,
-        ctrl_key: ctrlKey,
-        meta_key: metaKey,
-        key_code: keyCode,
-        shift_key: shiftKey,
-        location: location_1,
-        repeat: repeat,
-        which: which,
-        locale: "locale",
-      };
-    case "focus":
-    case "blur":
-      return {};
-    case "change":
-      var target = event.target;
-      var value = void 0;
-      if (target.type === "checkbox" || target.type === "radio") {
-        value = target.checked ? "true" : "false";
-      } else {
-        value =
-          (_a = target.value) !== null && _a !== void 0
-            ? _a
-            : target.textContent;
-      }
-      return {
-        value: value,
-      };
-    case "input":
-    case "invalid":
-    case "reset":
-    case "submit": {
-      var target_1 = event.target;
-      var value_1 =
-        (_b = target_1.value) !== null && _b !== void 0
-          ? _b
-          : target_1.textContent;
-      if (target_1.type == "checkbox") {
-        value_1 = target_1.checked ? "true" : "false";
-      }
-      return {
-        value: value_1,
-      };
-    }
-    case "click":
-    case "contextmenu":
-    case "doubleclick":
-    case "drag":
-    case "dragend":
-    case "dragenter":
-    case "dragexit":
-    case "dragleave":
-    case "dragover":
-    case "dragstart":
-    case "drop":
-    case "mousedown":
-    case "mouseenter":
-    case "mouseleave":
-    case "mousemove":
-    case "mouseout":
-    case "mouseover":
-    case "mouseup": {
-      var _d = event,
-        altKey_1 = _d.altKey,
-        button = _d.button,
-        buttons = _d.buttons,
-        clientX = _d.clientX,
-        clientY = _d.clientY,
-        ctrlKey_1 = _d.ctrlKey,
-        metaKey_1 = _d.metaKey,
-        pageX = _d.pageX,
-        pageY = _d.pageY,
-        screenX_1 = _d.screenX,
-        screenY_1 = _d.screenY,
-        shiftKey_1 = _d.shiftKey;
-      return {
-        alt_key: altKey_1,
-        button: button,
-        buttons: buttons,
-        client_x: clientX,
-        client_y: clientY,
-        ctrl_key: ctrlKey_1,
-        meta_key: metaKey_1,
-        page_x: pageX,
-        page_y: pageY,
-        screen_x: screenX_1,
-        screen_y: screenY_1,
-        shift_key: shiftKey_1,
-      };
-    }
-    case "pointerdown":
-    case "pointermove":
-    case "pointerup":
-    case "pointercancel":
-    case "gotpointercapture":
-    case "lostpointercapture":
-    case "pointerenter":
-    case "pointerleave":
-    case "pointerover":
-    case "pointerout": {
-      var _e = event,
-        altKey_2 = _e.altKey,
-        button = _e.button,
-        buttons = _e.buttons,
-        clientX = _e.clientX,
-        clientY = _e.clientY,
-        ctrlKey_2 = _e.ctrlKey,
-        metaKey_2 = _e.metaKey,
-        pageX = _e.pageX,
-        pageY = _e.pageY,
-        screenX_2 = _e.screenX,
-        screenY_2 = _e.screenY,
-        shiftKey_2 = _e.shiftKey,
-        pointerId = _e.pointerId,
-        width = _e.width,
-        height = _e.height,
-        pressure = _e.pressure,
-        tangentialPressure = _e.tangentialPressure,
-        tiltX = _e.tiltX,
-        tiltY = _e.tiltY,
-        twist = _e.twist,
-        pointerType = _e.pointerType,
-        isPrimary = _e.isPrimary;
-      return {
-        alt_key: altKey_2,
-        button: button,
-        buttons: buttons,
-        client_x: clientX,
-        client_y: clientY,
-        ctrl_key: ctrlKey_2,
-        meta_key: metaKey_2,
-        page_x: pageX,
-        page_y: pageY,
-        screen_x: screenX_2,
-        screen_y: screenY_2,
-        shift_key: shiftKey_2,
-        pointer_id: pointerId,
-        width: width,
-        height: height,
-        pressure: pressure,
-        tangential_pressure: tangentialPressure,
-        tilt_x: tiltX,
-        tilt_y: tiltY,
-        twist: twist,
-        pointer_type: pointerType,
-        is_primary: isPrimary,
-      };
-    }
-    case "select":
-      return {};
-    case "touchcancel":
-    case "touchend":
-    case "touchmove":
-    case "touchstart": {
-      var _f = event,
-        altKey_3 = _f.altKey,
-        ctrlKey_3 = _f.ctrlKey,
-        metaKey_3 = _f.metaKey,
-        shiftKey_3 = _f.shiftKey;
-      return {
-        // changed_touches: event.changedTouches,
-        // target_touches: event.targetTouches,
-        // touches: event.touches,
-        alt_key: altKey_3,
-        ctrl_key: ctrlKey_3,
-        meta_key: metaKey_3,
-        shift_key: shiftKey_3,
-      };
-    }
-    case "scroll":
-      return {};
-    case "wheel": {
-      var _g = event,
-        deltaX = _g.deltaX,
-        deltaY = _g.deltaY,
-        deltaZ = _g.deltaZ,
-        deltaMode = _g.deltaMode;
-      return {
-        delta_x: deltaX,
-        delta_y: deltaY,
-        delta_z: deltaZ,
-        delta_mode: deltaMode,
-      };
-    }
-    case "animationstart":
-    case "animationend":
-    case "animationiteration": {
-      var _h = event,
-        animationName = _h.animationName,
-        elapsedTime = _h.elapsedTime,
-        pseudoElement = _h.pseudoElement;
-      return {
-        animation_name: animationName,
-        elapsed_time: elapsedTime,
-        pseudo_element: pseudoElement,
-      };
-    }
-    case "transitionend": {
-      var _j = event,
-        propertyName = _j.propertyName,
-        elapsedTime = _j.elapsedTime,
-        pseudoElement = _j.pseudoElement;
-      return {
-        property_name: propertyName,
-        elapsed_time: elapsedTime,
-        pseudo_element: pseudoElement,
-      };
-    }
-    case "abort":
-    case "canplay":
-    case "canplaythrough":
-    case "durationchange":
-    case "emptied":
-    case "encrypted":
-    case "ended":
-    case "error":
-    case "loadeddata":
-    case "loadedmetadata":
-    case "loadstart":
-    case "pause":
-    case "play":
-    case "playing":
-    case "progress":
-    case "ratechange":
-    case "seeked":
-    case "seeking":
-    case "stalled":
-    case "suspend":
-    case "timeupdate":
-    case "volumechange":
-    case "waiting":
-      return {};
-    case "toggle":
-      return {};
-    default:
-      return {};
-  }
-}
-var bool_attrs = {
-  allowfullscreen: true,
-  allowpaymentrequest: true,
-  async: true,
-  autofocus: true,
-  autoplay: true,
-  checked: true,
-  controls: true,
-  default: true,
-  defer: true,
-  disabled: true,
-  formnovalidate: true,
-  hidden: true,
-  ismap: true,
-  itemscope: true,
-  loop: true,
-  multiple: true,
-  muted: true,
-  nomodule: true,
-  novalidate: true,
-  open: true,
-  playsinline: true,
-  readonly: true,
-  required: true,
-  reversed: true,
-  selected: true,
-  truespeed: true,
-};
-export var Interpreter = /** @class */ (function () {
-  function Interpreter(root) {
-    this.root = root;
-    this.stack = [root];
-    this.listeners = {};
-    this.lastNodeWasText = false;
-    this.nodes = [root];
-  }
-  Interpreter.prototype.top = function () {
-    return this.stack[this.stack.length - 1];
-  };
-  Interpreter.prototype.pop = function () {
-    return this.stack.pop();
-  };
-  Interpreter.prototype.PushRoot = function (root) {
-    var node = this.nodes[root];
-    this.stack.push(node);
-  };
-  Interpreter.prototype.AppendChildren = function (many) {
-    var root = this.stack[this.stack.length - (1 + many)];
-    var to_add = this.stack.splice(this.stack.length - many);
-    for (var i = 0; i < many; i++) {
-      root.appendChild(to_add[i]);
-    }
-  };
-  Interpreter.prototype.ReplaceWith = function (root_id, m) {
-    var root = this.nodes[root_id];
-    var els = this.stack.splice(this.stack.length - m);
-    root.replaceWith.apply(root, els);
-  };
-  Interpreter.prototype.InsertAfter = function (root, n) {
-    var old = this.nodes[root];
-    var new_nodes = this.stack.splice(this.stack.length - n);
-    old.after.apply(old, new_nodes);
-  };
-  Interpreter.prototype.InsertBefore = function (root, n) {
-    var old = this.nodes[root];
-    var new_nodes = this.stack.splice(this.stack.length - n);
-    old.before.apply(old, new_nodes);
-  };
-  Interpreter.prototype.Remove = function (root) {
-    var node = this.nodes[root];
-    if (node !== undefined) {
-      node.remove();
-    }
-  };
-  Interpreter.prototype.CreateTextNode = function (text, root) {
-    // todo: make it so the types are okay
-    var node = document.createTextNode(text);
-    this.nodes[root] = node;
-    this.stack.push(node);
-  };
-  Interpreter.prototype.CreateElement = function (tag, root) {
-    var el = document.createElement(tag);
-    el.setAttribute("dioxus-id", "".concat(root));
-    this.nodes[root] = el;
-    this.stack.push(el);
-  };
-  Interpreter.prototype.CreateElementNs = function (tag, root, ns) {
-    var el = document.createElementNS(ns, tag);
-    this.stack.push(el);
-    this.nodes[root] = el;
-  };
-  Interpreter.prototype.CreatePlaceholder = function (root) {
-    var el = document.createElement("pre");
-    el.hidden = true;
-    this.stack.push(el);
-    this.nodes[root] = el;
-  };
-  Interpreter.prototype.NewEventListener = function (event_name, scope, root) {
-    console.log("new event listener", event_name, root, scope);
-    var element = this.nodes[root];
-    element.setAttribute(
-      "dioxus-event-".concat(event_name),
-      "".concat(scope, ".").concat(root)
-    );
-    // if (!this.listeners[event_name]) {
-    //   this.listeners[event_name] = handler;
-    //   this.root.addEventListener(event_name, handler);
-    // }
-  };
-  Interpreter.prototype.RemoveEventListener = function (
-    root,
-    event_name,
-    scope
-  ) {
-    //
-  };
-  Interpreter.prototype.SetText = function (root, text) {
-    this.nodes[root].textContent = text;
-  };
-  Interpreter.prototype.SetAttribute = function (root, field, value, ns) {
-    var name = field;
-    var node = this.nodes[root];
-    if (ns == "style") {
-      // @ts-ignore
-      node.style[name] = value;
-    } else if (ns != null || ns != undefined) {
-      node.setAttributeNS(ns, name, value);
-    } else {
-      switch (name) {
-        case "value":
-          if (value != node.value) {
-            node.value = value;
-          }
-          break;
-        case "checked":
-          node.checked = value === "true";
-          break;
-        case "selected":
-          node.selected = value === "true";
-          break;
-        case "dangerous_inner_html":
-          node.innerHTML = value;
-          break;
-        default:
-          // https://github.com/facebook/react/blob/8b88ac2592c5f555f315f9440cbb665dd1e7457a/packages/react-dom/src/shared/DOMProperty.js#L352-L364
-          if (value == "false" && bool_attrs.hasOwnProperty(name)) {
-            node.removeAttribute(name);
-          } else {
-            node.setAttribute(name, value);
-          }
-      }
-    }
-  };
-  Interpreter.prototype.RemoveAttribute = function (root, name) {
-    var node = this.nodes[root];
-    node.removeAttribute(name);
-    if (name === "value") {
-      node.value = "";
-    }
-    if (name === "checked") {
-      node.checked = false;
-    }
-    if (name === "selected") {
-      node.selected = false;
-    }
-  };
-  Interpreter.prototype.handleEdits = function (edits) {
-    console.log("handling edits ", edits);
-    this.stack.push(this.root);
-    for (var _i = 0, edits_1 = edits; _i < edits_1.length; _i++) {
-      var edit = edits_1[_i];
-      this.handleEdit(edit);
-    }
-  };
-  Interpreter.prototype.handleEdit = function (edit) {
-    switch (edit.type) {
-      case "PushRoot":
-        this.PushRoot(edit.root);
-        break;
-      case "AppendChildren":
-        this.AppendChildren(edit.many);
-        break;
-      case "ReplaceWith":
-        this.ReplaceWith(edit.root, edit.m);
-        break;
-      case "InsertAfter":
-        this.InsertAfter(edit.root, edit.n);
-        break;
-      case "InsertBefore":
-        this.InsertBefore(edit.root, edit.n);
-        break;
-      case "Remove":
-        this.Remove(edit.root);
-        break;
-      case "CreateTextNode":
-        this.CreateTextNode(edit.text, edit.root);
-        break;
-      case "CreateElement":
-        this.CreateElement(edit.tag, edit.root);
-        break;
-      case "CreateElementNs":
-        this.CreateElementNs(edit.tag, edit.root, edit.ns);
-        break;
-      case "CreatePlaceholder":
-        this.CreatePlaceholder(edit.root);
-        break;
-      case "RemoveEventListener":
-        this.RemoveEventListener(edit.root, edit.event_name, edit.scope);
-        break;
-      case "NewEventListener":
-        // todo: only on desktop should we make our own handler
-        var handler = function (event) {
-          var target = event.target;
-          console.log("event", event);
-          if (target != null) {
-            var real_id = target.getAttribute("dioxus-id");
-            var should_prevent_default = target.getAttribute(
-              "dioxus-prevent-default"
-            );
-            var contents = serialize_event(event);
-            if (should_prevent_default === "on".concat(event.type)) {
-              event.preventDefault();
-            }
-            if (real_id == null) {
-              return;
-            }
-            window.rpc.call("user_event", {
-              event: edit.event_name,
-              mounted_dom_id: parseInt(real_id),
-              contents: contents,
-            });
-          }
-        };
-        this.NewEventListener(edit.event_name, edit.scope, edit.root);
-        // this.NewEventListener(edit, handler);
-        break;
-      case "SetText":
-        this.SetText(edit.root, edit.text);
-        break;
-      case "SetAttribute":
-        this.SetAttribute(edit.root, edit.field, edit.value, edit.ns);
-        break;
-      case "RemoveAttribute":
-        this.RemoveAttribute(edit.root, edit.name);
-        break;
-    }
-  };
-  return Interpreter;
-})();
-exports.Interpreter = Interpreter;
-function main() {
-  var root = window.document.getElementById("main");
-  if (root != null) {
-    window.interpreter = new Interpreter(root);
-    window.rpc.call("initialize");
-  }
-}

+ 0 - 1
packages/web/src/lib.rs

@@ -65,7 +65,6 @@ pub(crate) mod bindings;
 mod cache;
 mod cfg;
 mod dom;
-mod nodeslab;
 mod rehydrate;
 mod ric_raf;
 

+ 0 - 34
packages/web/src/nodeslab.rs

@@ -1,34 +0,0 @@
-//! This module provides a mirror of the VirtualDOM Element Slab using a Vector.
-
-use std::ops::{Index, IndexMut};
-use web_sys::Node;
-
-pub(crate) struct NodeSlab {
-    nodes: Vec<Option<Node>>,
-}
-
-impl NodeSlab {
-    pub fn new(capacity: usize) -> NodeSlab {
-        let nodes = Vec::with_capacity(capacity);
-        NodeSlab { nodes }
-    }
-}
-impl Index<usize> for NodeSlab {
-    type Output = Option<Node>;
-    fn index(&self, index: usize) -> &Self::Output {
-        &self.nodes[index]
-    }
-}
-
-impl IndexMut<usize> for NodeSlab {
-    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
-        if index >= self.nodes.capacity() * 3 {
-            panic!("Trying to mutate an element way too far out of bounds");
-        }
-
-        if index + 1 > self.nodes.len() {
-            self.nodes.resize_with(index + 1, || None);
-        }
-        &mut self.nodes[index]
-    }
-}

+ 68 - 0
packages/web/src/olddom.rs

@@ -787,3 +787,71 @@ fn event_name_from_typ(typ: &str) -> &'static str {
         }
     }
 }
+
+
+//! This module provides a mirror of the VirtualDOM Element Slab using a Vector.
+
+use std::ops::{Index, IndexMut};
+use web_sys::Node;
+
+pub(crate) struct NodeSlab {
+    nodes: Vec<Option<Node>>,
+}
+
+impl NodeSlab {
+    pub fn new(capacity: usize) -> NodeSlab {
+        let nodes = Vec::with_capacity(capacity);
+        NodeSlab { nodes }
+    }
+}
+impl Index<usize> for NodeSlab {
+    type Output = Option<Node>;
+    fn index(&self, index: usize) -> &Self::Output {
+        &self.nodes[index]
+    }
+}
+
+impl IndexMut<usize> for NodeSlab {
+    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+        if index >= self.nodes.capacity() * 3 {
+            panic!("Trying to mutate an element way too far out of bounds");
+        }
+
+        if index + 1 > self.nodes.len() {
+            self.nodes.resize_with(index + 1, || None);
+        }
+        &mut self.nodes[index]
+    }
+}
+
+
+#[derive(Debug, Default)]
+struct Stack {
+    list: Vec<Node>,
+}
+
+impl Stack {
+    #[inline]
+    fn with_capacity(cap: usize) -> Self {
+        Stack {
+            list: Vec::with_capacity(cap),
+        }
+    }
+
+    #[inline]
+    fn push(&mut self, node: Node) {
+        self.list.push(node);
+    }
+
+    #[inline]
+    fn pop(&mut self) -> Node {
+        self.list.pop().unwrap()
+    }
+
+    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"),
+        }
+    }
+}

+ 2 - 2
packages/web/src/rehydrate.rs

@@ -118,7 +118,7 @@ impl WebsysDom {
                 // we cant have the last node be text
                 let mut last_node_was_text = false;
                 for child in vel.children {
-                    self.rehydrate_single(nodes, place, dom, &child, &mut last_node_was_text)?;
+                    self.rehydrate_single(nodes, place, dom, child, &mut last_node_was_text)?;
                 }
 
                 place.pop();
@@ -146,7 +146,7 @@ impl WebsysDom {
 
             VNode::Fragment(el) => {
                 for el in el.children {
-                    self.rehydrate_single(nodes, place, dom, &el, last_node_was_text)?;
+                    self.rehydrate_single(nodes, place, dom, el, last_node_was_text)?;
                 }
             }
 

+ 1 - 2
packages/web/src/ric_raf.rs

@@ -68,8 +68,7 @@ impl RafLoop {
         let ric_fn = self.ric_closure.as_ref().dyn_ref::<Function>().unwrap();
         let _cb_id: u32 = self.window.request_idle_callback(ric_fn).unwrap();
         let deadline = self.ric_receiver.recv().await.unwrap();
-        let deadline = TimeoutFuture::new(deadline);
-        deadline
+        TimeoutFuture::new(deadline)
     }
 
     pub async fn wait_for_raf(&self) {